@mrclrchtr/supi-code-intelligence 2.0.6 → 2.1.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/README.md +71 -1
- package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/README.md +29 -21
- package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/package.json +2 -1
- package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/config/config-settings.ts +88 -69
- package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/config/config.ts +22 -8
- package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/config/prompt-surface.ts +357 -0
- package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/prompt-surface.ts +4 -0
- package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings/settings-command.ts +1 -1
- package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings/settings-registry.ts +51 -29
- package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings/settings-ui.ts +64 -18
- package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings.ts +11 -5
- package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/tool-framework.ts +10 -0
- package/node_modules/@mrclrchtr/supi-code-runtime/package.json +2 -2
- package/node_modules/@mrclrchtr/supi-core/README.md +29 -21
- package/node_modules/@mrclrchtr/supi-core/package.json +2 -1
- package/node_modules/@mrclrchtr/supi-core/src/config/config-settings.ts +88 -69
- package/node_modules/@mrclrchtr/supi-core/src/config/config.ts +22 -8
- package/node_modules/@mrclrchtr/supi-core/src/config/prompt-surface.ts +357 -0
- package/node_modules/@mrclrchtr/supi-core/src/prompt-surface.ts +4 -0
- package/node_modules/@mrclrchtr/supi-core/src/settings/settings-command.ts +1 -1
- package/node_modules/@mrclrchtr/supi-core/src/settings/settings-registry.ts +51 -29
- package/node_modules/@mrclrchtr/supi-core/src/settings/settings-ui.ts +64 -18
- package/node_modules/@mrclrchtr/supi-core/src/settings.ts +11 -5
- package/node_modules/@mrclrchtr/supi-core/src/tool-framework.ts +10 -0
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/README.md +29 -21
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/package.json +2 -1
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/config/config-settings.ts +88 -69
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/config/config.ts +22 -8
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/config/prompt-surface.ts +357 -0
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/prompt-surface.ts +4 -0
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings/settings-command.ts +1 -1
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings/settings-registry.ts +51 -29
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings/settings-ui.ts +64 -18
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings.ts +11 -5
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/tool-framework.ts +10 -0
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/package.json +2 -2
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/README.md +29 -21
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/package.json +2 -1
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/config/config-settings.ts +88 -69
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/config/config.ts +22 -8
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/config/prompt-surface.ts +357 -0
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/prompt-surface.ts +4 -0
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/settings/settings-command.ts +1 -1
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/settings/settings-registry.ts +51 -29
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/settings/settings-ui.ts +64 -18
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/settings.ts +11 -5
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/tool-framework.ts +10 -0
- package/node_modules/@mrclrchtr/supi-lsp/package.json +3 -3
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/README.md +29 -21
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/package.json +2 -1
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/config/config-settings.ts +88 -69
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/config/config.ts +22 -8
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/config/prompt-surface.ts +357 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/prompt-surface.ts +4 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings/settings-command.ts +1 -1
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings/settings-registry.ts +51 -29
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings/settings-ui.ts +64 -18
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings.ts +11 -5
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/tool-framework.ts +10 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/package.json +2 -2
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/README.md +29 -21
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/package.json +2 -1
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/config/config-settings.ts +88 -69
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/config/config.ts +22 -8
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/config/prompt-surface.ts +357 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/prompt-surface.ts +4 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/settings/settings-command.ts +1 -1
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/settings/settings-registry.ts +51 -29
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/settings/settings-ui.ts +64 -18
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/settings.ts +11 -5
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/tool-framework.ts +10 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/package.json +3 -3
- package/package.json +5 -5
- package/src/analysis/evidence.ts +13 -0
- package/src/analysis/search/pattern.ts +24 -13
- package/src/analysis/search/ripgrep.ts +92 -7
- package/src/extension.ts +1 -1
- package/src/session/capability-adapter.ts +218 -0
- package/src/session/session.ts +39 -1
- package/src/session/target-workflow.ts +430 -0
- package/src/substrate/lsp/settings.ts +7 -3
- package/src/tool/find/execute.ts +23 -10
- package/src/tool/find/orchestrate.ts +67 -54
- package/src/tool/find/semantic-search.ts +30 -16
- package/src/tool/graph/collect-relation.ts +2 -1
- package/src/tool/graph/execute.ts +40 -12
- package/src/tool/graph/markdown-base.ts +5 -37
- package/src/tool/graph/orchestrate.ts +9 -35
- package/src/tool/graph/tui.ts +2 -0
- package/src/tool/guidance.ts +1 -1
- package/src/tool/health/markdown.ts +12 -70
- package/src/tool/health/orchestrate.ts +5 -13
- package/src/tool/impact/analysis.ts +0 -27
- package/src/tool/impact/change-set-impact.ts +3 -2
- package/src/tool/impact/execute.ts +27 -0
- package/src/tool/impact/file-level-impact.ts +3 -2
- package/src/tool/impact/result.ts +2 -21
- package/src/tool/impact/single-impact.ts +3 -2
- package/src/tool/infra/error-results.ts +18 -196
- package/src/tool/infra/pipeline.ts +24 -1
- package/src/tool/inspect/markdown.ts +4 -41
- package/src/tool/inspect/orchestrate.ts +27 -28
- package/src/tool/orientation/orchestrate.ts +5 -8
- package/src/tool/orientation/precise-target.ts +65 -69
- package/src/tool/refactor-apply/orchestrate.ts +2 -7
- package/src/tool/refactor-plan/orchestrate.ts +31 -39
- package/src/tool/resolve/markdown.ts +5 -6
- package/src/tool/resolve/orchestrate.ts +7 -103
- package/src/tool/result/errors.ts +199 -0
- package/src/tool/result/find.ts +29 -0
- package/src/tool/result/graph.ts +93 -0
- package/src/tool/result/health.ts +94 -0
- package/src/tool/result/impact.ts +50 -0
- package/src/tool/result/inspect.ts +60 -0
- package/src/tool/result/orientation.ts +30 -0
- package/src/tool/result/refactor.ts +35 -0
- package/src/tool/result/resolve.ts +114 -0
- package/src/tool/result/types.ts +188 -0
- package/src/tool/schemas.ts +22 -1
- package/src/types/details.ts +17 -185
- package/src/ui/tui/common.ts +45 -1
package/README.md
CHANGED
|
@@ -24,6 +24,76 @@ pi install ./packages/supi-code-intelligence
|
|
|
24
24
|
|
|
25
25
|

