night-orch 0.3.2 → 0.4.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 (221) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +47 -108
  3. package/dist/cli/commands/doctor.d.ts +1 -0
  4. package/dist/cli/commands/doctor.d.ts.map +1 -1
  5. package/dist/cli/commands/doctor.js +18 -0
  6. package/dist/cli/commands/doctor.js.map +1 -1
  7. package/dist/cli/commands/monitoring.d.ts.map +1 -1
  8. package/dist/cli/commands/monitoring.js +7 -3
  9. package/dist/cli/commands/monitoring.js.map +1 -1
  10. package/dist/cli/commands/settings.d.ts.map +1 -1
  11. package/dist/cli/commands/settings.js +40 -4
  12. package/dist/cli/commands/settings.js.map +1 -1
  13. package/dist/cli/commands/status.d.ts.map +1 -1
  14. package/dist/cli/commands/status.js +26 -3
  15. package/dist/cli/commands/status.js.map +1 -1
  16. package/dist/cli/index.js +3 -2
  17. package/dist/cli/index.js.map +1 -1
  18. package/dist/cli/tui/app.d.ts.map +1 -1
  19. package/dist/cli/tui/app.js +52 -3
  20. package/dist/cli/tui/app.js.map +1 -1
  21. package/dist/cli/tui/header.d.ts.map +1 -1
  22. package/dist/cli/tui/header.js +2 -1
  23. package/dist/cli/tui/header.js.map +1 -1
  24. package/dist/cli/tui/settings-view.d.ts.map +1 -1
  25. package/dist/cli/tui/settings-view.js +22 -5
  26. package/dist/cli/tui/settings-view.js.map +1 -1
  27. package/dist/cli/tui/stats-view.js +2 -2
  28. package/dist/cli/tui/stats-view.js.map +1 -1
  29. package/dist/config/loader.d.ts.map +1 -1
  30. package/dist/config/loader.js +141 -13
  31. package/dist/config/loader.js.map +1 -1
  32. package/dist/config/schema.d.ts +903 -21
  33. package/dist/config/schema.d.ts.map +1 -1
  34. package/dist/config/schema.js +77 -6
  35. package/dist/config/schema.js.map +1 -1
  36. package/dist/forge/types.d.ts +7 -0
  37. package/dist/forge/types.d.ts.map +1 -1
  38. package/dist/git/repo.d.ts +8 -0
  39. package/dist/git/repo.d.ts.map +1 -1
  40. package/dist/git/repo.js +19 -0
  41. package/dist/git/repo.js.map +1 -1
  42. package/dist/git/worktree.d.ts +3 -0
  43. package/dist/git/worktree.d.ts.map +1 -1
  44. package/dist/git/worktree.js +43 -21
  45. package/dist/git/worktree.js.map +1 -1
  46. package/dist/loop/cost.d.ts +33 -8
  47. package/dist/loop/cost.d.ts.map +1 -1
  48. package/dist/loop/cost.js +250 -46
  49. package/dist/loop/cost.js.map +1 -1
  50. package/dist/loop/decision.js +3 -3
  51. package/dist/loop/decision.js.map +1 -1
  52. package/dist/loop/engine.d.ts +1 -0
  53. package/dist/loop/engine.d.ts.map +1 -1
  54. package/dist/loop/engine.js +76 -13
  55. package/dist/loop/engine.js.map +1 -1
  56. package/dist/loop/parallel.d.ts.map +1 -1
  57. package/dist/loop/parallel.js +2 -0
  58. package/dist/loop/parallel.js.map +1 -1
  59. package/dist/loop/pricing.d.ts +11 -4
  60. package/dist/loop/pricing.d.ts.map +1 -1
  61. package/dist/loop/pricing.js +62 -20
  62. package/dist/loop/pricing.js.map +1 -1
  63. package/dist/loop/progress.d.ts +24 -0
  64. package/dist/loop/progress.d.ts.map +1 -0
  65. package/dist/loop/progress.js +52 -0
  66. package/dist/loop/progress.js.map +1 -0
  67. package/dist/loop/step-executor.d.ts +4 -5
  68. package/dist/loop/step-executor.d.ts.map +1 -1
  69. package/dist/loop/step-executor.js +1 -0
  70. package/dist/loop/step-executor.js.map +1 -1
  71. package/dist/loop/types.d.ts +17 -0
  72. package/dist/loop/types.d.ts.map +1 -1
  73. package/dist/mcp/tools/admin.d.ts +29 -0
  74. package/dist/mcp/tools/admin.d.ts.map +1 -0
  75. package/dist/mcp/tools/admin.js +89 -0
  76. package/dist/mcp/tools/admin.js.map +1 -0
  77. package/dist/mcp/tools/auth.d.ts +3 -0
  78. package/dist/mcp/tools/auth.d.ts.map +1 -0
  79. package/dist/mcp/tools/auth.js +19 -0
  80. package/dist/mcp/tools/auth.js.map +1 -0
  81. package/dist/mcp/tools/index.d.ts.map +1 -1
  82. package/dist/mcp/tools/index.js +5 -533
  83. package/dist/mcp/tools/index.js.map +1 -1
  84. package/dist/mcp/tools/operations.d.ts +32 -0
  85. package/dist/mcp/tools/operations.d.ts.map +1 -0
  86. package/dist/mcp/tools/operations.js +95 -0
  87. package/dist/mcp/tools/operations.js.map +1 -0
  88. package/dist/mcp/tools/settings.d.ts +12 -0
  89. package/dist/mcp/tools/settings.d.ts.map +1 -0
  90. package/dist/mcp/tools/settings.js +58 -0
  91. package/dist/mcp/tools/settings.js.map +1 -0
  92. package/dist/mcp/tools/status.d.ts +25 -0
  93. package/dist/mcp/tools/status.d.ts.map +1 -0
  94. package/dist/mcp/tools/status.js +307 -0
  95. package/dist/mcp/tools/status.js.map +1 -0
  96. package/dist/ops/continue.js +6 -1
  97. package/dist/ops/continue.js.map +1 -1
  98. package/dist/ops/project-check.d.ts +15 -0
  99. package/dist/ops/project-check.d.ts.map +1 -0
  100. package/dist/ops/project-check.js +136 -0
  101. package/dist/ops/project-check.js.map +1 -0
  102. package/dist/ops/rebase-and-check.d.ts +2 -1
  103. package/dist/ops/rebase-and-check.d.ts.map +1 -1
  104. package/dist/ops/rebase-and-check.js +2 -2
  105. package/dist/ops/rebase-and-check.js.map +1 -1
  106. package/dist/ops/rebase.d.ts +8 -5
  107. package/dist/ops/rebase.d.ts.map +1 -1
  108. package/dist/ops/rebase.js +43 -29
  109. package/dist/ops/rebase.js.map +1 -1
  110. package/dist/runner/comment-commands.d.ts +20 -0
  111. package/dist/runner/comment-commands.d.ts.map +1 -0
  112. package/dist/runner/comment-commands.js +221 -0
  113. package/dist/runner/comment-commands.js.map +1 -0
  114. package/dist/runner/helpers.d.ts +57 -0
  115. package/dist/runner/helpers.d.ts.map +1 -0
  116. package/dist/runner/helpers.js +259 -0
  117. package/dist/runner/helpers.js.map +1 -0
  118. package/dist/runner/poller.d.ts.map +1 -1
  119. package/dist/runner/poller.js +19 -781
  120. package/dist/runner/poller.js.map +1 -1
  121. package/dist/runner/reaction-scan.d.ts +17 -0
  122. package/dist/runner/reaction-scan.d.ts.map +1 -0
  123. package/dist/runner/reaction-scan.js +33 -0
  124. package/dist/runner/reaction-scan.js.map +1 -0
  125. package/dist/runner/run-finalizer.d.ts +30 -0
  126. package/dist/runner/run-finalizer.d.ts.map +1 -0
  127. package/dist/runner/run-finalizer.js +217 -0
  128. package/dist/runner/run-finalizer.js.map +1 -0
  129. package/dist/settings/definitions/github.d.ts +3 -0
  130. package/dist/settings/definitions/github.d.ts.map +1 -0
  131. package/dist/settings/definitions/github.js +267 -0
  132. package/dist/settings/definitions/github.js.map +1 -0
  133. package/dist/settings/definitions/loop.d.ts +3 -0
  134. package/dist/settings/definitions/loop.d.ts.map +1 -0
  135. package/dist/settings/definitions/loop.js +113 -0
  136. package/dist/settings/definitions/loop.js.map +1 -0
  137. package/dist/settings/definitions/observability.d.ts +3 -0
  138. package/dist/settings/definitions/observability.d.ts.map +1 -0
  139. package/dist/settings/definitions/observability.js +74 -0
  140. package/dist/settings/definitions/observability.js.map +1 -0
  141. package/dist/settings/definitions/security.d.ts +3 -0
  142. package/dist/settings/definitions/security.d.ts.map +1 -0
  143. package/dist/settings/definitions/security.js +121 -0
  144. package/dist/settings/definitions/security.js.map +1 -0
  145. package/dist/settings/registry.d.ts +82 -6
  146. package/dist/settings/registry.d.ts.map +1 -1
  147. package/dist/settings/registry.js +301 -194
  148. package/dist/settings/registry.js.map +1 -1
  149. package/dist/settings/runtime.d.ts +5 -1
  150. package/dist/settings/runtime.d.ts.map +1 -1
  151. package/dist/settings/runtime.js +46 -9
  152. package/dist/settings/runtime.js.map +1 -1
  153. package/dist/state/db.d.ts.map +1 -1
  154. package/dist/state/db.js +2 -0
  155. package/dist/state/db.js.map +1 -1
  156. package/dist/state/migrations/020-cost-ledger.d.ts +3 -0
  157. package/dist/state/migrations/020-cost-ledger.d.ts.map +1 -0
  158. package/dist/state/migrations/020-cost-ledger.js +37 -0
  159. package/dist/state/migrations/020-cost-ledger.js.map +1 -0
  160. package/dist/state/runs.d.ts +1 -0
  161. package/dist/state/runs.d.ts.map +1 -1
  162. package/dist/state/runs.js +3 -0
  163. package/dist/state/runs.js.map +1 -1
  164. package/dist/state/stats.d.ts +20 -0
  165. package/dist/state/stats.d.ts.map +1 -1
  166. package/dist/state/stats.js +68 -8
  167. package/dist/state/stats.js.map +1 -1
  168. package/dist/utils/logger.d.ts +9 -0
  169. package/dist/utils/logger.d.ts.map +1 -1
  170. package/dist/utils/logger.js +13 -0
  171. package/dist/utils/logger.js.map +1 -1
  172. package/dist/web/routes/api-events.d.ts +10 -0
  173. package/dist/web/routes/api-events.d.ts.map +1 -0
  174. package/dist/web/routes/api-events.js +251 -0
  175. package/dist/web/routes/api-events.js.map +1 -0
  176. package/dist/web/routes/api-operations.d.ts +3 -0
  177. package/dist/web/routes/api-operations.d.ts.map +1 -0
  178. package/dist/web/routes/api-operations.js +371 -0
  179. package/dist/web/routes/api-operations.js.map +1 -0
  180. package/dist/web/routes/api-runs.d.ts +3 -0
  181. package/dist/web/routes/api-runs.d.ts.map +1 -0
  182. package/dist/web/routes/api-runs.js +96 -0
  183. package/dist/web/routes/api-runs.js.map +1 -0
  184. package/dist/web/routes/api-settings.d.ts +3 -0
  185. package/dist/web/routes/api-settings.d.ts.map +1 -0
  186. package/dist/web/routes/api-settings.js +61 -0
  187. package/dist/web/routes/api-settings.js.map +1 -0
  188. package/dist/web/routes/context.d.ts +15 -0
  189. package/dist/web/routes/context.d.ts.map +1 -0
  190. package/dist/web/routes/context.js +2 -0
  191. package/dist/web/routes/context.js.map +1 -0
  192. package/dist/web/server.d.ts +58 -1
  193. package/dist/web/server.d.ts.map +1 -1
  194. package/dist/web/server.js +116 -847
  195. package/dist/web/server.js.map +1 -1
  196. package/dist/web/shell-session.d.ts +74 -0
  197. package/dist/web/shell-session.d.ts.map +1 -0
  198. package/dist/web/shell-session.js +279 -0
  199. package/dist/web/shell-session.js.map +1 -0
  200. package/dist/web/snapshots.d.ts +159 -0
  201. package/dist/web/snapshots.d.ts.map +1 -0
  202. package/dist/web/snapshots.js +231 -0
  203. package/dist/web/snapshots.js.map +1 -0
  204. package/dist/workers/acp.d.ts.map +1 -1
  205. package/dist/workers/acp.js +116 -0
  206. package/dist/workers/acp.js.map +1 -1
  207. package/dist/workers/claude.d.ts.map +1 -1
  208. package/dist/workers/claude.js +13 -3
  209. package/dist/workers/claude.js.map +1 -1
  210. package/dist/workers/codex.d.ts.map +1 -1
  211. package/dist/workers/codex.js +16 -4
  212. package/dist/workers/codex.js.map +1 -1
  213. package/dist/workers/types.d.ts +14 -4
  214. package/dist/workers/types.d.ts.map +1 -1
  215. package/examples/config.example.yaml +12 -3
  216. package/package.json +8 -2
  217. package/web/dist/assets/index-BIrXUwFe.css +1 -0
  218. package/web/dist/assets/index-COMzHPcP.js +26 -0
  219. package/web/dist/index.html +2 -2
  220. package/web/dist/assets/index-k6kgdnzy.js +0 -9
  221. package/web/dist/assets/index-xm9qPlYB.css +0 -1
