pi-must-have-extension 0.4.0 → 0.4.3
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 +18 -0
- package/README.md +125 -59
- package/package.json +1 -1
- package/src/config/config-loader.ts +27 -7
- package/src/index.ts +6 -0
- package/src/types.ts +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.4.3] - 2026-03-04
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
- Use GitHub-compatible video embed format (thumbnail image linking to user-attachments video URL)
|
|
7
|
+
|
|
8
|
+
## [0.4.2] - 2026-03-04
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
- Restored missing asset references in README (demo.mp4 video and pi-must-have-extension.png image)
|
|
12
|
+
|
|
13
|
+
## [0.4.1] - 2026-03-04
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
- Rewrote README.md with professional documentation standards
|
|
17
|
+
- Added comprehensive feature documentation, configuration reference, and usage examples
|
|
18
|
+
- Improved legacy config path detection with centralized lookup
|
|
19
|
+
- Added migration source tracking to config loader feedback
|
|
20
|
+
|
|
3
21
|
## 0.4.0 - 2026-03-02
|
|
4
22
|
|
|
5
23
|
- Renamed package identity from `pi-must-have-plugin` to `pi-must-have-extension`.
|
package/README.md
CHANGED
|
@@ -1,111 +1,177 @@
|
|
|
1
1
|
# pi-must-have-extension
|
|
2
2
|
|
|
3
|
-
Normalize RFC 2119 language in Pi prompts by automatically rewriting lowercase modal terms (
|
|
3
|
+
Normalize RFC 2119 language in Pi prompts by automatically rewriting lowercase modal terms (`must`, `should not`, `optional`) into uppercase normative forms (`MUST`, `SHOULD NOT`, `OPTIONAL`).
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
This extension originated from the OpenCode plugin project: [ariane-emory/MUST-have-plugin](https://github.com/ariane-emory/MUST-have-plugin).
|
|
8
|
-
|
|
9
|
-
`pi-must-have-extension` is a Pi-harness adaptation of that original project, converted into a modular TypeScript Pi extension.
|
|
10
|
-
|
|
11
|
-
## Preview
|
|
5
|
+

|
|
12
6
|
|
|
13
|
-
|
|
7
|
+
## Demo
|
|
14
8
|
|
|
15
9
|
[](https://github.com/user-attachments/assets/22149125-8976-4d06-98cb-e7cfa180476d)
|
|
16
10
|
|
|
17
|
-
> npmjs.com README rendering does not reliably support inline `<video>` playback. Use the thumbnail above to play the demo video.
|
|
18
|
-
|
|
19
|
-
Direct links:
|
|
20
|
-
- Demo video (GitHub attachment): https://github.com/user-attachments/assets/22149125-8976-4d06-98cb-e7cfa180476d
|
|
21
|
-
- Demo video file: https://raw.githubusercontent.com/MasuRii/pi-must-have-extension/main/asset/demo.mp4
|
|
22
|
-
|
|
23
11
|
## Features
|
|
24
12
|
|
|
25
|
-
-
|
|
26
|
-
- Case-insensitive
|
|
27
|
-
- Word-boundary
|
|
28
|
-
-
|
|
29
|
-
-
|
|
30
|
-
-
|
|
31
|
-
-
|
|
13
|
+
- **RFC 2119/8174 compliance** — Transforms modal keywords to standard uppercase notation
|
|
14
|
+
- **Intelligent matching** — Case-insensitive with longest-first phrase replacement
|
|
15
|
+
- **Word-boundary aware** — Does not replace keywords embedded inside larger words
|
|
16
|
+
- **Configurable replacements** — Customize or extend the default keyword mappings
|
|
17
|
+
- **Input filtering** — Leaves slash commands (`/`) and shell input (`!`) unchanged
|
|
18
|
+
- **Auto-configuration** — Creates a default config file when none exists
|
|
19
|
+
- **Legacy migration** — Automatically migrates configs from previous plugin versions
|
|
20
|
+
- **Debug mode** — Optional TUI notifications showing replacement counts
|
|
32
21
|
|
|
33
22
|
## Installation
|
|
34
23
|
|
|
35
|
-
### Local
|
|
24
|
+
### Local Extension Folder
|
|
36
25
|
|
|
37
|
-
Copy this repository to:
|
|
26
|
+
Copy this repository to one of the following locations:
|
|
38
27
|
|
|
39
|
-
|
|
40
|
-
|
|
28
|
+
```text
|
|
29
|
+
~/.pi/agent/extensions/pi-must-have-extension # Global (all projects)
|
|
30
|
+
.pi/extensions/pi-must-have-extension # Project-specific
|
|
31
|
+
```
|
|
41
32
|
|
|
42
|
-
Pi will auto-discover
|
|
33
|
+
Pi will auto-discover the extension on startup.
|
|
43
34
|
|
|
44
|
-
### NPM
|
|
35
|
+
### NPM Package
|
|
45
36
|
|
|
46
37
|
```bash
|
|
47
38
|
pi install npm:pi-must-have-extension
|
|
48
39
|
```
|
|
49
40
|
|
|
50
|
-
##
|
|
41
|
+
## Usage
|
|
51
42
|
|
|
52
|
-
|
|
43
|
+
Once installed, the extension works automatically. When you type prompts containing RFC 2119 keywords:
|
|
53
44
|
|
|
45
|
+
**Input:**
|
|
54
46
|
```text
|
|
55
|
-
|
|
47
|
+
The function must validate input and should log errors.
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
**Transformed to:**
|
|
51
|
+
```text
|
|
52
|
+
The function MUST validate input and SHOULD log errors.
|
|
56
53
|
```
|
|
57
54
|
|
|
58
|
-
|
|
55
|
+
### Skipped Input
|
|
56
|
+
|
|
57
|
+
The extension does not transform:
|
|
58
|
+
|
|
59
|
+
- Slash commands (e.g., `/help`, `/reload`)
|
|
60
|
+
- Shell commands (e.g., `!ls`, `!git status`)
|
|
61
|
+
- Empty input
|
|
62
|
+
|
|
63
|
+
## Configuration
|
|
64
|
+
|
|
65
|
+
The extension uses a JSONC configuration file (JSON with comments):
|
|
59
66
|
|
|
60
67
|
```text
|
|
61
|
-
~/.pi/agent/extensions/pi-must-have-
|
|
62
|
-
~/.pi/agent/extensions/must-have-plugin/config.jsonc
|
|
63
|
-
~/.config/opencode/MUST-have-plugin.jsonc
|
|
68
|
+
~/.pi/agent/extensions/pi-must-have-extension/config.jsonc
|
|
64
69
|
```
|
|
65
70
|
|
|
66
|
-
|
|
71
|
+
### Default Configuration
|
|
67
72
|
|
|
68
73
|
```jsonc
|
|
69
74
|
{
|
|
70
|
-
|
|
75
|
+
// Enable debug notifications in the TUI
|
|
76
|
+
// "debug": true,
|
|
77
|
+
|
|
71
78
|
"replacements": {
|
|
72
79
|
"must": "MUST",
|
|
73
80
|
"must not": "MUST NOT",
|
|
74
|
-
"
|
|
81
|
+
"required": "REQUIRED",
|
|
82
|
+
"shall": "SHALL",
|
|
83
|
+
"shall not": "SHALL NOT",
|
|
84
|
+
"should": "SHOULD",
|
|
85
|
+
"should not": "SHOULD NOT",
|
|
86
|
+
"recommended": "RECOMMENDED",
|
|
87
|
+
"not recommended": "NOT RECOMMENDED",
|
|
88
|
+
"may": "MAY",
|
|
89
|
+
"optional": "OPTIONAL"
|
|
75
90
|
}
|
|
76
91
|
}
|
|
77
92
|
```
|
|
78
93
|
|
|
79
|
-
|
|
94
|
+
### Configuration Options
|
|
95
|
+
|
|
96
|
+
| Option | Type | Default | Description |
|
|
97
|
+
|--------|------|---------|-------------|
|
|
98
|
+
| `debug` | `boolean` | `false` | Enable TUI notifications showing replacement counts |
|
|
99
|
+
| `replacements` | `object` | RFC 2119 defaults | Key-value map of terms to replace |
|
|
100
|
+
|
|
101
|
+
### Custom Replacements
|
|
102
|
+
|
|
103
|
+
You can add custom replacement rules or modify existing ones:
|
|
104
|
+
|
|
105
|
+
```jsonc
|
|
106
|
+
{
|
|
107
|
+
"replacements": {
|
|
108
|
+
// Standard RFC 2119
|
|
109
|
+
"must": "MUST",
|
|
110
|
+
"should": "SHOULD",
|
|
111
|
+
|
|
112
|
+
// Custom shortcuts
|
|
113
|
+
"rfc!": "The key words in this document are to be interpreted as described in RFC 2119.\n\n",
|
|
114
|
+
"always": "**ALWAYS**",
|
|
115
|
+
"never": "**NEVER**"
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
An advanced replacement sample is included at `config/replacements.custom-sample.jsonc`.
|
|
121
|
+
|
|
122
|
+
### Legacy Config Paths
|
|
123
|
+
|
|
124
|
+
The extension supports migration from previous versions. Legacy configs are read from:
|
|
80
125
|
|
|
81
126
|
```text
|
|
82
|
-
|
|
127
|
+
~/.pi/agent/extensions/pi-must-have-plugin/config.jsonc
|
|
128
|
+
~/.pi/agent/extensions/must-have-plugin/config.jsonc
|
|
129
|
+
~/.config/opencode/MUST-have-plugin.jsonc
|
|
83
130
|
```
|
|
84
131
|
|
|
85
|
-
|
|
132
|
+
On first run, legacy configs are automatically migrated to the new location.
|
|
133
|
+
|
|
134
|
+
## Technical Details
|
|
135
|
+
|
|
136
|
+
### How It Works
|
|
137
|
+
|
|
138
|
+
1. **Session start**: Ensures config exists (creates default or migrates legacy)
|
|
139
|
+
2. **Input event**: Intercepts user prompts before sending to the agent
|
|
140
|
+
3. **Pattern matching**: Uses regex with word boundaries and longest-match-first ordering
|
|
141
|
+
4. **Transformation**: Returns modified text while preserving images and other input data
|
|
86
142
|
|
|
87
|
-
|
|
143
|
+
### Project Structure
|
|
144
|
+
|
|
145
|
+
```text
|
|
146
|
+
├── index.ts # Pi extension entrypoint
|
|
147
|
+
├── src/
|
|
148
|
+
│ ├── index.ts # Extension event wiring
|
|
149
|
+
│ ├── constants.ts # Paths, defaults, and extension name
|
|
150
|
+
│ ├── types.ts # TypeScript interfaces
|
|
151
|
+
│ ├── config/
|
|
152
|
+
│ │ ├── config-loader.ts # Config loading and migration
|
|
153
|
+
│ │ └── jsonc.ts # JSONC parser (strips comments)
|
|
154
|
+
│ └── replacements/
|
|
155
|
+
│ └── replacement-engine.ts # Core replacement logic
|
|
156
|
+
├── config/
|
|
157
|
+
│ ├── config.example.jsonc # Starter template
|
|
158
|
+
│ └── replacements.custom-sample.jsonc # Advanced samples
|
|
159
|
+
└── test/
|
|
160
|
+
└── replacement-engine.test.ts # Unit tests
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Development
|
|
88
164
|
|
|
89
165
|
```bash
|
|
90
|
-
npm install
|
|
91
|
-
npm run build
|
|
92
|
-
npm run
|
|
93
|
-
npm run test
|
|
94
|
-
npm run check
|
|
166
|
+
npm install # Install dependencies
|
|
167
|
+
npm run build # Type-check with TypeScript
|
|
168
|
+
npm run test # Run test suite
|
|
169
|
+
npm run check # Build + test
|
|
95
170
|
```
|
|
96
171
|
|
|
97
|
-
##
|
|
98
|
-
|
|
99
|
-
-
|
|
100
|
-
- `src/index.ts` - extension event wiring.
|
|
101
|
-
- `src/config/` - config loading and JSONC parsing.
|
|
102
|
-
- `src/replacements/` - replacement and input-skip engine.
|
|
103
|
-
- `src/constants.ts` - extension constants and defaults.
|
|
104
|
-
- `src/types.ts` - shared types.
|
|
105
|
-
- `test/` - Node test suite.
|
|
106
|
-
- `config/config.example.jsonc` - starter config template.
|
|
107
|
-
- `config/replacements.custom-sample.jsonc` - advanced custom replacement sample.
|
|
108
|
-
- `asset/` - README media (overview image and demo video).
|
|
172
|
+
## Origin
|
|
173
|
+
|
|
174
|
+
This extension is a Pi-harness adaptation of [ariane-emory/MUST-have-plugin](https://github.com/ariane-emory/MUST-have-plugin), converted into a modular TypeScript Pi extension.
|
|
109
175
|
|
|
110
176
|
## License
|
|
111
177
|
|
package/package.json
CHANGED
|
@@ -52,24 +52,44 @@ function parseConfigFromPath(path: string): Omit<ConfigLoadResult, "source"> {
|
|
|
52
52
|
};
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
+
const LEGACY_CONFIG_PATHS: readonly string[] = [
|
|
56
|
+
LEGACY_PI_MUST_HAVE_PLUGIN_CONFIG_PATH,
|
|
57
|
+
LEGACY_MUST_HAVE_PLUGIN_CONFIG_PATH,
|
|
58
|
+
LEGACY_OPENCODE_CONFIG_PATH,
|
|
59
|
+
];
|
|
60
|
+
|
|
61
|
+
function findLegacyConfigPath(): string | undefined {
|
|
62
|
+
for (const path of LEGACY_CONFIG_PATHS) {
|
|
63
|
+
if (existsSync(path)) {
|
|
64
|
+
return path;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return undefined;
|
|
69
|
+
}
|
|
70
|
+
|
|
55
71
|
export function ensureConfigExists(): EnsureConfigResult {
|
|
56
|
-
if (
|
|
57
|
-
existsSync(CONFIG_PATH) ||
|
|
58
|
-
existsSync(LEGACY_PI_MUST_HAVE_PLUGIN_CONFIG_PATH) ||
|
|
59
|
-
existsSync(LEGACY_MUST_HAVE_PLUGIN_CONFIG_PATH) ||
|
|
60
|
-
existsSync(LEGACY_OPENCODE_CONFIG_PATH)
|
|
61
|
-
) {
|
|
72
|
+
if (existsSync(CONFIG_PATH)) {
|
|
62
73
|
return { created: false };
|
|
63
74
|
}
|
|
64
75
|
|
|
76
|
+
const legacyPath = findLegacyConfigPath();
|
|
77
|
+
|
|
65
78
|
try {
|
|
66
79
|
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
80
|
+
|
|
81
|
+
if (legacyPath) {
|
|
82
|
+
const legacyContent = readFileSync(legacyPath, "utf-8");
|
|
83
|
+
writeFileSync(CONFIG_PATH, legacyContent, "utf-8");
|
|
84
|
+
return { created: true, migratedFrom: legacyPath };
|
|
85
|
+
}
|
|
86
|
+
|
|
67
87
|
writeFileSync(CONFIG_PATH, DEFAULT_CONFIG, "utf-8");
|
|
68
88
|
return { created: true };
|
|
69
89
|
} catch (error) {
|
|
70
90
|
return {
|
|
71
91
|
created: false,
|
|
72
|
-
error: `Failed to
|
|
92
|
+
error: `Failed to initialize config at ${CONFIG_PATH}: ${error instanceof Error ? error.message : String(error)}`,
|
|
73
93
|
};
|
|
74
94
|
}
|
|
75
95
|
}
|
package/src/index.ts
CHANGED
|
@@ -49,6 +49,12 @@ export default function mustHaveExtension(pi: ExtensionAPI): void {
|
|
|
49
49
|
if (ensureResult.error) {
|
|
50
50
|
warnOnce(ensureResult.error, ctx);
|
|
51
51
|
}
|
|
52
|
+
if (ensureResult.migratedFrom) {
|
|
53
|
+
warnOnce(
|
|
54
|
+
`${EXTENSION_NAME}: migrated legacy config from ${ensureResult.migratedFrom} to ${CONFIG_PATH}.`,
|
|
55
|
+
ctx,
|
|
56
|
+
);
|
|
57
|
+
}
|
|
52
58
|
|
|
53
59
|
const loaded = loadConfig();
|
|
54
60
|
if (loaded.warning) {
|