|
|
26
26
|
|
|
27
|
+
## Quickstart
|
|
28
|
+
|
|
29
|
+
### 1. Install the extension
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
pi install npm:@mrclrchtr/supi-code-intelligence
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### 2. Install the language server for your project
|
|
36
|
+
|
|
37
|
+
The extension auto-detects your project's language and tries to start the matching LSP server automatically. **You must install the server binary yourself** and ensure it is on your `PATH`.
|
|
38
|
+
|
|
39
|
+
| Language | Binary to install |
|
|
40
|
+
|---|---|
|
|
41
|
+
| TypeScript / JavaScript | `typescript-language-server` (npm) |
|
|
42
|
+
| Python | `pyright-langserver` (npm) |
|
|
43
|
+
| Rust | `rust-analyzer` (rustup) |
|
|
44
|
+
| Go | `gopls` (go install) |
|
|
45
|
+
| C / C++ | `clangd` (system package manager) |
|
|
46
|
+
| Bash | `bash-language-server` (npm) |
|
|
47
|
+
| HTML | `vscode-html-language-server` (npm) |
|
|
48
|
+
| SQL | `sql-language-server` (npm) |
|
|
49
|
+
| Ruby | `ruby-lsp` (gem) |
|
|
50
|
+
| Java | `jdtls` (system package manager) |
|
|
51
|
+
| Kotlin | `kotlin-lsp` (Kotlin tooling) |
|
|
52
|
+
| R | `R` with `languageserver` package installed |
|
|
53
|
+
|
|
54
|
+
If a server binary is missing, the extension emits a warning at session start telling you exactly which command was not found and which file types are affected.
|
|
55
|
+
|
|
56
|
+
### 3. Verify the stack is healthy
|
|
57
|
+
|
|
58
|
+
You can check status interactively with the overlay command:
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
/supi-ci-status
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
This shows which language servers are active, which are missing, and any degraded coverage warnings in a TUI overlay.
|
|
65
|
+
|
|
66
|
+
Alternatively, ask the pi agent to check for you:
|
|
67
|
+
|
|
68
|
+
> *"Check the status of code intelligence servers."*
|
|
69
|
+
|
|
70
|
+
The agent will run `code_health(include=["servers"])` and report back which servers are active. Semantic tools like `code_resolve` and `code_graph` need an active server for your project's language.
|
|
71
|
+
|
|
72
|
+
### 4. Optional: tune or disable servers
|
|
73
|
+
|
|
74
|
+
By default every detected language server starts concurrently. In polyglot repos this can spike CPU. To disable servers you do not need, run:
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
/supi-settings
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Navigate to **LSP → Disabled Servers** and toggle off any languages you are not using. This writes per-language opt-outs into `.pi/supi/config.json` (project) or `~/.pi/agent/supi/config.json` (global).
|
|
81
|
+
|
|
82
|
+
You can also edit the config file directly:
|
|
83
|
+
|
|
84
|
+
```json
|
|
85
|
+
{
|
|
86
|
+
"lsp": {
|
|
87
|
+
"servers": {
|
|
88
|
+
"python": { "enabled": false },
|
|
89
|
+
"rust": { "enabled": false }
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
> **Note:** The global `lsp.enabled` switch and `lsp.active` allowlist are deprecated since v0.7.0 and have no effect.
|
|
96
|
+
|
|
27
97
|
## What you get
|
|
28
98
|
|
|
29
99
|
After install, pi gets:
|
|
@@ -331,7 +401,7 @@ Unified ranked search tool with a strict evidence contract.
|
|
|
331
401
|
- AST `call` mode matches call-site identifiers by name, not by symbol identity; use `code_graph` with `relations: ["references"]` on a resolved target for identity-aware callers
|
|
332
402
|
- unsupported mode/kind combinations fail explicitly instead of being broadened into best-effort search
|
|
333
403
|
|
|
334
|
-
Supports `query` (required), `scope
|
|
404
|
+
Supports `query` (required), `scope` (one path or an array of paths), `mode`, `kind`, `contextLines`, and `maxResults`.
|
|
335
405
|
|
|
336
406
|
### `code_health`
|
|
337
407
|
Health/status summary for the current workspace or a scoped path.
|
package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/README.md
CHANGED
|
@@ -39,10 +39,9 @@ Config file locations:
|
|
|
39
39
|
|
|
40
40
|
### Settings helpers
|
|
41
41
|
|
|
42
|
-
- `
|
|
43
|
-
- `
|
|
44
|
-
- `
|
|
45
|
-
- `openSettingsOverlay()` — open the shared settings UI directly
|
|
42
|
+
- `registerConfigSettings(pi, options)` — contribute a config-backed settings section with scoped persistence helpers
|
|
43
|
+
- `registerSettingsCommand(pi)` — register `/supi-settings` (used by `@mrclrchtr/supi-settings`)
|
|
44
|
+
- `openSettingsOverlay(pi, ctx)` — open the shared settings UI directly
|
|
46
45
|
- `createInputSubmenu()` — helper for simple text-entry submenus
|
|
47
46
|
|
|
48
47
|
The built-in settings UI supports:
|
|
@@ -83,25 +82,34 @@ The built-in settings UI supports:
|
|
|
83
82
|
## Example
|
|
84
83
|
|
|
85
84
|
```ts
|
|
85
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
86
86
|
import { loadSupiConfig, registerConfigSettings, wrapExtensionContext } from "@mrclrchtr/supi-core/api";
|
|
87
87
|
|
|
88
|
-
|
|
89
|
-
enabled: true
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
registerConfigSettings({
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
}
|
|
88
|
+
export default function myExtension(pi: ExtensionAPI) {
|
|
89
|
+
const defaults = { enabled: true };
|
|
90
|
+
const config = loadSupiConfig("my-extension", process.cwd(), defaults);
|
|
91
|
+
|
|
92
|
+
registerConfigSettings(pi, {
|
|
93
|
+
id: "my-extension",
|
|
94
|
+
label: "My Extension",
|
|
95
|
+
section: "my-extension",
|
|
96
|
+
defaults,
|
|
97
|
+
buildItems: (settings) => [
|
|
98
|
+
{
|
|
99
|
+
id: "enabled",
|
|
100
|
+
label: "Enabled",
|
|
101
|
+
currentValue: settings.enabled ? "on" : "off",
|
|
102
|
+
values: ["on", "off"],
|
|
103
|
+
configType: "boolean" as const,
|
|
104
|
+
},
|
|
105
|
+
],
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
const message = wrapExtensionContext("my-extension", "hello", {
|
|
109
|
+
enabled: config.enabled,
|
|
110
|
+
});
|
|
111
|
+
void message;
|
|
112
|
+
}
|
|
105
113
|
```
|
|
106
114
|
|
|
107
115
|
## Source
|
package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mrclrchtr/supi-core",
|
|
3
|
-
"version": "2.0
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "SuPi core — shared infrastructure for SuPi extensions (XML context tags, config system)",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -70,6 +70,7 @@
|
|
|
70
70
|
"./status-spinner": "./src/status-spinner.ts",
|
|
71
71
|
"./terminal": "./src/terminal.ts",
|
|
72
72
|
"./tool-framework": "./src/tool-framework.ts",
|
|
73
|
+
"./prompt-surface": "./src/prompt-surface.ts",
|
|
73
74
|
"./types": "./src/types.ts"
|
|
74
75
|
}
|
|
75
76
|
}
|
|
@@ -1,14 +1,17 @@
|
|
|
1
|
-
// Config-aware settings helper for SuPi
|
|
2
|
-
// Wraps registerSettings() and centralizes selected-scope loading + scoped persistence.
|
|
1
|
+
// Config-aware settings contribution helper for SuPi packages.
|
|
3
2
|
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
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.
|
|
7
6
|
|
|
8
|
-
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
7
|
+
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
9
8
|
import type { SettingItem } from "@earendil-works/pi-tui";
|
|
10
|
-
import
|
|
11
|
-
|
|
9
|
+
import {
|
|
10
|
+
isSettingsContributionCollector,
|
|
11
|
+
type SettingsScope,
|
|
12
|
+
type SettingsSection,
|
|
13
|
+
SUPI_SETTINGS_COLLECT_EVENT,
|
|
14
|
+
} from "../settings/settings-registry.ts";
|
|
12
15
|
import { loadSupiConfigForScope, removeSupiConfigKey, writeSupiConfig } from "./config.ts";
|
|
13
16
|
|
|
14
17
|
// ── Types ──────────────────────────────────────────────────────────────────
|
|
@@ -22,22 +25,13 @@ import { loadSupiConfigForScope, removeSupiConfigKey, writeSupiConfig } from "./
|
|
|
22
25
|
*/
|
|
23
26
|
export type ConfigSettingType = "boolean" | "number" | "stringList";
|
|
24
27
|
|
|
25
|
-
/**
|
|
26
|
-
* Extended setting item that can declare its config type for auto-generated
|
|
27
|
-
* persistence handling.
|
|
28
|
-
*/
|
|
28
|
+
/** Extended setting item that can declare its config type for persistence. */
|
|
29
29
|
export interface ConfigSettingItem extends SettingItem {
|
|
30
|
-
/**
|
|
31
|
-
* When set, persistChange for this item is auto-generated.
|
|
32
|
-
* All items must declare a configType for auto-generation to activate.
|
|
33
|
-
*/
|
|
30
|
+
/** Config value type used for auto-generated persistence. */
|
|
34
31
|
configType?: ConfigSettingType;
|
|
35
32
|
}
|
|
36
33
|
|
|
37
|
-
/**
|
|
38
|
-
* Helpers provided to the persistChange callback for writing or removing
|
|
39
|
-
* scoped config values.
|
|
40
|
-
*/
|
|
34
|
+
/** Helpers provided to persistChange for scoped SuPi config writes. */
|
|
41
35
|
export interface ConfigSettingsHelpers {
|
|
42
36
|
/** Write a key to the selected scope's config section. */
|
|
43
37
|
set(key: string, value: unknown): void;
|
|
@@ -45,22 +39,23 @@ export interface ConfigSettingsHelpers {
|
|
|
45
39
|
unset(key: string): void;
|
|
46
40
|
}
|
|
47
41
|
|
|
42
|
+
export interface ConfigSettingsPersistedChange {
|
|
43
|
+
scope: SettingsScope;
|
|
44
|
+
cwd: string;
|
|
45
|
+
settingId: string;
|
|
46
|
+
value: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
48
49
|
export interface ConfigSettingsOptions<T> {
|
|
49
|
-
/**
|
|
50
|
+
/** Settings contribution identifier — e.g. "lsp", "claude-md". */
|
|
50
51
|
id: string;
|
|
51
|
-
/** Human-readable label shown in the UI */
|
|
52
|
+
/** Human-readable label shown in the UI. */
|
|
52
53
|
label: string;
|
|
53
|
-
/** SuPi config section name — e.g. "lsp", "claude-md" */
|
|
54
|
+
/** SuPi config section name — e.g. "lsp", "claude-md". */
|
|
54
55
|
section: string;
|
|
55
|
-
/** Default config values */
|
|
56
|
+
/** Default config values. */
|
|
56
57
|
defaults: T;
|
|
57
|
-
/**
|
|
58
|
-
* Build SettingItem[] from scoped config. Called by loadValues.
|
|
59
|
-
*
|
|
60
|
-
* Items can include a `configType` property for auto-generated
|
|
61
|
-
* persistChange handling. When ALL items declare a configType,
|
|
62
|
-
* the `persistChange` callback can be omitted.
|
|
63
|
-
*/
|
|
58
|
+
/** Build SettingItem[] from scoped config. */
|
|
64
59
|
buildItems: (
|
|
65
60
|
settings: T,
|
|
66
61
|
scope: SettingsScope,
|
|
@@ -68,10 +63,10 @@ export interface ConfigSettingsOptions<T> {
|
|
|
68
63
|
ctx?: ExtensionContext,
|
|
69
64
|
) => ConfigSettingItem[];
|
|
70
65
|
/**
|
|
71
|
-
*
|
|
66
|
+
* Convert a UI value into scoped SuPi config writes.
|
|
72
67
|
*
|
|
73
|
-
* Optional when
|
|
74
|
-
* Required when any item lacks
|
|
68
|
+
* Optional when every item returned by `buildItems` declares `configType`.
|
|
69
|
+
* Required when any item lacks `configType`.
|
|
75
70
|
*/
|
|
76
71
|
persistChange?: (
|
|
77
72
|
scope: SettingsScope,
|
|
@@ -80,6 +75,8 @@ export interface ConfigSettingsOptions<T> {
|
|
|
80
75
|
value: string,
|
|
81
76
|
helpers: ConfigSettingsHelpers,
|
|
82
77
|
) => void;
|
|
78
|
+
/** Optional live runtime sync after successful persistence. */
|
|
79
|
+
afterPersist?: (change: ConfigSettingsPersistedChange) => void;
|
|
83
80
|
/** Optional home directory for config resolution (testing). */
|
|
84
81
|
homeDir?: string;
|
|
85
82
|
}
|
|
@@ -128,23 +125,27 @@ function areAllItemsDeclarative(items: ConfigSettingItem[]): boolean {
|
|
|
128
125
|
return items.length > 0 && items.every((i) => i.configType !== undefined);
|
|
129
126
|
}
|
|
130
127
|
|
|
131
|
-
|
|
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
|
+
}
|
|
132
144
|
|
|
133
|
-
|
|
134
|
-
* Register a config-backed settings section.
|
|
135
|
-
*
|
|
136
|
-
* Loads display values from the selected scope only (`defaults <- selected scope`)
|
|
137
|
-
* instead of merged effective runtime config. Provides scoped `set` / `unset`
|
|
138
|
-
* persistence helpers so extensions don't need to wire `writeSupiConfig` /
|
|
139
|
-
* `removeSupiConfigKey` by hand.
|
|
140
|
-
*
|
|
141
|
-
* When every item returned by `buildItems` declares a `configType`, the
|
|
142
|
-
* `persistChange` callback is optional and will be auto-generated.
|
|
143
|
-
*/
|
|
144
|
-
export function registerConfigSettings<T>(options: ConfigSettingsOptions<T>): void {
|
|
145
|
+
function toSettingsSection<T>(options: ConfigSettingsOptions<T>): SettingsSection {
|
|
145
146
|
let cachedItems: ConfigSettingItem[] | undefined;
|
|
146
147
|
|
|
147
|
-
|
|
148
|
+
return {
|
|
148
149
|
id: options.id,
|
|
149
150
|
label: options.label,
|
|
150
151
|
loadValues: (scope, cwd, ctx) => {
|
|
@@ -157,32 +158,50 @@ export function registerConfigSettings<T>(options: ConfigSettingsOptions<T>): vo
|
|
|
157
158
|
return items;
|
|
158
159
|
},
|
|
159
160
|
persistChange: (scope, cwd, settingId, value) => {
|
|
160
|
-
const helpers
|
|
161
|
-
|
|
162
|
-
writeSupiConfig(
|
|
163
|
-
{ section: options.section, scope, cwd },
|
|
164
|
-
{ [key]: val },
|
|
165
|
-
{ homeDir: options.homeDir },
|
|
166
|
-
);
|
|
167
|
-
},
|
|
168
|
-
unset: (key) => {
|
|
169
|
-
removeSupiConfigKey({ section: options.section, scope, cwd }, key, {
|
|
170
|
-
homeDir: options.homeDir,
|
|
171
|
-
});
|
|
172
|
-
},
|
|
173
|
-
};
|
|
174
|
-
|
|
175
|
-
// Use manual persistChange when provided
|
|
161
|
+
const helpers = createHelpers(options, scope, cwd);
|
|
162
|
+
|
|
176
163
|
if (options.persistChange) {
|
|
177
164
|
options.persistChange(scope, cwd, settingId, value, helpers);
|
|
178
|
-
|
|
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);
|
|
179
173
|
}
|
|
180
174
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
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 });
|
|
185
180
|
}
|
|
186
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();
|
|
187
206
|
});
|
|
188
207
|
}
|
|
@@ -21,6 +21,15 @@ function getProjectConfigPath(cwd: string): string {
|
|
|
21
21
|
return path.join(cwd, PROJECT_CONFIG_DIR, CONFIG_FILE);
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
/** Return the SuPi config file path for one scope. */
|
|
25
|
+
export function getSupiConfigPath(
|
|
26
|
+
scope: "global" | "project",
|
|
27
|
+
cwd: string,
|
|
28
|
+
options?: SupiConfigOptions,
|
|
29
|
+
): string {
|
|
30
|
+
return scope === "global" ? getGlobalConfigPath(options?.homeDir) : getProjectConfigPath(cwd);
|
|
31
|
+
}
|
|
32
|
+
|
|
24
33
|
export function readJsonFile(filePath: string): Record<string, unknown> | null {
|
|
25
34
|
let content: string;
|
|
26
35
|
try {
|
|
@@ -95,15 +104,22 @@ export function loadSupiConfigForScope<T>(
|
|
|
95
104
|
defaults: T,
|
|
96
105
|
options: { scope: "global" | "project" } & SupiConfigOptions,
|
|
97
106
|
): T {
|
|
98
|
-
const config =
|
|
99
|
-
options.scope === "global"
|
|
100
|
-
? readJsonFile(getGlobalConfigPath(options.homeDir))
|
|
101
|
-
: readJsonFile(getProjectConfigPath(cwd));
|
|
107
|
+
const config = readJsonFile(getSupiConfigPath(options.scope, cwd, { homeDir: options.homeDir }));
|
|
102
108
|
|
|
103
109
|
const scopedSection = extractSection(config, section);
|
|
104
110
|
return shallowMerge(defaults, scopedSection);
|
|
105
111
|
}
|
|
106
112
|
|
|
113
|
+
/** Load the raw object for one config section and one scope. */
|
|
114
|
+
export function loadSupiConfigSectionForScope(
|
|
115
|
+
section: string,
|
|
116
|
+
cwd: string,
|
|
117
|
+
options: { scope: "global" | "project" } & SupiConfigOptions,
|
|
118
|
+
): Record<string, unknown> | null {
|
|
119
|
+
const config = readJsonFile(getSupiConfigPath(options.scope, cwd, { homeDir: options.homeDir }));
|
|
120
|
+
return extractSection(config, section);
|
|
121
|
+
}
|
|
122
|
+
|
|
107
123
|
export interface SupiConfigLocation {
|
|
108
124
|
section: string;
|
|
109
125
|
scope: "global" | "project";
|
|
@@ -118,8 +134,7 @@ export function writeSupiConfig(
|
|
|
118
134
|
value: Record<string, unknown>,
|
|
119
135
|
options?: SupiConfigOptions,
|
|
120
136
|
): void {
|
|
121
|
-
const configPath =
|
|
122
|
-
loc.scope === "global" ? getGlobalConfigPath(options?.homeDir) : getProjectConfigPath(loc.cwd);
|
|
137
|
+
const configPath = getSupiConfigPath(loc.scope, loc.cwd, options);
|
|
123
138
|
|
|
124
139
|
const dir = path.dirname(configPath);
|
|
125
140
|
fs.mkdirSync(dir, { recursive: true });
|
|
@@ -142,8 +157,7 @@ export function removeSupiConfigKey(
|
|
|
142
157
|
key: string,
|
|
143
158
|
options?: SupiConfigOptions,
|
|
144
159
|
): void {
|
|
145
|
-
const configPath =
|
|
146
|
-
loc.scope === "global" ? getGlobalConfigPath(options?.homeDir) : getProjectConfigPath(loc.cwd);
|
|
160
|
+
const configPath = getSupiConfigPath(loc.scope, loc.cwd, options);
|
|
147
161
|
|
|
148
162
|
const existing = readJsonFile(configPath);
|
|
149
163
|
if (!existing) return;
|