@@ -1,20 +1,28 @@
1
+ import type { z } from 'zod';
1
2
  import type { Config } from '../config/schema.js';
2
- export type SettingKey = 'github.pollIntervalSeconds' | 'security.maxDailyCostUsd' | 'security.maxCostPerRunUsd' | 'loop.maxReviewIterations' | 'loop.maxTotalAgentPasses' | 'observability.agentStreaming';
3
- export type SettingValue = number | boolean;
4
- export type SettingType = 'number' | 'boolean';
3
+ export type SettingKey = string;
4
+ export type JsonValue = string | number | boolean | null | JsonValue[] | {
5
+ [key: string]: JsonValue;
6
+ };
7
+ export type SettingValue = JsonValue;
8
+ export type SettingType = 'number' | 'boolean' | 'string' | 'json';
9
+ type SettingPath = readonly [string, ...string[]];
5
10
  interface SettingDefinitionBase<K extends SettingKey, V extends SettingValue> {
6
11
  key: K;
7
12
  label: string;
8
13
  description: string;
9
14
  details: string;
10
15
  type: SettingType;
11
- defaultValue: V;
12
- yamlPath: readonly [string, ...string[]];
16
+ mutable: boolean;
17
+ sensitive: boolean;
18
+ defaultValue: V | null;
19
+ yamlPath: SettingPath;
13
20
  read: (config: Config) => V;
14
21
  apply: (config: Config, value: V) => Config;
15
22
  parseInput: (raw: unknown) => V;
16
23
  parseStored: (raw: string) => V;
17
24
  serialize: (value: V) => string;
25
+ sanitizeForDisplay: (value: V) => SettingValue;
18
26
  }
