@mrclrchtr/supi-settings 11.1.0 → 11.3.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/CHANGELOG.md +6 -0
- package/README.md +2 -1
- package/node_modules/@mrclrchtr/supi-core/package.json +1 -1
- package/node_modules/@mrclrchtr/supi-core/src/child-web-tools.ts +110 -0
- package/node_modules/@mrclrchtr/supi-core/src/session.ts +11 -0
- package/package.json +4 -2
- package/skills/supi-setup/SKILL.md +129 -0
- package/src/extension.ts +8 -0
package/CHANGELOG.md
ADDED
package/README.md
CHANGED
|
@@ -30,9 +30,10 @@ pi install ./packages/supi-settings
|
|
|
30
30
|
|
|
31
31
|
## What it adds
|
|
32
32
|
|
|
33
|
-
The extension registers one slash command:
|
|
33
|
+
The extension registers one slash command and one skill:
|
|
34
34
|
|
|
35
35
|
- **`/supi-settings`** — open a searchable settings screen
|
|
36
|
+
- **`/skill:supi-setup`** — audit SuPi package declarations, language servers, TypeScript code-action formatting, Code Intelligence exclusions, stale config sections, and the Review bootstrap command; report findings with evidence and apply only confirmed fixes. User-invoked only; it adds no model context.
|
|
36
37
|
|
|
37
38
|
The package does not register a tool, a shortcut, or its own setting. The screen contains settings from other loaded SuPi extensions. If no extension contributes settings, Pi shows `No settings registered by SuPi extensions`.
|
|
38
39
|
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
// Session-provided Web tools for SuPi child sessions (Agent Runs and Reviewer Sessions).
|
|
2
|
+
//
|
|
3
|
+
// The loaded supi-web extension answers a synchronous request on the parent event bus.
|
|
4
|
+
// Consumers never depend on supi-web; when it is absent or provides no tools, the
|
|
5
|
+
// request returns undefined and the child simply lacks Web tools.
|
|
6
|
+
|
|
7
|
+
import type { ExtensionAPI, ExtensionFactory } from "@earendil-works/pi-coding-agent";
|
|
8
|
+
|
|
9
|
+
/** Web tools that child sessions may receive when the containing session provides them. */
|
|
10
|
+
export const CHILD_WEB_TOOL_NAMES = [
|
|
11
|
+
"web_fetch_md",
|
|
12
|
+
"web_search",
|
|
13
|
+
"web_docs_search",
|
|
14
|
+
"web_docs_fetch",
|
|
15
|
+
] as const;
|
|
16
|
+
|
|
17
|
+
/** One session-provided Web tool name. */
|
|
18
|
+
export type ChildWebToolName = (typeof CHILD_WEB_TOOL_NAMES)[number];
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Web tools currently callable in the containing session plus a child-only extension
|
|
22
|
+
* factory that registers them. The factory must not capture the parent session; it may
|
|
23
|
+
* capture plain data such as the containing session's configuration directory.
|
|
24
|
+
*/
|
|
25
|
+
export interface ChildWebToolProvision {
|
|
26
|
+
readonly toolNames: readonly ChildWebToolName[];
|
|
27
|
+
/** Register the requested subset of `toolNames` in a child session. */
|
|
28
|
+
readonly createFactory: (toolNames: readonly ChildWebToolName[]) => ExtensionFactory;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Plain containing-session data supplied with a child Web tool request. */
|
|
32
|
+
export interface ChildWebToolsRequestContext {
|
|
33
|
+
/**
|
|
34
|
+
* Working directory whose SuPi configuration governs Web settings such as Firecrawl.
|
|
35
|
+
* Children with a different cwd (for example a frozen Review Workspace) keep this policy.
|
|
36
|
+
*/
|
|
37
|
+
readonly configCwd: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
type EventBusLike = Pick<ExtensionAPI["events"], "on" | "emit">;
|
|
41
|
+
|
|
42
|
+
const REQUEST_CHANNEL = "supi:child-web-tools:request";
|
|
43
|
+
const RESPONSE_CHANNEL = "supi:child-web-tools:response";
|
|
44
|
+
|
|
45
|
+
interface ChildWebToolsRequest extends ChildWebToolsRequestContext {
|
|
46
|
+
readonly requestId: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
interface ChildWebToolsResponse {
|
|
50
|
+
readonly requestId: string;
|
|
51
|
+
readonly provision: ChildWebToolProvision;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
let nextRequestId = 0;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Answer child Web tool requests on the parent event bus. The callback must be synchronous
|
|
58
|
+
* because Pi's event bus does not await listeners. Returns an unsubscribe function.
|
|
59
|
+
*/
|
|
60
|
+
export function provideChildWebTools(
|
|
61
|
+
events: EventBusLike,
|
|
62
|
+
resolve: (context: ChildWebToolsRequestContext) => ChildWebToolProvision | undefined,
|
|
63
|
+
): () => void {
|
|
64
|
+
return events.on(REQUEST_CHANNEL, (data) => {
|
|
65
|
+
const request = data as Partial<ChildWebToolsRequest> | undefined;
|
|
66
|
+
if (typeof request?.requestId !== "string" || typeof request.configCwd !== "string") return;
|
|
67
|
+
const { requestId, configCwd } = request;
|
|
68
|
+
const provision = resolve({ configCwd });
|
|
69
|
+
if (!provision || provision.toolNames.length === 0) return;
|
|
70
|
+
events.emit(RESPONSE_CHANNEL, { requestId, provision } satisfies ChildWebToolsResponse);
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** Capture the Web tools the containing session currently provides, if any. */
|
|
75
|
+
export function requestChildWebTools(
|
|
76
|
+
events: EventBusLike,
|
|
77
|
+
context: ChildWebToolsRequestContext,
|
|
78
|
+
): ChildWebToolProvision | undefined {
|
|
79
|
+
const requestId = `child-web-${process.pid}-${++nextRequestId}`;
|
|
80
|
+
let provision: ChildWebToolProvision | undefined;
|
|
81
|
+
const unsubscribe = events.on(RESPONSE_CHANNEL, (data) => {
|
|
82
|
+
const response = data as Partial<ChildWebToolsResponse> | undefined;
|
|
83
|
+
if (response?.requestId === requestId && response.provision) provision = response.provision;
|
|
84
|
+
});
|
|
85
|
+
try {
|
|
86
|
+
events.emit(REQUEST_CHANNEL, { requestId, ...context } satisfies ChildWebToolsRequest);
|
|
87
|
+
} finally {
|
|
88
|
+
unsubscribe();
|
|
89
|
+
}
|
|
90
|
+
return provision;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Return the Web tools callable in a session under Pi's exposure rules: active `direct`
|
|
95
|
+
* tools, plus registered `codemode` and `deferred` tools. `model-only` and `hidden`
|
|
96
|
+
* tools are not callable.
|
|
97
|
+
*/
|
|
98
|
+
export function callableChildWebToolNames(
|
|
99
|
+
pi: Pick<ExtensionAPI, "getAllTools" | "getActiveTools">,
|
|
100
|
+
): ChildWebToolName[] {
|
|
101
|
+
const active = new Set(pi.getActiveTools());
|
|
102
|
+
const exposures = new Map(
|
|
103
|
+
pi.getAllTools().map((tool) => [tool.name, tool.exposure ?? "direct"] as const),
|
|
104
|
+
);
|
|
105
|
+
return CHILD_WEB_TOOL_NAMES.filter((name) => {
|
|
106
|
+
const exposure = exposures.get(name);
|
|
107
|
+
if (exposure === "direct") return active.has(name);
|
|
108
|
+
return exposure === "codemode" || exposure === "deferred";
|
|
109
|
+
});
|
|
110
|
+
}
|
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
// supi-core session domain — session utilities and registries.
|
|
2
2
|
|
|
3
|
+
export type {
|
|
4
|
+
ChildWebToolName,
|
|
5
|
+
ChildWebToolProvision,
|
|
6
|
+
ChildWebToolsRequestContext,
|
|
7
|
+
} from "./child-web-tools.ts";
|
|
8
|
+
export {
|
|
9
|
+
CHILD_WEB_TOOL_NAMES,
|
|
10
|
+
callableChildWebToolNames,
|
|
11
|
+
provideChildWebTools,
|
|
12
|
+
requestChildWebTools,
|
|
13
|
+
} from "./child-web-tools.ts";
|
|
3
14
|
export { createRegistry, createSessionStateRegistry } from "./registry-utils.ts";
|
|
4
15
|
export type {
|
|
5
16
|
SessionCapabilitySkill,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mrclrchtr/supi-settings",
|
|
3
|
-
"version": "11.
|
|
3
|
+
"version": "11.3.0",
|
|
4
4
|
"description": "One project/global settings UI for SuPi packages",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -26,11 +26,13 @@
|
|
|
26
26
|
],
|
|
27
27
|
"type": "module",
|
|
28
28
|
"files": [
|
|
29
|
+
"CHANGELOG.md",
|
|
29
30
|
"src/**/*.ts",
|
|
31
|
+
"skills",
|
|
30
32
|
"!__tests__"
|
|
31
33
|
],
|
|
32
34
|
"dependencies": {
|
|
33
|
-
"@mrclrchtr/supi-core": "11.
|
|
35
|
+
"@mrclrchtr/supi-core": "11.3.0"
|
|
34
36
|
},
|
|
35
37
|
"bundledDependencies": [
|
|
36
38
|
"@mrclrchtr/supi-core"
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: supi-setup
|
|
3
|
+
description: Audit SuPi packages and configuration for the current project and propose fixes.
|
|
4
|
+
disable-model-invocation: true
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# SuPi setup audit
|
|
8
|
+
|
|
9
|
+
Audit how SuPi is installed and configured for the current project, then propose fixes. **Report first; change nothing until the user confirms each change.**
|
|
10
|
+
|
|
11
|
+
Every finding carries its **evidence**: the file, command output, or tool result that shows it. A suspicion without evidence goes under "Not checked" instead of becoming a finding.
|
|
12
|
+
|
|
13
|
+
## Sources of truth
|
|
14
|
+
|
|
15
|
+
| What | Where |
|
|
16
|
+
| --- | --- |
|
|
17
|
+
| Global SuPi config | `~/.pi/agent/supi/config.json` |
|
|
18
|
+
| Project SuPi config (overrides global per key) | `.pi/supi/config.json` |
|
|
19
|
+
| Package declarations | `pi list` (project and user scope) |
|
|
20
|
+
| Server health and TypeScript backend | `code_health({ include: ["servers"] })` |
|
|
21
|
+
| Setting semantics | Each package's README (installed package directory, or `https://github.com/mrclrchtr/supi/tree/main/packages/<package>#readme`) |
|
|
22
|
+
|
|
23
|
+
Read both config files before any check. A missing file is normal; invalid JSON is a finding.
|
|
24
|
+
|
|
25
|
+
## Checks
|
|
26
|
+
|
|
27
|
+
Run every check. Each ends with a verdict: **ok**, **finding**, or **not checked** (with the reason, e.g. package not installed, tool unavailable).
|
|
28
|
+
|
|
29
|
+
### 1. Package declarations
|
|
30
|
+
|
|
31
|
+
Run `pi list`.
|
|
32
|
+
|
|
33
|
+
- **Obsolete direct declarations**: `@mrclrchtr/supi-agents`, `@mrclrchtr/supi-rtk`, `@mrclrchtr/supi-lsp`, `@mrclrchtr/supi-tree-sitter`. LSP and Tree-sitter are still bundled by Code Intelligence; only their direct declarations are obsolete. Propose `pi remove npm:<name>` (add `--local` for project scope).
|
|
34
|
+
- **Legacy root package** `@mrclrchtr/supi`, or Git/local SuPi checkouts outside SuPi development: conflicts that block the installer for that scope. Propose removal with `pi remove <source>`.
|
|
35
|
+
- **The same package in both scopes**: the project entry replaces the personal one (with `autoload: false` it filters the personal package instead). Report it; propose keeping one only if the user did not intend the override.
|
|
36
|
+
- **Missing recommended packages**: propose `npx @mrclrchtr/supi-installer@latest` and pressing `r` for the Recommended column. The installer is interactive; the user runs it.
|
|
37
|
+
- **Suggestions from project signals**, only with evidence, for example `supi-review` for a Git repository with active branches, or `supi-claude-md` when `CLAUDE.md` or `AGENTS.md` exists.
|
|
38
|
+
|
|
39
|
+
### 2. Language servers
|
|
40
|
+
|
|
41
|
+
Call `code_health({ include: ["servers"] })`. Compare it with the languages the project actually contains (manifests and file extensions).
|
|
42
|
+
|
|
43
|
+
- A detected language whose server is missing or failed is a finding. Name the server command from the `supi-lsp` README route matrix. SuPi never installs servers.
|
|
44
|
+
- TypeScript: report the active backend (`native` or `tsserver`) and compiler version. A selection failure or configuration conflict is a finding.
|
|
45
|
+
- Servers running for languages the project does not use are fine; do not propose disabling them unless they fail.
|
|
46
|
+
|
|
47
|
+
### 3. TypeScript code-action formatting
|
|
48
|
+
|
|
49
|
+
TypeScript servers format organize-imports and unused-import edits with their own defaults (4-space indentation) unless `lsp.servers.typescript.settings` says otherwise. SuPi does not infer formatting from project files.
|
|
50
|
+
|
|
51
|
+
1. Determine the project's indentation from the formatter config in effect: `biome.json`/`biome.jsonc` (`formatter.indentStyle`, `formatter.indentWidth`), Prettier config (`tabWidth`, `useTabs`), or `.editorconfig` (`indent_style`, `indent_size`). Note which source you used. With no source, report "not checked".
|
|
52
|
+
2. Compare with `lsp.servers.typescript.settings.typescript.format` and `.javascript.format` (`indentSize`, `tabSize`, `convertTabsToSpaces`).
|
|
53
|
+
3. A mismatch, or no settings while the project indentation is not 4 spaces, is a finding. Propose the settings in project scope:
|
|
54
|
+
|
|
55
|
+
```json
|
|
56
|
+
{
|
|
57
|
+
"lsp": {
|
|
58
|
+
"servers": {
|
|
59
|
+
"typescript": {
|
|
60
|
+
"settings": {
|
|
61
|
+
"typescript": { "format": { "indentSize": 2, "tabSize": 2, "convertTabsToSpaces": true } },
|
|
62
|
+
"javascript": { "format": { "indentSize": 2, "tabSize": 2, "convertTabsToSpaces": true } }
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Skip this check when the project has no TypeScript or JavaScript.
|
|
71
|
+
|
|
72
|
+
### 4. Code Intelligence exclusions
|
|
73
|
+
|
|
74
|
+
Automatic LSP work already skips `.git`, `.cache`, `.pi`, `.pnpm`, `node_modules`, `dist`, `build`, `out`, `coverage`, `.next`, `.nuxt`, `.turbo`, `__pycache__`, and `.gitignore` matches.
|
|
75
|
+
|
|
76
|
+
- Look for large **generated or vendored** directories that are none of these: tracked or non-ignored (`git ls-files`, `git status --porcelain --ignored=no`), e.g. `generated/`, `vendor/`, `third_party/`, snapshot or fixture dumps. Count files to show the size.
|
|
77
|
+
- A large generated directory not covered is a finding. Propose a `code-intelligence.exclude` pattern (gitignore syntax). Remember that a project list **replaces** the global list.
|
|
78
|
+
- Hand-written source is never an exclusion candidate, even when large.
|
|
79
|
+
|
|
80
|
+
### 5. Stale or orphaned config
|
|
81
|
+
|
|
82
|
+
- `lsp.exclude` is a migration error: propose moving it to `code-intelligence.exclude`.
|
|
83
|
+
- A top-level section whose owning package is not declared (check 1) is dead config. Report it; propose removal only if the user confirms the package is gone for good.
|
|
84
|
+
|
|
85
|
+
| Section | Owning package |
|
|
86
|
+
| --- | --- |
|
|
87
|
+
| `agent` | `supi-agent` |
|
|
88
|
+
| `ask-user` | `supi-ask-user` |
|
|
89
|
+
| `bash-timeout` | `supi-bash-timeout` |
|
|
90
|
+
| `cache` | `supi-cache` |
|
|
91
|
+
| `code-intelligence`, `lsp` | `supi-code-intelligence` |
|
|
92
|
+
| `consulting` | `supi-consulting` |
|
|
93
|
+
| `context` | `supi-context` |
|
|
94
|
+
| `debug` | `supi-debug` |
|
|
95
|
+
| `insights` | `supi-insights` |
|
|
96
|
+
| `promptImprover` | `supi-prompt-improver` |
|
|
97
|
+
| `promptSuggestions` | `supi-prompt-suggestions` |
|
|
98
|
+
| `review` | `supi-review` |
|
|
99
|
+
| `sessionCapabilities` | `supi-extras` |
|
|
100
|
+
| `skills` | `supi-skills` |
|
|
101
|
+
| `web` | `supi-web` |
|
|
102
|
+
|
|
103
|
+
An unknown top-level section is a finding with the verdict "unknown; verify against the package READMEs".
|
|
104
|
+
|
|
105
|
+
### 6. Review bootstrap
|
|
106
|
+
|
|
107
|
+
Only when `supi-review` is declared. `review.bootstrapCommand` runs once in each frozen Review Workspace.
|
|
108
|
+
|
|
109
|
+
- A JavaScript project with a lockfile and no bootstrap command: propose the matching install command (`pnpm install --frozen-lockfile`, `npm ci`, `yarn install --immutable`, `bun install --frozen-lockfile`).
|
|
110
|
+
- A bootstrap command for a different package manager than the lockfile is a finding.
|
|
111
|
+
- Other ecosystems: suggest a command only when the project documents one.
|
|
112
|
+
|
|
113
|
+
## Report
|
|
114
|
+
|
|
115
|
+
Present one table, one row per check:
|
|
116
|
+
|
|
117
|
+
| Check | Verdict | Evidence | Proposed change |
|
|
118
|
+
| --- | --- | --- | --- |
|
|
119
|
+
|
|
120
|
+
Then list the proposed changes as exact JSON patches for the target config file, or exact commands. Default to **project scope**; propose global scope only for settings that are personal rather than project facts (e.g. models).
|
|
121
|
+
|
|
122
|
+
## Apply
|
|
123
|
+
|
|
124
|
+
Ask the user which proposed changes to apply. For each confirmed change:
|
|
125
|
+
|
|
126
|
+
- Config: edit the scoped `config.json` with a minimal edit that preserves every other key. `/supi-settings` is an alternative for settings it exposes.
|
|
127
|
+
- Packages: run `pi remove …` yourself when confirmed. Leave the interactive installer to the user.
|
|
128
|
+
|
|
129
|
+
Finish by telling the user to run `/reload` or restart Pi, and list any checks reported as "not checked".
|
package/src/extension.ts
CHANGED
|
@@ -1,9 +1,17 @@
|
|
|
1
|
+
import { dirname, join } from "node:path";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
1
3
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
4
|
import { openSettingsOverlay } from "./ui/settings-ui.ts";
|
|
3
5
|
|
|
6
|
+
const baseDir = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
7
|
+
|
|
4
8
|
export default function (pi: ExtensionAPI): void {
|
|
5
9
|
pi.registerCommand("supi-settings", {
|
|
6
10
|
description: "Manage SuPi extension settings",
|
|
7
11
|
handler: async (_args, ctx) => openSettingsOverlay(pi, ctx),
|
|
8
12
|
});
|
|
13
|
+
|
|
14
|
+
pi.on("resources_discover", () => ({
|
|
15
|
+
skillPaths: [join(baseDir, "skills")],
|
|
16
|
+
}));
|
|
9
17
|
}
|