glimmervoid 0.35.0 → 0.36.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/README.md +2 -0
  2. package/dist/bin/glimmervoid.js +17 -12
  3. package/dist/chunks/{adapters-B37wqNti.js → adapters-BVozg-Lg.js} +1 -1
  4. package/dist/chunks/{adapters-CADejSpq.js → adapters-BdnLyJjf.js} +10 -49
  5. package/dist/chunks/{agent-api-cli-CRj_FYbz.js → agent-api-cli-DIqRLvu3.js} +1 -1
  6. package/dist/chunks/{agent-api-cli-vGwstJ1j.js → agent-api-cli-d-Bgsshx.js} +3 -3
  7. package/dist/chunks/{agent-api-core-D1233u1U.js → agent-api-core-BUC9WND7.js} +2 -2
  8. package/dist/chunks/{agent-setup-cli-BTAFcckd.js → agent-setup-cli-CH7EHsAX.js} +1 -1
  9. package/dist/chunks/{config-rPbbL4nW.js → config-CuZ16F9W.js} +47 -771
  10. package/dist/chunks/config-store-LqQ7MuyV.js +4181 -0
  11. package/dist/chunks/config-store-tVmt_nfm.js +1 -0
  12. package/dist/chunks/{contracts-DjIgIuDk.js → contracts-BLZAOP57.js} +55 -6
  13. package/dist/chunks/{grok-KKgdSe-7.js → grok-Ch4-35_r.js} +3 -3
  14. package/dist/chunks/{hook-command-core-DclEoE9e.js → hook-command-core-qTNK-xMF.js} +4 -1
  15. package/dist/chunks/{hook-tools-UX2fmt81.js → hook-tools-BkxllUHE.js} +9 -16
  16. package/dist/chunks/{knowledge-graph-cli-Rj5nj87L.js → knowledge-graph-cli-DD7QvcFd.js} +1 -1
  17. package/dist/chunks/{main-BTI0J5QE.js → main-Rmo83Ow-.js} +3087 -834
  18. package/dist/chunks/{pair-cli-Dcyzv3In.js → pair-cli-DzFeAmq5.js} +2 -2
  19. package/dist/chunks/{remote-config-Dd1T-VJA.js → remote-config-CPdSF2Xi.js} +1 -1
  20. package/dist/chunks/{rtk-hook-core-BmEz2aq9.js → rtk-hook-core-VrUafGAp.js} +15 -5
  21. package/dist/chunks/rtk-resolver-B8BPgN9L.js +1 -0
  22. package/dist/chunks/{rtk-resolver-B9pzjLsM.js → rtk-resolver-C_micGrL.js} +1 -1
  23. package/dist/chunks/session-B8RhqQJe.js +986 -0
  24. package/dist/chunks/{session-routes-BYy3am9m.js → session-routes-DB5aDKsx.js} +1 -1
  25. package/dist/chunks/settings-cli-C2TY6hl-.js +484 -0
  26. package/dist/chunks/{ssh-sign-cli-DPHpT22B.js → ssh-sign-cli-C2nUwJC-.js} +2 -2
  27. package/dist/client/assets/index-BIaSyXwH.css +1 -0
  28. package/dist/client/assets/index-Ddu7M4Ad.js +259 -0
  29. package/dist/client/index.html +5 -3
  30. package/dist/server/index.js +1 -1
  31. package/dist/session/hook-tool-relay.js +3 -3
  32. package/package.json +3 -3
  33. package/dist/chunks/config-store-BeIxAZNn.js +0 -1
  34. package/dist/chunks/config-store-BtsYbNC3.js +0 -1713
  35. package/dist/chunks/rtk-resolver-SWU5VVM7.js +0 -1
  36. package/dist/chunks/session-D6xXN0UU.js +0 -232
  37. package/dist/client/assets/index-DE2GUmqs.css +0 -1
  38. package/dist/client/assets/index-Ds4ngkHp.js +0 -254
@@ -1,4 +1,4 @@
1
- import { g as SESSION_COMMANDS } from "./session-D6xXN0UU.js";
1
+ import { h as SESSION_COMMANDS } from "./session-B8RhqQJe.js";
2
2
  //#region session/core/session-routes.ts
3
3
  var SUPERVISION_LINE = "Glimmervoid supervises this session. Run glimmervoid --help for the commands it gives you and this session's limits.";
