codex-configurator 0.2.2 → 0.2.4
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/README.md +17 -1
- package/index.js +119 -13
- package/package.json +1 -1
- package/src/components/ConfigNavigator.js +178 -89
- package/src/configFeatures.js +3 -26
- package/src/configHelp.js +97 -8
- package/src/configParser.js +1 -5
- package/src/configReference.js +13 -2
- package/src/constants.js +2 -1
- package/src/fuzzySearch.js +39 -0
- package/src/reference/config-reference.json +578 -2921
package/src/configHelp.js
CHANGED
|
@@ -2,7 +2,12 @@ import {
|
|
|
2
2
|
getConfigFeatureDefinition,
|
|
3
3
|
getConfigFeatureDefinitionOrFallback,
|
|
4
4
|
} from './configFeatures.js';
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
getReferenceOptionForPath,
|
|
7
|
+
getReferenceCustomIdPlaceholder,
|
|
8
|
+
getReferenceDescendantOptions,
|
|
9
|
+
getReferenceTableDefinitions,
|
|
10
|
+
} from './configReference.js';
|
|
6
11
|
|
|
7
12
|
const CONFIG_VALUE_OPTIONS = {
|
|
8
13
|
model: [
|
|
@@ -16,12 +21,6 @@ const CONFIG_VALUE_OPTIONS = {
|
|
|
16
21
|
};
|
|
17
22
|
|
|
18
23
|
const CONFIG_PATH_EXPLANATIONS = [
|
|
19
|
-
{
|
|
20
|
-
path: ['tools', 'web_search'],
|
|
21
|
-
short: 'Deprecated legacy web search flag.',
|
|
22
|
-
usage: 'Use the top-level web_search setting instead.',
|
|
23
|
-
deprecation: 'tools.web_search is deprecated; use the top-level web_search setting instead.',
|
|
24
|
-
},
|
|
25
24
|
{
|
|
26
25
|
path: ['projects', '*', 'trust_level'],
|
|
27
26
|
short: 'Controls how much trust this project gets for command execution.',
|
|
@@ -54,6 +53,24 @@ const CONFIG_OPTION_EXPLANATIONS = {
|
|
|
54
53
|
untrusted: 'Limits risky actions and prompts more often.',
|
|
55
54
|
},
|
|
56
55
|
};
|
|
56
|
+
const SECTION_PURPOSE_OVERRIDES = {
|
|
57
|
+
agents: 'Named agent definitions and per-agent configuration file references.',
|
|
58
|
+
apps: 'Per-app enablement rules and tool-level approval controls.',
|
|
59
|
+
features: 'Feature flags for optional and experimental Codex behavior.',
|
|
60
|
+
feedback: 'Feedback submission settings for Codex surfaces.',
|
|
61
|
+
history: 'Session history retention policy and on-disk size limits.',
|
|
62
|
+
mcp_servers: 'MCP server definitions, transport settings, and authentication configuration.',
|
|
63
|
+
model_providers: 'Model provider definitions, API endpoints, and credential settings.',
|
|
64
|
+
notice: 'Visibility toggles for startup and migration notices.',
|
|
65
|
+
otel: 'OpenTelemetry exporter configuration for telemetry and traces.',
|
|
66
|
+
profiles: 'Named profile overrides you can select per session.',
|
|
67
|
+
projects: 'Project/worktree trust settings scoped by filesystem path.',
|
|
68
|
+
sandbox_workspace_write: 'Workspace-write sandbox behavior, writable roots, and network access rules.',
|
|
69
|
+
shell_environment_policy: 'Shell environment inheritance and variable override policy.',
|
|
70
|
+
skills: 'Skill discovery and loading controls.',
|
|
71
|
+
tools: 'Tool-related configuration, including legacy compatibility flags.',
|
|
72
|
+
tui: 'Terminal UI behavior, notifications, and presentation settings.',
|
|
73
|
+
};
|
|
57
74
|
|
|
58
75
|
const makePathSegments = (segments, key) => {
|
|
59
76
|
const normalizedSegments = Array.isArray(segments)
|
|
@@ -78,6 +95,73 @@ const getContextEntry = (segments, key, candidates) => {
|
|
|
78
95
|
|
|
79
96
|
const getReferenceEntry = (segments, key) => getReferenceOptionForPath(makePathSegments(segments, key));
|
|
80
97
|
|
|
98
|
+
const formatPlaceholderLabel = (placeholder) => {
|
|
99
|
+
const cleaned = String(placeholder || '')
|
|
100
|
+
.replace(/^</, '')
|
|
101
|
+
.replace(/>$/, '');
|
|
102
|
+
|
|
103
|
+
return cleaned || 'id';
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
const toFirstSentence = (text) => {
|
|
107
|
+
const normalized = String(text || '').replace(/\s+/g, ' ').trim();
|
|
108
|
+
if (!normalized) {
|
|
109
|
+
return '';
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const periodIndex = normalized.indexOf('. ');
|
|
113
|
+
if (periodIndex < 0) {
|
|
114
|
+
return normalized;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return normalized.slice(0, periodIndex + 1);
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
const getSectionPurposeDescription = (descendantOptions) => {
|
|
121
|
+
for (const option of descendantOptions) {
|
|
122
|
+
const firstSentence = toFirstSentence(option?.description);
|
|
123
|
+
if (firstSentence) {
|
|
124
|
+
return firstSentence;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return '';
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
const buildInferredSectionHelp = (segments, key) => {
|
|
132
|
+
const sectionPath = makePathSegments(segments, key);
|
|
133
|
+
const childDefinitions = getReferenceTableDefinitions(sectionPath);
|
|
134
|
+
const descendantOptions = getReferenceDescendantOptions(sectionPath);
|
|
135
|
+
const customPlaceholder = getReferenceCustomIdPlaceholder(sectionPath);
|
|
136
|
+
const parentCustomPlaceholder = getReferenceCustomIdPlaceholder(sectionPath.slice(0, -1));
|
|
137
|
+
|
|
138
|
+
if (childDefinitions.length === 0 && descendantOptions.length === 0 && !customPlaceholder) {
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const rootOverride = sectionPath.length === 1
|
|
143
|
+
? SECTION_PURPOSE_OVERRIDES[sectionPath[0]]
|
|
144
|
+
: null;
|
|
145
|
+
const customLabel = customPlaceholder ? formatPlaceholderLabel(customPlaceholder) : '';
|
|
146
|
+
const bestPurposeDescription = getSectionPurposeDescription(descendantOptions);
|
|
147
|
+
const dynamicEntryLabel = parentCustomPlaceholder
|
|
148
|
+
? formatPlaceholderLabel(parentCustomPlaceholder)
|
|
149
|
+
: '';
|
|
150
|
+
const short = rootOverride
|
|
151
|
+
|| (dynamicEntryLabel
|
|
152
|
+
? `Configuration for this ${dynamicEntryLabel} entry.`
|
|
153
|
+
: '')
|
|
154
|
+
|| bestPurposeDescription
|
|
155
|
+
|| (customLabel
|
|
156
|
+
? `Section for custom ${customLabel} entries.`
|
|
157
|
+
: 'Section with related settings.');
|
|
158
|
+
|
|
159
|
+
return {
|
|
160
|
+
short,
|
|
161
|
+
usage: null,
|
|
162
|
+
};
|
|
163
|
+
};
|
|
164
|
+
|
|
81
165
|
const getReferenceUsage = (entry) => {
|
|
82
166
|
if (entry.deprecated) {
|
|
83
167
|
return 'This option is deprecated in the official configuration reference.';
|
|
@@ -92,7 +176,7 @@ const getReferenceUsage = (entry) => {
|
|
|
92
176
|
}
|
|
93
177
|
|
|
94
178
|
if (entry.type === 'table') {
|
|
95
|
-
return '
|
|
179
|
+
return 'Press Enter to open this section and edit nested settings.';
|
|
96
180
|
}
|
|
97
181
|
|
|
98
182
|
if (entry.type.startsWith('array<')) {
|
|
@@ -144,6 +228,11 @@ export const getConfigHelp = (segments, key) => {
|
|
|
144
228
|
return referenceHelp;
|
|
145
229
|
}
|
|
146
230
|
|
|
231
|
+
const inferredSectionHelp = buildInferredSectionHelp(segments, key);
|
|
232
|
+
if (inferredSectionHelp) {
|
|
233
|
+
return inferredSectionHelp;
|
|
234
|
+
}
|
|
235
|
+
|
|
147
236
|
return null;
|
|
148
237
|
};
|
|
149
238
|
|
package/src/configParser.js
CHANGED
|
@@ -409,8 +409,7 @@ const formatRowLabel = (key, kind, value) =>
|
|
|
409
409
|
: `${key} = ${previewValue(value)}`;
|
|
410
410
|
|
|
411
411
|
const isPathDeprecated = (pathSegments, key) =>
|
|
412
|
-
Boolean(getReferenceOptionForPath([...pathSegments, String(key)])?.deprecated)
|
|
413
|
-
isToolsWebSearchDeprecated(pathSegments, key);
|
|
412
|
+
Boolean(getReferenceOptionForPath([...pathSegments, String(key)])?.deprecated);
|
|
414
413
|
|
|
415
414
|
const sortRowsAlphabetically = (rows) =>
|
|
416
415
|
[...rows].sort((left, right) => String(left.key).localeCompare(String(right.key)));
|
|
@@ -523,9 +522,6 @@ const buildRootRows = (node) => buildDefinedRows(node, getReferenceRootDefinitio
|
|
|
523
522
|
const getTableDefinitions = (pathSegments) =>
|
|
524
523
|
Array.isArray(pathSegments) ? getReferenceTableDefinitions(pathSegments) : [];
|
|
525
524
|
|
|
526
|
-
const isToolsWebSearchDeprecated = (pathSegments, key) =>
|
|
527
|
-
pathSegments[pathSegments.length - 1] === 'tools' && key === 'web_search';
|
|
528
|
-
|
|
529
525
|
export const getNodeAtPath = (root, segments) => {
|
|
530
526
|
let current = root;
|
|
531
527
|
|
package/src/configReference.js
CHANGED
|
@@ -5,7 +5,6 @@ const CONFIG_REFERENCE_DATA = require('./reference/config-reference.json');
|
|
|
5
5
|
|
|
6
6
|
const DOCUMENT_ID = 'config.toml';
|
|
7
7
|
const PLACEHOLDER_SEGMENT = /^<[^>]+>$/;
|
|
8
|
-
const NON_DEPRECATED_KEYS = new Set(['approval_policy']);
|
|
9
8
|
const KIND_PRIORITY = {
|
|
10
9
|
value: 1,
|
|
11
10
|
array: 2,
|
|
@@ -93,7 +92,7 @@ const referenceOptions = Array.isArray(configDocument?.options)
|
|
|
93
92
|
? option.enum_values.map((value) => String(value))
|
|
94
93
|
: [],
|
|
95
94
|
description: String(option?.description || ''),
|
|
96
|
-
deprecated: option?.deprecated === true
|
|
95
|
+
deprecated: option?.deprecated === true,
|
|
97
96
|
};
|
|
98
97
|
})
|
|
99
98
|
: [];
|
|
@@ -218,3 +217,15 @@ export const getReferenceCustomIdPlaceholder = (pathSegments = []) => {
|
|
|
218
217
|
const [firstMatch] = [...placeholders];
|
|
219
218
|
return firstMatch || null;
|
|
220
219
|
};
|
|
220
|
+
|
|
221
|
+
export const getReferenceDescendantOptions = (pathSegments = []) => {
|
|
222
|
+
const normalizedPath = normalizeSegments(pathSegments);
|
|
223
|
+
|
|
224
|
+
return referenceOptions
|
|
225
|
+
.filter(
|
|
226
|
+
(option) =>
|
|
227
|
+
pathPrefixMatches(option.keyPath, normalizedPath) &&
|
|
228
|
+
option.keyPath.length > normalizedPath.length
|
|
229
|
+
)
|
|
230
|
+
.sort((left, right) => left.keyPath.length - right.keyPath.length || left.key.localeCompare(right.key));
|
|
231
|
+
};
|
package/src/constants.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
export const CONTROL_HINT = '↑/↓ move • PgUp/PgDn page • Home/End jump • Enter: open section or edit • Del: unset value • ←/Backspace: back • r: reload • q: quit';
|
|
1
|
+
export const CONTROL_HINT = '↑/↓ move • PgUp/PgDn page • Home/End jump • Enter: open section or edit • /: filter • Del: unset value • ←/Backspace: back • r: reload • q: quit';
|
|
2
2
|
export const EDIT_CONTROL_HINT = '↑/↓ choose • PgUp/PgDn page • Home/End jump • Enter: save • Esc/Backspace/←: cancel • Del: delete char (text input) • r: reload • q: quit';
|
|
3
|
+
export const FILTER_CONTROL_HINT = 'Type filter • Enter/Esc: done • Del/Backspace: delete • Ctrl+U: clear';
|
|
3
4
|
export const BRAND = 'CODEX CONFIGURATOR';
|
|
4
5
|
export const CONFIG_TAGS = ['Node.js', 'React', 'Ink', 'TOML'];
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
const normalizeText = (value) => String(value || '').toLowerCase();
|
|
2
|
+
|
|
3
|
+
export const isFuzzyMatch = (query, text) => {
|
|
4
|
+
const normalizedQuery = normalizeText(query).trim();
|
|
5
|
+
if (!normalizedQuery) {
|
|
6
|
+
return true;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const normalizedText = normalizeText(text);
|
|
10
|
+
let queryIndex = 0;
|
|
11
|
+
|
|
12
|
+
for (let textIndex = 0; textIndex < normalizedText.length; textIndex += 1) {
|
|
13
|
+
if (normalizedText[textIndex] === normalizedQuery[queryIndex]) {
|
|
14
|
+
queryIndex += 1;
|
|
15
|
+
if (queryIndex >= normalizedQuery.length) {
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return false;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const rowSearchableTexts = (row) => [
|
|
25
|
+
row?.label,
|
|
26
|
+
row?.key,
|
|
27
|
+
row?.preview,
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
export const filterRowsByQuery = (rows, query) => {
|
|
31
|
+
const normalizedQuery = String(query || '').trim();
|
|
32
|
+
if (!normalizedQuery) {
|
|
33
|
+
return rows;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return rows.filter((row) =>
|
|
37
|
+
rowSearchableTexts(row).some((value) => isFuzzyMatch(normalizedQuery, value))
|
|
38
|
+
);
|
|
39
|
+
};
|