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.
- package/LICENSE +21 -0
- package/README.md +47 -108
- package/dist/cli/commands/doctor.d.ts +1 -0
- package/dist/cli/commands/doctor.d.ts.map +1 -1
- package/dist/cli/commands/doctor.js +18 -0
- package/dist/cli/commands/doctor.js.map +1 -1
- package/dist/cli/commands/monitoring.d.ts.map +1 -1
- package/dist/cli/commands/monitoring.js +7 -3
- package/dist/cli/commands/monitoring.js.map +1 -1
- package/dist/cli/commands/settings.d.ts.map +1 -1
- package/dist/cli/commands/settings.js +40 -4
- package/dist/cli/commands/settings.js.map +1 -1
- package/dist/cli/commands/status.d.ts.map +1 -1
- package/dist/cli/commands/status.js +26 -3
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/cli/index.js +3 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/tui/app.d.ts.map +1 -1
- package/dist/cli/tui/app.js +52 -3
- package/dist/cli/tui/app.js.map +1 -1
- package/dist/cli/tui/header.d.ts.map +1 -1
- package/dist/cli/tui/header.js +2 -1
- package/dist/cli/tui/header.js.map +1 -1
- package/dist/cli/tui/settings-view.d.ts.map +1 -1
- package/dist/cli/tui/settings-view.js +22 -5
- package/dist/cli/tui/settings-view.js.map +1 -1
- package/dist/cli/tui/stats-view.js +2 -2
- package/dist/cli/tui/stats-view.js.map +1 -1
- package/dist/config/loader.d.ts.map +1 -1
- package/dist/config/loader.js +141 -13
- package/dist/config/loader.js.map +1 -1
- package/dist/config/schema.d.ts +903 -21
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +77 -6
- package/dist/config/schema.js.map +1 -1
- package/dist/forge/types.d.ts +7 -0
- package/dist/forge/types.d.ts.map +1 -1
- package/dist/git/repo.d.ts +8 -0
- package/dist/git/repo.d.ts.map +1 -1
- package/dist/git/repo.js +19 -0
- package/dist/git/repo.js.map +1 -1
- package/dist/git/worktree.d.ts +3 -0
- package/dist/git/worktree.d.ts.map +1 -1
- package/dist/git/worktree.js +43 -21
- package/dist/git/worktree.js.map +1 -1
- package/dist/loop/cost.d.ts +33 -8
- package/dist/loop/cost.d.ts.map +1 -1
- package/dist/loop/cost.js +250 -46
- package/dist/loop/cost.js.map +1 -1
- package/dist/loop/decision.js +3 -3
- package/dist/loop/decision.js.map +1 -1
- package/dist/loop/engine.d.ts +1 -0
- package/dist/loop/engine.d.ts.map +1 -1
- package/dist/loop/engine.js +76 -13
- package/dist/loop/engine.js.map +1 -1
- package/dist/loop/parallel.d.ts.map +1 -1
- package/dist/loop/parallel.js +2 -0
- package/dist/loop/parallel.js.map +1 -1
- package/dist/loop/pricing.d.ts +11 -4
- package/dist/loop/pricing.d.ts.map +1 -1
- package/dist/loop/pricing.js +62 -20
- package/dist/loop/pricing.js.map +1 -1
- package/dist/loop/progress.d.ts +24 -0
- package/dist/loop/progress.d.ts.map +1 -0
- package/dist/loop/progress.js +52 -0
- package/dist/loop/progress.js.map +1 -0
- package/dist/loop/step-executor.d.ts +4 -5
- package/dist/loop/step-executor.d.ts.map +1 -1
- package/dist/loop/step-executor.js +1 -0
- package/dist/loop/step-executor.js.map +1 -1
- package/dist/loop/types.d.ts +17 -0
- package/dist/loop/types.d.ts.map +1 -1
- package/dist/mcp/tools/admin.d.ts +29 -0
- package/dist/mcp/tools/admin.d.ts.map +1 -0
- package/dist/mcp/tools/admin.js +89 -0
- package/dist/mcp/tools/admin.js.map +1 -0
- package/dist/mcp/tools/auth.d.ts +3 -0
- package/dist/mcp/tools/auth.d.ts.map +1 -0
- package/dist/mcp/tools/auth.js +19 -0
- package/dist/mcp/tools/auth.js.map +1 -0
- package/dist/mcp/tools/index.d.ts.map +1 -1
- package/dist/mcp/tools/index.js +5 -533
- package/dist/mcp/tools/index.js.map +1 -1
- package/dist/mcp/tools/operations.d.ts +32 -0
- package/dist/mcp/tools/operations.d.ts.map +1 -0
- package/dist/mcp/tools/operations.js +95 -0
- package/dist/mcp/tools/operations.js.map +1 -0
- package/dist/mcp/tools/settings.d.ts +12 -0
- package/dist/mcp/tools/settings.d.ts.map +1 -0
- package/dist/mcp/tools/settings.js +58 -0
- package/dist/mcp/tools/settings.js.map +1 -0
- package/dist/mcp/tools/status.d.ts +25 -0
- package/dist/mcp/tools/status.d.ts.map +1 -0
- package/dist/mcp/tools/status.js +307 -0
- package/dist/mcp/tools/status.js.map +1 -0
- package/dist/ops/continue.js +6 -1
- package/dist/ops/continue.js.map +1 -1
- package/dist/ops/project-check.d.ts +15 -0
- package/dist/ops/project-check.d.ts.map +1 -0
- package/dist/ops/project-check.js +136 -0
- package/dist/ops/project-check.js.map +1 -0
- package/dist/ops/rebase-and-check.d.ts +2 -1
- package/dist/ops/rebase-and-check.d.ts.map +1 -1
- package/dist/ops/rebase-and-check.js +2 -2
- package/dist/ops/rebase-and-check.js.map +1 -1
- package/dist/ops/rebase.d.ts +8 -5
- package/dist/ops/rebase.d.ts.map +1 -1
- package/dist/ops/rebase.js +43 -29
- package/dist/ops/rebase.js.map +1 -1
- package/dist/runner/comment-commands.d.ts +20 -0
- package/dist/runner/comment-commands.d.ts.map +1 -0
- package/dist/runner/comment-commands.js +221 -0
- package/dist/runner/comment-commands.js.map +1 -0
- package/dist/runner/helpers.d.ts +57 -0
- package/dist/runner/helpers.d.ts.map +1 -0
- package/dist/runner/helpers.js +259 -0
- package/dist/runner/helpers.js.map +1 -0
- package/dist/runner/poller.d.ts.map +1 -1
- package/dist/runner/poller.js +19 -781
- package/dist/runner/poller.js.map +1 -1
- package/dist/runner/reaction-scan.d.ts +17 -0
- package/dist/runner/reaction-scan.d.ts.map +1 -0
- package/dist/runner/reaction-scan.js +33 -0
- package/dist/runner/reaction-scan.js.map +1 -0
- package/dist/runner/run-finalizer.d.ts +30 -0
- package/dist/runner/run-finalizer.d.ts.map +1 -0
- package/dist/runner/run-finalizer.js +217 -0
- package/dist/runner/run-finalizer.js.map +1 -0
- package/dist/settings/definitions/github.d.ts +3 -0
- package/dist/settings/definitions/github.d.ts.map +1 -0
- package/dist/settings/definitions/github.js +267 -0
- package/dist/settings/definitions/github.js.map +1 -0
- package/dist/settings/definitions/loop.d.ts +3 -0
- package/dist/settings/definitions/loop.d.ts.map +1 -0
- package/dist/settings/definitions/loop.js +113 -0
- package/dist/settings/definitions/loop.js.map +1 -0
- package/dist/settings/definitions/observability.d.ts +3 -0
- package/dist/settings/definitions/observability.d.ts.map +1 -0
- package/dist/settings/definitions/observability.js +74 -0
- package/dist/settings/definitions/observability.js.map +1 -0
- package/dist/settings/definitions/security.d.ts +3 -0
- package/dist/settings/definitions/security.d.ts.map +1 -0
- package/dist/settings/definitions/security.js +121 -0
- package/dist/settings/definitions/security.js.map +1 -0
- package/dist/settings/registry.d.ts +82 -6
- package/dist/settings/registry.d.ts.map +1 -1
- package/dist/settings/registry.js +301 -194
- package/dist/settings/registry.js.map +1 -1
- package/dist/settings/runtime.d.ts +5 -1
- package/dist/settings/runtime.d.ts.map +1 -1
- package/dist/settings/runtime.js +46 -9
- package/dist/settings/runtime.js.map +1 -1
- package/dist/state/db.d.ts.map +1 -1
- package/dist/state/db.js +2 -0
- package/dist/state/db.js.map +1 -1
- package/dist/state/migrations/020-cost-ledger.d.ts +3 -0
- package/dist/state/migrations/020-cost-ledger.d.ts.map +1 -0
- package/dist/state/migrations/020-cost-ledger.js +37 -0
- package/dist/state/migrations/020-cost-ledger.js.map +1 -0
- package/dist/state/runs.d.ts +1 -0
- package/dist/state/runs.d.ts.map +1 -1
- package/dist/state/runs.js +3 -0
- package/dist/state/runs.js.map +1 -1
- package/dist/state/stats.d.ts +20 -0
- package/dist/state/stats.d.ts.map +1 -1
- package/dist/state/stats.js +68 -8
- package/dist/state/stats.js.map +1 -1
- package/dist/utils/logger.d.ts +9 -0
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js +13 -0
- package/dist/utils/logger.js.map +1 -1
- package/dist/web/routes/api-events.d.ts +10 -0
- package/dist/web/routes/api-events.d.ts.map +1 -0
- package/dist/web/routes/api-events.js +251 -0
- package/dist/web/routes/api-events.js.map +1 -0
- package/dist/web/routes/api-operations.d.ts +3 -0
- package/dist/web/routes/api-operations.d.ts.map +1 -0
- package/dist/web/routes/api-operations.js +371 -0
- package/dist/web/routes/api-operations.js.map +1 -0
- package/dist/web/routes/api-runs.d.ts +3 -0
- package/dist/web/routes/api-runs.d.ts.map +1 -0
- package/dist/web/routes/api-runs.js +96 -0
- package/dist/web/routes/api-runs.js.map +1 -0
- package/dist/web/routes/api-settings.d.ts +3 -0
- package/dist/web/routes/api-settings.d.ts.map +1 -0
- package/dist/web/routes/api-settings.js +61 -0
- package/dist/web/routes/api-settings.js.map +1 -0
- package/dist/web/routes/context.d.ts +15 -0
- package/dist/web/routes/context.d.ts.map +1 -0
- package/dist/web/routes/context.js +2 -0
- package/dist/web/routes/context.js.map +1 -0
- package/dist/web/server.d.ts +58 -1
- package/dist/web/server.d.ts.map +1 -1
- package/dist/web/server.js +116 -847
- package/dist/web/server.js.map +1 -1
- package/dist/web/shell-session.d.ts +74 -0
- package/dist/web/shell-session.d.ts.map +1 -0
- package/dist/web/shell-session.js +279 -0
- package/dist/web/shell-session.js.map +1 -0
- package/dist/web/snapshots.d.ts +159 -0
- package/dist/web/snapshots.d.ts.map +1 -0
- package/dist/web/snapshots.js +231 -0
- package/dist/web/snapshots.js.map +1 -0
- package/dist/workers/acp.d.ts.map +1 -1
- package/dist/workers/acp.js +116 -0
- package/dist/workers/acp.js.map +1 -1
- package/dist/workers/claude.d.ts.map +1 -1
- package/dist/workers/claude.js +13 -3
- package/dist/workers/claude.js.map +1 -1
- package/dist/workers/codex.d.ts.map +1 -1
- package/dist/workers/codex.js +16 -4
- package/dist/workers/codex.js.map +1 -1
- package/dist/workers/types.d.ts +14 -4
- package/dist/workers/types.d.ts.map +1 -1
- package/examples/config.example.yaml +12 -3
- package/package.json +8 -2
- package/web/dist/assets/index-BIrXUwFe.css +1 -0
- package/web/dist/assets/index-COMzHPcP.js +26 -0
- package/web/dist/index.html +2 -2
- package/web/dist/assets/index-k6kgdnzy.js +0 -9
- 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 =
|
|
3
|
-
export type
|
|
4
|
-
|
|
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
|
-
|
|
12
|
-
|
|
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
|
|
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;
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/settings/registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,190 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
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 (
|
|
235
|
-
throw new Error(`${options.key} must be
|
|
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
|
|
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
|
-
|
|
281
|
-
|
|
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
|