pi-skill-shiori 0.4.0 → 0.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/CHANGELOG.md +14 -0
- package/README.md +41 -9
- package/package.json +1 -1
- package/src/discovery.ts +36 -3
- package/src/index.ts +32 -8
- package/src/inventory.ts +58 -0
- package/src/metrics.ts +2 -0
- package/src/policy.ts +11 -0
- package/src/types.ts +8 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,20 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
This project follows semantic versioning.
|
|
6
6
|
|
|
7
|
+
## [0.5.0] - 2026-06-28
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- Vault-wide skill inventory: Shiori indexes skills from project `.pi/skills`, `.agents/skills`, the user-global `~/.pi/agent/skills` root, and optional policy `inventory.roots`.
|
|
12
|
+
- Automatic inventory refresh when skill files change under any indexed root (enabled by default; disable with `inventory.autoRefreshOnChange: false`).
|
|
13
|
+
- `/shiori:doctor` now lists indexed roots with per-root skill counts and auto-refresh status.
|
|
14
|
+
- `/shiori:stats` counters for manual and automatic inventory refreshes.
|
|
15
|
+
- Tests for multi-root discovery, refresh after local changes, and policy-aware retrieval.
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
|
|
19
|
+
- `/shiori:reload` rebuilds the vault-wide inventory and SQLite FTS index instead of relying on the session-start snapshot only.
|
|
20
|
+
|
|
7
21
|
## [0.4.0] - 2026-06-28
|
|
8
22
|
|
|
9
23
|
### Added
|
package/README.md
CHANGED
|
@@ -12,12 +12,13 @@ For maintenance priorities and the phased plan, see [`ROADMAP.md`](ROADMAP.md).
|
|
|
12
12
|
- **Policy-based retrieval**: treats skills as explicit by default and only candidates skills marked as triggerable.
|
|
13
13
|
- **Compact candidate injection**: injects short skill suggestions instead of full `SKILL.md` files.
|
|
14
14
|
- **On-demand loading**: exposes `shiori_load_skill` so the model can load one selected skill body when needed.
|
|
15
|
+
- **Vault-wide skill inventory**: indexes skills from project and user-global roots, with optional extra roots in policy.
|
|
15
16
|
- **SQLite FTS retrieval**: indexes skill names, descriptions, and policy triggers with `node:sqlite` + FTS5, with token-match fallback.
|
|
16
17
|
- **Compact UI output**: keeps skill-load logs short while still passing full skill text to the model.
|
|
17
18
|
|
|
18
19
|
## Status
|
|
19
20
|
|
|
20
|
-
`0.
|
|
21
|
+
`0.5.0` is an early working release. It is useful for local Pi workflows, but the prompt-boundary suppression logic is intentionally conservative: if Shiori cannot safely recognize a catalog boundary, it leaves the prompt untouched and warns instead of deleting too much.
|
|
21
22
|
|
|
22
23
|
## Requirements
|
|
23
24
|
|
|
@@ -39,7 +40,7 @@ Pi core packages are peer dependencies and should be supplied by the Pi runtime:
|
|
|
39
40
|
After the package is published to npm:
|
|
40
41
|
|
|
41
42
|
```bash
|
|
42
|
-
pi install npm:pi-skill-shiori@0.
|
|
43
|
+
pi install npm:pi-skill-shiori@0.5.0
|
|
43
44
|
```
|
|
44
45
|
|
|
45
46
|
Without a version pin:
|
|
@@ -53,7 +54,7 @@ pi install npm:pi-skill-shiori
|
|
|
53
54
|
Use `-l` to write the package to the current project’s `.pi/settings.json`:
|
|
54
55
|
|
|
55
56
|
```bash
|
|
56
|
-
pi install -l npm:pi-skill-shiori@0.
|
|
57
|
+
pi install -l npm:pi-skill-shiori@0.5.0
|
|
57
58
|
```
|
|
58
59
|
|
|
59
60
|
Without a version pin:
|
|
@@ -67,7 +68,7 @@ Equivalent pinned manual `.pi/settings.json` entry:
|
|
|
67
68
|
```json
|
|
68
69
|
{
|
|
69
70
|
"packages": [
|
|
70
|
-
"npm:pi-skill-shiori@0.
|
|
71
|
+
"npm:pi-skill-shiori@0.5.0"
|
|
71
72
|
]
|
|
72
73
|
}
|
|
73
74
|
```
|
|
@@ -85,7 +86,7 @@ Equivalent unpinned manual `.pi/settings.json` entry:
|
|
|
85
86
|
### Global install from GitHub
|
|
86
87
|
|
|
87
88
|
```bash
|
|
88
|
-
pi install git:github.com/eiei114/pi-skill-shiori@v0.
|
|
89
|
+
pi install git:github.com/eiei114/pi-skill-shiori@v0.5.0
|
|
89
90
|
```
|
|
90
91
|
|
|
91
92
|
Without a tag pin:
|
|
@@ -97,7 +98,7 @@ pi install git:github.com/eiei114/pi-skill-shiori
|
|
|
97
98
|
### Project-local install from GitHub
|
|
98
99
|
|
|
99
100
|
```bash
|
|
100
|
-
pi install -l git:github.com/eiei114/pi-skill-shiori@v0.
|
|
101
|
+
pi install -l git:github.com/eiei114/pi-skill-shiori@v0.5.0
|
|
101
102
|
```
|
|
102
103
|
|
|
103
104
|
Without a tag pin:
|
|
@@ -131,7 +132,38 @@ Or add a relative local path to `.pi/settings.json`:
|
|
|
131
132
|
}
|
|
132
133
|
```
|
|
133
134
|
|
|
134
|
-
> Note: policy/index changes can be refreshed with `/shiori:reload`,
|
|
135
|
+
> Note: policy/index changes can be refreshed with `/shiori:reload`, and Shiori auto-refreshes the vault-wide inventory when skill files change under indexed roots. Extension code changes still require restarting the Pi process because Node keeps imported extension modules cached.
|
|
136
|
+
|
|
137
|
+
## Vault-wide skill inventory
|
|
138
|
+
|
|
139
|
+
Shiori builds a searchable inventory from these roots (in discovery order; first match wins on duplicate skill names):
|
|
140
|
+
|
|
141
|
+
| Root | Scope |
|
|
142
|
+
|---|---|
|
|
143
|
+
| `<cwd>/.pi/skills` | Project-local Pi skills |
|
|
144
|
+
| `<cwd>/.agents/skills` | Project-local Agent skills |
|
|
145
|
+
| `~/.pi/agent/skills` | User-global Pi agent skills |
|
|
146
|
+
| `inventory.roots` entries | Optional extra roots (relative to `<cwd>` or absolute) |
|
|
147
|
+
|
|
148
|
+
Refresh behavior:
|
|
149
|
+
|
|
150
|
+
- **Session start** builds the initial inventory and SQLite FTS index.
|
|
151
|
+
- **Auto-refresh** (default) rescans roots before retrieval when any `SKILL.md` path changes. This is a directory walk only; it rebuilds the FTS index when the fingerprint changes.
|
|
152
|
+
- **Manual refresh** via `/shiori:reload` always rebuilds the inventory and FTS index immediately.
|
|
153
|
+
- Disable auto-refresh when you prefer a fixed snapshot:
|
|
154
|
+
|
|
155
|
+
```yaml
|
|
156
|
+
inventory:
|
|
157
|
+
autoRefreshOnChange: false
|
|
158
|
+
roots:
|
|
159
|
+
- custom-skills
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Cost/latency trade-offs:
|
|
163
|
+
|
|
164
|
+
- Auto-refresh adds a shallow filesystem walk on each agent turn while enabled. It avoids stale search results after local skill edits without restarting Pi.
|
|
165
|
+
- A full refresh rebuilds the SQLite FTS database and scales with total indexed skills and description length. Large vaults with many roots may prefer `autoRefreshOnChange: false` plus explicit `/shiori:reload` after bulk imports.
|
|
166
|
+
- Search stays description-first and policy-aware: only `triggerable` skills become candidates, with FTS ranking over names, descriptions, and policy triggers.
|
|
135
167
|
|
|
136
168
|
## Configure
|
|
137
169
|
|
|
@@ -185,7 +217,7 @@ This writes a generated review file next to `.pi/skill-shiori.yml`. Review it be
|
|
|
185
217
|
|
|
186
218
|
| Command | Purpose |
|
|
187
219
|
|---|---|
|
|
188
|
-
| `/shiori:doctor` | Show policy path, inventory count, retrieval backend, suppression status, and code marker. |
|
|
220
|
+
| `/shiori:doctor` | Show policy path, indexed roots, inventory count, retrieval backend, suppression status, and code marker. |
|
|
189
221
|
| `/shiori:bootstrap` | Generate a review draft policy from discovered skill descriptions. |
|
|
190
222
|
| `/shiori:reload` | Ask what to reload, then rebuild Shiori’s skill inventory and optionally ask Pi to reload runtime resources. Code changes may still need full restart. |
|
|
191
223
|
| `/shiori:recommend` | Ask what you need help with, then either pre-load matches and queue the task for the agent or review recommendations only. Planning phrases (e.g. `計画を立てたい`) return the dev-plan intake template without dumping SKILL bodies. |
|
|
@@ -281,7 +313,7 @@ npm login
|
|
|
281
313
|
After publishing, verify the Pi install path:
|
|
282
314
|
|
|
283
315
|
```bash
|
|
284
|
-
pi install npm:pi-skill-shiori@0.
|
|
316
|
+
pi install npm:pi-skill-shiori@0.5.0
|
|
285
317
|
pi install npm:pi-skill-shiori
|
|
286
318
|
pi list
|
|
287
319
|
/shiori:doctor
|
package/package.json
CHANGED
package/src/discovery.ts
CHANGED
|
@@ -1,18 +1,42 @@
|
|
|
1
1
|
import { readdir, readFile, stat } from "node:fs/promises";
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
|
-
import { basename, dirname, join, resolve } from "node:path";
|
|
3
|
+
import { basename, dirname, isAbsolute, join, resolve } from "node:path";
|
|
4
4
|
import { parse as parseYaml } from "yaml";
|
|
5
|
-
import type { SkillRecord } from "./types.js";
|
|
5
|
+
import type { ShioriPolicy, SkillRecord } from "./types.js";
|
|
6
6
|
|
|
7
7
|
const SKILL_FILE = "SKILL.md";
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
/** Project-local skill roots scanned on every vault-wide inventory build. */
|
|
10
|
+
export const VAULT_LOCAL_SKILL_ROOT_SEGMENTS = [".pi/skills", ".agents/skills"] as const;
|
|
11
|
+
|
|
12
|
+
/** User-global Pi agent skills root (lowest discovery precedence). */
|
|
13
|
+
export const GLOBAL_AGENT_SKILL_ROOT_SEGMENTS = ".pi/agent/skills";
|
|
14
|
+
|
|
15
|
+
export function resolveVaultSkillRoots(cwd: string, policy?: Pick<ShioriPolicy, "inventory">): string[] {
|
|
10
16
|
const roots = [
|
|
11
17
|
join(cwd, ".pi", "skills"),
|
|
12
18
|
join(cwd, ".agents", "skills"),
|
|
13
19
|
join(homedir(), ".pi", "agent", "skills"),
|
|
14
20
|
];
|
|
15
21
|
|
|
22
|
+
for (const entry of policy?.inventory?.roots ?? []) {
|
|
23
|
+
const trimmed = entry.trim();
|
|
24
|
+
if (!trimmed) continue;
|
|
25
|
+
const resolved = isAbsolute(trimmed) ? resolve(trimmed) : resolve(cwd, trimmed);
|
|
26
|
+
if (!roots.includes(resolved)) {
|
|
27
|
+
roots.push(resolved);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return roots;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export async function discoverSkills(cwd: string, policy?: ShioriPolicy): Promise<SkillRecord[]> {
|
|
35
|
+
const roots = resolveVaultSkillRoots(cwd, policy);
|
|
36
|
+
return discoverSkillsFromRoots(roots);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export async function discoverSkillsFromRoots(roots: string[]): Promise<SkillRecord[]> {
|
|
16
40
|
const records: SkillRecord[] = [];
|
|
17
41
|
for (const root of roots) {
|
|
18
42
|
const files = await findSkillFiles(root);
|
|
@@ -23,6 +47,15 @@ export async function discoverSkills(cwd: string): Promise<SkillRecord[]> {
|
|
|
23
47
|
return dedupeByDiscoveryOrder(records);
|
|
24
48
|
}
|
|
25
49
|
|
|
50
|
+
export async function computeInventoryFingerprint(roots: string[]): Promise<string> {
|
|
51
|
+
const parts: string[] = [];
|
|
52
|
+
for (const root of roots) {
|
|
53
|
+
const files = await findSkillFiles(root);
|
|
54
|
+
parts.push(`${root}:${files.sort().join(",")}`);
|
|
55
|
+
}
|
|
56
|
+
return parts.join("|");
|
|
57
|
+
}
|
|
58
|
+
|
|
26
59
|
export function findDuplicates(records: SkillRecord[]): Map<string, SkillRecord[]> {
|
|
27
60
|
const groups = new Map<string, SkillRecord[]>();
|
|
28
61
|
for (const record of records) {
|
package/src/index.ts
CHANGED
|
@@ -3,8 +3,8 @@ import { Text } from "@earendil-works/pi-tui";
|
|
|
3
3
|
import { Type } from "typebox";
|
|
4
4
|
import { readFile, writeFile } from "node:fs/promises";
|
|
5
5
|
import { evaluateAlwaysVisible, formatAlwaysVisibleDiagnostics } from "./always-visible.js";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
6
|
+
import { findDuplicates, formatInventoryRoots, isAutoRefreshEnabled, isInventoryStale, refreshSkillInventory } from "./inventory.js";
|
|
7
|
+
import type { SkillIndex } from "./indexer.js";
|
|
8
8
|
import { loadRecommendedSkills } from "./load-skills.js";
|
|
9
9
|
import { formatPlanningKickoffMessage, isPlanningIntent } from "./planning-kickoff.js";
|
|
10
10
|
import { createStats } from "./metrics.js";
|
|
@@ -36,23 +36,42 @@ const CANCEL_CHOICE = "Cancel";
|
|
|
36
36
|
|
|
37
37
|
export default function piSkillShiori(pi: ExtensionAPI) {
|
|
38
38
|
let index: SkillIndex | undefined;
|
|
39
|
+
let inventoryFingerprint: string | undefined;
|
|
40
|
+
let inventoryRoots: string[] = [];
|
|
39
41
|
let warnedAlwaysVisibleMissing = new Set<string>();
|
|
40
42
|
const stats = createStats();
|
|
41
43
|
|
|
42
44
|
async function reload(cwd: string): Promise<SkillIndex> {
|
|
43
|
-
const
|
|
44
|
-
index
|
|
45
|
-
index =
|
|
46
|
-
|
|
47
|
-
|
|
45
|
+
const policy = await loadPolicy(cwd);
|
|
46
|
+
const inventory = await refreshSkillInventory(cwd, policy, index);
|
|
47
|
+
index = inventory.index;
|
|
48
|
+
inventoryFingerprint = inventory.fingerprint;
|
|
49
|
+
inventoryRoots = inventory.roots;
|
|
50
|
+
stats.inventoryCount = index.skills.length;
|
|
51
|
+
stats.duplicateCount = findDuplicates(index.skills).size;
|
|
48
52
|
stats.lastReloadAt = index.builtAt;
|
|
49
53
|
stats.retrievalBackend = index.retrievalBackend;
|
|
50
54
|
stats.suppressionStatus = policy.zeroCatalog.enabled ? "not-needed" : "disabled";
|
|
55
|
+
stats.inventoryRefreshCount += 1;
|
|
51
56
|
return index;
|
|
52
57
|
}
|
|
53
58
|
|
|
54
59
|
async function ensureIndex(cwd: string): Promise<SkillIndex> {
|
|
55
|
-
|
|
60
|
+
if (!index || !inventoryFingerprint) {
|
|
61
|
+
return reload(cwd);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const policy = await loadPolicy(cwd);
|
|
65
|
+
if (!isAutoRefreshEnabled(policy)) {
|
|
66
|
+
return index;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (await isInventoryStale(cwd, policy, inventoryFingerprint)) {
|
|
70
|
+
stats.inventoryAutoRefreshCount += 1;
|
|
71
|
+
return reload(cwd);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return index;
|
|
56
75
|
}
|
|
57
76
|
|
|
58
77
|
function withRecommendLimits(current: SkillIndex) {
|
|
@@ -72,6 +91,8 @@ export default function piSkillShiori(pi: ExtensionAPI) {
|
|
|
72
91
|
pi.on("session_shutdown", () => {
|
|
73
92
|
index?.close?.();
|
|
74
93
|
index = undefined;
|
|
94
|
+
inventoryFingerprint = undefined;
|
|
95
|
+
inventoryRoots = [];
|
|
75
96
|
});
|
|
76
97
|
|
|
77
98
|
pi.on("input", async (event) => {
|
|
@@ -210,6 +231,9 @@ export default function piSkillShiori(pi: ExtensionAPI) {
|
|
|
210
231
|
`duplicates: ${duplicates.size}`,
|
|
211
232
|
`alwaysVisible: ${current.policy.alwaysVisible.join(", ") || "none"}`,
|
|
212
233
|
...formatAlwaysVisibleDiagnostics(alwaysVisible),
|
|
234
|
+
"inventoryRoots:",
|
|
235
|
+
...formatInventoryRoots(inventoryRoots, current.skills).map((line) => ` - ${line}`),
|
|
236
|
+
`autoRefreshOnChange: ${isAutoRefreshEnabled(current.policy) ? "enabled" : "disabled"}`,
|
|
213
237
|
`retrievalBackend: ${current.retrievalBackend}`,
|
|
214
238
|
`suppression: ${stats.suppressionStatus}`,
|
|
215
239
|
`code: ${SHIORI_CODE_MARKER}`,
|
package/src/inventory.ts
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import {
|
|
2
|
+
computeInventoryFingerprint,
|
|
3
|
+
discoverSkillsFromRoots,
|
|
4
|
+
findDuplicates,
|
|
5
|
+
resolveVaultSkillRoots,
|
|
6
|
+
} from "./discovery.js";
|
|
7
|
+
import { buildSkillIndex, type SkillIndex } from "./indexer.js";
|
|
8
|
+
import type { ShioriPolicy } from "./types.js";
|
|
9
|
+
|
|
10
|
+
export interface SkillInventory {
|
|
11
|
+
index: SkillIndex;
|
|
12
|
+
roots: string[];
|
|
13
|
+
fingerprint: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function isAutoRefreshEnabled(policy: ShioriPolicy): boolean {
|
|
17
|
+
return policy.inventory?.autoRefreshOnChange !== false;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export async function refreshSkillInventory(
|
|
21
|
+
cwd: string,
|
|
22
|
+
policy: ShioriPolicy,
|
|
23
|
+
previous?: SkillIndex,
|
|
24
|
+
): Promise<SkillInventory> {
|
|
25
|
+
previous?.close?.();
|
|
26
|
+
const roots = resolveVaultSkillRoots(cwd, policy);
|
|
27
|
+
const [skills, fingerprint] = await Promise.all([
|
|
28
|
+
discoverSkillsFromRoots(roots),
|
|
29
|
+
computeInventoryFingerprint(roots),
|
|
30
|
+
]);
|
|
31
|
+
const index = await buildSkillIndex(cwd, skills, policy);
|
|
32
|
+
return { index, roots, fingerprint };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export async function isInventoryStale(
|
|
36
|
+
cwd: string,
|
|
37
|
+
policy: ShioriPolicy,
|
|
38
|
+
fingerprint: string,
|
|
39
|
+
): Promise<boolean> {
|
|
40
|
+
const roots = resolveVaultSkillRoots(cwd, policy);
|
|
41
|
+
const current = await computeInventoryFingerprint(roots);
|
|
42
|
+
return current !== fingerprint;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function countSkillsByRoot(skills: SkillIndex["skills"], roots: string[]): Map<string, number> {
|
|
46
|
+
const counts = new Map(roots.map((root) => [root, 0]));
|
|
47
|
+
for (const skill of skills) {
|
|
48
|
+
counts.set(skill.source, (counts.get(skill.source) ?? 0) + 1);
|
|
49
|
+
}
|
|
50
|
+
return counts;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function formatInventoryRoots(roots: string[], skills: SkillIndex["skills"]): string[] {
|
|
54
|
+
const counts = countSkillsByRoot(skills, roots);
|
|
55
|
+
return roots.map((root) => `${root} (${counts.get(root) ?? 0} skills)`);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export { findDuplicates };
|
package/src/metrics.ts
CHANGED
package/src/policy.ts
CHANGED
|
@@ -30,6 +30,10 @@ export async function loadPolicy(cwd: string): Promise<ShioriPolicy> {
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
function normalizePolicy(policy: Partial<ShioriPolicy> | undefined): ShioriPolicy {
|
|
33
|
+
const extraRoots = (policy?.inventory?.roots ?? [])
|
|
34
|
+
.map((root) => (typeof root === "string" ? root.trim() : ""))
|
|
35
|
+
.filter(Boolean);
|
|
36
|
+
|
|
33
37
|
return {
|
|
34
38
|
zeroCatalog: {
|
|
35
39
|
enabled: policy?.zeroCatalog?.enabled ?? DEFAULT_POLICY.zeroCatalog.enabled,
|
|
@@ -42,6 +46,13 @@ function normalizePolicy(policy: Partial<ShioriPolicy> | undefined): ShioriPolic
|
|
|
42
46
|
minScore: policy?.candidateInjection?.minScore ?? DEFAULT_POLICY.candidateInjection.minScore,
|
|
43
47
|
},
|
|
44
48
|
alwaysVisible: normalizeAlwaysVisible(policy?.alwaysVisible ?? DEFAULT_POLICY.alwaysVisible).allowlist,
|
|
49
|
+
inventory:
|
|
50
|
+
extraRoots.length > 0 || policy?.inventory?.autoRefreshOnChange === false
|
|
51
|
+
? {
|
|
52
|
+
roots: extraRoots.length > 0 ? extraRoots : undefined,
|
|
53
|
+
autoRefreshOnChange: policy?.inventory?.autoRefreshOnChange,
|
|
54
|
+
}
|
|
55
|
+
: undefined,
|
|
45
56
|
skills: policy?.skills ?? DEFAULT_POLICY.skills,
|
|
46
57
|
};
|
|
47
58
|
}
|
package/src/types.ts
CHANGED
|
@@ -14,6 +14,12 @@ export interface ShioriPolicy {
|
|
|
14
14
|
minScore: number;
|
|
15
15
|
};
|
|
16
16
|
alwaysVisible: string[];
|
|
17
|
+
inventory?: {
|
|
18
|
+
/** Extra skill roots relative to cwd or absolute paths. */
|
|
19
|
+
roots?: string[];
|
|
20
|
+
/** Rebuild the index when skill files change under any root (default: true). */
|
|
21
|
+
autoRefreshOnChange?: boolean;
|
|
22
|
+
};
|
|
17
23
|
skills: Record<string, SkillPolicy>;
|
|
18
24
|
}
|
|
19
25
|
|
|
@@ -49,4 +55,6 @@ export interface ShioriStats {
|
|
|
49
55
|
retrievalBackend: RetrievalBackend;
|
|
50
56
|
suppressionStatus: SuppressionStatus;
|
|
51
57
|
lastReloadAt?: string;
|
|
58
|
+
inventoryRefreshCount: number;
|
|
59
|
+
inventoryAutoRefreshCount: number;
|
|
52
60
|
}
|