pi-skill-shiori 0.6.10 → 0.6.12
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 +13 -0
- package/README.md +4 -4
- package/package.json +4 -4
- package/src/retrieval-expanded.ts +8 -4
- package/src/retrieval.ts +49 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## [0.6.12] - 2026-09-30
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
|
|
9
|
+
- Update `@earendil-works/pi-*` dependencies to `0.99.1`.
|
|
10
|
+
|
|
11
|
+
## [0.6.11] - 2026-09-21
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- Rank curated trigger matches ahead of heuristic description matches when enforcing candidate limits. Derived single-token query variants can score a perfect `1.00` from substring matches while trigger matches are fixed at `0.95`, so a genuine trigger match could be dropped by the candidate cap. The same ordering now applies at both cap sites, because the per-variant cap runs before expanded retrieval merges variants and a match dropped there can never be restored.
|
|
16
|
+
- Apply the original query's `exclude` triggers across merged variants in expanded retrieval. A derived single-token variant could drop the context that made an exclude match (`do not use auth` becomes `auth`), which reintroduced an excluded skill.
|
|
17
|
+
|
|
5
18
|
## [0.6.10] - 2026-09-21
|
|
6
19
|
|
|
7
20
|
### Fixed
|
package/README.md
CHANGED
|
@@ -19,7 +19,7 @@ For maintenance priorities and the phased plan, see [`ROADMAP.md`](ROADMAP.md).
|
|
|
19
19
|
|
|
20
20
|
Pi Skill Shiori is a [Pi](https://pi.dev/) package for vaults or projects with many Agent Skills where the default catalog becomes noisy and expensive. It hides the normal skill catalog when safe, recommends triggerable skills with compact summaries, and loads full `SKILL.md` bodies on demand.
|
|
21
21
|
|
|
22
|
-
`0.6.
|
|
22
|
+
`0.6.12` is the current working release. Prompt-boundary suppression is intentionally conservative: if Shiori cannot safely recognize a catalog boundary, it leaves the prompt untouched and warns instead of deleting too much.
|
|
23
23
|
|
|
24
24
|
## Features
|
|
25
25
|
|
|
@@ -37,7 +37,7 @@ Pi Skill Shiori is a [Pi](https://pi.dev/) package for vaults or projects with m
|
|
|
37
37
|
### Global install from npm
|
|
38
38
|
|
|
39
39
|
```bash
|
|
40
|
-
pi install npm:pi-skill-shiori@0.6.
|
|
40
|
+
pi install npm:pi-skill-shiori@0.6.12
|
|
41
41
|
```
|
|
42
42
|
|
|
43
43
|
Without a version pin:
|
|
@@ -49,7 +49,7 @@ pi install npm:pi-skill-shiori
|
|
|
49
49
|
### Project-local install from npm
|
|
50
50
|
|
|
51
51
|
```bash
|
|
52
|
-
pi install -l npm:pi-skill-shiori@0.6.
|
|
52
|
+
pi install -l npm:pi-skill-shiori@0.6.12
|
|
53
53
|
```
|
|
54
54
|
|
|
55
55
|
Without a version pin:
|
|
@@ -61,7 +61,7 @@ pi install -l npm:pi-skill-shiori
|
|
|
61
61
|
### Install from GitHub
|
|
62
62
|
|
|
63
63
|
```bash
|
|
64
|
-
pi install git:github.com/eiei114/pi-skill-shiori@v0.6.
|
|
64
|
+
pi install git:github.com/eiei114/pi-skill-shiori@v0.6.12
|
|
65
65
|
pi install -l git:github.com/eiei114/pi-skill-shiori
|
|
66
66
|
```
|
|
67
67
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-skill-shiori",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.12",
|
|
4
4
|
"description": "Pi extension that reduces Agent Skill catalog tokens with policy-based skill retrieval and on-demand skill loading.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -54,9 +54,9 @@
|
|
|
54
54
|
"typebox": "*"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
|
-
"@earendil-works/pi-ai": "^0.
|
|
58
|
-
"@earendil-works/pi-coding-agent": "^0.
|
|
59
|
-
"@earendil-works/pi-tui": "^0.
|
|
57
|
+
"@earendil-works/pi-ai": "^0.99.1",
|
|
58
|
+
"@earendil-works/pi-coding-agent": "^0.99.1",
|
|
59
|
+
"@earendil-works/pi-tui": "^0.99.1",
|
|
60
60
|
"@types/node": "^26.0.0",
|
|
61
61
|
"tsx": "^4.22.4",
|
|
62
62
|
"typebox": "latest",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { buildRetrievalQueries } from "./query.js";
|
|
2
|
-
import { retrieveCandidates } from "./retrieval.js";
|
|
2
|
+
import { compareCandidates, excludedSkillNames, retrieveCandidates } from "./retrieval.js";
|
|
3
3
|
import type { ShioriPolicy, SkillCandidate, SkillRecord } from "./types.js";
|
|
4
4
|
|
|
5
5
|
interface RetrievalIndex {
|
|
@@ -14,17 +14,21 @@ export function retrieveCandidatesExpanded(
|
|
|
14
14
|
): SkillCandidate[] {
|
|
15
15
|
const byName = new Map<string, SkillCandidate>();
|
|
16
16
|
const max = policy.candidateInjection.maxCandidates;
|
|
17
|
+
// Apply the original query's excludes across the merged set. A derived
|
|
18
|
+
// single-token variant can drop the context that made an exclude match
|
|
19
|
+
// ("do not use auth" becomes "auth"), which would otherwise let an excluded
|
|
20
|
+
// skill back in once variants are merged.
|
|
21
|
+
const excluded = excludedSkillNames(query, skills, policy);
|
|
17
22
|
|
|
18
23
|
for (const variant of buildRetrievalQueries(query)) {
|
|
19
24
|
for (const candidate of retrieveCandidates(variant, skills, policy, index)) {
|
|
25
|
+
if (excluded.has(candidate.skill.name)) continue;
|
|
20
26
|
const previous = byName.get(candidate.skill.name);
|
|
21
27
|
byName.set(candidate.skill.name, preferExpandedCandidate(previous, candidate));
|
|
22
28
|
}
|
|
23
29
|
}
|
|
24
30
|
|
|
25
|
-
return [...byName.values()]
|
|
26
|
-
.sort((a, b) => b.score - a.score || a.skill.name.localeCompare(b.skill.name))
|
|
27
|
-
.slice(0, max);
|
|
31
|
+
return [...byName.values()].sort(compareCandidates).slice(0, max);
|
|
28
32
|
}
|
|
29
33
|
|
|
30
34
|
/** Keep trigger badges when expanded query variants also score the description higher. */
|
package/src/retrieval.ts
CHANGED
|
@@ -34,10 +34,58 @@ export function retrieveCandidates(
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
return [...candidatesByName.values()]
|
|
37
|
-
.sort(
|
|
37
|
+
.sort(compareCandidates)
|
|
38
38
|
.slice(0, policy.candidateInjection.maxCandidates);
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
/**
|
|
42
|
+
* Order candidates so curated trigger matches rank ahead of heuristic
|
|
43
|
+
* description matches.
|
|
44
|
+
*
|
|
45
|
+
* Trigger matches carry a fixed score (0.95, see `evaluateSkill`), while
|
|
46
|
+
* description matches can reach a higher score from short query tokens that
|
|
47
|
+
* happen to appear as substrings — "is" in "history", "fix" in "prefix".
|
|
48
|
+
* Sorting by score alone therefore lets that noise push a genuine trigger match
|
|
49
|
+
* past a candidate cap, where it is dropped without a trace. A trigger is an
|
|
50
|
+
* explicit statement that the skill is relevant, so it outranks a heuristic
|
|
51
|
+
* substring match even when the heuristic scored higher.
|
|
52
|
+
*
|
|
53
|
+
* Every cap site must use this comparator: the per-variant cap inside
|
|
54
|
+
* `retrieveCandidates` runs before expanded retrieval merges variants, so a
|
|
55
|
+
* trigger match dropped there can never be restored downstream.
|
|
56
|
+
*/
|
|
57
|
+
export function compareCandidates(a: SkillCandidate, b: SkillCandidate): number {
|
|
58
|
+
const triggerDelta = Number(b.reason === "trigger") - Number(a.reason === "trigger");
|
|
59
|
+
if (triggerDelta !== 0) return triggerDelta;
|
|
60
|
+
return b.score - a.score || a.skill.name.localeCompare(b.skill.name);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Skill names the original query excludes via policy exclude triggers.
|
|
65
|
+
*
|
|
66
|
+
* `retrieveCandidates` evaluates excludes against whichever query string it
|
|
67
|
+
* receives. Expanded retrieval passes derived variants, and a derived variant can
|
|
68
|
+
* drop the surrounding context that made an exclude match ("do not use auth"
|
|
69
|
+
* becomes "auth"), so the exclusion no longer applies and the skill leaks back
|
|
70
|
+
* in. Callers that merge variants should apply the original query's excludes
|
|
71
|
+
* across the merged set.
|
|
72
|
+
*/
|
|
73
|
+
export function excludedSkillNames(
|
|
74
|
+
query: string,
|
|
75
|
+
skills: SkillRecord[],
|
|
76
|
+
policy: ShioriPolicy,
|
|
77
|
+
): Set<string> {
|
|
78
|
+
const normalizedQuery = normalize(query);
|
|
79
|
+
const excluded = new Set<string>();
|
|
80
|
+
for (const skill of skills) {
|
|
81
|
+
const excludes = policy.skills[skill.name]?.triggers?.exclude ?? [];
|
|
82
|
+
if (excludes.some((trigger) => includesNormalized(normalizedQuery, trigger))) {
|
|
83
|
+
excluded.add(skill.name);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return excluded;
|
|
87
|
+
}
|
|
88
|
+
|
|
41
89
|
function evaluateSkill(
|
|
42
90
|
skill: SkillRecord,
|
|
43
91
|
normalizedQuery: string,
|