@fish-under-sea/magpie-purge 0.1.0 → 0.1.1
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 +1 -1
- package/hooks.js +4 -3
- package/lib/state.mjs +34 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -101,7 +101,7 @@ node preview/serve.mjs --demo # http://127.0.0.1:55133
|
|
|
101
101
|
## 开发
|
|
102
102
|
|
|
103
103
|
```bash
|
|
104
|
-
# 测试(
|
|
104
|
+
# 测试(36 个用例:判型/校验/改写/选人/快照/钩子端到端/options 回读)
|
|
105
105
|
node --test --test-isolation=none "tests/*.test.mjs"
|
|
106
106
|
|
|
107
107
|
# 离线清点,看看本机 purge 目录里都认得什么
|
package/hooks.js
CHANGED
|
@@ -13,7 +13,7 @@ import { existsSync, mkdirSync, writeFileSync } from 'node:fs'
|
|
|
13
13
|
import { dirname, join } from 'node:path'
|
|
14
14
|
import { fileURLToPath } from 'node:url'
|
|
15
15
|
import { MODES, compose, rewrite, supported } from './lib/rewrite.mjs'
|
|
16
|
-
import { loadCatalog, paths, sync } from './lib/state.mjs'
|
|
16
|
+
import { loadCatalog, ownOptions, paths, sync } from './lib/state.mjs'
|
|
17
17
|
|
|
18
18
|
const here = dirname(fileURLToPath(import.meta.url))
|
|
19
19
|
|
|
@@ -110,8 +110,9 @@ export function createHook(root = here, { deadlineMs = 400, rescanMs = 30_000, w
|
|
|
110
110
|
return job
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
-
/** warm
|
|
114
|
-
const
|
|
113
|
+
/** warm 在模块加载时就起:读回自己的 options(页面要能无流量也显示条目),再扫一遍。 */
|
|
114
|
+
const own = ownOptions(root)
|
|
115
|
+
const warm = warmUp ? scanOnce(own || {}) : Promise.resolve(null)
|
|
115
116
|
|
|
116
117
|
/** ensureCatalog 拿条目表,最多等 deadlineMs;等不到就返回 null,让这次请求放行。 */
|
|
117
118
|
async function ensureCatalog(options) {
|
package/lib/state.mjs
CHANGED
|
@@ -8,10 +8,12 @@
|
|
|
8
8
|
// 这里(Bun 侧)把文件复制进 state/imports,再重新扫描,页面下次刷新就看到结果。
|
|
9
9
|
import { createHash } from 'node:crypto'
|
|
10
10
|
import { copyFileSync, existsSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from 'node:fs'
|
|
11
|
-
import {
|
|
11
|
+
import { homedir } from 'node:os'
|
|
12
|
+
import { basename, extname, join, normalize } from 'node:path'
|
|
12
13
|
import {
|
|
13
14
|
LIMITS,
|
|
14
15
|
defaultSources,
|
|
16
|
+
expandHome,
|
|
15
17
|
mergeEntries,
|
|
16
18
|
scan,
|
|
17
19
|
snapshotOf,
|
|
@@ -66,6 +68,36 @@ export function loadLast(p) {
|
|
|
66
68
|
return readJson(p.lastFile, null)
|
|
67
69
|
}
|
|
68
70
|
|
|
71
|
+
/**
|
|
72
|
+
* ownOptions 从 magpie 自己的 plugins.json 里读回「这个插件」的 options。
|
|
73
|
+
*
|
|
74
|
+
* 为什么需要它:网关钩子的 onRequest 只有真的来了请求才会被调用,而插件页要能
|
|
75
|
+
* 在没有任何流量时也显示条目。宿主在改 options 后会重建插件宿主进程(我们的
|
|
76
|
+
* 模块随之重新加载),所以模块加载时读一次 plugins.json 就能拿到最新设置。
|
|
77
|
+
*
|
|
78
|
+
* 找不到就返回 null,让调用方退回默认来源;读不到不算错。
|
|
79
|
+
*/
|
|
80
|
+
export function ownOptions(here, env = process.env) {
|
|
81
|
+
const dirs = []
|
|
82
|
+
const xdg = String(env.XDG_CONFIG_HOME || '').trim()
|
|
83
|
+
if (xdg) dirs.push(join(xdg, 'magpie'))
|
|
84
|
+
dirs.push(join(homedir(), '.config', 'magpie'))
|
|
85
|
+
const want = normalize(here).toLowerCase()
|
|
86
|
+
for (const dir of dirs) {
|
|
87
|
+
const file = join(dir, 'plugins.json')
|
|
88
|
+
if (!existsSync(file)) continue
|
|
89
|
+
const data = readJson(file, null)
|
|
90
|
+
const rows = Array.isArray(data?.plugins) ? data.plugins : []
|
|
91
|
+
for (const row of rows) {
|
|
92
|
+
if (!row || typeof row.spec !== 'string') continue
|
|
93
|
+
const spec = expandHome(row.spec, dir).toLowerCase()
|
|
94
|
+
if (spec !== want) continue
|
|
95
|
+
return row.options && typeof row.options === 'object' ? row.options : {}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return null
|
|
99
|
+
}
|
|
100
|
+
|
|
69
101
|
/**
|
|
70
102
|
* sync 重新清点来源目录,必要时处理导入请求,然后写两份产物。
|
|
71
103
|
* @returns {{ catalog: object, changed: boolean, snapshot: object }}
|
|
@@ -79,7 +111,7 @@ export function sync(here, options = {}, { force = false, limits = LIMITS, now =
|
|
|
79
111
|
const sources = configured.length ? configured : defaultSources()
|
|
80
112
|
const imports = Array.isArray(options.imports) ? options.imports.filter((i) => i && typeof i.path === 'string') : []
|
|
81
113
|
const previous = loadCatalog(p)
|
|
82
|
-
const signature = sourceSignature(sources
|
|
114
|
+
const signature = sourceSignature(sources, imports, options.refreshAt ?? 0)
|
|
83
115
|
|
|
84
116
|
if (!force && previous.signature === signature) {
|
|
85
117
|
return { catalog: previous, changed: false, snapshot: snapshotFrom(p, previous, options, now) }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fish-under-sea/magpie-purge",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Purge in Magpie: a magpie page plugin that treats a local purge folder as a free plugin/skill source, inspects and validates what is in it, and rewrites the gateway's system prompt by mode (off / strict / replace / append).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|