@curdx/flow 2.3.1 → 2.3.3
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.
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
},
|
|
7
7
|
"metadata": {
|
|
8
8
|
"description": "Claude Code Discipline Layer — spec-driven workflow + goal-backward verification + Karpathy 4 principles enforced via gates. Stops Claude from faking \"done\" on non-trivial features.",
|
|
9
|
-
"version": "2.3.
|
|
9
|
+
"version": "2.3.3"
|
|
10
10
|
},
|
|
11
11
|
"allowCrossMarketplaceDependenciesOn": [
|
|
12
12
|
"context7-marketplace"
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"name": "curdx-flow",
|
|
17
17
|
"source": "./",
|
|
18
18
|
"description": "Claude Code Discipline Layer — spec-driven workflow + goal-backward verification + Karpathy 4 principles enforced via gates. Stops Claude from faking \"done\" on non-trivial features.",
|
|
19
|
-
"version": "2.3.
|
|
19
|
+
"version": "2.3.3",
|
|
20
20
|
"author": {
|
|
21
21
|
"name": "wdx",
|
|
22
22
|
"email": "bydongxin@gmail.com"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "curdx-flow",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.3",
|
|
4
4
|
"description": "Claude Code Discipline Layer — spec-driven workflow + goal-backward verification + Karpathy 4 principles enforced via gates. Stops Claude from faking \"done\" on non-trivial features.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "wdx",
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import fs from "node:fs/promises";
|
|
2
|
+
import os from "node:os";
|
|
2
3
|
import path from "node:path";
|
|
3
4
|
|
|
4
5
|
const PROJECT_ONLY_IGNORED_SETTINGS = [
|
|
@@ -99,6 +100,23 @@ const CURDX_FLOW_REQUIRED_TOOLS = [
|
|
|
99
100
|
"Glob",
|
|
100
101
|
];
|
|
101
102
|
const CURDX_FLOW_PLUGIN_ID = "curdx-flow@curdx-flow-marketplace";
|
|
103
|
+
const CURDX_FLOW_PLUGIN_OPTIONS = {
|
|
104
|
+
autonomous_blocking: {
|
|
105
|
+
type: "boolean",
|
|
106
|
+
default: true,
|
|
107
|
+
},
|
|
108
|
+
daily_dependency_check: {
|
|
109
|
+
type: "boolean",
|
|
110
|
+
default: true,
|
|
111
|
+
},
|
|
112
|
+
monitor_interval_seconds: {
|
|
113
|
+
type: "number",
|
|
114
|
+
default: 8,
|
|
115
|
+
integer: true,
|
|
116
|
+
min: 3,
|
|
117
|
+
max: 60,
|
|
118
|
+
},
|
|
119
|
+
};
|
|
102
120
|
const CURDX_FLOW_REQUIRED_PLUGIN_IDS = ["context7-plugin@context7-marketplace"];
|
|
103
121
|
const HTTP_HOOK_SETTINGS = ["allowedHttpHookUrls", "httpHookAllowedEnvVars"];
|
|
104
122
|
const PERSISTED_EFFORT_LEVELS = ["low", "medium", "high", "xhigh"];
|
|
@@ -171,6 +189,201 @@ function pushScopedWarning(target, kind, message, scope = "project") {
|
|
|
171
189
|
target.push(warning);
|
|
172
190
|
}
|
|
173
191
|
|
|
192
|
+
function createCurdxFlowPluginOptionsState() {
|
|
193
|
+
const definitions = Object.entries(CURDX_FLOW_PLUGIN_OPTIONS).map(([key, value]) => ({
|
|
194
|
+
key,
|
|
195
|
+
type: value.type,
|
|
196
|
+
default: value.default,
|
|
197
|
+
min: value.min,
|
|
198
|
+
max: value.max,
|
|
199
|
+
integer: value.integer === true,
|
|
200
|
+
}));
|
|
201
|
+
|
|
202
|
+
const repoEffective = Object.fromEntries(
|
|
203
|
+
definitions.map((definition) => [
|
|
204
|
+
definition.key,
|
|
205
|
+
{ value: definition.default, source: "default" },
|
|
206
|
+
])
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
return {
|
|
210
|
+
pluginId: CURDX_FLOW_PLUGIN_ID,
|
|
211
|
+
definitions,
|
|
212
|
+
user: {
|
|
213
|
+
pluginConfigsPresent: false,
|
|
214
|
+
pluginConfigPresent: false,
|
|
215
|
+
optionsPresent: false,
|
|
216
|
+
overrides: {},
|
|
217
|
+
},
|
|
218
|
+
project: {
|
|
219
|
+
pluginConfigsPresent: false,
|
|
220
|
+
pluginConfigPresent: false,
|
|
221
|
+
optionsPresent: false,
|
|
222
|
+
overrides: {},
|
|
223
|
+
},
|
|
224
|
+
local: {
|
|
225
|
+
pluginConfigsPresent: false,
|
|
226
|
+
pluginConfigPresent: false,
|
|
227
|
+
optionsPresent: false,
|
|
228
|
+
overrides: {},
|
|
229
|
+
},
|
|
230
|
+
repoEffective,
|
|
231
|
+
machineEffective: structuredClone(repoEffective),
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
function pluginScopeLabel(scope) {
|
|
236
|
+
if (scope === "local") return "settings.local.json";
|
|
237
|
+
if (scope === "user") return "~/.claude/settings.json";
|
|
238
|
+
return "settings.json";
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
function invalidSettingKindForScope(scope) {
|
|
242
|
+
if (scope === "local") return "invalid-local-setting";
|
|
243
|
+
if (scope === "user") return "invalid-user-setting";
|
|
244
|
+
return "invalid-project-setting";
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function applyCurdxFlowPluginOptionOverride(pluginOptionsState, key, value, scope) {
|
|
248
|
+
pluginOptionsState.machineEffective[key] = {
|
|
249
|
+
value,
|
|
250
|
+
source: scope,
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
if (scope === "project" || scope === "local") {
|
|
254
|
+
pluginOptionsState.repoEffective[key] = {
|
|
255
|
+
value,
|
|
256
|
+
source: scope,
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function auditCurdxFlowPluginOptions(parsed, warnings, pluginOptionsState, scope = "project") {
|
|
262
|
+
if (!isNonArrayObject(parsed) || !("pluginConfigs" in parsed)) {
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const target = scope === "local"
|
|
267
|
+
? pluginOptionsState.local
|
|
268
|
+
: scope === "user"
|
|
269
|
+
? pluginOptionsState.user
|
|
270
|
+
: pluginOptionsState.project;
|
|
271
|
+
const settingsLabel = pluginScopeLabel(scope);
|
|
272
|
+
target.pluginConfigsPresent = true;
|
|
273
|
+
|
|
274
|
+
if (!isNonArrayObject(parsed.pluginConfigs)) {
|
|
275
|
+
pushScopedWarning(
|
|
276
|
+
warnings,
|
|
277
|
+
invalidSettingKindForScope(scope),
|
|
278
|
+
`pluginConfigs in ${settingsLabel} must be an object keyed by plugin@marketplace id`,
|
|
279
|
+
scope
|
|
280
|
+
);
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
const pluginConfig = parsed.pluginConfigs[CURDX_FLOW_PLUGIN_ID];
|
|
285
|
+
if (pluginConfig === undefined) {
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
target.pluginConfigPresent = true;
|
|
290
|
+
|
|
291
|
+
if (!isNonArrayObject(pluginConfig)) {
|
|
292
|
+
pushScopedWarning(
|
|
293
|
+
warnings,
|
|
294
|
+
invalidSettingKindForScope(scope),
|
|
295
|
+
`pluginConfigs[${CURDX_FLOW_PLUGIN_ID}] in ${settingsLabel} must be an object when set`,
|
|
296
|
+
scope
|
|
297
|
+
);
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
if (!("options" in pluginConfig)) {
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
target.optionsPresent = true;
|
|
306
|
+
|
|
307
|
+
if (!isNonArrayObject(pluginConfig.options)) {
|
|
308
|
+
pushScopedWarning(
|
|
309
|
+
warnings,
|
|
310
|
+
invalidSettingKindForScope(scope),
|
|
311
|
+
`pluginConfigs[${CURDX_FLOW_PLUGIN_ID}].options in ${settingsLabel} must be an object when set`,
|
|
312
|
+
scope
|
|
313
|
+
);
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
for (const [key, value] of Object.entries(pluginConfig.options)) {
|
|
318
|
+
const definition = CURDX_FLOW_PLUGIN_OPTIONS[key];
|
|
319
|
+
|
|
320
|
+
if (!definition) {
|
|
321
|
+
pushScopedWarning(
|
|
322
|
+
warnings,
|
|
323
|
+
"unknown-plugin-option",
|
|
324
|
+
`unknown CurDX-Flow plugin option in ${settingsLabel}: ${key}`,
|
|
325
|
+
scope
|
|
326
|
+
);
|
|
327
|
+
continue;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
if (definition.type === "boolean" && typeof value !== "boolean") {
|
|
331
|
+
pushScopedWarning(
|
|
332
|
+
warnings,
|
|
333
|
+
invalidSettingKindForScope(scope),
|
|
334
|
+
`CurDX-Flow plugin option ${key} in ${settingsLabel} must be boolean`,
|
|
335
|
+
scope
|
|
336
|
+
);
|
|
337
|
+
continue;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
if (definition.type === "number") {
|
|
341
|
+
if (typeof value !== "number" || Number.isNaN(value)) {
|
|
342
|
+
pushScopedWarning(
|
|
343
|
+
warnings,
|
|
344
|
+
invalidSettingKindForScope(scope),
|
|
345
|
+
`CurDX-Flow plugin option ${key} in ${settingsLabel} must be a number`,
|
|
346
|
+
scope
|
|
347
|
+
);
|
|
348
|
+
continue;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
if (definition.integer && !Number.isInteger(value)) {
|
|
352
|
+
pushScopedWarning(
|
|
353
|
+
warnings,
|
|
354
|
+
invalidSettingKindForScope(scope),
|
|
355
|
+
`CurDX-Flow plugin option ${key} in ${settingsLabel} must be an integer`,
|
|
356
|
+
scope
|
|
357
|
+
);
|
|
358
|
+
continue;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
if (typeof definition.min === "number" && value < definition.min) {
|
|
362
|
+
pushScopedWarning(
|
|
363
|
+
warnings,
|
|
364
|
+
invalidSettingKindForScope(scope),
|
|
365
|
+
`CurDX-Flow plugin option ${key} in ${settingsLabel} must be between ${definition.min} and ${definition.max}`,
|
|
366
|
+
scope
|
|
367
|
+
);
|
|
368
|
+
continue;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
if (typeof definition.max === "number" && value > definition.max) {
|
|
372
|
+
pushScopedWarning(
|
|
373
|
+
warnings,
|
|
374
|
+
invalidSettingKindForScope(scope),
|
|
375
|
+
`CurDX-Flow plugin option ${key} in ${settingsLabel} must be between ${definition.min} and ${definition.max}`,
|
|
376
|
+
scope
|
|
377
|
+
);
|
|
378
|
+
continue;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
target.overrides[key] = value;
|
|
383
|
+
applyCurdxFlowPluginOptionOverride(pluginOptionsState, key, value, scope);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
174
387
|
function auditLocalClaudeSettings(parsed, warnings) {
|
|
175
388
|
const scope = "local";
|
|
176
389
|
const permissions = parsed?.permissions && typeof parsed.permissions === "object"
|
|
@@ -362,10 +575,15 @@ function auditLocalClaudeSettings(parsed, warnings) {
|
|
|
362
575
|
}
|
|
363
576
|
}
|
|
364
577
|
|
|
365
|
-
export async function readProjectClaudeSettings(cwd = process.cwd()) {
|
|
578
|
+
export async function readProjectClaudeSettings(cwd = process.cwd(), { homeDir = os.homedir() } = {}) {
|
|
366
579
|
const settingsPath = path.join(cwd, ".claude", "settings.json");
|
|
367
580
|
const localSettingsPath = path.join(cwd, ".claude", "settings.local.json");
|
|
581
|
+
const userSettingsPath = path.join(homeDir, ".claude", "settings.json");
|
|
368
582
|
const state = {
|
|
583
|
+
userExists: false,
|
|
584
|
+
userInvalid: false,
|
|
585
|
+
userParseError: null,
|
|
586
|
+
userWarnings: [],
|
|
369
587
|
exists: false,
|
|
370
588
|
localExists: false,
|
|
371
589
|
invalid: false,
|
|
@@ -374,8 +592,16 @@ export async function readProjectClaudeSettings(cwd = process.cwd()) {
|
|
|
374
592
|
localInvalid: false,
|
|
375
593
|
localParseError: null,
|
|
376
594
|
localWarnings: [],
|
|
595
|
+
pluginOptions: createCurdxFlowPluginOptionsState(),
|
|
377
596
|
};
|
|
378
597
|
|
|
598
|
+
try {
|
|
599
|
+
const userStat = await fs.stat(userSettingsPath);
|
|
600
|
+
state.userExists = userStat.isFile();
|
|
601
|
+
} catch {
|
|
602
|
+
state.userExists = false;
|
|
603
|
+
}
|
|
604
|
+
|
|
379
605
|
try {
|
|
380
606
|
const localStat = await fs.stat(localSettingsPath);
|
|
381
607
|
state.localExists = localStat.isFile();
|
|
@@ -383,6 +609,16 @@ export async function readProjectClaudeSettings(cwd = process.cwd()) {
|
|
|
383
609
|
state.localExists = false;
|
|
384
610
|
}
|
|
385
611
|
|
|
612
|
+
if (state.userExists) {
|
|
613
|
+
try {
|
|
614
|
+
const userParsed = JSON.parse(await fs.readFile(userSettingsPath, "utf-8"));
|
|
615
|
+
auditCurdxFlowPluginOptions(userParsed, state.userWarnings, state.pluginOptions, "user");
|
|
616
|
+
} catch (error) {
|
|
617
|
+
state.userInvalid = true;
|
|
618
|
+
state.userParseError = error?.message || String(error);
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
|
|
386
622
|
let parsed;
|
|
387
623
|
try {
|
|
388
624
|
const stat = await fs.stat(settingsPath);
|
|
@@ -407,6 +643,8 @@ export async function readProjectClaudeSettings(cwd = process.cwd()) {
|
|
|
407
643
|
const allow = Array.isArray(permissions.allow) ? permissions.allow : [];
|
|
408
644
|
const deny = Array.isArray(permissions.deny) ? permissions.deny : [];
|
|
409
645
|
|
|
646
|
+
auditCurdxFlowPluginOptions(parsed, state.warnings, state.pluginOptions, "project");
|
|
647
|
+
|
|
410
648
|
if ("enabledPlugins" in parsed && (
|
|
411
649
|
!parsed.enabledPlugins ||
|
|
412
650
|
typeof parsed.enabledPlugins !== "object" ||
|
|
@@ -726,6 +964,7 @@ export async function readProjectClaudeSettings(cwd = process.cwd()) {
|
|
|
726
964
|
if (state.localExists) {
|
|
727
965
|
try {
|
|
728
966
|
const localParsed = JSON.parse(await fs.readFile(localSettingsPath, "utf-8"));
|
|
967
|
+
auditCurdxFlowPluginOptions(localParsed, state.localWarnings, state.pluginOptions, "local");
|
|
729
968
|
auditLocalClaudeSettings(localParsed, state.localWarnings);
|
|
730
969
|
} catch (error) {
|
|
731
970
|
state.localInvalid = true;
|
package/cli/lib/doctor-report.js
CHANGED
|
@@ -13,7 +13,54 @@ function pluginErrorDetails(plugin) {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
function projectSettingsWarningDetails(warning) {
|
|
16
|
+
if (warning?.scope === "user") {
|
|
17
|
+
if (warning.kind === "unknown-plugin-option") {
|
|
18
|
+
return [
|
|
19
|
+
"~/.claude/settings.json applies across all your repositories on this machine",
|
|
20
|
+
"remove the unknown key or rename it to a supported CurDX-Flow plugin option under pluginConfigs[curdx-flow@curdx-flow-marketplace].options",
|
|
21
|
+
];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (
|
|
25
|
+
warning.kind === "invalid-user-setting" &&
|
|
26
|
+
(
|
|
27
|
+
warning.message?.includes("pluginConfigs[curdx-flow@curdx-flow-marketplace]") ||
|
|
28
|
+
warning.message?.includes("CurDX-Flow plugin option")
|
|
29
|
+
)
|
|
30
|
+
) {
|
|
31
|
+
return [
|
|
32
|
+
"CurDX-Flow plugin options in ~/.claude/settings.json apply across all local repositories unless a project or local override wins",
|
|
33
|
+
"use boolean values for autonomous_blocking and daily_dependency_check, and keep monitor_interval_seconds as an integer between 3 and 60",
|
|
34
|
+
];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return [
|
|
38
|
+
"~/.claude/settings.json applies across all your repositories on this machine",
|
|
39
|
+
"fix or remove the user-scoped override if CurDX-Flow behaves unexpectedly everywhere",
|
|
40
|
+
];
|
|
41
|
+
}
|
|
42
|
+
|
|
16
43
|
if (warning?.scope === "local") {
|
|
44
|
+
if (warning.kind === "unknown-plugin-option") {
|
|
45
|
+
return [
|
|
46
|
+
"settings.local.json overrides shared project settings on this machine",
|
|
47
|
+
"remove the unknown key or rename it to a supported CurDX-Flow plugin option under pluginConfigs[curdx-flow@curdx-flow-marketplace].options",
|
|
48
|
+
];
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (
|
|
52
|
+
warning.kind === "invalid-local-setting" &&
|
|
53
|
+
(
|
|
54
|
+
warning.message?.includes("pluginConfigs[curdx-flow@curdx-flow-marketplace]") ||
|
|
55
|
+
warning.message?.includes("CurDX-Flow plugin option")
|
|
56
|
+
)
|
|
57
|
+
) {
|
|
58
|
+
return [
|
|
59
|
+
"CurDX-Flow plugin options in settings.local.json override project and user settings on this machine",
|
|
60
|
+
"use boolean values for autonomous_blocking and daily_dependency_check, and keep monitor_interval_seconds as an integer between 3 and 60",
|
|
61
|
+
];
|
|
62
|
+
}
|
|
63
|
+
|
|
17
64
|
if (warning.kind === "invalid-local-setting") {
|
|
18
65
|
return [
|
|
19
66
|
"settings.local.json is the highest-precedence repo-scoped settings surface on this machine",
|
|
@@ -41,6 +88,26 @@ function projectSettingsWarningDetails(warning) {
|
|
|
41
88
|
];
|
|
42
89
|
}
|
|
43
90
|
|
|
91
|
+
if (warning.kind === "unknown-plugin-option") {
|
|
92
|
+
return [
|
|
93
|
+
"CurDX-Flow only reads keys declared in the plugin manifest",
|
|
94
|
+
"remove the unknown key or rename it under pluginConfigs[curdx-flow@curdx-flow-marketplace].options",
|
|
95
|
+
];
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (
|
|
99
|
+
warning.kind === "invalid-project-setting" &&
|
|
100
|
+
(
|
|
101
|
+
warning.message?.includes("pluginConfigs[curdx-flow@curdx-flow-marketplace]") ||
|
|
102
|
+
warning.message?.includes("CurDX-Flow plugin option")
|
|
103
|
+
)
|
|
104
|
+
) {
|
|
105
|
+
return [
|
|
106
|
+
"CurDX-Flow non-sensitive plugin options belong under pluginConfigs[curdx-flow@curdx-flow-marketplace].options in .claude/settings.json",
|
|
107
|
+
"use boolean values for autonomous_blocking and daily_dependency_check, and keep monitor_interval_seconds as an integer between 3 and 60",
|
|
108
|
+
];
|
|
109
|
+
}
|
|
110
|
+
|
|
44
111
|
if (!warning?.kind) {
|
|
45
112
|
return [
|
|
46
113
|
"project settings are shared with collaborators",
|
|
@@ -116,6 +183,11 @@ function projectSettingsWarningDetails(warning) {
|
|
|
116
183
|
];
|
|
117
184
|
}
|
|
118
185
|
|
|
186
|
+
function formatInlineValue(value) {
|
|
187
|
+
if (typeof value === "string") return `"${value}"`;
|
|
188
|
+
return String(value);
|
|
189
|
+
}
|
|
190
|
+
|
|
119
191
|
export function buildDoctorReport({
|
|
120
192
|
claudeVersionValue,
|
|
121
193
|
nodeVersion,
|
|
@@ -403,6 +475,129 @@ export function buildDoctorReport({
|
|
|
403
475
|
}
|
|
404
476
|
}
|
|
405
477
|
|
|
478
|
+
if (
|
|
479
|
+
bundledPluginRuntimeDefaults?.exists ||
|
|
480
|
+
projectClaudeSettings?.pluginOptions
|
|
481
|
+
) {
|
|
482
|
+
const configuredOptionsSection = createSection("CurDX-Flow configured options:");
|
|
483
|
+
const optionState = projectClaudeSettings?.pluginOptions;
|
|
484
|
+
const userOverrides = optionState?.user?.overrides || {};
|
|
485
|
+
const projectOverrides = optionState?.project?.overrides || {};
|
|
486
|
+
const localOverrides = optionState?.local?.overrides || {};
|
|
487
|
+
const machineEffective = optionState?.machineEffective || optionState?.repoEffective || {};
|
|
488
|
+
const definitions = bundledPluginRuntimeDefaults?.userConfig?.length
|
|
489
|
+
? bundledPluginRuntimeDefaults.userConfig
|
|
490
|
+
: (optionState?.definitions || []);
|
|
491
|
+
|
|
492
|
+
pushSectionLine(
|
|
493
|
+
configuredOptionsSection,
|
|
494
|
+
"info",
|
|
495
|
+
"Scope precedence settings.local.json > settings.json > ~/.claude/settings.json > bundled default",
|
|
496
|
+
[
|
|
497
|
+
"managed settings and command-line overrides are not inspected here",
|
|
498
|
+
"effective values below reflect this machine only",
|
|
499
|
+
]
|
|
500
|
+
);
|
|
501
|
+
|
|
502
|
+
if (projectClaudeSettings?.userExists) {
|
|
503
|
+
if (Object.keys(userOverrides).length > 0) {
|
|
504
|
+
const summary = Object.entries(userOverrides)
|
|
505
|
+
.map(([key, value]) => `${key}=${formatInlineValue(value)}`)
|
|
506
|
+
.join(", ");
|
|
507
|
+
pushSectionLine(
|
|
508
|
+
configuredOptionsSection,
|
|
509
|
+
"info",
|
|
510
|
+
`~/.claude/settings.json ${Object.keys(userOverrides).length} valid override(s)`,
|
|
511
|
+
[
|
|
512
|
+
summary,
|
|
513
|
+
"user-scoped overrides apply across repositories unless project/local settings win",
|
|
514
|
+
]
|
|
515
|
+
);
|
|
516
|
+
} else {
|
|
517
|
+
pushSectionLine(
|
|
518
|
+
configuredOptionsSection,
|
|
519
|
+
"info",
|
|
520
|
+
"~/.claude/settings.json present without valid CurDX-Flow overrides"
|
|
521
|
+
);
|
|
522
|
+
}
|
|
523
|
+
} else {
|
|
524
|
+
pushSectionLine(
|
|
525
|
+
configuredOptionsSection,
|
|
526
|
+
"info",
|
|
527
|
+
"~/.claude/settings.json not present"
|
|
528
|
+
);
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
if (Object.keys(projectOverrides).length > 0) {
|
|
532
|
+
const summary = Object.entries(projectOverrides)
|
|
533
|
+
.map(([key, value]) => `${key}=${formatInlineValue(value)}`)
|
|
534
|
+
.join(", ");
|
|
535
|
+
pushSectionLine(
|
|
536
|
+
configuredOptionsSection,
|
|
537
|
+
"info",
|
|
538
|
+
`.claude/settings.json ${Object.keys(projectOverrides).length} valid override(s)`,
|
|
539
|
+
[
|
|
540
|
+
summary,
|
|
541
|
+
"path: pluginConfigs[curdx-flow@curdx-flow-marketplace].options",
|
|
542
|
+
]
|
|
543
|
+
);
|
|
544
|
+
} else {
|
|
545
|
+
pushSectionLine(
|
|
546
|
+
configuredOptionsSection,
|
|
547
|
+
"info",
|
|
548
|
+
".claude/settings.json no CurDX-Flow repo override"
|
|
549
|
+
);
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
if (projectClaudeSettings?.localExists) {
|
|
553
|
+
if (Object.keys(localOverrides).length > 0) {
|
|
554
|
+
const summary = Object.entries(localOverrides)
|
|
555
|
+
.map(([key, value]) => `${key}=${formatInlineValue(value)}`)
|
|
556
|
+
.join(", ");
|
|
557
|
+
pushSectionLine(
|
|
558
|
+
configuredOptionsSection,
|
|
559
|
+
"info",
|
|
560
|
+
`.claude/settings.local.json ${Object.keys(localOverrides).length} valid override(s)`,
|
|
561
|
+
[
|
|
562
|
+
summary,
|
|
563
|
+
"local overrides have higher precedence than .claude/settings.json on this machine",
|
|
564
|
+
]
|
|
565
|
+
);
|
|
566
|
+
} else {
|
|
567
|
+
pushSectionLine(
|
|
568
|
+
configuredOptionsSection,
|
|
569
|
+
"info",
|
|
570
|
+
".claude/settings.local.json present without valid CurDX-Flow overrides"
|
|
571
|
+
);
|
|
572
|
+
}
|
|
573
|
+
} else {
|
|
574
|
+
pushSectionLine(
|
|
575
|
+
configuredOptionsSection,
|
|
576
|
+
"info",
|
|
577
|
+
".claude/settings.local.json not present"
|
|
578
|
+
);
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
for (const definition of definitions) {
|
|
582
|
+
const effective = machineEffective[definition.key] || {
|
|
583
|
+
value: definition.default,
|
|
584
|
+
source: "default",
|
|
585
|
+
};
|
|
586
|
+
const sourceLabel = effective.source === "local"
|
|
587
|
+
? "local"
|
|
588
|
+
: effective.source === "project"
|
|
589
|
+
? "project"
|
|
590
|
+
: effective.source === "user"
|
|
591
|
+
? "user"
|
|
592
|
+
: "bundled default";
|
|
593
|
+
pushSectionLine(
|
|
594
|
+
configuredOptionsSection,
|
|
595
|
+
"ok",
|
|
596
|
+
`${definition.key.padEnd(22)} ${formatInlineValue(effective.value)} (${sourceLabel})`
|
|
597
|
+
);
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
|
|
406
601
|
const localProjectSection = createSection("Local project:");
|
|
407
602
|
if (projectState?.exists) {
|
|
408
603
|
pushSectionLine(localProjectSection, "ok", `.flow/ ${cwd}`);
|
|
@@ -490,6 +685,33 @@ export function buildDoctorReport({
|
|
|
490
685
|
}
|
|
491
686
|
|
|
492
687
|
const projectSettingsSection = createSection("Project Claude settings:");
|
|
688
|
+
const userSettingsSection = createSection("User Claude settings:");
|
|
689
|
+
|
|
690
|
+
if (projectClaudeSettings?.userExists) {
|
|
691
|
+
if (projectClaudeSettings.userInvalid) {
|
|
692
|
+
pushSectionLine(
|
|
693
|
+
userSettingsSection,
|
|
694
|
+
"err",
|
|
695
|
+
"~/.claude/settings.json invalid JSON",
|
|
696
|
+
[projectClaudeSettings.userParseError]
|
|
697
|
+
);
|
|
698
|
+
} else if ((projectClaudeSettings.userWarnings || []).length > 0) {
|
|
699
|
+
pushSectionLine(userSettingsSection, "warn", "~/.claude/settings.json affects CurDX-Flow globally");
|
|
700
|
+
for (const warning of projectClaudeSettings.userWarnings) {
|
|
701
|
+
pushSectionLine(
|
|
702
|
+
userSettingsSection,
|
|
703
|
+
"warn",
|
|
704
|
+
warning.message,
|
|
705
|
+
projectSettingsWarningDetails(warning)
|
|
706
|
+
);
|
|
707
|
+
}
|
|
708
|
+
} else {
|
|
709
|
+
pushSectionLine(userSettingsSection, "ok", "~/.claude/settings.json present");
|
|
710
|
+
}
|
|
711
|
+
} else {
|
|
712
|
+
pushSectionLine(userSettingsSection, "info", "~/.claude/settings.json not present");
|
|
713
|
+
}
|
|
714
|
+
|
|
493
715
|
if (projectClaudeSettings?.exists) {
|
|
494
716
|
if (projectClaudeSettings.invalid) {
|
|
495
717
|
pushSectionLine(
|