19
27
  export interface NumberSettingDefinition<K extends SettingKey = SettingKey> extends SettingDefinitionBase<K, number> {
20
28
  type: 'number';
@@ -25,13 +33,81 @@ export interface NumberSettingDefinition<K extends SettingKey = SettingKey> exte
25
33
  export interface BooleanSettingDefinition<K extends SettingKey = SettingKey> extends SettingDefinitionBase<K, boolean> {
26
34
  type: 'boolean';
27
35
  }
28
- export type SettingDefinition = NumberSettingDefinition | BooleanSettingDefinition;
36
+ export interface StringSettingDefinition<K extends SettingKey = SettingKey> extends SettingDefinitionBase<K, string | null> {
37
+ type: 'string';
38
+ options?: readonly string[];
39
+ allowNull?: boolean;
40
+ }
41
+ export interface JsonSettingDefinition<K extends SettingKey = SettingKey> extends SettingDefinitionBase<K, JsonValue> {
42
+ type: 'json';
43
+ }
44
+ export type SettingDefinition = NumberSettingDefinition | BooleanSettingDefinition | StringSettingDefinition | JsonSettingDefinition;
29
45
  export interface SettingYamlValue {
30
46
  hasYamlValue: boolean;
31
47
  yamlValue: SettingValue | null;
32
48
  }
33
49
  export declare function listSettingDefinitions(): SettingDefinition[];
34
50
  export declare function getSettingDefinition(key: string): SettingDefinition | null;
51
+ export declare function sanitizeSettingValueForDisplay(definition: SettingDefinition, value: SettingValue | null): SettingValue | null;
35
52
  export declare function resolveSettingYamlValue(definition: SettingDefinition, rawConfig: unknown, baseConfig: Config): SettingYamlValue;
53
+ export interface NumberSettingOptions {
54
+ key: string;
55
+ label: string;
56
+ description: string;
57
+ details: string;
58
+ defaultValue: number;
59
+ yamlPath: SettingPath;
60
+ integer: boolean;
61
+ min?: number;
62
+ max?: number;
63
+ step?: number;
64
+ mutable?: boolean;
65
+ sensitive?: boolean;
66
+ sanitizeForDisplay?: (value: number) => SettingValue;
67
+ }
68
+ export declare function numberSetting(options: NumberSettingOptions): NumberSettingDefinition;
69
+ export interface BooleanSettingOptions {
70
+ key: string;
71
+ label: string;
72
+ description: string;
73
+ details: string;
74
+ defaultValue: boolean;
75
+ yamlPath: SettingPath;
76
+ mutable?: boolean;
77
+ sensitive?: boolean;
78
+ sanitizeForDisplay?: (value: boolean) => SettingValue;
79
+ }
80
+ export declare function booleanSetting(options: BooleanSettingOptions): BooleanSettingDefinition;
81
+ export interface StringSettingOptions {
82
+ key: string;
83
+ label: string;
84
+ description: string;
85
+ details: string;
86
+ defaultValue: string | null;
87
+ yamlPath: SettingPath;
88
+ options?: readonly string[];
89
+ allowNull?: boolean;
90
+ minLength?: number;
91
+ url?: boolean;
92
+ validate?: (value: string) => string | null;
93
+ mutable?: boolean;
94
+ sensitive?: boolean;
95
+ sanitizeForDisplay?: (value: string | null) => SettingValue;
96
+ }
97
+ export declare function stringSetting(options: StringSettingOptions): StringSettingDefinition;
98
+ export interface JsonSettingOptions {
99
+ key: string;
100
+ label: string;
101
+ description: string;
102
+ details: string;
103
+ defaultValue: JsonValue;
104
+ yamlPath: SettingPath;
105
+ mutable?: boolean;
106
+ sensitive?: boolean;
107
+ normalize?: (value: JsonValue) => JsonValue;
108
+ sanitizeForDisplay?: (value: JsonValue) => SettingValue;
109
+ }
110
+ export declare function jsonSetting(options: JsonSettingOptions): JsonSettingDefinition;
111
+ export declare function validateJsonSettingShape<T>(value: JsonValue, schema: z.ZodType<T>, key: string): JsonValue;
36
112
  export {};
37
113
  //# sourceMappingURL=registry.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/settings/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAEjD,MAAM,MAAM,UAAU,GAClB,4BAA4B,GAC5B,0BAA0B,GAC1B,2BAA2B,GAC3B,0BAA0B,GAC1B,0BAA0B,GAC1B,8BAA8B,CAAA;AAElC,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,OAAO,CAAA;AAC3C,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,SAAS,CAAA;AAE9C,UAAU,qBAAqB,CAAC,CAAC,SAAS,UAAU,EAAE,CAAC,SAAS,YAAY;IAC1E,GAAG,EAAE,CAAC,CAAA;IACN,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,MAAM,CAAA;IACnB,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,WAAW,CAAA;IACjB,YAAY,EAAE,CAAC,CAAA;IACf,QAAQ,EAAE,SAAS,CAAC,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC,CAAA;IACxC,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,CAAC,CAAA;IAC3B,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,KAAK,MAAM,CAAA;IAC3C,UAAU,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,CAAC,CAAA;IAC/B,WAAW,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,CAAC,CAAA;IAC/B,SAAS,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,MAAM,CAAA;CAChC;AAED,MAAM,WAAW,uBAAuB,CAAC,CAAC,SAAS,UAAU,GAAG,UAAU,CACxE,SAAQ,qBAAqB,CAAC,CAAC,EAAE,MAAM,CAAC;IACxC,IAAI,EAAE,QAAQ,CAAA;IACd,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,wBAAwB,CAAC,CAAC,SAAS,UAAU,GAAG,UAAU,CACzE,SAAQ,qBAAqB,CAAC,CAAC,EAAE,OAAO,CAAC;IACzC,IAAI,EAAE,SAAS,CAAA;CAChB;AAED,MAAM,MAAM,iBAAiB,GAAG,uBAAuB,GAAG,wBAAwB,CAAA;AAElF,MAAM,WAAW,gBAAgB;IAC/B,YAAY,EAAE,OAAO,CAAA;IACrB,SAAS,EAAE,YAAY,GAAG,IAAI,CAAA;CAC/B;AAgMD,wBAAgB,sBAAsB,IAAI,iBAAiB,EAAE,CAE5D;AAED,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI,CAE1E;AAED,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,iBAAiB,EAC7B,SAAS,EAAE,OAAO,EAClB,UAAU,EAAE,MAAM,GACjB,gBAAgB,CAYlB"}
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/settings/registry.ts"],"names":[],"mappings":"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"}
@@ -1,190 +1,8 @@
1
- const SETTING_DEFINITIONS = {
2
- 'github.pollIntervalSeconds': {
3
- key: 'github.pollIntervalSeconds',
4
- label: 'Poll Interval (seconds)',
5
- description: 'Delay between automatic poll cycles.',
6
- details: 'Controls how often night-orch checks configured repos for work. Lower values react faster but increase API traffic; higher values reduce background load.',
7
- type: 'number',
8
- defaultValue: 300,
9
- yamlPath: ['github', 'pollIntervalSeconds'],
10
- min: 5,
11
- max: 3600,
12
- step: 5,
13
- read: (config) => config.github.pollIntervalSeconds,
14
- apply: (config, value) => ({
15
- ...config,
16
- github: {
17
- ...config.github,
18
- pollIntervalSeconds: value,
19
- },
20
- }),
21
- parseInput: (raw) => parseNumberInput(raw, {
22
- key: 'github.pollIntervalSeconds',
23
- integer: true,
24
- min: 5,
25
- max: 3600,
26
- }),
27
- parseStored: (raw) => parseStoredNumber(raw, {
28
- key: 'github.pollIntervalSeconds',
29
- integer: true,
30
- min: 5,
31
- max: 3600,
32
- }),
33
- serialize: (value) => JSON.stringify(value),
34
- },
35
- 'security.maxDailyCostUsd': {
36
- key: 'security.maxDailyCostUsd',
37
- label: 'Daily Cost Budget (USD)',
38
- description: 'Maximum allowed spend per UTC day before new runs are blocked.',
39
- details: 'Sets the global daily spend cap for pay-per-use mode. When the cap is reached, new runs are blocked until the next UTC day or until you raise the limit.',
40
- type: 'number',
41
- defaultValue: 50,
42
- yamlPath: ['security', 'maxDailyCostUsd'],
43
- min: 1,
44
- max: 10000,
45
- step: 1,
46
- read: (config) => config.security.maxDailyCostUsd,
47
- apply: (config, value) => ({
48
- ...config,
49
- security: {
50
- ...config.security,
51
- maxDailyCostUsd: value,
52
- },
53
- }),
54
- parseInput: (raw) => parseNumberInput(raw, {
55
- key: 'security.maxDailyCostUsd',
56
- integer: false,
57
- min: 1,
58
- max: 10000,
59
- }),
60
- parseStored: (raw) => parseStoredNumber(raw, {
61
- key: 'security.maxDailyCostUsd',
62
- integer: false,
63
- min: 1,
64
- max: 10000,
65
- }),
66
- serialize: (value) => JSON.stringify(value),
67
- },
68
- 'security.maxCostPerRunUsd': {
69
- key: 'security.maxCostPerRunUsd',
70
- label: 'Per-Run Cost Budget (USD)',
71
- description: 'Maximum allowed spend for a single run before it is blocked.',
72
- details: 'Sets the per-issue run cost ceiling. Useful for preventing one expensive issue from consuming most of the daily budget.',
73
- type: 'number',
74
- defaultValue: 10,
75
- yamlPath: ['security', 'maxCostPerRunUsd'],
76
- min: 0.1,
77
- max: 1000,
78
- step: 0.5,
79
- read: (config) => config.security.maxCostPerRunUsd,
80
- apply: (config, value) => ({
81
- ...config,
82
- security: {
83
- ...config.security,
84
- maxCostPerRunUsd: value,
85
- },
86
- }),
87
- parseInput: (raw) => parseNumberInput(raw, {
88
- key: 'security.maxCostPerRunUsd',
89
- integer: false,
90
- min: 0.1,
91
- max: 1000,
92
- }),
93
- parseStored: (raw) => parseStoredNumber(raw, {
94
- key: 'security.maxCostPerRunUsd',
95
- integer: false,
96
- min: 0.1,
97
- max: 1000,
98
- }),
99
- serialize: (value) => JSON.stringify(value),
100
- },
101
- 'loop.maxReviewIterations': {
102
- key: 'loop.maxReviewIterations',
103
- label: 'Max Review Iterations',
104
- description: 'Maximum review correction loops per run.',
105
- details: 'Limits how many review-fix-review cycles a run can execute before stopping. Higher values can improve completion rate, but may increase runtime and cost.',
106
- type: 'number',
107
- defaultValue: 4,
108
- yamlPath: ['loop', 'maxReviewIterations'],
109
- min: 1,
110
- max: 20,
111
- step: 1,
112
- read: (config) => config.loop.maxReviewIterations,
113
- apply: (config, value) => ({
114
- ...config,
115
- loop: {
116
- ...config.loop,
117
- maxReviewIterations: value,
118
- },
119
- }),
120
- parseInput: (raw) => parseNumberInput(raw, {
121
- key: 'loop.maxReviewIterations',
122
- integer: true,
123
- min: 1,
124
- max: 20,
125
- }),
126
- parseStored: (raw) => parseStoredNumber(raw, {
127
- key: 'loop.maxReviewIterations',
128
- integer: true,
129
- min: 1,
130
- max: 20,
131
- }),
132
- serialize: (value) => JSON.stringify(value),
133
- },
134
- 'loop.maxTotalAgentPasses': {
135
- key: 'loop.maxTotalAgentPasses',
136
- label: 'Max Total Agent Passes',
137
- description: 'Hard cap on planner/coder/reviewer passes in one run.',
138
- details: 'Caps total planner/coder/reviewer passes across the full run. This is a safety guard against long loops and runaway spend.',
139
- type: 'number',
140
- defaultValue: 10,
141
- yamlPath: ['loop', 'maxTotalAgentPasses'],
142
- min: 1,
143
- max: 50,
144
- step: 1,
145
- read: (config) => config.loop.maxTotalAgentPasses,
146
- apply: (config, value) => ({
147
- ...config,
148
- loop: {
149
- ...config.loop,
150
- maxTotalAgentPasses: value,
151
- },
152
- }),
153
- parseInput: (raw) => parseNumberInput(raw, {
154
- key: 'loop.maxTotalAgentPasses',
155
- integer: true,
156
- min: 1,
157
- max: 50,
158
- }),
159
- parseStored: (raw) => parseStoredNumber(raw, {
160
- key: 'loop.maxTotalAgentPasses',
161
- integer: true,
162
- min: 1,
163
- max: 50,
164
- }),
165
- serialize: (value) => JSON.stringify(value),
166
- },
167
- 'observability.agentStreaming': {
168
- key: 'observability.agentStreaming',
169
- label: 'Agent Streaming',
170
- description: 'Enable in-flight agent event streaming to TUI/Web.',
171
- details: 'Turns live agent event streaming on or off for terminal and web views. Disable this if you want quieter live output while runs are active.',
172
- type: 'boolean',
173
- defaultValue: true,
174
- yamlPath: ['observability', 'agentStreaming'],
175
- read: (config) => config.observability?.agentStreaming ?? true,
176
- apply: (config, value) => ({
177
- ...config,
178
- observability: {
179
- ...buildDefaultObservability(config),
180
- agentStreaming: value,
181
- },
182
- }),
183
- parseInput: (raw) => parseBooleanInput(raw, 'observability.agentStreaming'),
184
- parseStored: (raw) => parseStoredBoolean(raw, 'observability.agentStreaming'),
185
- serialize: (value) => JSON.stringify(value),
186
- },
187
- };
1
+ import { githubDefinitions } from './definitions/github.js';
2
+ import { loopDefinitions } from './definitions/loop.js';
3
+ import { observabilityDefinitions } from './definitions/observability.js';
4
+ import { securityDefinitions } from './definitions/security.js';
5
+ const SETTING_DEFINITIONS = buildSettingDefinitions();
188
6
  const SETTING_KEYS = Object.keys(SETTING_DEFINITIONS);
189
7
  export function listSettingDefinitions() {
190
8
  return SETTING_KEYS.map((key) => SETTING_DEFINITIONS[key]);
@@ -192,6 +10,13 @@ export function listSettingDefinitions() {
192
10
  export function getSettingDefinition(key) {
193
11
  return SETTING_DEFINITIONS[key] ?? null;
194
12
  }
13
+ export function sanitizeSettingValueForDisplay(definition, value) {
14
+ if (value === null) {
15
+ return null;
16
+ }
17
+ const sanitize = definition.sanitizeForDisplay;
18
+ return sanitize(value);
19
+ }
195
20
  export function resolveSettingYamlValue(definition, rawConfig, baseConfig) {
196
21
  if (!hasValueAtPath(rawConfig, definition.yamlPath)) {
197
22
  return {
@@ -204,6 +29,144 @@ export function resolveSettingYamlValue(definition, rawConfig, baseConfig) {
204
29
  yamlValue: definition.read(baseConfig),
205
30
  };
206
31
  }
32
+ function buildSettingDefinitions() {
33
+ const definitions = [
34
+ ...githubDefinitions(),
35
+ ...loopDefinitions(),
36
+ ...securityDefinitions(),
37
+ ...observabilityDefinitions(),
38
+ ];
39
+ const entries = new Map();
40
+ for (const definition of definitions) {
41
+ if (entries.has(definition.key)) {
42
+ throw new Error(`Duplicate runtime setting key: ${definition.key}`);
43
+ }
44
+ entries.set(definition.key, definition);
45
+ }
46
+ return Object.fromEntries(entries);
47
+ }
48
+ export function numberSetting(options) {
49
+ return {
50
+ key: options.key,
51
+ label: options.label,
52
+ description: options.description,
53
+ details: options.details,
54
+ type: 'number',
55
+ mutable: options.mutable ?? true,
56
+ sensitive: options.sensitive ?? false,
57
+ defaultValue: options.defaultValue,
58
+ yamlPath: options.yamlPath,
59
+ ...(options.min !== undefined ? { min: options.min } : {}),
60
+ ...(options.max !== undefined ? { max: options.max } : {}),
61
+ ...(options.step !== undefined ? { step: options.step } : {}),
62
+ read: (config) => readNumberValue(config, options.yamlPath, options.defaultValue),
63
+ apply: (config, value) => setConfigValue(config, options.yamlPath, value),
64
+ parseInput: (raw) => parseNumberInput(raw, {
65
+ key: options.key,
66
+ integer: options.integer,
67
+ min: options.min,
68
+ max: options.max,
69
+ }),
70
+ parseStored: (raw) => parseStoredNumber(raw, {
71
+ key: options.key,
72
+ integer: options.integer,
73
+ min: options.min,
74
+ max: options.max,
75
+ }),
76
+ serialize: (value) => JSON.stringify(value),
77
+ sanitizeForDisplay: options.sanitizeForDisplay ?? identitySanitize,
78
+ };
79
+ }
80
+ export function booleanSetting(options) {
81
+ return {
82
+ key: options.key,
83
+ label: options.label,
84
+ description: options.description,
85
+ details: options.details,
86
+ type: 'boolean',
87
+ mutable: options.mutable ?? true,
88
+ sensitive: options.sensitive ?? false,
89
+ defaultValue: options.defaultValue,
90
+ yamlPath: options.yamlPath,
91
+ read: (config) => readBooleanValue(config, options.yamlPath, options.defaultValue),
92
+ apply: (config, value) => setConfigValue(config, options.yamlPath, value),
93
+ parseInput: (raw) => parseBooleanInput(raw, options.key),
94
+ parseStored: (raw) => parseStoredBoolean(raw, options.key),
95
+ serialize: (value) => JSON.stringify(value),
96
+ sanitizeForDisplay: options.sanitizeForDisplay ?? identitySanitize,
97
+ };
98
+ }
99
+ export function stringSetting(options) {
100
+ return {
101
+ key: options.key,
102
+ label: options.label,
103
+ description: options.description,
104
+ details: options.details,
105
+ type: 'string',
106
+ mutable: options.mutable ?? true,
107
+ sensitive: options.sensitive ?? false,
108
+ defaultValue: options.defaultValue,
109
+ yamlPath: options.yamlPath,
110
+ ...(options.options ? { options: options.options } : {}),
111
+ ...(options.allowNull ? { allowNull: true } : {}),
112
+ read: (config) => readStringValue(config, options.yamlPath, options.defaultValue, options.allowNull ?? false),
113
+ apply: (config, value) => setConfigValue(config, options.yamlPath, value),
114
+ parseInput: (raw) => parseStringInput(raw, {
115
+ key: options.key,
116
+ allowNull: options.allowNull,
117
+ options: options.options,
118
+ minLength: options.minLength,
119
+ url: options.url,
120
+ validate: options.validate,
121
+ }),
122
+ parseStored: (raw) => parseStoredString(raw, {
123
+ key: options.key,
124
+ allowNull: options.allowNull,
125
+ options: options.options,
126
+ minLength: options.minLength,
127
+ url: options.url,
128
+ validate: options.validate,
129
+ }),
130
+ serialize: (value) => JSON.stringify(value),
131
+ sanitizeForDisplay: options.sanitizeForDisplay ?? identitySanitize,
132
+ };
133
+ }
134
+ export function jsonSetting(options) {
135
+ return {
136
+ key: options.key,
137
+ label: options.label,
138
+ description: options.description,
139
+ details: options.details,
140
+ type: 'json',
141
+ mutable: options.mutable ?? true,
142
+ sensitive: options.sensitive ?? false,
143
+ defaultValue: options.defaultValue,
144
+ yamlPath: options.yamlPath,
145
+ read: (config) => readJsonValue(config, options.yamlPath, options.defaultValue),
146
+ apply: (config, value) => setConfigValue(config, options.yamlPath, value),
147
+ parseInput: (raw) => {
148
+ const parsed = parseJsonInput(raw, options.key);
149
+ return options.normalize ? options.normalize(parsed) : parsed;
150
+ },
151
+ parseStored: (raw) => {
152
+ const parsed = parseStoredJson(raw, options.key);
153
+ return options.normalize ? options.normalize(parsed) : parsed;
154
+ },
155
+ serialize: (value) => JSON.stringify(value),
156
+ sanitizeForDisplay: options.sanitizeForDisplay ?? identitySanitize,
157
+ };
158
+ }
159
+ export function validateJsonSettingShape(value, schema, key) {
160
+ const result = schema.safeParse(value);
161
+ if (result.success) {
162
+ return result.data;
163
+ }
164
+ const issue = result.error.issues[0];
165
+ const path = issue?.path.length ? issue.path.join('.') : key;
166
+ const message = issue?.message ?? 'invalid structure';
167
+ throw new Error(`${key} has invalid structure (${path}): ${message}`);
168
+ }
169
+ // --- Internal helpers ---
207
170
  function parseNumberInput(raw, options) {
208
171
  const parsed = typeof raw === 'number'
209
172
  ? raw
@@ -231,8 +194,11 @@ function validateNumber(value, options) {
231
194
  if (options.integer && !Number.isInteger(value)) {
232
195
  throw new Error(`${options.key} must be an integer`);
233
196
  }
234
- if (value < options.min || value > options.max) {
235
- throw new Error(`${options.key} must be between ${options.min} and ${options.max}`);
197
+ if (options.min !== undefined && value < options.min) {
198
+ throw new Error(`${options.key} must be >= ${options.min}`);
199
+ }
200
+ if (options.max !== undefined && value > options.max) {
201
+ throw new Error(`${options.key} must be <= ${options.max}`);
236
202
  }
237
203
  return value;
238
204
  }
@@ -275,12 +241,138 @@ function parseStoredBoolean(raw, key) {
275
241
  throw new Error(`Invalid stored value for ${key}: ${err.message}`);
276
242
  }
277
243
  }
278
- function buildDefaultObservability(config) {
244
+ function parseStringInput(raw, options) {
245
+ if (raw === null) {
246
+ if (options.allowNull) {
247
+ return null;
248
+ }
249
+ throw new Error(`${options.key} must be a string`);
250
+ }
251
+ if (typeof raw !== 'string') {
252
+ throw new Error(`${options.key} must be a string`);
253
+ }
254
+ if (options.allowNull && raw.trim().toLowerCase() === 'null') {
255
+ return null;
256
+ }
257
+ const value = raw;
258
+ if (options.minLength !== undefined && value.trim().length < options.minLength) {
259
+ throw new Error(`${options.key} must be at least ${options.minLength} character(s)`);
260
+ }
261
+ if (options.options && !options.options.includes(value)) {
262
+ throw new Error(`${options.key} must be one of: ${options.options.join(', ')}`);
263
+ }
264
+ if (options.url) {
265
+ try {
266
+ void new URL(value);
267
+ }
268
+ catch {
269
+ throw new Error(`${options.key} must be a valid URL`);
270
+ }
271
+ }
272
+ const validationError = options.validate?.(value);
273
+ if (validationError) {
274
+ throw new Error(validationError);
275
+ }
276
+ return value;
277
+ }
278
+ function parseStoredString(raw, options) {
279
+ try {
280
+ const parsed = JSON.parse(raw);
281
+ if (typeof parsed !== 'string' && parsed !== null) {
282
+ throw new Error(`Stored value for ${options.key} is not string/null`);
283
+ }
284
+ return parseStringInput(parsed, options);
285
+ }
286
+ catch (err) {
287
+ throw new Error(`Invalid stored value for ${options.key}: ${err.message}`);
288
+ }
289
+ }
290
+ function parseJsonInput(raw, key) {
291
+ if (typeof raw === 'string') {
292
+ try {
293
+ const parsed = JSON.parse(raw);
294
+ if (!isJsonValue(parsed)) {
295
+ throw new Error('must be valid JSON');
296
+ }
297
+ return parsed;
298
+ }
299
+ catch (err) {
300
+ throw new Error(`${key} must be valid JSON: ${err.message}`);
301
+ }
302
+ }
303
+ if (!isJsonValue(raw)) {
304
+ throw new Error(`${key} must be valid JSON`);
305
+ }
306
+ return raw;
307
+ }
308
+ function parseStoredJson(raw, key) {
309
+ try {
310
+ const parsed = JSON.parse(raw);
311
+ if (!isJsonValue(parsed)) {
312
+ throw new Error(`Stored value for ${key} is not valid JSON`);
313
+ }
314
+ return parsed;
315
+ }
316
+ catch (err) {
317
+ throw new Error(`Invalid stored value for ${key}: ${err.message}`);
318
+ }
319
+ }
320
+ function identitySanitize(value) {
321
+ return value;
322
+ }
323
+ function readNumberValue(config, path, fallback) {
324
+ const value = readPathValue(config, path);
325
+ return typeof value === 'number' ? value : fallback;
326
+ }
327
+ function readBooleanValue(config, path, fallback) {
328
+ const value = readPathValue(config, path);
329
+ return typeof value === 'boolean' ? value : fallback;
330
+ }
331
+ function readStringValue(config, path, fallback, allowNull) {
332
+ const value = readPathValue(config, path);
333
+ if (typeof value === 'string') {
334
+ return value;
335
+ }
336
+ if (allowNull && value === null) {
337
+ return null;
338
+ }
339
+ return fallback;
340
+ }
341
+ function readJsonValue(config, path, fallback) {
342
+ const value = readPathValue(config, path);
343
+ return isJsonValue(value) ? value : fallback;
344
+ }
345
+ function setConfigValue(config, path, value) {
346
+ return setPathValue(config, path, value);
347
+ }
348
+ function readPathValue(source, path) {
349
+ let current = source;
350
+ for (const segment of path) {
351
+ if (!isRecord(current)) {
352
+ return undefined;
353
+ }
354
+ current = current[segment];
355
+ }
356
+ return current;
357
+ }
358
+ function setPathValue(source, path, value) {
359
+ if (path.length === 0) {
360
+ return isRecord(source) ? { ...source } : {};
361
+ }
362
+ const [segment, ...rest] = path;
363
+ if (segment === undefined) {
364
+ return isRecord(source) ? { ...source } : {};
365
+ }
366
+ const current = isRecord(source) ? source : {};
367
+ if (rest.length === 0) {
368
+ return {
369
+ ...current,
370
+ [segment]: value,
371
+ };
372
+ }
279
373
  return {
280
- agentStreaming: config.observability?.agentStreaming ?? true,
281
- eventRetention: config.observability?.eventRetention ?? 1000,
282
- sessionLogs: config.observability?.sessionLogs ?? true,
283
- sessionLogRetention: config.observability?.sessionLogRetention ?? 7,
374
+ ...current,
375
+ [segment]: setPathValue(current[segment], rest, value),
284
376
  };
285
377
  }
286
378
  function hasValueAtPath(source, path) {
@@ -296,4 +388,19 @@ function hasValueAtPath(source, path) {
296
388
  function isRecord(value) {
297
389
  return typeof value === 'object' && value !== null;
298
390
  }
391
+ function isJsonValue(value) {
392
+ if (value === null
393
+ || typeof value === 'string'
394
+ || typeof value === 'number'
395
+ || typeof value === 'boolean') {
396
+ return true;
397
+ }
398
+ if (Array.isArray(value)) {
399
+ return value.every((entry) => isJsonValue(entry));
400
+ }
401
+ if (!isRecord(value)) {
402
+ return false;
403
+ }
404
+ return Object.values(value).every((entry) => isJsonValue(entry));
405
+ }
299
406
  //# sourceMappingURL=registry.js.map