4
4
  var GUARDRAILS_LINE = "Its guardrails are OS-enforced, so a read, write or connection they refuse will not succeed on retry.";
@@ -0,0 +1,484 @@
1
+ import { r as errorMessage, t as errorCode } from "./text-DoirglWV.js";
2
+ import "./session-B8RhqQJe.js";
3
+ import { t as renderTable } from "./ascii-figure-core-pDAwtlKO.js";
4
+ import { n as glimmervoidHomeDir, t as decideConfigPath } from "./config-path-core-DFt-TemS.js";
5
+ import { n as isRecord } from "./coerce-NSst8oRP.js";
6
+ import { r as BrowserConfig } from "./config-CuZ16F9W.js";
7
+ import { $ as withEnvSecrets, A as settingsOf, C as deleteValueAtPath, D as scoreSettingsSearch, E as parsePosthogProjectSelection, M as FILE_ONLY_GROUPS, N as SETTINGS_REGISTRY, O as setValueAtPath, S as cloneValue, T as hasScaledUnit, X as ENV_SECRET_BINDINGS, Z as readEnvSecrets, j as valueAtPath, k as settingsGroupOf, l as saveConfigFileOnce, s as loadConfigFile, u as validateConfig, w as displayText, x as SETTINGS_INDEX } from "./config-store-LqQ7MuyV.js";
8
+ import fs from "node:fs";
9
+ import os from "node:os";
10
+ import { parseArgs } from "node:util";
11
+ //#region server/settings-cli.ts
12
+ var usage = `glimmervoid settings: read and change config.json from the command line
13
+
14
+ glimmervoid settings list every config.json setting with its value and where the value comes from
15
+ glimmervoid settings get <path> one setting; a secret shows as configured or not configured, never its value
16
+ glimmervoid settings set <path> <value> validate the whole file and write it; a running Glimmervoid reloads it
17
+ glimmervoid settings unset <path> remove the key from config.json so the default applies
18
+ glimmervoid settings search <text> find settings by title, keyword, key path or section
19
+ glimmervoid settings schema every setting: id, path, type, default, unit, effect and section (needs no config file)
20
+
21
+ <path> is a config.json key path such as posthog.trafficSpikeEnabled, or a setting id such as posthog-traffic-enabled.
22
+ <value> is true or false for a toggle, a number, text, a comma-separated or JSON list, or JSON for a structured value.
23
+ A number is in the unit config.json stores, as schema's Stored unit column names: set visions.dispatch.quietMs 45000 means 45000 ms.
24
+ Where the dashboard shows another unit, get, list and set add it in parentheses, such as 30000 (30 seconds).
25
+ A secret (a bot token or API key) is never set or unset here, since a value on the command line lands in shell history;
26
+ change it in the dashboard settings or through its environment variable.
27
+ --json machine-readable output`;
28
+ var VALUE_COLUMN_WIDTH = 40;
29
+ var EFFECT_NOTES = Object.freeze({
30
+ now: "A running Glimmervoid applies it without a restart.",
31
+ "new-sessions": "Sessions started after this change use it.",
32
+ restart: "Restart Glimmervoid to apply it."
33
+ });
34
+ var HAND_EDITED_SETTING_REASONS = /* @__PURE__ */ new Map([["port", "a listener port that clashes with remote.port stops Glimmervoid from starting"]]);
35
+ var SECTION_BY_SETTING_ID = new Map([...SETTINGS_REGISTRY.sections.flatMap((section) => section.settings.map((setting) => [setting.id, {
36
+ id: section.id,
37
+ title: section.title
38
+ }])), ...SETTINGS_REGISTRY.fileOnly.map((setting) => {
39
+ const groupId = setting.group ?? "";
40
+ return [setting.id, {
41
+ id: groupId,
42
+ title: settingsGroupOf(groupId)?.title ?? groupId
43
+ }];
44
+ })]);
45
+ var ALL_SETTINGS = [...settingsOf(SETTINGS_REGISTRY.sections), ...SETTINGS_REGISTRY.fileOnly];
46
+ var SECTION_ORDER = [...SETTINGS_REGISTRY.sections.map((section) => ({
47
+ id: section.id,
48
+ title: section.title
49
+ })), ...Object.entries(FILE_ONLY_GROUPS).map(([id, group]) => ({
50
+ id,
51
+ title: group.title
52
+ }))];
53
+ function fail(message) {
54
+ return {
55
+ ok: false,
56
+ message
57
+ };
58
+ }
59
+ function succeed(value) {
60
+ return {
61
+ ok: true,
62
+ value
63
+ };
64
+ }
65
+ function isConfigFileSetting(setting) {
66
+ return setting.scope === "machine" && setting.control !== "readonly";
67
+ }
68
+ function sectionOf(setting) {
69
+ return SECTION_BY_SETTING_ID.get(setting.id) ?? {
70
+ id: "",
71
+ title: ""
72
+ };
73
+ }
74
+ function describeSetting(setting) {
75
+ const descriptor = {
76
+ id: setting.id,
77
+ path: setting.path,
78
+ title: setting.title,
79
+ description: setting.description,
80
+ type: setting.control,
81
+ scope: setting.scope,
82
+ access: setting.access,
83
+ effect: setting.takesEffect,
84
+ default: cloneValue(setting.defaultValue) ?? null,
85
+ unit: setting.unit?.storedLabel ?? setting.unit?.label ?? null,
86
+ displayUnit: setting.unit?.label ?? null,
87
+ storedPerDisplay: setting.unit?.storedPerDisplay ?? 1,
88
+ section: sectionOf(setting)
89
+ };
90
+ if (setting.options) descriptor.options = setting.options.map((option) => option.value);
91
+ if (setting.range) descriptor.range = setting.range;
92
+ if (setting.fileOnlyReason) descriptor.fileOnlyReason = setting.fileOnlyReason;
93
+ return descriptor;
94
+ }
95
+ function isStoredSecret(value) {
96
+ return typeof value === "string" && value.length > 0;
97
+ }
98
+ function readSetting(setting, view) {
99
+ const stored = valueAtPath(view.config, setting.path);
100
+ const source = view.secretSources[setting.path] ?? (stored !== void 0 ? "config.json" : "default");
101
+ const readout = {
102
+ ...describeSetting(setting),
103
+ secret: setting.control === "password",
104
+ source
105
+ };
106
+ if (readout.secret) {
107
+ readout.configured = isStoredSecret(stored);
108
+ return readout;
109
+ }
110
+ readout.value = stored !== void 0 ? cloneValue(stored) : readout.default;
111
+ return readout;
112
+ }
113
+ function fitColumn(text) {
114
+ if (text.length <= VALUE_COLUMN_WIDTH) return text;
115
+ return `${text.slice(0, 37)}...`;
116
+ }
117
+ function storedValueText(setting, value) {
118
+ if (setting.valueKind) return displayText(setting, value);
119
+ const stored = JSON.stringify(value ?? null);
120
+ if (typeof value !== "number" || !hasScaledUnit(setting)) return stored;
121
+ return `${stored} (${displayText(setting, value)})`;
122
+ }
123
+ function valueText(readout, setting) {
124
+ if (readout.secret) return readout.configured ? "configured" : "not configured";
125
+ return storedValueText(setting, readout.value);
126
+ }
127
+ function defaultText(setting) {
128
+ return storedValueText(setting, setting.defaultValue);
129
+ }
130
+ function settingsBySection(settings) {
131
+ return SECTION_ORDER.map((section) => ({
132
+ section,
133
+ settings: settings.filter((setting) => sectionOf(setting).id === section.id)
134
+ })).filter((group) => group.settings.length > 0);
135
+ }
136
+ function renderSectionTables(settings, headers, rowOf) {
137
+ return settingsBySection(settings).map(({ section, settings: grouped }) => renderTable({
138
+ title: section.title,
139
+ headers,
140
+ rows: grouped.map(rowOf),
141
+ align: headers.map(() => "left")
142
+ })).join("\n\n");
143
+ }
144
+ function resolveSetting(argument) {
145
+ return SETTINGS_INDEX.byPath.get(argument) ?? SETTINGS_INDEX.byId.get(argument) ?? null;
146
+ }
147
+ function requireConfigFileSetting(argument, configPath) {
148
+ const setting = resolveSetting(argument);
149
+ if (!setting) return fail(`${argument} is not a setting in the registry, so this command cannot read or change it; edit config.json at ${configPath} by hand`);
150
+ if (setting.scope === "browser") return fail(`${setting.id} is a browser preference saved in each browser, not in config.json; change it in the dashboard under Settings > ${sectionOf(setting).title}`);
151
+ if (setting.control === "readonly") return fail(`${setting.id} is a read-only status row under Settings > ${sectionOf(setting).title}; it has no config.json key`);
152
+ return succeed(setting);
153
+ }
154
+ function requirePositional(positionals, index, name) {
155
+ const value = positionals[index];
156
+ if (value === void 0) throw new Error(`missing <${name}>\n\n${usage}`);
157
+ return value;
158
+ }
159
+ function parseListValue(path, raw) {
160
+ const listError = `${path} must be a comma-separated list or a JSON array of strings`;
161
+ if (!raw.trim().startsWith("[")) return succeed(raw.split(",").map((entry) => entry.trim()).filter((entry) => entry !== ""));
162
+ try {
163
+ const parsed = JSON.parse(raw);
164
+ if (Array.isArray(parsed) && parsed.every((entry) => typeof entry === "string")) return succeed(parsed);
165
+ } catch {
166
+ return fail(listError);
167
+ }
168
+ return fail(listError);
169
+ }
170
+ function parseNumberValue(setting, raw) {
171
+ if (setting.nullable && raw.trim() === "") return succeed(null);
172
+ const number = Number(raw);
173
+ if (raw.trim() === "" || !Number.isFinite(number)) return fail(`${setting.path} must be a number`);
174
+ if (setting.integer !== false && !Number.isInteger(number)) return fail(`${setting.path} must be a whole number`);
175
+ if (setting.zeroIsNull && number <= 0) return succeed(null);
176
+ return succeed(number);
177
+ }
178
+ function parseSettingValue(setting, raw) {
179
+ if (setting.valueKind === "posthog-projects") {
180
+ const selection = parsePosthogProjectSelection(raw);
181
+ if (selection === null) return fail(`${setting.path} must be all, none or a comma-separated list of positive integer project ids`);
182
+ return succeed(selection);
183
+ }
184
+ if (setting.control === "toggle") {
185
+ if (/^(true|on|yes|1)$/i.test(raw.trim())) return succeed(true);
186
+ if (/^(false|off|no|0)$/i.test(raw.trim())) return succeed(false);
187
+ return fail(`${setting.path} must be a boolean: true or false`);
188
+ }
189
+ if (setting.control === "number") return parseNumberValue(setting, raw);
190
+ if (setting.control === "list" || setting.control === "projects") return parseListValue(setting.path, raw);
191
+ if (setting.control === "json") try {
192
+ return succeed(JSON.parse(raw));
193
+ } catch (error) {
194
+ return fail(`${setting.path} must be JSON: ${errorMessage(error)}`);
195
+ }
196
+ const text = raw.trim();
197
+ if (setting.nullable && text === "") return succeed(null);
198
+ return succeed(text);
199
+ }
200
+ function rangeLabel(range) {
201
+ if (range.label) return range.label;
202
+ if (range.max !== void 0) return `between ${range.min} and ${range.max}`;
203
+ return range.exclusiveMin ? `greater than ${range.min}` : `at least ${range.min}`;
204
+ }
205
+ function registryValueError(setting, value) {
206
+ if (value === null) return null;
207
+ if (setting.control === "number" && typeof value === "number" && setting.range) {
208
+ const belowMin = setting.range.exclusiveMin ? value <= setting.range.min : value < setting.range.min;
209
+ const aboveMax = setting.range.max !== void 0 && value > setting.range.max;
210
+ if (belowMin || aboveMax) return `${setting.path} must be ${rangeLabel(setting.range)}`;
211
+ }
212
+ if (setting.options && typeof value === "string" && !setting.options.some((option) => option.value === value)) return `${setting.path} must be one of ${setting.options.map((option) => option.value).join(", ")}`;
213
+ return null;
214
+ }
215
+ function isBrowserConfigKey(key) {
216
+ return Object.hasOwn(BrowserConfig.shape, key);
217
+ }
218
+ function dashboardSchemaCheck(setting) {
219
+ const [topLevelKey, ...nestedParts] = setting.path.split(".");
220
+ return (candidate) => {
221
+ if (!isBrowserConfigKey(topLevelKey)) return null;
222
+ const parsed = BrowserConfig.shape[topLevelKey].safeParse(candidate[topLevelKey]);
223
+ if (parsed.success) return null;
224
+ const issue = parsed.error.issues.find((candidateIssue) => nestedParts.every((part, index) => String(candidateIssue.path[index]) === part)) ?? parsed.error.issues.at(0);
225
+ if (!issue) return null;
226
+ const issueKeyPath = [topLevelKey, ...issue.path.map(String)].join(".");
227
+ return issue.message.includes(issueKeyPath) ? issue.message : `${issueKeyPath}: ${issue.message}`;
228
+ };
229
+ }
230
+ function validationErrorOf(view, mutate, settingPath, checks) {
231
+ const candidate = cloneValue(view.config);
232
+ if (!isRecord(candidate)) return "config must be a plain object";
233
+ mutate(candidate);
234
+ const validation = validateConfig(withEnvSecrets(candidate, readEnvSecrets(process.env)));
235
+ if (!validation.ok) {
236
+ const schemaMessage = validation.errors.join("; ");
237
+ return schemaMessage.includes(settingPath) ? schemaMessage : `${settingPath}: ${schemaMessage}`;
238
+ }
239
+ for (const check of checks) {
240
+ const error = check(candidate);
241
+ if (error) return error;
242
+ }
243
+ return null;
244
+ }
245
+ function applyValidatedMutation(view, setting, mutate, checks = []) {
246
+ const validationError = validationErrorOf(view, mutate, setting.path, checks);
247
+ if (validationError) throw new Error(validationError);
248
+ const saved = saveConfigFileOnce(view.configPath, mutate);
249
+ if (!saved.ok) throw new Error(saved.message);
250
+ return saved.config;
251
+ }
252
+ function unreadableHomeMessage(homeDir, error) {
253
+ return `cannot read the Glimmervoid home at ${homeDir} (${errorCode(error) ?? errorMessage(error)}). A session with guardrails cannot read it; run this command from a shell outside the session`;
254
+ }
255
+ function homeReadError(homeDir) {
256
+ try {
257
+ fs.accessSync(homeDir, fs.constants.R_OK);
258
+ return null;
259
+ } catch (error) {
260
+ if (errorCode(error) === "ENOENT" && !process.env["GLIMMERVOID_AGENT_URL"]) return null;
261
+ return unreadableHomeMessage(homeDir, error);
262
+ }
263
+ }
264
+ function readConfigFile(configPath, homeDir) {
265
+ try {
266
+ const loaded = loadConfigFile(configPath, { exitOnError: false });
267
+ if (!loaded.config) return fail(loaded.message);
268
+ return succeed(loaded.config);
269
+ } catch (error) {
270
+ if (errorCode(error) === "EACCES" || errorCode(error) === "EPERM") return fail(unreadableHomeMessage(homeDir, error));
271
+ return fail(`could not read ${configPath}: ${errorMessage(error)}`);
272
+ }
273
+ }
274
+ function openConfigFile() {
275
+ const env = process.env;
276
+ const homeDir = glimmervoidHomeDir(os.homedir(), env);
277
+ const homeError = homeReadError(homeDir);
278
+ if (homeError) return fail(homeError);
279
+ const decided = decideConfigPath({
280
+ env,
281
+ homeDir
282
+ }, (candidate) => fs.existsSync(candidate));
283
+ if (!decided.path && decided.source === "env") return fail(`config file not found: ${decided.envPath}`);
284
+ if (!decided.path) return fail(`no config.json at ${decided.homePath}. Start Glimmervoid once to create it; glimmervoid settings schema needs no config file`);
285
+ const loaded = readConfigFile(decided.path, homeDir);
286
+ if (!loaded.ok) return fail(loaded.message);
287
+ const secretSources = Object.fromEntries(readEnvSecrets(env).map((secret) => [`${secret.blockName}.${secret.secretKey}`, secret.environmentVariable]));
288
+ return succeed({
289
+ configPath: decided.path,
290
+ config: loaded.value,
291
+ secretSources
292
+ });
293
+ }
294
+ function print(context, jsonValue, text) {
295
+ context.writeOutput(`${context.isJson ? JSON.stringify(jsonValue, null, 2) : text}\n`);
296
+ return 0;
297
+ }
298
+ function requireView() {
299
+ const opened = openConfigFile();
300
+ if (!opened.ok) throw new Error(opened.message);
301
+ return opened.value;
302
+ }
303
+ function requireSetting(context, view) {
304
+ const resolved = requireConfigFileSetting(requirePositional(context.positionals, 1, "path"), view.configPath);
305
+ if (!resolved.ok) throw new Error(resolved.message);
306
+ return resolved.value;
307
+ }
308
+ function secretRefusal(setting) {
309
+ const binding = ENV_SECRET_BINDINGS.find((candidate) => `${candidate.blockName}.${candidate.secretKey}` === setting.path);
310
+ const environmentWay = binding ? `, or set ${binding.environmentVariable} in the environment Glimmervoid starts with` : "";
311
+ return `${setting.path} is a secret, so this command never takes or removes it, since a value on the command line lands in shell history; change it in the dashboard under Settings > ${sectionOf(setting).title}${environmentWay}`;
312
+ }
313
+ function writeRefusal(setting, configPath) {
314
+ if (setting.control === "password") return secretRefusal(setting);
315
+ const handEditedReason = HAND_EDITED_SETTING_REASONS.get(setting.path);
316
+ if (handEditedReason) return `${setting.path} cannot be changed from this command, because ${handEditedReason}; edit config.json at ${configPath} by hand`;
317
+ return null;
318
+ }
319
+ function requireWritableSetting(context, view) {
320
+ const setting = requireSetting(context, view);
321
+ const refusal = writeRefusal(setting, view.configPath);
322
+ if (refusal) throw new Error(refusal);
323
+ return setting;
324
+ }
325
+ var commands = {
326
+ list: (context) => {
327
+ const view = requireView();
328
+ const settings = ALL_SETTINGS.filter(isConfigFileSetting);
329
+ const readouts = settings.map((setting) => readSetting(setting, view));
330
+ const readoutById = new Map(readouts.map((readout) => [readout.id, readout]));
331
+ const rowOf = (setting) => {
332
+ const readout = readoutById.get(setting.id);
333
+ if (!readout) return [
334
+ setting.path,
335
+ "",
336
+ ""
337
+ ];
338
+ return [
339
+ setting.path,
340
+ fitColumn(valueText(readout, setting)),
341
+ readout.source
342
+ ];
343
+ };
344
+ return print(context, readouts, renderSectionTables(settings, [
345
+ "Setting",
346
+ "Value",
347
+ "Source"
348
+ ], rowOf));
349
+ },
350
+ get: (context) => {
351
+ const view = requireView();
352
+ const setting = requireSetting(context, view);
353
+ const readout = readSetting(setting, view);
354
+ const sourceNote = readout.secret && !readout.configured ? "" : ` (${readout.source})`;
355
+ return print(context, readout, `${setting.path} = ${valueText(readout, setting)}${sourceNote}`);
356
+ },
357
+ set: (context) => {
358
+ const view = requireView();
359
+ const setting = requireWritableSetting(context, view);
360
+ const parsed = parseSettingValue(setting, requirePositional(context.positionals, 2, "value"));
361
+ if (!parsed.ok) throw new Error(parsed.message);
362
+ const previous = cloneValue(valueAtPath(view.config, setting.path)) ?? null;
363
+ const written = applyValidatedMutation(view, setting, (config) => setValueAtPath(config, setting.path, parsed.value), [() => registryValueError(setting, parsed.value), dashboardSchemaCheck(setting)]);
364
+ const readout = readSetting(setting, {
365
+ ...view,
366
+ config: written
367
+ });
368
+ return print(context, {
369
+ ...readout,
370
+ previous,
371
+ configPath: view.configPath
372
+ }, `${setting.path} = ${valueText(readout, setting)}\n${EFFECT_NOTES[setting.takesEffect]}`);
373
+ },
374
+ unset: (context) => {
375
+ const view = requireView();
376
+ const setting = requireWritableSetting(context, view);
377
+ if (valueAtPath(view.config, setting.path) === void 0) return print(context, {
378
+ ...readSetting(setting, view),
379
+ configPath: view.configPath,
380
+ changed: false
381
+ }, `${setting.path} is not set in config.json; the default ${defaultText(setting)} already applies`);
382
+ const written = applyValidatedMutation(view, setting, (config) => deleteValueAtPath(config, setting.path), [dashboardSchemaCheck(setting)]);
383
+ return print(context, {
384
+ ...readSetting(setting, {
385
+ ...view,
386
+ config: written
387
+ }),
388
+ configPath: view.configPath,
389
+ changed: true
390
+ }, `${setting.path} unset; the default ${defaultText(setting)} applies\n${EFFECT_NOTES[setting.takesEffect]}`);
391
+ },
392
+ search: (context) => {
393
+ const query = context.positionals.slice(1).join(" ");
394
+ if (query.trim() === "") throw new Error(`missing <text>\n\n${usage}`);
395
+ const results = scoreSettingsSearch(SETTINGS_REGISTRY.sections, query, SETTINGS_REGISTRY.fileOnly);
396
+ const rows = results.map((result) => [
397
+ result.setting.scope === "browser" ? `${result.setting.id} (browser preference)` : result.setting.path,
398
+ result.setting.title,
399
+ sectionOf(result.setting).title
400
+ ]);
401
+ const text = results.length === 0 ? "(no matches)" : renderTable({
402
+ title: `Settings matching ${query}`,
403
+ headers: [
404
+ "Setting",
405
+ "Title",
406
+ "Section"
407
+ ],
408
+ rows,
409
+ align: [
410
+ "left",
411
+ "left",
412
+ "left"
413
+ ]
414
+ });
415
+ return print(context, results.map((result) => ({
416
+ ...describeSetting(result.setting),
417
+ score: result.score
418
+ })), text);
419
+ },
420
+ schema: (context) => {
421
+ const rowOf = (setting) => [
422
+ setting.id,
423
+ setting.scope === "browser" ? `${setting.path} (browser)` : setting.path,
424
+ setting.control,
425
+ fitColumn(JSON.stringify(setting.defaultValue ?? null)),
426
+ setting.unit?.storedLabel ?? setting.unit?.label ?? "",
427
+ setting.unit?.label ?? "",
428
+ setting.takesEffect
429
+ ];
430
+ return print(context, ALL_SETTINGS.map(describeSetting), renderSectionTables(ALL_SETTINGS, [
431
+ "Id",
432
+ "Path",
433
+ "Type",
434
+ "Default",
435
+ "Stored unit",
436
+ "Display unit",
437
+ "Effect"
438
+ ], rowOf));
439
+ }
440
+ };
441
+ function runCommandLine(commandArguments, io) {
442
+ const { values, positionals } = parseArgs({
443
+ args: commandArguments,
444
+ allowPositionals: true,
445
+ options: {
446
+ json: {
447
+ type: "boolean",
448
+ default: false
449
+ },
450
+ help: {
451
+ type: "boolean",
452
+ short: "h",
453
+ default: false
454
+ }
455
+ }
456
+ });
457
+ const commandName = positionals[0];
458
+ const command = commandName === void 0 ? void 0 : commands[commandName];
459
+ if (values.help || commandName === void 0 || command === void 0) {
460
+ io.writeOutput(`${usage}\n`);
461
+ return values.help ? 0 : 1;
462
+ }
463
+ return command({
464
+ positionals,
465
+ isJson: values.json,
466
+ writeOutput: io.writeOutput
467
+ });
468
+ }
469
+ function processIo() {
470
+ return {
471
+ writeOutput: (text) => process.stdout.write(text),
472
+ writeError: (text) => process.stderr.write(text)
473
+ };
474
+ }
475
+ function runSettingsCommand(commandArguments, io = processIo()) {
476
+ try {
477
+ return runCommandLine(commandArguments, io);
478
+ } catch (error) {
479
+ io.writeError(`settings: ${errorMessage(error)}\n`);
480
+ return 1;
481
+ }
482
+ }
483
+ //#endregion
484
+ export { runSettingsCommand };
@@ -1,8 +1,8 @@
1
1
  import { r as errorMessage } from "./text-DoirglWV.js";
2
- import { w as SshSignReply, y as SIGN_URL_ENV } from "./session-D6xXN0UU.js";
2
+ import { C as SshSignReply, v as SIGN_URL_ENV } from "./session-B8RhqQJe.js";
3
3
  import { n as execFileAsync, o as spawn } from "./child-process-safe-CbQnyh7D.js";
4
4
  import { a as isLoopbackHostname } from "./hook-relay-core-DA_bz2KA.js";
5
- import { t as postToAgentIngress } from "./agent-api-cli-vGwstJ1j.js";
5
+ import { t as postToAgentIngress } from "./agent-api-cli-d-Bgsshx.js";
6
6
  import { l as parseSshPublicKey } from "./ssh-signing-core-CRhVVWNW.js";
7
7
  import path from "node:path";
8
8
  import fsp from "node:fs/promises";