@mrclrchtr/supi-cache 1.3.1 → 1.5.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 +56 -71
- package/node_modules/@mrclrchtr/supi-core/README.md +52 -41
- package/node_modules/@mrclrchtr/supi-core/package.json +1 -1
- package/node_modules/@mrclrchtr/supi-core/src/api.ts +15 -13
- package/node_modules/@mrclrchtr/supi-core/src/{config-settings.ts → config/config-settings.ts} +2 -2
- package/node_modules/@mrclrchtr/supi-core/src/{context-provider-registry.ts → context/context-provider-registry.ts} +1 -1
- package/node_modules/@mrclrchtr/supi-core/src/extension.ts +1 -1
- package/node_modules/@mrclrchtr/supi-core/src/index.ts +15 -13
- package/node_modules/@mrclrchtr/supi-core/src/path-utils.ts +40 -0
- package/node_modules/@mrclrchtr/supi-core/src/registry-utils.ts +42 -10
- package/node_modules/@mrclrchtr/supi-core/src/{settings-registry.ts → settings/settings-registry.ts} +1 -1
- package/package.json +2 -2
- package/src/monitor/monitor.ts +4 -13
- package/src/tool/guidance.ts +16 -0
- /package/node_modules/@mrclrchtr/supi-core/src/{config.ts → config/config.ts} +0 -0
- /package/node_modules/@mrclrchtr/supi-core/src/{context-messages.ts → context/context-messages.ts} +0 -0
- /package/node_modules/@mrclrchtr/supi-core/src/{context-tag.ts → context/context-tag.ts} +0 -0
- /package/node_modules/@mrclrchtr/supi-core/src/{settings-command.ts → settings/settings-command.ts} +0 -0
- /package/node_modules/@mrclrchtr/supi-core/src/{settings-ui.ts → settings/settings-ui.ts} +0 -0
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @mrclrchtr/supi-cache
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Adds prompt-cache monitoring and cache-regression forensics to the [pi coding agent](https://github.com/earendil-works/pi).
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
@@ -8,8 +8,7 @@ Prompt cache health monitoring and cross-session forensics for the [pi coding ag
|
|
|
8
8
|
pi install npm:@mrclrchtr/supi-cache
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
> Install directly when you need cache forensics.
|
|
11
|
+
This is a **beta** package. It is not bundled in `@mrclrchtr/supi`.
|
|
13
12
|
|
|
14
13
|
For local development:
|
|
15
14
|
|
|
@@ -17,60 +16,72 @@ For local development:
|
|
|
17
16
|
pi install ./packages/supi-cache
|
|
18
17
|
```
|
|
19
18
|
|
|
20
|
-
|
|
19
|
+
After editing the source, run `/reload`.
|
|
21
20
|
|
|
22
|
-
## What
|
|
21
|
+
## What you get
|
|
23
22
|
|
|
24
|
-
|
|
23
|
+
After install, the package does two things:
|
|
25
24
|
|
|
26
|
-
|
|
25
|
+
1. **Monitor the current session**
|
|
26
|
+
- records per-turn cache usage from assistant messages
|
|
27
|
+
- updates a footer status for cache health
|
|
28
|
+
- warns when the cache hit rate drops enough to count as a regression
|
|
29
|
+
- tries to explain the drop as compaction, model change, prompt change, or unknown
|
|
27
30
|
|
|
28
|
-
|
|
29
|
-
-
|
|
30
|
-
-
|
|
31
|
-
-
|
|
31
|
+
2. **Investigate past sessions**
|
|
32
|
+
- scans session files for cache regressions across time
|
|
33
|
+
- groups findings into a few built-in query patterns
|
|
34
|
+
- keeps agent-facing results redacted to structural fingerprints instead of raw command text or file paths
|
|
32
35
|
|
|
33
36
|
## Commands and tool
|
|
34
37
|
|
|
35
|
-
|
|
36
|
-
|----------|------|-------------|
|
|
37
|
-
| Command | `/supi-cache-history` | Per-turn cache metrics table for the current session, with annotated regression details and fingerprint diffs |
|
|
38
|
-
| Command | `/supi-cache-forensics` | Cross-session investigation with themed TUI report. Accepts `--pattern`, `--since`, `--min-drop` filters |
|
|
39
|
-
| Tool | `supi_cache_forensics` | Agent-callable — returns structured JSON with shape fingerprints (param types and lengths, no raw content) |
|
|
38
|
+
### `/supi-cache-history`
|
|
40
39
|
|
|
41
|
-
|
|
40
|
+
Shows cache history for the current session.
|
|
42
41
|
|
|
43
|
-
|
|
44
|
-
# Show per-turn history for the current session
|
|
45
|
-
/supi-cache-history
|
|
42
|
+
The report includes per-turn values for:
|
|
46
43
|
|
|
47
|
-
|
|
48
|
-
|
|
44
|
+
- input tokens
|
|
45
|
+
- cache read tokens
|
|
46
|
+
- cache write tokens
|
|
47
|
+
- hit rate
|
|
48
|
+
- notes about detected regressions
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
/supi-cache-forensics --pattern hotspots --since 3d --min-drop 20
|
|
50
|
+
### `/supi-cache-forensics`
|
|
52
51
|
|
|
53
|
-
|
|
54
|
-
/supi-cache-forensics --pattern idle
|
|
55
|
-
```
|
|
52
|
+
Runs a cross-session investigation.
|
|
56
53
|
|
|
57
|
-
|
|
54
|
+
Supported patterns:
|
|
58
55
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
56
|
+
- `breakdown` — count regressions by cause
|
|
57
|
+
- `hotspots` — show the largest drops
|
|
58
|
+
- `correlate` — show which preceding tool calls correlate with drops
|
|
59
|
+
- `idle` — show drops after long gaps between turns
|
|
60
|
+
|
|
61
|
+
Useful flags:
|
|
62
|
+
|
|
63
|
+
- `--since 7d`
|
|
64
|
+
- `--pattern breakdown`
|
|
65
|
+
- `--min-drop 20`
|
|
66
|
+
|
|
67
|
+
### `supi_cache_forensics`
|
|
68
|
+
|
|
69
|
+
Adds one model-callable tool with the same four patterns: `hotspots`, `breakdown`, `correlate`, and `idle`.
|
|
70
|
+
|
|
71
|
+
The tool returns JSON text. Before results are returned to the model, human-only details such as `_pathsInvolved` and `_commandSummaries` are stripped out.
|
|
72
|
+
|
|
73
|
+
## Settings
|
|
74
|
+
|
|
75
|
+
This package registers a **Cache** section in `/supi-settings`.
|
|
65
76
|
|
|
66
|
-
|
|
77
|
+
Available settings:
|
|
67
78
|
|
|
68
|
-
|
|
79
|
+
- `enabled` — turn monitoring on or off
|
|
80
|
+
- `notifications` — show warning notifications for regressions
|
|
81
|
+
- `regressionThreshold` — percentage-point drop that counts as a regression warning
|
|
82
|
+
- `idleThresholdMinutes` — inactivity gap used to classify idle-time regressions
|
|
69
83
|
|
|
70
|
-
|
|
71
|
-
|-------|------|
|
|
72
|
-
| Global | `~/.pi/agent/supi/config.json` |
|
|
73
|
-
| Project | `.pi/supi/config.json` |
|
|
84
|
+
Defaults:
|
|
74
85
|
|
|
75
86
|
```json
|
|
76
87
|
{
|
|
@@ -83,37 +94,11 @@ Config files (project overrides global):
|
|
|
83
94
|
}
|
|
84
95
|
```
|
|
85
96
|
|
|
86
|
-
|
|
87
|
-
|---------|-------------|---------|
|
|
88
|
-
| `enabled` | Enable/disable monitoring | `true` |
|
|
89
|
-
| `notifications` | Show regression warning notifications | `true` |
|
|
90
|
-
| `regressionThreshold` | Percentage-point drop that triggers a warning and gates forensics findings | `25` |
|
|
91
|
-
| `idleThresholdMinutes` | Minutes of inactivity to classify as idle-time regression | `5` |
|
|
92
|
-
|
|
93
|
-
Upgrades from the old `cache-monitor` config section are handled automatically.
|
|
94
|
-
|
|
95
|
-
If you have `/supi-settings` available (for example when also installing the `@mrclrchtr/supi` meta-package), the **Cache** section also appears there with editable fields.
|
|
96
|
-
|
|
97
|
-
## Provider notes
|
|
98
|
-
|
|
99
|
-
Some providers do not report cache write tokens in their usage metadata. For example, Anthropic's API returns `cache_read_input_tokens` and `input_tokens` but does not expose cache writes. When using such a provider, the `CacheW` column in `/supi-cache-history` will always show `0`. Providers that do report cache writes (e.g. Google Gemini) will populate the column normally.
|
|
100
|
-
|
|
101
|
-
## Agent safety
|
|
102
|
-
|
|
103
|
-
The `supi_cache_forensics` tool returns shape fingerprints, not raw content:
|
|
104
|
-
|
|
105
|
-
| If the agent sees | It does NOT see |
|
|
106
|
-
|---|---|
|
|
107
|
-
| `{ "toolName": "bash", "paramKeys": ["command"], "paramShapes": { "command": { "kind": "string", "len": 340, "multiline": true } } }` | The 340-char command text |
|
|
108
|
-
| `{ "toolName": "write", "paramKeys": ["file_path", "content"] }` | The file content or exact path |
|
|
109
|
-
|
|
110
|
-
Human-only detail (`_pathsInvolved`, `_commandSummaries`) is stripped before returning to the agent — the TUI renderer shows richer information.
|
|
111
|
-
|
|
112
|
-
## Requirements
|
|
113
|
-
|
|
114
|
-
- `@earendil-works/pi-coding-agent`
|
|
115
|
-
- `@mrclrchtr/supi-core`
|
|
97
|
+
The config loader also reads the legacy `cache-monitor` section for upgrades, but `supi-cache` is the current config section.
|
|
116
98
|
|
|
117
99
|
## Source
|
|
118
100
|
|
|
119
|
-
|
|
101
|
+
- `src/monitor/monitor.ts` — live monitoring, commands, and tool registration
|
|
102
|
+
- `src/forensics/forensics.ts` — cross-session scan pipeline
|
|
103
|
+
- `src/report/history.ts` — current-session history report
|
|
104
|
+
- `src/report/forensics.ts` — cross-session forensics report
|
|
@@ -1,65 +1,78 @@
|
|
|
1
1
|
# @mrclrchtr/supi-core
|
|
2
2
|
|
|
3
|
-
Shared infrastructure for SuPi
|
|
3
|
+
Shared infrastructure for SuPi extensions.
|
|
4
|
+
|
|
5
|
+
This package is mainly for extension authors. It gives you a common config system, settings plumbing, context helpers, registries, and a small extension surface that registers `/supi-settings`.
|
|
4
6
|
|
|
5
7
|
## Install
|
|
6
8
|
|
|
7
|
-
|
|
9
|
+
### As a dependency for another extension
|
|
8
10
|
|
|
9
11
|
```bash
|
|
10
12
|
pnpm add @mrclrchtr/supi-core
|
|
11
13
|
```
|
|
12
14
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
`@mrclrchtr/supi-core` now has two explicit surfaces:
|
|
15
|
+
### As a pi package
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
`pi.extensions` still points at the real file path `./src/extension.ts` inside the package. The `/api` and `/extension` paths are consumer-facing package exports, not manifest aliases.
|
|
17
|
+
```bash
|
|
18
|
+
pi install npm:@mrclrchtr/supi-core
|
|
19
|
+
```
|
|
21
20
|
|
|
22
|
-
|
|
21
|
+
Installing it as a pi package adds the minimal `/supi-settings` extension surface.
|
|
23
22
|
|
|
24
|
-
|
|
23
|
+
## Package surfaces
|
|
25
24
|
|
|
26
|
-
-
|
|
27
|
-
-
|
|
28
|
-
- the shared settings registry, overlay UI, and `registerSettingsCommand()` helper
|
|
29
|
-
- XML `<extension-context>` wrapping plus context-message utilities
|
|
30
|
-
- context-provider and debug-event registries reused across SuPi packages
|
|
31
|
-
- project root and path helpers reused by packages such as `supi-lsp`
|
|
25
|
+
- `@mrclrchtr/supi-core/api` — reusable helpers for other packages and extensions
|
|
26
|
+
- `@mrclrchtr/supi-core/extension` — minimal pi extension that registers `/supi-settings`
|
|
32
27
|
|
|
33
|
-
##
|
|
28
|
+
## What you get from the API
|
|
34
29
|
|
|
35
|
-
Config
|
|
30
|
+
### Config helpers
|
|
36
31
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
32
|
+
- `loadSupiConfig()` — merged config with resolution order `defaults <- global <- project`
|
|
33
|
+
- `loadSupiConfigForScope()` — load one scope at a time for settings UIs
|
|
34
|
+
- `writeSupiConfig()` — persist values
|
|
35
|
+
- `removeSupiConfigKey()` — remove a key or override
|
|
40
36
|
|
|
41
37
|
Config file locations:
|
|
42
38
|
|
|
43
39
|
- global: `~/.pi/agent/supi/config.json`
|
|
44
40
|
- project: `.pi/supi/config.json`
|
|
45
41
|
|
|
46
|
-
|
|
42
|
+
### Settings helpers
|
|
43
|
+
|
|
44
|
+
- `registerSettings()` — register an arbitrary settings section
|
|
45
|
+
- `registerConfigSettings()` — register a config-backed settings section with scoped persistence helpers
|
|
46
|
+
- `registerSettingsCommand()` — register `/supi-settings`
|
|
47
|
+
- `openSettingsOverlay()` — open the shared settings UI directly
|
|
48
|
+
- `createInputSubmenu()` — helper for simple text-entry submenus
|
|
49
|
+
|
|
50
|
+
The built-in settings UI supports:
|
|
47
51
|
|
|
48
|
-
-
|
|
49
|
-
-
|
|
50
|
-
-
|
|
51
|
-
- `removeSupiConfigKey()`
|
|
52
|
-
- `registerConfigSettings()`
|
|
52
|
+
- project/global scope toggle
|
|
53
|
+
- grouped extension sections
|
|
54
|
+
- searchable setting lists
|
|
53
55
|
|
|
54
|
-
|
|
56
|
+
### Context helpers
|
|
55
57
|
|
|
56
|
-
- `wrapExtensionContext()`
|
|
58
|
+
- `wrapExtensionContext()` — wrap injected text in SuPi's `<extension-context>` tag
|
|
57
59
|
- `findLastUserMessageIndex()`
|
|
58
60
|
- `getContextToken()`
|
|
61
|
+
- `getPromptContent()`
|
|
59
62
|
- `pruneAndReorderContextMessages()`
|
|
60
|
-
- `
|
|
61
|
-
|
|
62
|
-
|
|
63
|
+
- `restorePromptContent()`
|
|
64
|
+
|
|
65
|
+
### Shared registries
|
|
66
|
+
|
|
67
|
+
- context-provider registry for `/supi-context`
|
|
68
|
+
- debug-event registry for producers that want shared debug capture
|
|
69
|
+
- settings registry used by `/supi-settings`
|
|
70
|
+
|
|
71
|
+
### Project and session helpers
|
|
72
|
+
|
|
73
|
+
- project-root detection and directory walking helpers such as `findProjectRoot()` and `walkProject()`
|
|
74
|
+
- active-branch session helper: `getActiveBranchEntries()`
|
|
75
|
+
- terminal helpers such as `formatTitle()`, `signalWaiting()`, and `signalDone()`
|
|
63
76
|
|
|
64
77
|
## Example
|
|
65
78
|
|
|
@@ -80,17 +93,15 @@ registerConfigSettings({
|
|
|
80
93
|
});
|
|
81
94
|
|
|
82
95
|
const message = wrapExtensionContext("my-extension", "hello", {
|
|
83
|
-
turn: 1,
|
|
84
96
|
file: "CLAUDE.md",
|
|
97
|
+
turn: 1,
|
|
85
98
|
});
|
|
86
99
|
```
|
|
87
100
|
|
|
88
|
-
## Requirements
|
|
89
|
-
|
|
90
|
-
- `@earendil-works/pi-coding-agent`
|
|
91
|
-
- `@earendil-works/pi-tui`
|
|
92
|
-
|
|
93
101
|
## Source
|
|
94
102
|
|
|
95
|
-
-
|
|
96
|
-
-
|
|
103
|
+
- `src/api.ts` — exported library surface
|
|
104
|
+
- `src/extension.ts` — minimal `/supi-settings` entrypoint
|
|
105
|
+
- `src/config.ts` — shared config loading and writing
|
|
106
|
+
- `src/config-settings.ts` — config-backed settings registration helper
|
|
107
|
+
- `src/settings-ui.ts` — shared settings overlay
|
|
@@ -2,30 +2,30 @@
|
|
|
2
2
|
// Provides XML context tag wrapping, unified config system, context-message utilities,
|
|
3
3
|
// and settings registry for supi-wide TUI settings.
|
|
4
4
|
|
|
5
|
-
export type { SupiConfigLocation, SupiConfigOptions } from "./config.ts";
|
|
5
|
+
export type { SupiConfigLocation, SupiConfigOptions } from "./config/config.ts";
|
|
6
6
|
export {
|
|
7
7
|
loadSupiConfig,
|
|
8
8
|
loadSupiConfigForScope,
|
|
9
9
|
removeSupiConfigKey,
|
|
10
10
|
writeSupiConfig,
|
|
11
|
-
} from "./config.ts";
|
|
12
|
-
export type { ConfigSettingsHelpers, ConfigSettingsOptions } from "./config-settings.ts";
|
|
13
|
-
export { registerConfigSettings } from "./config-settings.ts";
|
|
14
|
-
export type { ContextMessageLike } from "./context-messages.ts";
|
|
11
|
+
} from "./config/config.ts";
|
|
12
|
+
export type { ConfigSettingsHelpers, ConfigSettingsOptions } from "./config/config-settings.ts";
|
|
13
|
+
export { registerConfigSettings } from "./config/config-settings.ts";
|
|
14
|
+
export type { ContextMessageLike } from "./context/context-messages.ts";
|
|
15
15
|
export {
|
|
16
16
|
findLastUserMessageIndex,
|
|
17
17
|
getContextToken,
|
|
18
18
|
getPromptContent,
|
|
19
19
|
pruneAndReorderContextMessages,
|
|
20
20
|
restorePromptContent,
|
|
21
|
-
} from "./context-messages.ts";
|
|
22
|
-
export type { ContextProvider } from "./context-provider-registry.ts";
|
|
21
|
+
} from "./context/context-messages.ts";
|
|
22
|
+
export type { ContextProvider } from "./context/context-provider-registry.ts";
|
|
23
23
|
export {
|
|
24
24
|
clearRegisteredContextProviders,
|
|
25
25
|
getRegisteredContextProviders,
|
|
26
26
|
registerContextProvider,
|
|
27
|
-
} from "./context-provider-registry.ts";
|
|
28
|
-
export { wrapExtensionContext } from "./context-tag.ts";
|
|
27
|
+
} from "./context/context-provider-registry.ts";
|
|
28
|
+
export { wrapExtensionContext } from "./context/context-tag.ts";
|
|
29
29
|
export type {
|
|
30
30
|
DebugAgentAccess,
|
|
31
31
|
DebugEvent,
|
|
@@ -49,6 +49,7 @@ export {
|
|
|
49
49
|
redactDebugData,
|
|
50
50
|
resetDebugRegistry,
|
|
51
51
|
} from "./debug-registry.ts";
|
|
52
|
+
export { fileToUri, resolveToolPath, stripToolPathPrefix, uriToFile } from "./path-utils.ts";
|
|
52
53
|
export type { KnownRootEntry } from "./project-roots.ts";
|
|
53
54
|
export {
|
|
54
55
|
buildKnownRootsMap,
|
|
@@ -63,15 +64,16 @@ export {
|
|
|
63
64
|
sortRootsBySpecificity,
|
|
64
65
|
walkProject,
|
|
65
66
|
} from "./project-roots.ts";
|
|
67
|
+
export { createRegistry, createSessionStateRegistry } from "./registry-utils.ts";
|
|
66
68
|
export { getActiveBranchEntries } from "./session-utils.ts";
|
|
67
|
-
export { registerSettingsCommand } from "./settings-command.ts";
|
|
68
|
-
export type { SettingsScope, SettingsSection } from "./settings-registry.ts";
|
|
69
|
+
export { registerSettingsCommand } from "./settings/settings-command.ts";
|
|
70
|
+
export type { SettingsScope, SettingsSection } from "./settings/settings-registry.ts";
|
|
69
71
|
export {
|
|
70
72
|
clearRegisteredSettings,
|
|
71
73
|
getRegisteredSettings,
|
|
72
74
|
registerSettings,
|
|
73
|
-
} from "./settings-registry.ts";
|
|
74
|
-
export { createInputSubmenu, openSettingsOverlay } from "./settings-ui.ts";
|
|
75
|
+
} from "./settings/settings-registry.ts";
|
|
76
|
+
export { createInputSubmenu, openSettingsOverlay } from "./settings/settings-ui.ts";
|
|
75
77
|
export type { TitleTarget } from "./terminal.ts";
|
|
76
78
|
export {
|
|
77
79
|
DONE_SYMBOL,
|
package/node_modules/@mrclrchtr/supi-core/src/{config-settings.ts → config/config-settings.ts}
RENAMED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
// Wraps registerSettings() and centralizes selected-scope loading + scoped persistence.
|
|
3
3
|
|
|
4
4
|
import type { SettingItem } from "@earendil-works/pi-tui";
|
|
5
|
+
import type { SettingsScope } from "../settings/settings-registry.ts";
|
|
6
|
+
import { registerSettings } from "../settings/settings-registry.ts";
|
|
5
7
|
import { loadSupiConfigForScope, removeSupiConfigKey, writeSupiConfig } from "./config.ts";
|
|
6
|
-
import type { SettingsScope } from "./settings-registry.ts";
|
|
7
|
-
import { registerSettings } from "./settings-registry.ts";
|
|
8
8
|
|
|
9
9
|
export interface ConfigSettingsHelpers {
|
|
10
10
|
/** Write a key to the selected scope's config section. */
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// Extensions declare context data providers via `registerContextProvider()` during their
|
|
4
4
|
// factory function. The `/supi-context` command reads them via `getRegisteredContextProviders()`.
|
|
5
5
|
|
|
6
|
-
import { createRegistry } from "
|
|
6
|
+
import { createRegistry } from "../registry-utils.ts";
|
|
7
7
|
|
|
8
8
|
export interface ContextProvider {
|
|
9
9
|
/** Unique identifier — e.g. "rtk" */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { registerSettingsCommand as default } from "./settings-command.ts";
|
|
1
|
+
export { registerSettingsCommand as default } from "./settings/settings-command.ts";
|
|
@@ -2,30 +2,30 @@
|
|
|
2
2
|
// Provides XML context tag wrapping, unified config system, context-message utilities,
|
|
3
3
|
// and settings registry for supi-wide TUI settings.
|
|
4
4
|
|
|
5
|
-
export type { SupiConfigLocation, SupiConfigOptions } from "./config.ts";
|
|
5
|
+
export type { SupiConfigLocation, SupiConfigOptions } from "./config/config.ts";
|
|
6
6
|
export {
|
|
7
7
|
loadSupiConfig,
|
|
8
8
|
loadSupiConfigForScope,
|
|
9
9
|
removeSupiConfigKey,
|
|
10
10
|
writeSupiConfig,
|
|
11
|
-
} from "./config.ts";
|
|
12
|
-
export type { ConfigSettingsHelpers, ConfigSettingsOptions } from "./config-settings.ts";
|
|
13
|
-
export { registerConfigSettings } from "./config-settings.ts";
|
|
14
|
-
export type { ContextMessageLike } from "./context-messages.ts";
|
|
11
|
+
} from "./config/config.ts";
|
|
12
|
+
export type { ConfigSettingsHelpers, ConfigSettingsOptions } from "./config/config-settings.ts";
|
|
13
|
+
export { registerConfigSettings } from "./config/config-settings.ts";
|
|
14
|
+
export type { ContextMessageLike } from "./context/context-messages.ts";
|
|
15
15
|
export {
|
|
16
16
|
findLastUserMessageIndex,
|
|
17
17
|
getContextToken,
|
|
18
18
|
getPromptContent,
|
|
19
19
|
pruneAndReorderContextMessages,
|
|
20
20
|
restorePromptContent,
|
|
21
|
-
} from "./context-messages.ts";
|
|
22
|
-
export type { ContextProvider } from "./context-provider-registry.ts";
|
|
21
|
+
} from "./context/context-messages.ts";
|
|
22
|
+
export type { ContextProvider } from "./context/context-provider-registry.ts";
|
|
23
23
|
export {
|
|
24
24
|
clearRegisteredContextProviders,
|
|
25
25
|
getRegisteredContextProviders,
|
|
26
26
|
registerContextProvider,
|
|
27
|
-
} from "./context-provider-registry.ts";
|
|
28
|
-
export { wrapExtensionContext } from "./context-tag.ts";
|
|
27
|
+
} from "./context/context-provider-registry.ts";
|
|
28
|
+
export { wrapExtensionContext } from "./context/context-tag.ts";
|
|
29
29
|
export type {
|
|
30
30
|
DebugAgentAccess,
|
|
31
31
|
DebugEvent,
|
|
@@ -49,6 +49,7 @@ export {
|
|
|
49
49
|
redactDebugData,
|
|
50
50
|
resetDebugRegistry,
|
|
51
51
|
} from "./debug-registry.ts";
|
|
52
|
+
export { fileToUri, resolveToolPath, stripToolPathPrefix, uriToFile } from "./path-utils.ts";
|
|
52
53
|
export type { KnownRootEntry } from "./project-roots.ts";
|
|
53
54
|
export {
|
|
54
55
|
buildKnownRootsMap,
|
|
@@ -63,15 +64,16 @@ export {
|
|
|
63
64
|
sortRootsBySpecificity,
|
|
64
65
|
walkProject,
|
|
65
66
|
} from "./project-roots.ts";
|
|
67
|
+
export { createRegistry, createSessionStateRegistry } from "./registry-utils.ts";
|
|
66
68
|
export { getActiveBranchEntries } from "./session-utils.ts";
|
|
67
|
-
export { registerSettingsCommand } from "./settings-command.ts";
|
|
68
|
-
export type { SettingsScope, SettingsSection } from "./settings-registry.ts";
|
|
69
|
+
export { registerSettingsCommand } from "./settings/settings-command.ts";
|
|
70
|
+
export type { SettingsScope, SettingsSection } from "./settings/settings-registry.ts";
|
|
69
71
|
export {
|
|
70
72
|
clearRegisteredSettings,
|
|
71
73
|
getRegisteredSettings,
|
|
72
74
|
registerSettings,
|
|
73
|
-
} from "./settings-registry.ts";
|
|
74
|
-
export { createInputSubmenu, openSettingsOverlay } from "./settings-ui.ts";
|
|
75
|
+
} from "./settings/settings-registry.ts";
|
|
76
|
+
export { createInputSubmenu, openSettingsOverlay } from "./settings/settings-ui.ts";
|
|
75
77
|
export type { TitleTarget } from "./terminal.ts";
|
|
76
78
|
export {
|
|
77
79
|
DONE_SYMBOL,
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import * as path from "node:path";
|
|
2
|
+
|
|
3
|
+
/** Strip pi's optional leading `@` file-path prefix from a tool input. */
|
|
4
|
+
export function stripToolPathPrefix(target: string): string {
|
|
5
|
+
return target.startsWith("@") ? target.slice(1) : target;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Resolve a tool-style file path from a session cwd.
|
|
10
|
+
*
|
|
11
|
+
* Built-in pi file tools accept a leading `@` prefix in path arguments, so
|
|
12
|
+
* shared SuPi path helpers normalize that prefix before resolving relative
|
|
13
|
+
* paths.
|
|
14
|
+
*/
|
|
15
|
+
export function resolveToolPath(cwd: string, target: string): string {
|
|
16
|
+
return path.resolve(cwd, stripToolPathPrefix(target));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** Convert a file path to a file:// URI. */
|
|
20
|
+
export function fileToUri(filePath: string): string {
|
|
21
|
+
const resolved = path.resolve(filePath);
|
|
22
|
+
if (process.platform === "win32") {
|
|
23
|
+
return `file:///${resolved.replace(/\\/g, "/")}`;
|
|
24
|
+
}
|
|
25
|
+
return `file://${resolved}`;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Convert a file:// URI to a file path. */
|
|
29
|
+
export function uriToFile(uri: string): string {
|
|
30
|
+
if (!uri.startsWith("file://")) return uri;
|
|
31
|
+
let filePath = decodeURIComponent(uri.slice(7));
|
|
32
|
+
if (
|
|
33
|
+
process.platform === "win32" &&
|
|
34
|
+
filePath.startsWith("/") &&
|
|
35
|
+
/^[A-Za-z]:/.test(filePath.slice(1))
|
|
36
|
+
) {
|
|
37
|
+
filePath = filePath.slice(1);
|
|
38
|
+
}
|
|
39
|
+
return filePath;
|
|
40
|
+
}
|
|
@@ -5,8 +5,20 @@
|
|
|
5
5
|
// Without this, each symlink path gets its own module copy and its own Map,
|
|
6
6
|
// so registrations from one instance are invisible to consumers in another.
|
|
7
7
|
|
|
8
|
+
import * as path from "node:path";
|
|
9
|
+
|
|
8
10
|
const SYMBOL_PREFIX = "@mrclrchtr/supi-core/";
|
|
9
11
|
|
|
12
|
+
function getGlobalRegistryMap<T>(name: string): Map<string, T> {
|
|
13
|
+
const key = Symbol.for(SYMBOL_PREFIX + name);
|
|
14
|
+
let map = (globalThis as Record<symbol, unknown>)[key] as Map<string, T> | undefined;
|
|
15
|
+
if (!map) {
|
|
16
|
+
map = new Map<string, T>();
|
|
17
|
+
(globalThis as Record<symbol, unknown>)[key] = map;
|
|
18
|
+
}
|
|
19
|
+
return map;
|
|
20
|
+
}
|
|
21
|
+
|
|
10
22
|
/**
|
|
11
23
|
* Create a named registry backed by `globalThis` + `Symbol.for`.
|
|
12
24
|
*
|
|
@@ -18,16 +30,7 @@ const SYMBOL_PREFIX = "@mrclrchtr/supi-core/";
|
|
|
18
30
|
* @returns An object with `register`, `getAll`, and `clear` functions.
|
|
19
31
|
*/
|
|
20
32
|
export function createRegistry<T>(name: string) {
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
const getMap = (): Map<string, T> => {
|
|
24
|
-
let map = (globalThis as Record<symbol, unknown>)[key] as Map<string, T> | undefined;
|
|
25
|
-
if (!map) {
|
|
26
|
-
map = new Map<string, T>();
|
|
27
|
-
(globalThis as Record<symbol, unknown>)[key] = map;
|
|
28
|
-
}
|
|
29
|
-
return map;
|
|
30
|
-
};
|
|
33
|
+
const getMap = (): Map<string, T> => getGlobalRegistryMap<T>(name);
|
|
31
34
|
|
|
32
35
|
return {
|
|
33
36
|
/**
|
|
@@ -52,3 +55,32 @@ export function createRegistry<T>(name: string) {
|
|
|
52
55
|
},
|
|
53
56
|
};
|
|
54
57
|
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Create a named session-state registry keyed by normalized cwd.
|
|
61
|
+
*
|
|
62
|
+
* This helper is intended for session-scoped runtime services that should be
|
|
63
|
+
* shared across duplicate jiti module instances while keeping package-specific
|
|
64
|
+
* state unions and convenience wrappers local to the calling package.
|
|
65
|
+
*/
|
|
66
|
+
export function createSessionStateRegistry<TState>(name: string) {
|
|
67
|
+
const getMap = (): Map<string, TState> => getGlobalRegistryMap<TState>(name);
|
|
68
|
+
const normalizeCwd = (cwd: string): string => path.resolve(cwd);
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
/** Get the current state for one session cwd. */
|
|
72
|
+
get: (cwd: string): TState | undefined => {
|
|
73
|
+
return getMap().get(normalizeCwd(cwd));
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
/** Store the current state for one session cwd. */
|
|
77
|
+
set: (cwd: string, state: TState): void => {
|
|
78
|
+
getMap().set(normalizeCwd(cwd), state);
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
/** Clear the current state for one session cwd. */
|
|
82
|
+
clear: (cwd: string): void => {
|
|
83
|
+
getMap().delete(normalizeCwd(cwd));
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
}
|
package/node_modules/@mrclrchtr/supi-core/src/{settings-registry.ts → settings/settings-registry.ts}
RENAMED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// factory function. The generic settings UI reads them via `getRegisteredSettings()`.
|
|
5
5
|
|
|
6
6
|
import type { SettingItem } from "@earendil-works/pi-tui";
|
|
7
|
-
import { createRegistry } from "
|
|
7
|
+
import { createRegistry } from "../registry-utils.ts";
|
|
8
8
|
|
|
9
9
|
export type SettingsScope = "project" | "global";
|
|
10
10
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mrclrchtr/supi-cache",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "SuPi Cache — prompt cache health monitoring and cross-session forensics",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"README.md"
|
|
21
21
|
],
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@mrclrchtr/supi-core": "1.
|
|
23
|
+
"@mrclrchtr/supi-core": "1.5.0"
|
|
24
24
|
},
|
|
25
25
|
"bundledDependencies": [
|
|
26
26
|
"@mrclrchtr/supi-core"
|
package/src/monitor/monitor.ts
CHANGED
|
@@ -14,6 +14,7 @@ import { stripHumanDetail } from "../forensics/redact.ts";
|
|
|
14
14
|
import { formatForensicsReport } from "../report/forensics.ts";
|
|
15
15
|
import { type CacheReportSnapshot, formatCacheReport } from "../report/history.ts";
|
|
16
16
|
import { registerCacheMonitorSettings } from "../settings-registration.ts";
|
|
17
|
+
import { promptGuidelines, promptSnippet, toolDescription } from "../tool/guidance.ts";
|
|
17
18
|
import { CacheMonitorState, type RegressionResult } from "./state.ts";
|
|
18
19
|
import { formatCacheStatus } from "./status.ts";
|
|
19
20
|
|
|
@@ -226,11 +227,8 @@ export default function cacheMonitorExtension(pi: ExtensionAPI) {
|
|
|
226
227
|
pi.registerTool({
|
|
227
228
|
name: "supi_cache_forensics",
|
|
228
229
|
label: "Cache Forensics",
|
|
229
|
-
description:
|
|
230
|
-
|
|
231
|
-
"Provides four query patterns: hotspots (worst drops), breakdown (cause tally), " +
|
|
232
|
-
"correlate (tools before regressions), and idle (long-gap regressions). " +
|
|
233
|
-
'Example: {"pattern": "hotspots", "since": "7d", "minDrop": 20}',
|
|
230
|
+
description: toolDescription,
|
|
231
|
+
promptSnippet,
|
|
234
232
|
parameters: Type.Object({
|
|
235
233
|
pattern: StringEnum(["hotspots", "breakdown", "correlate", "idle"], {
|
|
236
234
|
description: "Query pattern",
|
|
@@ -254,14 +252,7 @@ export default function cacheMonitorExtension(pi: ExtensionAPI) {
|
|
|
254
252
|
}),
|
|
255
253
|
),
|
|
256
254
|
}),
|
|
257
|
-
promptGuidelines
|
|
258
|
-
"Use `supi_cache_forensics` when the user asks about cache performance patterns, suspects idle-time cache expiry, or wants to understand what preceded a cache drop.",
|
|
259
|
-
"Prefer `pattern: 'breakdown'` for a quick overview of regression causes.",
|
|
260
|
-
"Use `pattern: 'hotspots'` with `minDrop: 20` or higher to surface the worst regressions.",
|
|
261
|
-
"Use `pattern: 'idle'` to detect cache drops caused by long gaps between turns.",
|
|
262
|
-
"Use `pattern: 'correlate'` to see which tool calls preceded regressions.",
|
|
263
|
-
"The tool returns shape fingerprints (param types and lengths), not raw file paths or command text.",
|
|
264
|
-
],
|
|
255
|
+
promptGuidelines,
|
|
265
256
|
// biome-ignore lint/complexity/useMaxParams: pi tool execute signature
|
|
266
257
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
267
258
|
const config = loadCacheMonitorConfig(ctx.cwd);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// Prompt guidance and tool description for the supi_cache_forensics tool.
|
|
2
|
+
|
|
3
|
+
export const toolDescription =
|
|
4
|
+
'Investigate prompt cache regressions across historical PI sessions. Query patterns: hotspots (worst drops), breakdown (cause tally), correlate (tools before regressions), and idle (long-gap regressions). Results redact raw file paths and command text into shape fingerprints. Example: {"pattern": "hotspots", "since": "7d", "minDrop": 20}';
|
|
5
|
+
|
|
6
|
+
export const promptSnippet =
|
|
7
|
+
"supi_cache_forensics — investigate historical prompt cache regressions, causes, idle drops, and preceding tool activity";
|
|
8
|
+
|
|
9
|
+
export const promptGuidelines = [
|
|
10
|
+
"Use supi_cache_forensics when the user asks about cache performance patterns, suspects idle-time cache expiry, or wants to understand what preceded a cache drop.",
|
|
11
|
+
'Use supi_cache_forensics with `pattern: "breakdown"` for a quick overview of regression causes.',
|
|
12
|
+
'Use supi_cache_forensics with `pattern: "hotspots"` and `minDrop: 20` or higher to surface the worst regressions.',
|
|
13
|
+
'Use supi_cache_forensics with `pattern: "idle"` to detect cache drops caused by long gaps between turns.',
|
|
14
|
+
'Use supi_cache_forensics with `pattern: "correlate"` to see which tool-call shapes preceded regressions.',
|
|
15
|
+
"supi_cache_forensics returns shape fingerprints and parameter summaries, not raw file paths or command text.",
|
|
16
|
+
];
|
|
File without changes
|
/package/node_modules/@mrclrchtr/supi-core/src/{context-messages.ts → context/context-messages.ts}
RENAMED
|
File without changes
|
|
File without changes
|
/package/node_modules/@mrclrchtr/supi-core/src/{settings-command.ts → settings/settings-command.ts}
RENAMED
|
File without changes
|
|
File without changes
|