@mrclrchtr/supi-lsp 2.1.0 → 2.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/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/README.md +9 -8
- package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/package.json +1 -1
- package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/config.ts +2 -3
- package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/debug-registry.ts +0 -5
- package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings/scoped-settings-list.ts +372 -0
- package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings/settings-action-menu.ts +101 -0
- package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings/settings-registry.ts +13 -7
- package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings/settings-schema.ts +464 -0
- package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings/settings-submenus.ts +124 -0
- package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings/settings-ui.ts +50 -309
- package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings-ui.ts +2 -5
- package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings.ts +17 -1
- package/node_modules/@mrclrchtr/supi-code-runtime/package.json +2 -2
- package/node_modules/@mrclrchtr/supi-core/README.md +9 -8
- package/node_modules/@mrclrchtr/supi-core/package.json +1 -1
- package/node_modules/@mrclrchtr/supi-core/src/config.ts +2 -3
- package/node_modules/@mrclrchtr/supi-core/src/debug-registry.ts +0 -5
- package/node_modules/@mrclrchtr/supi-core/src/settings/scoped-settings-list.ts +372 -0
- package/node_modules/@mrclrchtr/supi-core/src/settings/settings-action-menu.ts +101 -0
- package/node_modules/@mrclrchtr/supi-core/src/settings/settings-registry.ts +13 -7
- package/node_modules/@mrclrchtr/supi-core/src/settings/settings-schema.ts +464 -0
- package/node_modules/@mrclrchtr/supi-core/src/settings/settings-submenus.ts +124 -0
- package/node_modules/@mrclrchtr/supi-core/src/settings/settings-ui.ts +50 -309
- package/node_modules/@mrclrchtr/supi-core/src/settings-ui.ts +2 -5
- package/node_modules/@mrclrchtr/supi-core/src/settings.ts +17 -1
- package/package.json +3 -3
- package/src/config/lsp-settings.ts +1 -1
- package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/config/config-settings.ts +0 -207
- package/node_modules/@mrclrchtr/supi-core/src/config/config-settings.ts +0 -207
|
@@ -1,207 +0,0 @@
|
|
|
1
|
-
// Config-aware settings contribution helper for SuPi packages.
|
|
2
|
-
//
|
|
3
|
-
// Registers config-backed settings sections through PI's shared event bus so
|
|
4
|
-
// /supi-settings can collect contributions from all loaded extensions without
|
|
5
|
-
// relying on a shared supi-core module instance.
|
|
6
|
-
|
|
7
|
-
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
8
|
-
import type { SettingItem } from "@earendil-works/pi-tui";
|
|
9
|
-
import {
|
|
10
|
-
isSettingsContributionCollector,
|
|
11
|
-
type SettingsScope,
|
|
12
|
-
type SettingsSection,
|
|
13
|
-
SUPI_SETTINGS_COLLECT_EVENT,
|
|
14
|
-
} from "../settings/settings-registry.ts";
|
|
15
|
-
import { loadSupiConfigForScope, removeSupiConfigKey, writeSupiConfig } from "./config.ts";
|
|
16
|
-
|
|
17
|
-
// ── Types ──────────────────────────────────────────────────────────────────
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Supported config value types for declarative persistChange.
|
|
21
|
-
*
|
|
22
|
-
* - `"boolean"`: maps "on" → true, "off" → false
|
|
23
|
-
* - `"number"`: parses integer via Number.parseInt, falls back to unset on invalid
|
|
24
|
-
* - `"stringList"`: splits on comma, trims whitespace, unsets on empty
|
|
25
|
-
*/
|
|
26
|
-
export type ConfigSettingType = "boolean" | "number" | "stringList";
|
|
27
|
-
|
|
28
|
-
/** Extended setting item that can declare its config type for persistence. */
|
|
29
|
-
export interface ConfigSettingItem extends SettingItem {
|
|
30
|
-
/** Config value type used for auto-generated persistence. */
|
|
31
|
-
configType?: ConfigSettingType;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/** Helpers provided to persistChange for scoped SuPi config writes. */
|
|
35
|
-
export interface ConfigSettingsHelpers {
|
|
36
|
-
/** Write a key to the selected scope's config section. */
|
|
37
|
-
set(key: string, value: unknown): void;
|
|
38
|
-
/** Remove a key from the selected scope's config section. */
|
|
39
|
-
unset(key: string): void;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export interface ConfigSettingsPersistedChange {
|
|
43
|
-
scope: SettingsScope;
|
|
44
|
-
cwd: string;
|
|
45
|
-
settingId: string;
|
|
46
|
-
value: string;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export interface ConfigSettingsOptions<T> {
|
|
50
|
-
/** Settings contribution identifier — e.g. "lsp", "claude-md". */
|
|
51
|
-
id: string;
|
|
52
|
-
/** Human-readable label shown in the UI. */
|
|
53
|
-
label: string;
|
|
54
|
-
/** SuPi config section name — e.g. "lsp", "claude-md". */
|
|
55
|
-
section: string;
|
|
56
|
-
/** Default config values. */
|
|
57
|
-
defaults: T;
|
|
58
|
-
/** Build SettingItem[] from scoped config. */
|
|
59
|
-
buildItems: (
|
|
60
|
-
settings: T,
|
|
61
|
-
scope: SettingsScope,
|
|
62
|
-
cwd: string,
|
|
63
|
-
ctx?: ExtensionContext,
|
|
64
|
-
) => ConfigSettingItem[];
|
|
65
|
-
/**
|
|
66
|
-
* Convert a UI value into scoped SuPi config writes.
|
|
67
|
-
*
|
|
68
|
-
* Optional when every item returned by `buildItems` declares `configType`.
|
|
69
|
-
* Required when any item lacks `configType`.
|
|
70
|
-
*/
|
|
71
|
-
persistChange?: (
|
|
72
|
-
scope: SettingsScope,
|
|
73
|
-
cwd: string,
|
|
74
|
-
settingId: string,
|
|
75
|
-
value: string,
|
|
76
|
-
helpers: ConfigSettingsHelpers,
|
|
77
|
-
) => void;
|
|
78
|
-
/** Optional live runtime sync after successful persistence. */
|
|
79
|
-
afterPersist?: (change: ConfigSettingsPersistedChange) => void;
|
|
80
|
-
/** Optional home directory for config resolution (testing). */
|
|
81
|
-
homeDir?: string;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// ── Auto-generated persistChange ───────────────────────────────────────────
|
|
85
|
-
|
|
86
|
-
function autoPersistChange(
|
|
87
|
-
settingId: string,
|
|
88
|
-
value: string,
|
|
89
|
-
helpers: ConfigSettingsHelpers,
|
|
90
|
-
items: ConfigSettingItem[],
|
|
91
|
-
): void {
|
|
92
|
-
const item = items.find((i) => i.id === settingId);
|
|
93
|
-
if (!item?.configType) return;
|
|
94
|
-
|
|
95
|
-
switch (item.configType) {
|
|
96
|
-
case "boolean": {
|
|
97
|
-
helpers.set(settingId, value === "on");
|
|
98
|
-
break;
|
|
99
|
-
}
|
|
100
|
-
case "number": {
|
|
101
|
-
const num = Number.parseInt(value, 10);
|
|
102
|
-
if (Number.isFinite(num) && num > 0) {
|
|
103
|
-
helpers.set(settingId, num);
|
|
104
|
-
} else {
|
|
105
|
-
helpers.unset(settingId);
|
|
106
|
-
}
|
|
107
|
-
break;
|
|
108
|
-
}
|
|
109
|
-
case "stringList": {
|
|
110
|
-
const names = value
|
|
111
|
-
.split(",")
|
|
112
|
-
.map((s) => s.trim())
|
|
113
|
-
.filter((s) => s.length > 0);
|
|
114
|
-
if (names.length > 0) {
|
|
115
|
-
helpers.set(settingId, names);
|
|
116
|
-
} else {
|
|
117
|
-
helpers.unset(settingId);
|
|
118
|
-
}
|
|
119
|
-
break;
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
function areAllItemsDeclarative(items: ConfigSettingItem[]): boolean {
|
|
125
|
-
return items.length > 0 && items.every((i) => i.configType !== undefined);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
function createHelpers<T>(options: ConfigSettingsOptions<T>, scope: SettingsScope, cwd: string) {
|
|
129
|
-
return {
|
|
130
|
-
set: (key: string, val: unknown) => {
|
|
131
|
-
writeSupiConfig(
|
|
132
|
-
{ section: options.section, scope, cwd },
|
|
133
|
-
{ [key]: val },
|
|
134
|
-
{ homeDir: options.homeDir },
|
|
135
|
-
);
|
|
136
|
-
},
|
|
137
|
-
unset: (key: string) => {
|
|
138
|
-
removeSupiConfigKey({ section: options.section, scope, cwd }, key, {
|
|
139
|
-
homeDir: options.homeDir,
|
|
140
|
-
});
|
|
141
|
-
},
|
|
142
|
-
} satisfies ConfigSettingsHelpers;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
function toSettingsSection<T>(options: ConfigSettingsOptions<T>): SettingsSection {
|
|
146
|
-
let cachedItems: ConfigSettingItem[] | undefined;
|
|
147
|
-
|
|
148
|
-
return {
|
|
149
|
-
id: options.id,
|
|
150
|
-
label: options.label,
|
|
151
|
-
loadValues: (scope, cwd, ctx) => {
|
|
152
|
-
const settings = loadSupiConfigForScope(options.section, cwd, options.defaults, {
|
|
153
|
-
scope,
|
|
154
|
-
homeDir: options.homeDir,
|
|
155
|
-
});
|
|
156
|
-
const items = options.buildItems(settings, scope, cwd, ctx);
|
|
157
|
-
cachedItems = items;
|
|
158
|
-
return items;
|
|
159
|
-
},
|
|
160
|
-
persistChange: (scope, cwd, settingId, value) => {
|
|
161
|
-
const helpers = createHelpers(options, scope, cwd);
|
|
162
|
-
|
|
163
|
-
if (options.persistChange) {
|
|
164
|
-
options.persistChange(scope, cwd, settingId, value, helpers);
|
|
165
|
-
} else {
|
|
166
|
-
const items = cachedItems ?? options.buildItems(options.defaults, scope, cwd, undefined);
|
|
167
|
-
if (!areAllItemsDeclarative(items)) {
|
|
168
|
-
throw new Error(
|
|
169
|
-
`Settings contribution "${options.id}" needs persistChange or configType on every item.`,
|
|
170
|
-
);
|
|
171
|
-
}
|
|
172
|
-
autoPersistChange(settingId, value, helpers, items);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
try {
|
|
176
|
-
options.afterPersist?.({ scope, cwd, settingId, value });
|
|
177
|
-
} catch (error) {
|
|
178
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
179
|
-
throw new Error(`Saved setting, but live sync failed: ${message}`, { cause: error });
|
|
180
|
-
}
|
|
181
|
-
},
|
|
182
|
-
};
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
// ── Registration ───────────────────────────────────────────────────────────
|
|
186
|
-
|
|
187
|
-
/**
|
|
188
|
-
* Register a config-backed settings contribution for `/supi-settings`.
|
|
189
|
-
*
|
|
190
|
-
* Contributions are collected through PI's process-local event bus. Call this
|
|
191
|
-
* during the extension factory function, not in async session handlers.
|
|
192
|
-
*/
|
|
193
|
-
export function registerConfigSettings<T>(
|
|
194
|
-
pi: ExtensionAPI,
|
|
195
|
-
options: ConfigSettingsOptions<T>,
|
|
196
|
-
): void {
|
|
197
|
-
const section = toSettingsSection(options);
|
|
198
|
-
const dispose = pi.events.on(SUPI_SETTINGS_COLLECT_EVENT, (collector) => {
|
|
199
|
-
if (isSettingsContributionCollector(collector)) {
|
|
200
|
-
collector.add(section);
|
|
201
|
-
}
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
pi.on("session_shutdown", () => {
|
|
205
|
-
dispose();
|
|
206
|
-
});
|
|
207
|
-
}
|