@letrquan/book 0.2.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/CHANGELOG.md +2504 -0
- package/LICENSE +123 -0
- package/README.md +1383 -0
- package/dist/app-MOXXWEOY.js +18945 -0
- package/dist/app-MOXXWEOY.js.map +1 -0
- package/dist/chunk-24AXE6SP.js +12 -0
- package/dist/chunk-24AXE6SP.js.map +1 -0
- package/dist/chunk-3U5IBM24.js +213 -0
- package/dist/chunk-3U5IBM24.js.map +1 -0
- package/dist/chunk-574C6MQR.js +743 -0
- package/dist/chunk-574C6MQR.js.map +1 -0
- package/dist/chunk-5GDZ22YP.js +449 -0
- package/dist/chunk-5GDZ22YP.js.map +1 -0
- package/dist/chunk-5KLVH3PY.js +167 -0
- package/dist/chunk-5KLVH3PY.js.map +1 -0
- package/dist/chunk-5RDRAO4B.js +92 -0
- package/dist/chunk-5RDRAO4B.js.map +1 -0
- package/dist/chunk-7N4J557C.js +10 -0
- package/dist/chunk-7N4J557C.js.map +1 -0
- package/dist/chunk-A7JLBK2Y.js +3506 -0
- package/dist/chunk-A7JLBK2Y.js.map +1 -0
- package/dist/chunk-ANSJPYGI.js +84 -0
- package/dist/chunk-ANSJPYGI.js.map +1 -0
- package/dist/chunk-BTZZUCLI.js +264 -0
- package/dist/chunk-BTZZUCLI.js.map +1 -0
- package/dist/chunk-C7D4NJ2D.js +217 -0
- package/dist/chunk-C7D4NJ2D.js.map +1 -0
- package/dist/chunk-CAGOB2N4.js +208 -0
- package/dist/chunk-CAGOB2N4.js.map +1 -0
- package/dist/chunk-DGMQEI6Y.js +98 -0
- package/dist/chunk-DGMQEI6Y.js.map +1 -0
- package/dist/chunk-E75IPST5.js +289 -0
- package/dist/chunk-E75IPST5.js.map +1 -0
- package/dist/chunk-EYGD6X2T.js +180 -0
- package/dist/chunk-EYGD6X2T.js.map +1 -0
- package/dist/chunk-GTVB4HEM.js +765 -0
- package/dist/chunk-GTVB4HEM.js.map +1 -0
- package/dist/chunk-J7MIZ5CA.js +1907 -0
- package/dist/chunk-J7MIZ5CA.js.map +1 -0
- package/dist/chunk-KWHQ2XXL.js +626 -0
- package/dist/chunk-KWHQ2XXL.js.map +1 -0
- package/dist/chunk-L6LK2QIQ.js +657 -0
- package/dist/chunk-L6LK2QIQ.js.map +1 -0
- package/dist/chunk-MAQXCUR4.js +1007 -0
- package/dist/chunk-MAQXCUR4.js.map +1 -0
- package/dist/chunk-S4XL7HOM.js +402 -0
- package/dist/chunk-S4XL7HOM.js.map +1 -0
- package/dist/chunk-URLQAXTR.js +60 -0
- package/dist/chunk-URLQAXTR.js.map +1 -0
- package/dist/chunk-V4BOYR52.js +3504 -0
- package/dist/chunk-V4BOYR52.js.map +1 -0
- package/dist/chunk-VZQXX3WW.js +210 -0
- package/dist/chunk-VZQXX3WW.js.map +1 -0
- package/dist/chunk-WKBO5R4O.js +34 -0
- package/dist/chunk-WKBO5R4O.js.map +1 -0
- package/dist/chunk-XIFFTATU.js +15753 -0
- package/dist/chunk-XIFFTATU.js.map +1 -0
- package/dist/command-approvals-6Y57VCWZ.js +28 -0
- package/dist/command-approvals-6Y57VCWZ.js.map +1 -0
- package/dist/context-ZC5IFEAX.js +25 -0
- package/dist/context-ZC5IFEAX.js.map +1 -0
- package/dist/hook-approvals-CTUFKEJT.js +22 -0
- package/dist/hook-approvals-CTUFKEJT.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2582 -0
- package/dist/index.js.map +1 -0
- package/dist/interactive-assets-CCAAWVKH.js +31 -0
- package/dist/interactive-assets-CCAAWVKH.js.map +1 -0
- package/dist/job-runner.d.ts +2 -0
- package/dist/job-runner.js +235 -0
- package/dist/job-runner.js.map +1 -0
- package/dist/loader-4IDS2RIE.js +15 -0
- package/dist/loader-4IDS2RIE.js.map +1 -0
- package/dist/mcp-approvals-WNPH65BK.js +18 -0
- package/dist/mcp-approvals-WNPH65BK.js.map +1 -0
- package/dist/mcp-config-YIJIES2C.js +16 -0
- package/dist/mcp-config-YIJIES2C.js.map +1 -0
- package/dist/model-window-store-YFVNXCIP.js +27 -0
- package/dist/model-window-store-YFVNXCIP.js.map +1 -0
- package/dist/openai-compatible-RHZUBHV6.js +10 -0
- package/dist/openai-compatible-RHZUBHV6.js.map +1 -0
- package/dist/permission-approvals-76PVREFD.js +14 -0
- package/dist/permission-approvals-76PVREFD.js.map +1 -0
- package/dist/permissions-CHCKTFQQ.js +28 -0
- package/dist/permissions-CHCKTFQQ.js.map +1 -0
- package/dist/sandbox-CNVAQDA7.js +23 -0
- package/dist/sandbox-CNVAQDA7.js.map +1 -0
- package/dist/scrollback-LUKLIBVI.js +136 -0
- package/dist/scrollback-LUKLIBVI.js.map +1 -0
- package/dist/sdk.d.ts +4574 -0
- package/dist/sdk.js +665 -0
- package/dist/sdk.js.map +1 -0
- package/dist/settings-loader-M2QP5TX2.js +21 -0
- package/dist/settings-loader-M2QP5TX2.js.map +1 -0
- package/dist/settings-removed-JWWPT4WA.js +19 -0
- package/dist/settings-removed-JWWPT4WA.js.map +1 -0
- package/dist/shell-selection-V6QAYXPX.js +17 -0
- package/dist/shell-selection-V6QAYXPX.js.map +1 -0
- package/package.json +143 -0
- package/patches/ink+6.8.0.patch +13 -0
- package/scripts/apply-ink-patch.mjs +29 -0
- package/scripts/ink-patch.mjs +59 -0
- package/scripts/verify-ink-patch.mjs +11 -0
|
@@ -0,0 +1,743 @@
|
|
|
1
|
+
// src/settings.ts
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
var permissionRuleSchema = z.string().min(1);
|
|
4
|
+
var sandboxSchema = z.object({
|
|
5
|
+
enabled: z.boolean().default(false),
|
|
6
|
+
failIfUnavailable: z.boolean().default(false),
|
|
7
|
+
autoAllowBashIfSandboxed: z.boolean().default(true),
|
|
8
|
+
excludedCommands: z.array(z.string()).default([]),
|
|
9
|
+
allowUnsandboxedCommands: z.boolean().default(true),
|
|
10
|
+
filesystem: z.object({
|
|
11
|
+
allowWrite: z.array(z.string()).default([]),
|
|
12
|
+
denyWrite: z.array(z.string()).default([]),
|
|
13
|
+
denyRead: z.array(z.string()).default([])
|
|
14
|
+
}).default({}),
|
|
15
|
+
network: z.object({
|
|
16
|
+
allowedDomains: z.array(z.string()).default([]),
|
|
17
|
+
deniedDomains: z.array(z.string()).default([])
|
|
18
|
+
}).default({})
|
|
19
|
+
});
|
|
20
|
+
var projectAllowRuleChoiceSchema = z.enum(["approved", "rejected"]);
|
|
21
|
+
var permissionsSchema = z.object({
|
|
22
|
+
allow: z.array(permissionRuleSchema).default([]),
|
|
23
|
+
ask: z.array(permissionRuleSchema).default([]),
|
|
24
|
+
deny: z.array(permissionRuleSchema).default([]),
|
|
25
|
+
/**
|
|
26
|
+
* Decisions about `allow` rules the project layer declared. A project rule
|
|
27
|
+
* with no `approved` entry here never reaches the resolved allow list.
|
|
28
|
+
*/
|
|
29
|
+
projectAllowRules: z.record(projectAllowRuleChoiceSchema).default({})
|
|
30
|
+
});
|
|
31
|
+
var hookEntrySchema = z.object({
|
|
32
|
+
/** Tool(specifier) pattern to filter which events trigger this hook. */
|
|
33
|
+
matcher: z.string().optional(),
|
|
34
|
+
/** Shell command to run (passed through system shell). */
|
|
35
|
+
command: z.string().min(1),
|
|
36
|
+
/** Extra environment variables for this hook. */
|
|
37
|
+
env: z.record(z.string()).default({})
|
|
38
|
+
});
|
|
39
|
+
var projectHookChoiceSchema = z.enum(["approved", "rejected"]);
|
|
40
|
+
var HOOK_EVENTS = [
|
|
41
|
+
"SessionStart",
|
|
42
|
+
"SessionEnd",
|
|
43
|
+
"UserPromptSubmit",
|
|
44
|
+
"PreToolUse",
|
|
45
|
+
"PostToolUse",
|
|
46
|
+
"Stop",
|
|
47
|
+
"PreCompact",
|
|
48
|
+
"PostCompact",
|
|
49
|
+
"SubagentStart",
|
|
50
|
+
"SubagentStop",
|
|
51
|
+
/**
|
|
52
|
+
* Something a human should know about while nobody is watching: a run parked on
|
|
53
|
+
* a rejected credential, a budget crossing its ceiling, a refused spawn because
|
|
54
|
+
* the disk is nearly full. Wire ntfy/Slack/SMS here as an ordinary shell hook.
|
|
55
|
+
*
|
|
56
|
+
* Only `severity: 'alarm'` is meant to wake anyone; everything else is a line to
|
|
57
|
+
* tail. `hooksSchema` is generated from this array, so the schema cost is one
|
|
58
|
+
* entry.
|
|
59
|
+
*/
|
|
60
|
+
"Notification"
|
|
61
|
+
];
|
|
62
|
+
var hooksSchema = z.object({
|
|
63
|
+
...Object.fromEntries(HOOK_EVENTS.map((e) => [e, z.array(hookEntrySchema).default([])])),
|
|
64
|
+
/**
|
|
65
|
+
* Decisions about hook entries the checked-in project layer declared. An
|
|
66
|
+
* entry whose fingerprint has no `approved` record here never reaches the
|
|
67
|
+
* resolved hooks.
|
|
68
|
+
*/
|
|
69
|
+
projectEntries: z.record(projectHookChoiceSchema).default({})
|
|
70
|
+
});
|
|
71
|
+
var retrySettingsSchema = z.object({
|
|
72
|
+
maxAttempts: z.number().int().min(0).max(15).default(10),
|
|
73
|
+
baseDelayMs: z.number().int().min(100).max(6e4).default(1e3),
|
|
74
|
+
maxDelayMs: z.number().int().min(100).max(3e5).default(3e4),
|
|
75
|
+
totalBudgetMs: z.number().int().min(0).max(6e5).default(0),
|
|
76
|
+
requestTimeoutMs: z.number().int().min(5e3).max(6e5).default(6e5),
|
|
77
|
+
streamStallTimeoutMs: z.number().int().min(5e3).max(12e4).default(2e4),
|
|
78
|
+
/**
|
|
79
|
+
* Stall ceiling while the model is thinking, which is a different regime.
|
|
80
|
+
*
|
|
81
|
+
* `streamStallTimeoutMs` is tuned for a chat: 20s of silence means something
|
|
82
|
+
* broke. But with adaptive thinking on — the default for every Opus and Sonnet
|
|
83
|
+
* model here, at `high` effort unless told otherwise — a long quiet stretch
|
|
84
|
+
* before the first token is the model working, not a fault. Applying the chat
|
|
85
|
+
* timeout to it cancels a healthy request and reports `stream_stall`.
|
|
86
|
+
*/
|
|
87
|
+
thinkingStallTimeoutMs: z.number().int().min(1e4).max(18e5).default(9e5),
|
|
88
|
+
toolRetries: z.number().int().min(0).max(3).default(1),
|
|
89
|
+
watchdog: z.boolean().default(false),
|
|
90
|
+
/**
|
|
91
|
+
* How many times a turn may be re-sent after a transport fault that left the
|
|
92
|
+
* work intact — a stalled stream, a dropped socket.
|
|
93
|
+
*
|
|
94
|
+
* `maxAttempts` covers connection setup only; once a 200 response is streaming
|
|
95
|
+
* it is out of scope, so without this a single 20-second provider silence ended
|
|
96
|
+
* the run. Set to 0 to restore that behavior exactly.
|
|
97
|
+
*/
|
|
98
|
+
streamReissueAttempts: z.number().int().min(0).max(10).default(3),
|
|
99
|
+
/**
|
|
100
|
+
* Separate allowance for continuing after the provider's output cap. A large
|
|
101
|
+
* generated file legitimately hits the cap on consecutive turns, and sharing
|
|
102
|
+
* the transport budget would leave nothing for a real socket drop afterwards.
|
|
103
|
+
*/
|
|
104
|
+
outputCapContinuations: z.number().int().min(0).max(50).default(10)
|
|
105
|
+
});
|
|
106
|
+
var effortLevelSchema = z.enum(["low", "medium", "high", "xhigh", "max"]);
|
|
107
|
+
var providerModelSchema = z.object({
|
|
108
|
+
label: z.string().optional(),
|
|
109
|
+
contextWindow: z.number().int().positive().optional(),
|
|
110
|
+
maxOutputTokens: z.number().int().positive().optional(),
|
|
111
|
+
/** Whether this model accepts image input. Unknown models remain optimistic. */
|
|
112
|
+
vision: z.boolean().optional(),
|
|
113
|
+
/**
|
|
114
|
+
* Entered by hand rather than returned by the endpoint's model-list API.
|
|
115
|
+
* Refreshing the catalog keeps these, since they exist precisely because
|
|
116
|
+
* discovery does not list them.
|
|
117
|
+
*/
|
|
118
|
+
manual: z.boolean().optional(),
|
|
119
|
+
/** Mutation-tool preference for this model; defaults to a family-level prior. */
|
|
120
|
+
editFormat: z.enum(["patch", "replace", "whole"]).optional(),
|
|
121
|
+
effort: z.union([
|
|
122
|
+
z.literal(false),
|
|
123
|
+
z.object({
|
|
124
|
+
default: effortLevelSchema.optional(),
|
|
125
|
+
levels: z.array(effortLevelSchema).optional()
|
|
126
|
+
})
|
|
127
|
+
]).optional()
|
|
128
|
+
});
|
|
129
|
+
var providerConfigSchema = z.object({
|
|
130
|
+
type: z.enum(["openai", "anthropic"]).default("openai"),
|
|
131
|
+
baseURL: z.string().min(1).optional(),
|
|
132
|
+
baseUrl: z.string().min(1).optional(),
|
|
133
|
+
apiKey: z.string().min(1).optional(),
|
|
134
|
+
models: z.record(providerModelSchema).default({})
|
|
135
|
+
});
|
|
136
|
+
var continuationSettingsSchema = z.object({
|
|
137
|
+
enabled: z.boolean().default(false),
|
|
138
|
+
/** Consecutive host-authored continuations before the run stops regardless. */
|
|
139
|
+
maxConsecutive: z.number().int().min(1).max(1e3).default(50),
|
|
140
|
+
/**
|
|
141
|
+
* Identical progress witnesses in a row before the run stops as no-progress.
|
|
142
|
+
* Minimum 1: a 0 here would fire on the first boundary, before any witness
|
|
143
|
+
* exists, and label a run that never got a chance to spin as spinning.
|
|
144
|
+
*/
|
|
145
|
+
noProgressLimit: z.number().int().min(1).max(20).default(3),
|
|
146
|
+
/**
|
|
147
|
+
* Consecutive turns in which EVERY tool call was refused before the run stops.
|
|
148
|
+
*
|
|
149
|
+
* Enforced even when `enabled` is false, deliberately. The spin it catches
|
|
150
|
+
* predates continuation and needs no continuation to happen: a headless run in
|
|
151
|
+
* the default permission mode answers every prompt `deny`, so the model can
|
|
152
|
+
* re-issue a refused call forever while `toolCalls.length > 0` keeps the
|
|
153
|
+
* turn-end gate from ever firing. None of the existing anti-loop signals see it
|
|
154
|
+
* either — the repeated-failure breaker ignores anything that is not `error`,
|
|
155
|
+
* and `toolCallStats.failures` excludes `blocked` by construction.
|
|
156
|
+
*
|
|
157
|
+
* 0 disables the guard.
|
|
158
|
+
*/
|
|
159
|
+
blockedToolTurnLimit: z.number().int().min(0).max(100).default(3),
|
|
160
|
+
/** Turns between host-authored work-state messages; 0 disables them. */
|
|
161
|
+
planRefreshTurns: z.number().int().min(0).max(500).default(25),
|
|
162
|
+
/** Wall-clock ceiling for one continued run; 0 means no ceiling. */
|
|
163
|
+
maxWallClockMs: z.number().int().min(0).default(0)
|
|
164
|
+
});
|
|
165
|
+
var memorySettingsSchema = z.object({
|
|
166
|
+
enabled: z.boolean().default(true),
|
|
167
|
+
autoSave: z.boolean().default(true),
|
|
168
|
+
requireApproval: z.boolean().default(true)
|
|
169
|
+
});
|
|
170
|
+
var agentSettingsSchema = z.object({
|
|
171
|
+
mode: z.enum(["adaptive", "manual", "off"]).default("adaptive"),
|
|
172
|
+
maxConcurrent: z.number().int().min(1).max(16).default(3),
|
|
173
|
+
maxSpawned: z.number().int().min(1).max(64).default(8),
|
|
174
|
+
maxDepth: z.literal(1).default(1),
|
|
175
|
+
persist: z.boolean().default(true),
|
|
176
|
+
includeUntrackedInSnapshot: z.boolean().default(true),
|
|
177
|
+
telemetry: z.boolean().default(true),
|
|
178
|
+
retentionDays: z.number().int().min(1).max(3650).default(30),
|
|
179
|
+
checks: z.record(z.union([z.string().min(1), z.array(z.string().min(1)).min(1)])).default({}),
|
|
180
|
+
/**
|
|
181
|
+
* Wall-clock ceiling for one `Check` run. The 120s default suits a focused
|
|
182
|
+
* suite; a full `npm test` on a large repository routinely exceeds it, and a
|
|
183
|
+
* check that always times out is worse than no check because the timeout was
|
|
184
|
+
* reported as a failing suite. Raise it per project rather than per invocation.
|
|
185
|
+
*/
|
|
186
|
+
checkTimeoutMs: z.number().int().min(1e3).max(72e5).default(12e4),
|
|
187
|
+
/**
|
|
188
|
+
* Simultaneous agent worktrees per repository; 0 disables the check.
|
|
189
|
+
*
|
|
190
|
+
* Nothing reclaims a worktree automatically outside the TUI, and the store's
|
|
191
|
+
* retention sweep runs once at startup with a 30-day default — so on a long
|
|
192
|
+
* unattended run the count only grows. Sized above `maxConcurrent` so ordinary
|
|
193
|
+
* fan-out is unaffected and only accumulation trips it.
|
|
194
|
+
*/
|
|
195
|
+
maxWorktrees: z.number().int().min(0).max(256).default(24),
|
|
196
|
+
/**
|
|
197
|
+
* Re-drive agents that were interrupted by process death on the next start.
|
|
198
|
+
*
|
|
199
|
+
* A restart otherwise converts the whole pending backlog into terminal records
|
|
200
|
+
* nothing picks up, silently losing hours of child work on a wide fan-out. The
|
|
201
|
+
* re-drive is contained: explorers are read-only and patchers/validators run in
|
|
202
|
+
* their own worktree, so nothing reaches the parent workspace without the usual
|
|
203
|
+
* evidence gate. Only `process_exit` interruptions qualify — a user stop stays
|
|
204
|
+
* stopped.
|
|
205
|
+
*/
|
|
206
|
+
resumeInterrupted: z.boolean().default(true),
|
|
207
|
+
/**
|
|
208
|
+
* Refuse a new worktree when free disk would fall below this; 0 disables.
|
|
209
|
+
* Worktrees share the filesystem with the workspace, so exhausting it breaks
|
|
210
|
+
* the root agent's own Edit and Bash, not just the child's.
|
|
211
|
+
*/
|
|
212
|
+
minFreeDiskBytes: z.number().int().min(0).default(2 * 1024 * 1024 * 1024),
|
|
213
|
+
profiles: z.record(
|
|
214
|
+
z.object({
|
|
215
|
+
model: z.string().min(1).optional(),
|
|
216
|
+
effort: effortLevelSchema.optional(),
|
|
217
|
+
maxTurns: z.number().int().min(1).optional(),
|
|
218
|
+
color: z.string().optional()
|
|
219
|
+
})
|
|
220
|
+
).default({}),
|
|
221
|
+
ui: z.object({ enabled: z.boolean().default(true) }).default({}),
|
|
222
|
+
routing: z.object({
|
|
223
|
+
inlineSearchBudget: z.number().int().min(1).max(20).default(3),
|
|
224
|
+
exploreReminder: z.boolean().default(true)
|
|
225
|
+
}).default({}),
|
|
226
|
+
forwardTextEvents: z.boolean().default(false)
|
|
227
|
+
});
|
|
228
|
+
var toolDiscoverySettingsSchema = z.object({
|
|
229
|
+
mode: z.enum(["auto", "eager", "deferred"]).default("auto"),
|
|
230
|
+
eagerToolCount: z.number().int().min(1).max(100).default(10),
|
|
231
|
+
schemaTokenBudget: z.number().int().min(1e3).max(1e5).default(8e3),
|
|
232
|
+
maxLoadedTools: z.number().int().min(1).max(100).default(15),
|
|
233
|
+
searchLimit: z.number().int().min(1).max(5).default(5)
|
|
234
|
+
});
|
|
235
|
+
var toolExecutionSettingsSchema = z.object({
|
|
236
|
+
/** Shared across the root loop and managed children for parallel-safe tools. */
|
|
237
|
+
maxConcurrent: z.number().int().min(1).max(8).default(4)
|
|
238
|
+
});
|
|
239
|
+
var observabilitySettingsSchema = z.object({
|
|
240
|
+
/** Persist a per-tool-call JSONL record for `book tool-stats`. */
|
|
241
|
+
toolTelemetry: z.boolean().default(true),
|
|
242
|
+
/**
|
|
243
|
+
* Default reporting window (in days) for `book tool-stats` and the target for
|
|
244
|
+
* `book tool-stats --prune`. Disk use is bounded by size-based log rotation;
|
|
245
|
+
* records are only deleted when they rotate out or are explicitly pruned.
|
|
246
|
+
*/
|
|
247
|
+
toolTelemetryRetentionDays: z.number().int().min(1).max(3650).default(30)
|
|
248
|
+
});
|
|
249
|
+
var mcpProjectServerChoiceSchema = z.object({
|
|
250
|
+
/** Hash of the server's command/args/env at decision time; a mismatch re-prompts. */
|
|
251
|
+
fingerprint: z.string().min(1),
|
|
252
|
+
choice: z.enum(["approved", "rejected"])
|
|
253
|
+
});
|
|
254
|
+
var mcpSettingsSchema = z.object({
|
|
255
|
+
/**
|
|
256
|
+
* Per-server trust decisions for workspace `.mcp.json` declarations.
|
|
257
|
+
* User-global servers (<BOOK_HOME>/.book/mcp.json) never require approval.
|
|
258
|
+
*/
|
|
259
|
+
projectServers: z.record(mcpProjectServerChoiceSchema).default({})
|
|
260
|
+
});
|
|
261
|
+
var projectCommandChoiceSchema = z.object({
|
|
262
|
+
/** Digest of the shell the body substitutes at decision time; a mismatch re-prompts. */
|
|
263
|
+
fingerprint: z.string().min(1),
|
|
264
|
+
choice: z.enum(["approved", "rejected"])
|
|
265
|
+
});
|
|
266
|
+
var commandSettingsSchema = z.object({
|
|
267
|
+
/**
|
|
268
|
+
* Per-command trust decisions for `<workspace>/.book/commands/*.md` files
|
|
269
|
+
* that substitute shell into their prompt. That substitution runs outside the
|
|
270
|
+
* permission system and outside the sandbox, so a repository-controlled file
|
|
271
|
+
* needs a decision before it runs. User-global commands
|
|
272
|
+
* (<BOOK_HOME>/commands) were written by the user and never require one.
|
|
273
|
+
*/
|
|
274
|
+
projectCommands: z.record(projectCommandChoiceSchema).default({})
|
|
275
|
+
});
|
|
276
|
+
var uiSettingsSchema = z.object({
|
|
277
|
+
/** Show provider-native and embedded model reasoning in the interactive transcript. */
|
|
278
|
+
showThinking: z.boolean().default(true),
|
|
279
|
+
/** Play the full-screen fire sequence on a newly created interactive startup session. */
|
|
280
|
+
startupAnimation: z.boolean().default(true)
|
|
281
|
+
});
|
|
282
|
+
var skillActivationSchema = z.enum(["auto", "name-only", "manual", "off"]);
|
|
283
|
+
var skillExecutionSchema = z.enum(["inherit", "ask", "deny"]);
|
|
284
|
+
var skillSettingsSchema = z.object({
|
|
285
|
+
/** Emergency switch that removes skill prompt and runtime effects without deleting packages. */
|
|
286
|
+
enabled: z.boolean().default(true),
|
|
287
|
+
/** Per-skill visibility overrides keyed by the skill's declared name. */
|
|
288
|
+
overrides: z.record(skillActivationSchema).default({}),
|
|
289
|
+
/** Per-skill activation consent policy. Tool calls still use the normal permission system. */
|
|
290
|
+
execution: z.record(skillExecutionSchema).default({})
|
|
291
|
+
});
|
|
292
|
+
var compactStrategySchema = z.literal("summary");
|
|
293
|
+
var bookSettingsSchema = z.object({
|
|
294
|
+
model: z.string().optional(),
|
|
295
|
+
/** Default strategy used to reduce historical conversation context. */
|
|
296
|
+
compactStrategy: compactStrategySchema.optional(),
|
|
297
|
+
/** Optional model used only to generate historical conversation checkpoints. */
|
|
298
|
+
compactModel: z.string().min(1).optional(),
|
|
299
|
+
/** Max agent turns per user message. Omit for unlimited. */
|
|
300
|
+
maxTurns: z.number().int().min(1).optional(),
|
|
301
|
+
maxTokens: z.number().int().min(1e3).optional(),
|
|
302
|
+
effort: effortLevelSchema.optional(),
|
|
303
|
+
/** TUI color theme: apple (default), dark, light, auto, a bundled palette, or a custom theme filename. */
|
|
304
|
+
theme: z.string().min(1).optional(),
|
|
305
|
+
/**
|
|
306
|
+
* The shell the Bash tool spawns: `bash`, `pwsh`, `powershell`, `cmd`, `sh`,
|
|
307
|
+
* or an executable path. Honoured from the user-global layer, an explicit
|
|
308
|
+
* `--settings` document, or `BOOK_SHELL` only: a workspace file cannot pick
|
|
309
|
+
* the program every command is handed to.
|
|
310
|
+
*/
|
|
311
|
+
shell: z.string().min(1).optional(),
|
|
312
|
+
ui: uiSettingsSchema.default({}),
|
|
313
|
+
skills: skillSettingsSchema.default({}),
|
|
314
|
+
autoCompactEnabled: z.boolean().optional(),
|
|
315
|
+
/** Permission mode used by each host when no invocation-specific mode is supplied. */
|
|
316
|
+
defaultMode: z.enum(["default", "acceptEdits", "plan", "auto", "dontAsk", "bypassPermissions"]).optional(),
|
|
317
|
+
disableBypassPermissionsMode: z.boolean().optional(),
|
|
318
|
+
additionalDirectories: z.array(z.string()).default([]),
|
|
319
|
+
env: z.record(z.string()).default({}),
|
|
320
|
+
provider: z.record(providerConfigSchema).default({}),
|
|
321
|
+
permissions: permissionsSchema.default({}),
|
|
322
|
+
sandbox: sandboxSchema.default({}),
|
|
323
|
+
hooks: hooksSchema.default({}),
|
|
324
|
+
retry: retrySettingsSchema.default({}),
|
|
325
|
+
memory: memorySettingsSchema.default({}),
|
|
326
|
+
continuation: continuationSettingsSchema.default({}),
|
|
327
|
+
agents: agentSettingsSchema.default({}),
|
|
328
|
+
toolDiscovery: toolDiscoverySettingsSchema.default({}),
|
|
329
|
+
toolExecution: toolExecutionSettingsSchema.default({}),
|
|
330
|
+
observability: observabilitySettingsSchema.default({}),
|
|
331
|
+
mcp: mcpSettingsSchema.default({}),
|
|
332
|
+
commands: commandSettingsSchema.default({})
|
|
333
|
+
});
|
|
334
|
+
var DEFAULT_SETTINGS = {
|
|
335
|
+
compactStrategy: "summary",
|
|
336
|
+
permissions: { allow: [], ask: [], deny: [], projectAllowRules: {} },
|
|
337
|
+
sandbox: {
|
|
338
|
+
enabled: false,
|
|
339
|
+
failIfUnavailable: false,
|
|
340
|
+
autoAllowBashIfSandboxed: true,
|
|
341
|
+
excludedCommands: [],
|
|
342
|
+
allowUnsandboxedCommands: true,
|
|
343
|
+
filesystem: { allowWrite: [], denyWrite: [], denyRead: [] },
|
|
344
|
+
network: { allowedDomains: [], deniedDomains: [] }
|
|
345
|
+
},
|
|
346
|
+
hooks: {
|
|
347
|
+
SessionStart: [],
|
|
348
|
+
SessionEnd: [],
|
|
349
|
+
UserPromptSubmit: [],
|
|
350
|
+
PreToolUse: [],
|
|
351
|
+
PostToolUse: [],
|
|
352
|
+
Stop: [],
|
|
353
|
+
PreCompact: [],
|
|
354
|
+
PostCompact: [],
|
|
355
|
+
SubagentStart: [],
|
|
356
|
+
SubagentStop: [],
|
|
357
|
+
Notification: [],
|
|
358
|
+
projectEntries: {}
|
|
359
|
+
},
|
|
360
|
+
additionalDirectories: [],
|
|
361
|
+
env: {},
|
|
362
|
+
provider: {},
|
|
363
|
+
ui: { showThinking: true, startupAnimation: true },
|
|
364
|
+
skills: { enabled: true, overrides: {}, execution: {} },
|
|
365
|
+
retry: {
|
|
366
|
+
maxAttempts: 10,
|
|
367
|
+
baseDelayMs: 1e3,
|
|
368
|
+
maxDelayMs: 3e4,
|
|
369
|
+
totalBudgetMs: 0,
|
|
370
|
+
requestTimeoutMs: 6e5,
|
|
371
|
+
streamStallTimeoutMs: 2e4,
|
|
372
|
+
thinkingStallTimeoutMs: 9e5,
|
|
373
|
+
toolRetries: 1,
|
|
374
|
+
watchdog: false,
|
|
375
|
+
streamReissueAttempts: 3,
|
|
376
|
+
outputCapContinuations: 10
|
|
377
|
+
},
|
|
378
|
+
continuation: {
|
|
379
|
+
enabled: false,
|
|
380
|
+
maxConsecutive: 50,
|
|
381
|
+
noProgressLimit: 3,
|
|
382
|
+
blockedToolTurnLimit: 3,
|
|
383
|
+
planRefreshTurns: 25,
|
|
384
|
+
maxWallClockMs: 0
|
|
385
|
+
},
|
|
386
|
+
memory: {
|
|
387
|
+
enabled: true,
|
|
388
|
+
autoSave: true,
|
|
389
|
+
requireApproval: true
|
|
390
|
+
},
|
|
391
|
+
agents: {
|
|
392
|
+
mode: "adaptive",
|
|
393
|
+
maxConcurrent: 3,
|
|
394
|
+
maxSpawned: 8,
|
|
395
|
+
maxDepth: 1,
|
|
396
|
+
persist: true,
|
|
397
|
+
includeUntrackedInSnapshot: true,
|
|
398
|
+
telemetry: true,
|
|
399
|
+
retentionDays: 30,
|
|
400
|
+
checks: {},
|
|
401
|
+
checkTimeoutMs: 12e4,
|
|
402
|
+
maxWorktrees: 24,
|
|
403
|
+
resumeInterrupted: true,
|
|
404
|
+
minFreeDiskBytes: 2 * 1024 * 1024 * 1024,
|
|
405
|
+
profiles: {},
|
|
406
|
+
ui: { enabled: true },
|
|
407
|
+
routing: { inlineSearchBudget: 3, exploreReminder: true },
|
|
408
|
+
forwardTextEvents: false
|
|
409
|
+
},
|
|
410
|
+
toolDiscovery: {
|
|
411
|
+
mode: "auto",
|
|
412
|
+
eagerToolCount: 10,
|
|
413
|
+
schemaTokenBudget: 8e3,
|
|
414
|
+
maxLoadedTools: 15,
|
|
415
|
+
searchLimit: 5
|
|
416
|
+
},
|
|
417
|
+
toolExecution: {
|
|
418
|
+
maxConcurrent: 4
|
|
419
|
+
},
|
|
420
|
+
observability: {
|
|
421
|
+
toolTelemetry: true,
|
|
422
|
+
toolTelemetryRetentionDays: 30
|
|
423
|
+
},
|
|
424
|
+
mcp: {
|
|
425
|
+
projectServers: {}
|
|
426
|
+
},
|
|
427
|
+
commands: {
|
|
428
|
+
projectCommands: {}
|
|
429
|
+
}
|
|
430
|
+
};
|
|
431
|
+
|
|
432
|
+
// src/settings-repository.ts
|
|
433
|
+
import {
|
|
434
|
+
closeSync,
|
|
435
|
+
existsSync,
|
|
436
|
+
fsyncSync,
|
|
437
|
+
mkdirSync,
|
|
438
|
+
openSync,
|
|
439
|
+
readFileSync,
|
|
440
|
+
renameSync,
|
|
441
|
+
statSync,
|
|
442
|
+
unlinkSync,
|
|
443
|
+
writeSync
|
|
444
|
+
} from "fs";
|
|
445
|
+
import { basename, dirname, join } from "path";
|
|
446
|
+
|
|
447
|
+
// src/cli/utils.ts
|
|
448
|
+
function getNestedValue(obj, path) {
|
|
449
|
+
const parts = path.split(".");
|
|
450
|
+
let current = obj;
|
|
451
|
+
for (const part of parts) {
|
|
452
|
+
if (current === null || current === void 0 || typeof current !== "object") return void 0;
|
|
453
|
+
current = current[part];
|
|
454
|
+
}
|
|
455
|
+
return current;
|
|
456
|
+
}
|
|
457
|
+
function setNestedValue(obj, path, value) {
|
|
458
|
+
const parts = path.split(".");
|
|
459
|
+
let current = obj;
|
|
460
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
461
|
+
if (!(parts[i] in current) || typeof current[parts[i]] !== "object" || current[parts[i]] === null) {
|
|
462
|
+
current[parts[i]] = {};
|
|
463
|
+
}
|
|
464
|
+
current = current[parts[i]];
|
|
465
|
+
}
|
|
466
|
+
current[parts[parts.length - 1]] = value;
|
|
467
|
+
}
|
|
468
|
+
function deleteNestedValue(obj, path) {
|
|
469
|
+
const parts = typeof path === "string" ? path.split(".") : [...path];
|
|
470
|
+
const ancestors = [];
|
|
471
|
+
let current = obj;
|
|
472
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
473
|
+
const key = parts[i];
|
|
474
|
+
if (!Object.prototype.hasOwnProperty.call(current, key)) return false;
|
|
475
|
+
const next = current[key];
|
|
476
|
+
if (typeof next !== "object" || next === null || Array.isArray(next)) return false;
|
|
477
|
+
ancestors.push({ parent: current, key });
|
|
478
|
+
current = next;
|
|
479
|
+
}
|
|
480
|
+
const leaf = parts[parts.length - 1];
|
|
481
|
+
if (!Object.prototype.hasOwnProperty.call(current, leaf)) return false;
|
|
482
|
+
delete current[leaf];
|
|
483
|
+
for (let i = ancestors.length - 1; i >= 0; i--) {
|
|
484
|
+
const { parent, key } = ancestors[i];
|
|
485
|
+
const child = parent[key];
|
|
486
|
+
if (typeof child === "object" && child !== null && !Array.isArray(child) && Object.keys(child).length === 0) {
|
|
487
|
+
delete parent[key];
|
|
488
|
+
} else {
|
|
489
|
+
break;
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
return true;
|
|
493
|
+
}
|
|
494
|
+
function parseNumericFlag(raw, flag, opts = {}) {
|
|
495
|
+
if (raw === void 0 || raw === null || raw === "") return void 0;
|
|
496
|
+
const text = String(raw).trim();
|
|
497
|
+
const value = opts.integer ? Number.parseInt(text, 10) : Number.parseFloat(text);
|
|
498
|
+
if (!Number.isFinite(value) || !/^[+-]?(\d+\.?\d*|\.\d+)$/.test(text)) {
|
|
499
|
+
throw new Error(`${flag} expects a number, but received "${text}".`);
|
|
500
|
+
}
|
|
501
|
+
if (opts.integer && text.includes(".")) {
|
|
502
|
+
throw new Error(`${flag} expects a whole number, but received "${text}".`);
|
|
503
|
+
}
|
|
504
|
+
const min = opts.min ?? 0;
|
|
505
|
+
if (value < min) {
|
|
506
|
+
throw new Error(`${flag} must be at least ${min}, but received "${text}".`);
|
|
507
|
+
}
|
|
508
|
+
return value;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
// src/settings-redaction.ts
|
|
512
|
+
var REDACTED_SECRET = "*** (stored)";
|
|
513
|
+
function redactProviderRecord(value) {
|
|
514
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return value;
|
|
515
|
+
const clone = structuredClone(value);
|
|
516
|
+
if ("apiKey" in clone) clone.apiKey = REDACTED_SECRET;
|
|
517
|
+
return clone;
|
|
518
|
+
}
|
|
519
|
+
function redactProviderMap(value) {
|
|
520
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return value;
|
|
521
|
+
const clone = structuredClone(value);
|
|
522
|
+
for (const [id, provider] of Object.entries(clone)) clone[id] = redactProviderRecord(provider);
|
|
523
|
+
return clone;
|
|
524
|
+
}
|
|
525
|
+
var REMOVED_SECRET_BEARING_BLOCKS = ["auth"];
|
|
526
|
+
function redactSettingValue(path, value) {
|
|
527
|
+
const parts = path.split(".");
|
|
528
|
+
if (parts[0] && REMOVED_SECRET_BEARING_BLOCKS.includes(parts[0])) return REDACTED_SECRET;
|
|
529
|
+
if (parts[0] !== "provider") return value;
|
|
530
|
+
if (parts.length === 1) return redactProviderMap(value);
|
|
531
|
+
if (parts.length === 2) return redactProviderRecord(value);
|
|
532
|
+
return parts[parts.length - 1] === "apiKey" ? REDACTED_SECRET : value;
|
|
533
|
+
}
|
|
534
|
+
function redactSettingsForDisplay(value) {
|
|
535
|
+
if (!value || typeof value !== "object") return value;
|
|
536
|
+
const clone = structuredClone(value);
|
|
537
|
+
clone.provider = redactProviderMap(clone.provider);
|
|
538
|
+
for (const key of REMOVED_SECRET_BEARING_BLOCKS) {
|
|
539
|
+
if (clone[key] !== void 0) clone[key] = REDACTED_SECRET;
|
|
540
|
+
}
|
|
541
|
+
return clone;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
// src/settings-repository.ts
|
|
545
|
+
var SETTINGS_TOP_LEVEL_KEYS = Object.freeze(Object.keys(bookSettingsSchema.shape).sort());
|
|
546
|
+
function formatSettingsKeyHelp(heading = "Supported top-level settings:") {
|
|
547
|
+
return `${heading}
|
|
548
|
+
${SETTINGS_TOP_LEVEL_KEYS.map((key) => ` ${key}`).join("\n")}`;
|
|
549
|
+
}
|
|
550
|
+
function issueDiagnostic(path, issue) {
|
|
551
|
+
return {
|
|
552
|
+
path,
|
|
553
|
+
issuePath: issue.path.join("."),
|
|
554
|
+
message: issue.message
|
|
555
|
+
};
|
|
556
|
+
}
|
|
557
|
+
function safeMessage(error) {
|
|
558
|
+
return error instanceof Error ? error.message : String(error);
|
|
559
|
+
}
|
|
560
|
+
function readSettingsDocument(path) {
|
|
561
|
+
if (!existsSync(path)) return { status: "absent", path };
|
|
562
|
+
let parsed;
|
|
563
|
+
try {
|
|
564
|
+
parsed = JSON.parse(readFileSync(path, "utf-8"));
|
|
565
|
+
} catch (error) {
|
|
566
|
+
return { status: "malformed", path, error: safeMessage(error) };
|
|
567
|
+
}
|
|
568
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
569
|
+
return { status: "non-object", path, error: "Settings must contain a JSON object." };
|
|
570
|
+
}
|
|
571
|
+
return { status: "valid", path, document: parsed };
|
|
572
|
+
}
|
|
573
|
+
function writeFileAtomic(path, contents) {
|
|
574
|
+
const directory = dirname(path);
|
|
575
|
+
mkdirSync(directory, { recursive: true });
|
|
576
|
+
const temporaryPath = join(
|
|
577
|
+
directory,
|
|
578
|
+
`.${basename(path)}.${process.pid}.${crypto.randomUUID()}.tmp`
|
|
579
|
+
);
|
|
580
|
+
let descriptor;
|
|
581
|
+
try {
|
|
582
|
+
descriptor = openSync(temporaryPath, "wx", 384);
|
|
583
|
+
writeSync(descriptor, contents, void 0, "utf-8");
|
|
584
|
+
fsyncSync(descriptor);
|
|
585
|
+
closeSync(descriptor);
|
|
586
|
+
descriptor = void 0;
|
|
587
|
+
renameSync(temporaryPath, path);
|
|
588
|
+
} catch (error) {
|
|
589
|
+
if (descriptor !== void 0) closeSync(descriptor);
|
|
590
|
+
try {
|
|
591
|
+
unlinkSync(temporaryPath);
|
|
592
|
+
} catch {
|
|
593
|
+
}
|
|
594
|
+
throw error;
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
function validateTopLevelKeys(path, document) {
|
|
598
|
+
const supported = new Set(SETTINGS_TOP_LEVEL_KEYS);
|
|
599
|
+
return Object.keys(document).filter((key) => !supported.has(key)).map((key) => ({
|
|
600
|
+
path,
|
|
601
|
+
issuePath: key,
|
|
602
|
+
message: `Unknown top-level setting. Supported keys: ${SETTINGS_TOP_LEVEL_KEYS.join(", ")}`
|
|
603
|
+
}));
|
|
604
|
+
}
|
|
605
|
+
var SettingsRepository = class {
|
|
606
|
+
constructor(path, options = {}) {
|
|
607
|
+
this.path = path;
|
|
608
|
+
this.writeAtomic = options.writeAtomic ?? writeFileAtomic;
|
|
609
|
+
}
|
|
610
|
+
path;
|
|
611
|
+
writeAtomic;
|
|
612
|
+
read() {
|
|
613
|
+
return readSettingsDocument(this.path);
|
|
614
|
+
}
|
|
615
|
+
set(values) {
|
|
616
|
+
return this.mutate((candidate) => {
|
|
617
|
+
for (const [key, value] of Object.entries(values)) setNestedValue(candidate, key, value);
|
|
618
|
+
}, values);
|
|
619
|
+
}
|
|
620
|
+
remove(paths) {
|
|
621
|
+
return this.mutate((candidate) => {
|
|
622
|
+
for (const path of paths) deleteNestedValue(candidate, path.split("."));
|
|
623
|
+
}, {});
|
|
624
|
+
}
|
|
625
|
+
update(mutation, displayValues = {}) {
|
|
626
|
+
return this.mutate(mutation, displayValues);
|
|
627
|
+
}
|
|
628
|
+
mutate(mutation, values) {
|
|
629
|
+
let lock;
|
|
630
|
+
try {
|
|
631
|
+
lock = this.acquireLock();
|
|
632
|
+
return this.mutateLocked(mutation, values);
|
|
633
|
+
} catch (error) {
|
|
634
|
+
return {
|
|
635
|
+
ok: false,
|
|
636
|
+
path: this.path,
|
|
637
|
+
diagnostics: [{ path: this.path, message: safeMessage(error) }]
|
|
638
|
+
};
|
|
639
|
+
} finally {
|
|
640
|
+
if (lock !== void 0) this.releaseLock(lock);
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
acquireLock() {
|
|
644
|
+
mkdirSync(dirname(this.path), { recursive: true });
|
|
645
|
+
const lockPath = `${this.path}.lock`;
|
|
646
|
+
for (let attempt = 0; attempt < 50; attempt++) {
|
|
647
|
+
try {
|
|
648
|
+
return openSync(lockPath, "wx", 384);
|
|
649
|
+
} catch (error) {
|
|
650
|
+
if (error.code !== "EEXIST") throw error;
|
|
651
|
+
try {
|
|
652
|
+
if (Date.now() - statSync(lockPath).mtimeMs > 1e4) unlinkSync(lockPath);
|
|
653
|
+
} catch {
|
|
654
|
+
}
|
|
655
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 10);
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
throw new Error(`Timed out waiting for settings lock: ${lockPath}`);
|
|
659
|
+
}
|
|
660
|
+
releaseLock(descriptor) {
|
|
661
|
+
closeSync(descriptor);
|
|
662
|
+
try {
|
|
663
|
+
unlinkSync(`${this.path}.lock`);
|
|
664
|
+
} catch {
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
mutateLocked(mutation, values) {
|
|
668
|
+
const source = this.read();
|
|
669
|
+
if (source.status === "malformed" || source.status === "non-object") {
|
|
670
|
+
return {
|
|
671
|
+
ok: false,
|
|
672
|
+
path: this.path,
|
|
673
|
+
diagnostics: [{ path: this.path, message: source.error }]
|
|
674
|
+
};
|
|
675
|
+
}
|
|
676
|
+
const candidate = structuredClone(source.status === "valid" ? source.document : {});
|
|
677
|
+
try {
|
|
678
|
+
mutation(candidate);
|
|
679
|
+
} catch (error) {
|
|
680
|
+
return {
|
|
681
|
+
ok: false,
|
|
682
|
+
path: this.path,
|
|
683
|
+
diagnostics: [{ path: this.path, message: safeMessage(error) }]
|
|
684
|
+
};
|
|
685
|
+
}
|
|
686
|
+
const keyDiagnostics = validateTopLevelKeys(this.path, candidate);
|
|
687
|
+
const validation = bookSettingsSchema.safeParse(candidate);
|
|
688
|
+
const diagnostics = [
|
|
689
|
+
...keyDiagnostics,
|
|
690
|
+
...validation.success ? [] : validation.error.issues.map((issue) => issueDiagnostic(this.path, issue))
|
|
691
|
+
];
|
|
692
|
+
if (diagnostics.length > 0) return { ok: false, path: this.path, diagnostics };
|
|
693
|
+
try {
|
|
694
|
+
const changed = source.status !== "valid" || JSON.stringify(source.document) !== JSON.stringify(candidate);
|
|
695
|
+
if (changed) this.writeAtomic(this.path, JSON.stringify(candidate, null, 2) + "\n");
|
|
696
|
+
return {
|
|
697
|
+
ok: true,
|
|
698
|
+
path: this.path,
|
|
699
|
+
document: candidate,
|
|
700
|
+
changed,
|
|
701
|
+
values: Object.fromEntries(
|
|
702
|
+
Object.entries(values).map(([key, value]) => [key, redactSettingValue(key, value)])
|
|
703
|
+
)
|
|
704
|
+
};
|
|
705
|
+
} catch (error) {
|
|
706
|
+
return {
|
|
707
|
+
ok: false,
|
|
708
|
+
path: this.path,
|
|
709
|
+
diagnostics: [{ path: this.path, message: safeMessage(error) }]
|
|
710
|
+
};
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
};
|
|
714
|
+
function formatSettingsDiagnostics(diagnostics) {
|
|
715
|
+
return diagnostics.map((diagnostic) => {
|
|
716
|
+
const location = diagnostic.issuePath ? `${diagnostic.path} (${diagnostic.issuePath})` : diagnostic.path;
|
|
717
|
+
return `${location}: ${diagnostic.message}`;
|
|
718
|
+
}).join("\n");
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
export {
|
|
722
|
+
projectAllowRuleChoiceSchema,
|
|
723
|
+
projectHookChoiceSchema,
|
|
724
|
+
HOOK_EVENTS,
|
|
725
|
+
effortLevelSchema,
|
|
726
|
+
providerConfigSchema,
|
|
727
|
+
mcpProjectServerChoiceSchema,
|
|
728
|
+
projectCommandChoiceSchema,
|
|
729
|
+
bookSettingsSchema,
|
|
730
|
+
DEFAULT_SETTINGS,
|
|
731
|
+
getNestedValue,
|
|
732
|
+
setNestedValue,
|
|
733
|
+
parseNumericFlag,
|
|
734
|
+
redactSettingValue,
|
|
735
|
+
redactSettingsForDisplay,
|
|
736
|
+
SETTINGS_TOP_LEVEL_KEYS,
|
|
737
|
+
formatSettingsKeyHelp,
|
|
738
|
+
readSettingsDocument,
|
|
739
|
+
writeFileAtomic,
|
|
740
|
+
SettingsRepository,
|
|
741
|
+
formatSettingsDiagnostics
|
|
742
|
+
};
|
|
743
|
+
//# sourceMappingURL=chunk-574C6MQR.js.map
|