@microi.net/cli 4.9.6 → 4.9.8
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/.codebuddy-plugin/marketplace.json +2 -2
- package/.codebuddy-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/.workbuddy-plugin/marketplace.json +2 -2
- package/.workbuddy-plugin/plugin.json +1 -1
- package/assets/build-meta.json +6 -5
- package/package.json +1 -1
- package/scripts/mcp-server.js +83 -83
- package/scripts/microi-cli.js +55 -85
- package/scripts/microi-codex-broker.js +418 -0
- package/scripts/microi-codex-router.js +129 -65
- package/scripts/microi-skills.meta.json +310 -151
- package/skills/.microi-skills-version.json +2 -2
- package/skills/.progressive-disclosure-manifest.json +3566 -0
- package/skills/ai-platform-governance/SKILL.md +21 -166
- package/skills/ai-platform-governance/references/progressive-01-/345/212/237/350/203/275/345/274/200/345/205/263.md +190 -0
- package/skills/microi-client-frontend/SKILL.md +17 -434
- package/skills/microi-client-frontend/references/progressive-01-3-/345/212/250/346/200/201/346/214/211/351/222/256/347/263/273/347/273/237.md +144 -0
- package/skills/microi-client-frontend/references/progressive-02-8-/350/277/220/350/241/214/346/227/266/351/253/230/351/242/221/345/235/221/345/244/215/347/233/230.md +178 -0
- package/skills/microi-client-frontend/references/progressive-03-vue3-/345/211/215/347/253/257/345/276/256/346/234/215/345/212/241/345/256/277/344/270/273/350/247/204/345/210/231.md +144 -0
- package/skills/microi-db-schema/SKILL.md +3 -3
- package/skills/microi-db-schema/references/schema-overview.md +1 -1
- package/skills/microi-db-schema/references/schema.md +1 -1
- package/skills/microi-db-schema/references/table-catalog.md +1 -1
- package/skills/microi-form-engine/SKILL.md +1 -1
- package/skills/microi-form-layout/SKILL.md +19 -225
- package/skills/microi-form-layout/references/progressive-01-3-/344/270/211/347/247/215/345/210/206/347/273/204/347/232/204/345/255/230/345/202/250/344/270/216/351/205/215/347/275/256.md +235 -0
- package/skills/microi-frontend-sdk/SKILL.md +17 -151
- package/skills/microi-frontend-sdk/references/progressive-01-token-/345/275/223/345/211/215/347/231/273/345/275/225/347/224/250/346/210/267/344/270/216/345/275/223/345/211/215/347/273/210/347/253/257/347/231/273/345/275/225/345/215/217/350/256/256.md +171 -0
- package/skills/microi-mobile-app-quality/SKILL.md +22 -288
- package/skills/microi-mobile-app-quality/references/progressive-01-4-/351/207/215/350/246/201/346/214/211/351/222/256/345/277/205/351/241/273/345/270/246/345/233/276/346/240/207.md +209 -0
- package/skills/microi-mobile-app-quality/references/progressive-02-9-/344/270/273/351/242/230/345/210/207/346/215/242/345/277/205/351/241/273/347/234/237/345/256/236/344/270/224/345/205/250/345/261/200/347/224/237/346/225/210.md +117 -0
- package/skills/microi-system-delivery/SKILL.md +16 -380
- package/skills/microi-system-delivery/references/progressive-01-/346/240/207/345/207/206/345/267/245/344/275/234/346/265/201.md +186 -0
- package/skills/microi-system-delivery/references/progressive-02-/350/207/252/345/212/250/345/214/226/346/265/213/350/257/225/345/277/205/351/241/273/350/246/206/347/233/226/347/232/204/345/235/221.md +210 -0
- package/skills/microi-ui/SKILL.md +19 -169
- package/skills/microi-ui/references/progressive-01-/347/247/273/345/212/250/347/253/257/345/234/272/346/231/257/350/223/235/345/233/276.md +183 -0
- package/skills/microi-uniapp-frontend/SKILL.md +26 -335
- package/skills/microi-uniapp-frontend/references/progressive-01-/347/247/273/345/212/250/347/253/257/345/210/206/347/261/273-/345/217/214/346/240/217/345/210/227/350/241/250/347/213/254/347/253/213/346/273/232/345/212/250.md +225 -0
- package/skills/microi-uniapp-frontend/references/progressive-02-/345/205/263/351/224/256/344/270/232/345/212/241/350/265/204/344/272/247/344/270/215/345/276/227/351/273/230/350/256/244/351/200/211/344/270/255.md +154 -0
- package/skills/page-engine/SKILL.md +23 -271
- package/skills/page-engine/references/progressive-01-/346/211/200/346/234/211/347/273/204/344/273/266/347/261/273/345/236/213.md +234 -0
- package/skills/page-engine/references/progressive-02-/347/211/210/346/234/254/345/216/206/345/217/262-/345/271/266/345/217/221/344/277/235/345/255/230/344/270/216/345/233/236/346/273/232.md +60 -0
- package/skills/playwright-e2e/SKILL.md +24 -590
- package/skills/playwright-e2e/references/progressive-01-/345/205/250/350/207/252/345/212/250/347/231/273/345/275/225-/345/205/215/351/252/214/350/257/201/347/240/201-/344/275/206/344/270/215/345/205/215/345/257/206/347/240/201-/345/277/205/350/257/273.md +173 -0
- package/skills/playwright-e2e/references/progressive-02-/346/226/207/345/255/227/345/257/271/346/257/224/345/272/246/344/270/216/345/217/257/350/257/273/346/200/247/350/207/252/345/212/250/345/214/226/346/243/200/346/237/245-/345/277/205/345/201/232.md +183 -0
- package/skills/playwright-e2e/references/progressive-03-microi-helper-/346/250/241/346/235/277.md +221 -0
- package/skills/playwright-e2e/references/progressive-04-ci-/345/273/272/350/256/256.md +69 -0
- package/skills/scripts/optimize-progressive-disclosure.mjs +204 -0
- package/skills/scripts/refresh-progressive-disclosure.mjs +64 -0
- package/skills/scripts/validate-progressive-disclosure.mjs +52 -0
- package/skills/ui-design/SKILL.md +26 -1461
- package/skills/ui-design/references/progressive-01-/351/242/234/350/211/262/344/275/223/347/263/273-css-variables-/346/224/257/346/214/201/344/270/273/351/242/230/345/210/207/346/215/242.md +218 -0
- package/skills/ui-design/references/progressive-02-/345/255/227/344/275/223.md +155 -0
- package/skills/ui-design/references/progressive-03-/345/212/250/346/225/210/350/247/204/350/214/203-/344/270/260/345/257/214/344/275/206/344/270/215/345/215/241.md +235 -0
- package/skills/ui-design/references/progressive-04-/347/273/204/344/273/266/351/243/216/346/240/274/351/200/237/346/237/245.md +152 -0
- package/skills/ui-design/references/progressive-05-/347/247/273/345/212/250/347/253/257/344/270/223/347/224/250/350/247/204/350/214/203.md +238 -0
- package/skills/ui-design/references/progressive-06-/344/270/273/351/242/230/345/210/207/346/215/242/345/256/236/347/216/260.md +194 -0
- package/skills/ui-design/references/progressive-07-/351/200/237/346/237/245-/344/273/216/345/244/264/346/220/255/345/273/272/344/270/200/344/270/252/347/247/273/345/212/250/347/253/257/351/241/265/351/235/242.md +207 -0
- package/skills/ui-design/references/progressive-08-/350/241/250/345/215/225/345/210/206/347/273/204/350/247/204/350/214/203-tabs-vs-collapsegroup-/345/274/272/345/210/266.md +142 -0
- package/skills/v8-crud-api/SKILL.md +20 -245
- package/skills/v8-crud-api/references/progressive-01-/346/237/245/350/257/242/345/210/227/350/241/250-/345/210/206/351/241/265.md +226 -0
- package/skills/v8-crud-api/references/progressive-02-where-/346/235/241/344/273/266/350/257/255/346/263/225/351/200/237/346/237/245.md +49 -0
- package/skills/v8-export-import/SKILL.md +15 -425
- package/skills/v8-export-import/references/progressive-01-excellayout-/351/253/230/347/272/247/350/207/252/347/224/261/345/270/203/345/261/200.md +211 -0
- package/skills/v8-export-import/references/progressive-02-powerpoint-/345/257/274/345/207/272.md +202 -0
- package/skills/v8-export-import/references/progressive-03-/345/256/211/345/205/250-/346/200/247/350/203/275/346/263/250/346/204/217.md +42 -0
- package/skills/v8-file-upload/SKILL.md +16 -354
- package/skills/v8-file-upload/references/progressive-01-/345/205/254/346/234/211/346/241/266-vs-/347/247/201/346/234/211/346/241/266.md +227 -0
- package/skills/v8-file-upload/references/progressive-02-office-/346/226/207/344/273/266/345/234/250/347/272/277/347/274/226/350/276/221/347/211/210/346/234/254/345/217/267/350/247/204/345/210/231.md +149 -0
- package/skills/v8-frontend-events/SKILL.md +19 -205
- package/skills/v8-frontend-events/references/progressive-01-/345/210/227/350/241/250/344/272/213/344/273/266.md +219 -0
- package/skills/v8-http-integration/SKILL.md +14 -236
- package/skills/v8-http-integration/references/progressive-01-get-/350/257/267/346/261/202.md +220 -0
- package/skills/v8-http-integration/references/progressive-02-/351/224/231/350/257/257/345/244/204/347/220/206/346/250/241/345/274/217.md +44 -0
- package/skills/v8-menu-buttons/SKILL.md +15 -511
- package/skills/v8-menu-buttons/references/progressive-01-2-/346/214/211/351/222/256/345/257/271/350/261/241-schema.md +221 -0
- package/skills/v8-menu-buttons/references/progressive-02-8-/346/250/241/345/274/217-f-/345/220/216/345/217/260/344/273/273/345/212/241/346/214/211/351/222/256-/351/225/277/344/273/273/345/212/241.md +224 -0
- package/skills/v8-menu-buttons/references/progressive-03-10-/345/217/215/346/250/241/345/274/217-/351/201/277/345/205/215.md +104 -0
- package/skills/v8-mq-mqtt/SKILL.md +11 -175
- package/skills/v8-mq-mqtt/references/progressive-01-v8-mqtt-iot-/347/211/251/350/201/224/347/275/221.md +181 -0
- package/skills/v8-security/SKILL.md +16 -329
- package/skills/v8-security/references/progressive-01-2-/346/235/203/351/231/220/346/240/241/351/252/214.md +199 -0
- package/skills/v8-security/references/progressive-02-7-/346/227/245/345/277/227/350/256/260/345/275/225.md +158 -0
- package/skills/v8-table-event/SKILL.md +16 -236
- package/skills/v8-table-event/references/progressive-01-informv8-js-/350/241/250/345/215/225/346/211/223/345/274/200/344/272/213/344/273/266.md +216 -0
- package/skills/v8-table-event/references/progressive-02-/345/211/215/347/253/257/344/272/213/344/273/266/345/220/215-v8-eventname-/345/217/257/350/203/275/347/232/204/345/200/274.md +46 -0
- package/skills/v8-workflow/SKILL.md +19 -160
- package/skills/v8-workflow/references/progressive-01-/350/212/202/347/202/271/345/274/200/345/247/213-v8-/344/272/213/344/273/266.md +180 -0
- package/skills/workspace-conventions/SKILL.md +29 -361
- package/skills/workspace-conventions/references/progressive-01-/347/211/210/346/234/254/346/233/264/346/226/260/346/227/245/345/277/227/344/277/235/346/212/244/350/247/204/345/210/231-/345/274/272/345/210/266.md +208 -0
- package/skills/workspace-conventions/references/progressive-02-microi-net-api-/346/234/254/345/234/260/345/220/257/345/212/250/347/272/246/345/256/232.md +196 -0
- package/skills/workspace-conventions/references/progressive-03-cli-/344/270/216-ide-/346/217/222/344/273/266/351/224/231/347/211/210/345/205/261/345/255/230/347/272/246/345/256/232.md +27 -0
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import crypto from 'node:crypto'
|
|
2
|
+
import fs from 'node:fs'
|
|
3
|
+
import path from 'node:path'
|
|
4
|
+
import { fileURLToPath } from 'node:url'
|
|
5
|
+
|
|
6
|
+
const skillsRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..')
|
|
7
|
+
const manifestPath = path.join(skillsRoot, '.progressive-disclosure-manifest.json')
|
|
8
|
+
const maxEntryLines = 285
|
|
9
|
+
const keepBudgetLines = 170
|
|
10
|
+
const referenceBudgetLines = 245
|
|
11
|
+
|
|
12
|
+
const hash = (value) => crypto.createHash('sha256').update(value).digest('hex')
|
|
13
|
+
const lineCount = (value) => value.length === 0 ? 0 : value.split(/\r?\n/).length
|
|
14
|
+
const slug = (value) => value
|
|
15
|
+
.replace(/^#+\s*/, '')
|
|
16
|
+
.replace(/[`*_]/g, '')
|
|
17
|
+
.trim()
|
|
18
|
+
.toLowerCase()
|
|
19
|
+
.replace(/[^\p{L}\p{N}]+/gu, '-')
|
|
20
|
+
.replace(/^-|-$/g, '')
|
|
21
|
+
.slice(0, 48) || 'reference'
|
|
22
|
+
|
|
23
|
+
const splitAtHeading = (value, headingPattern) => {
|
|
24
|
+
const matches = [...value.matchAll(headingPattern)]
|
|
25
|
+
if (matches.length <= 1) return [value]
|
|
26
|
+
const parts = []
|
|
27
|
+
if (matches[0].index > 0) parts.push(value.slice(0, matches[0].index))
|
|
28
|
+
for (let index = 0; index < matches.length; index += 1) {
|
|
29
|
+
parts.push(value.slice(matches[index].index, matches[index + 1]?.index ?? value.length))
|
|
30
|
+
}
|
|
31
|
+
return parts.filter(Boolean)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const splitOversized = (value, eol) => {
|
|
35
|
+
if (lineCount(value) <= referenceBudgetLines) return [value]
|
|
36
|
+
let parts = splitAtHeading(value, /^###\s+.+$/gm)
|
|
37
|
+
if (parts.length === 1) parts = splitAtHeading(value, /^####\s+.+$/gm)
|
|
38
|
+
const output = []
|
|
39
|
+
for (const part of parts) {
|
|
40
|
+
if (lineCount(part) <= referenceBudgetLines) {
|
|
41
|
+
output.push(part)
|
|
42
|
+
continue
|
|
43
|
+
}
|
|
44
|
+
const lines = part.split(/\r?\n/)
|
|
45
|
+
let start = 0
|
|
46
|
+
while (start < lines.length) {
|
|
47
|
+
let end = Math.min(start + referenceBudgetLines - 8, lines.length)
|
|
48
|
+
if (end < lines.length) {
|
|
49
|
+
for (let cursor = end; cursor > start + 40; cursor -= 1) {
|
|
50
|
+
if (lines[cursor - 1].trim() === '') {
|
|
51
|
+
end = cursor
|
|
52
|
+
break
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
const hasTrailingBreak = end < lines.length || part.endsWith(eol)
|
|
57
|
+
output.push(lines.slice(start, end).join(eol) + (hasTrailingBreak ? eol : ''))
|
|
58
|
+
start = end
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return output
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const headingOf = (value, fallback) => value.match(/^#{2,4}\s+(.+)$/m)?.[1]?.trim() || fallback
|
|
65
|
+
|
|
66
|
+
const skillDirectories = fs.readdirSync(skillsRoot, { withFileTypes: true })
|
|
67
|
+
.filter((entry) => entry.isDirectory() && fs.existsSync(path.join(skillsRoot, entry.name, 'SKILL.md')))
|
|
68
|
+
.map((entry) => entry.name)
|
|
69
|
+
.sort()
|
|
70
|
+
|
|
71
|
+
const manifest = {
|
|
72
|
+
version: 1,
|
|
73
|
+
generatedAt: new Date().toISOString(),
|
|
74
|
+
policy: {
|
|
75
|
+
maxEntryLines,
|
|
76
|
+
referenceBudgetLines,
|
|
77
|
+
note: 'Original prefix and ordered chunks reconstruct the exact pre-split SKILL.md bytes.'
|
|
78
|
+
},
|
|
79
|
+
skills: {}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
for (const skillName of skillDirectories) {
|
|
83
|
+
const skillPath = path.join(skillsRoot, skillName, 'SKILL.md')
|
|
84
|
+
const original = fs.readFileSync(skillPath, 'utf8')
|
|
85
|
+
if (lineCount(original) <= 300) continue
|
|
86
|
+
if (original.includes('<!-- microi-progressive:begin -->')) {
|
|
87
|
+
throw new Error(`${skillName} is already optimized; validate instead of running twice`)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const eol = original.includes('\r\n') ? '\r\n' : '\n'
|
|
91
|
+
const sectionMatches = [...original.matchAll(/^##\s+.+$/gm)]
|
|
92
|
+
if (sectionMatches.length < 2) {
|
|
93
|
+
throw new Error(`${skillName} needs at least two level-2 sections for safe semantic splitting`)
|
|
94
|
+
}
|
|
95
|
+
const prefix = original.slice(0, sectionMatches[0].index)
|
|
96
|
+
const sections = sectionMatches.map((match, index) => ({
|
|
97
|
+
heading: match[0].replace(/^##\s+/, '').trim(),
|
|
98
|
+
raw: original.slice(match.index, sectionMatches[index + 1]?.index ?? original.length),
|
|
99
|
+
}))
|
|
100
|
+
|
|
101
|
+
const kept = []
|
|
102
|
+
const moved = []
|
|
103
|
+
let keptLines = lineCount(prefix)
|
|
104
|
+
for (const section of sections) {
|
|
105
|
+
// Keep one contiguous prefix only. Picking a later short section after an
|
|
106
|
+
// earlier section was moved would reorder the original knowledge stream.
|
|
107
|
+
if (moved.length === 0 && (kept.length === 0 || keptLines + lineCount(section.raw) <= keepBudgetLines)) {
|
|
108
|
+
kept.push(section)
|
|
109
|
+
keptLines += lineCount(section.raw)
|
|
110
|
+
} else {
|
|
111
|
+
moved.push(section)
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
if (moved.length === 0) {
|
|
115
|
+
moved.push(kept.pop())
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const fragments = moved.flatMap((section) => splitOversized(section.raw, eol).map((raw, index) => ({
|
|
119
|
+
raw,
|
|
120
|
+
heading: headingOf(raw, `${section.heading} (${index + 1})`),
|
|
121
|
+
})))
|
|
122
|
+
|
|
123
|
+
const referenceGroups = []
|
|
124
|
+
let current = []
|
|
125
|
+
let currentLines = 5
|
|
126
|
+
for (const fragment of fragments) {
|
|
127
|
+
const cost = lineCount(fragment.raw) + 3
|
|
128
|
+
if (current.length && currentLines + cost > referenceBudgetLines) {
|
|
129
|
+
referenceGroups.push(current)
|
|
130
|
+
current = []
|
|
131
|
+
currentLines = 5
|
|
132
|
+
}
|
|
133
|
+
current.push(fragment)
|
|
134
|
+
currentLines += cost
|
|
135
|
+
}
|
|
136
|
+
if (current.length) referenceGroups.push(current)
|
|
137
|
+
|
|
138
|
+
const referencesDirectory = path.join(skillsRoot, skillName, 'references')
|
|
139
|
+
fs.mkdirSync(referencesDirectory, { recursive: true })
|
|
140
|
+
const chunkRecords = []
|
|
141
|
+
let ordinal = 0
|
|
142
|
+
const wrapChunk = (raw, destination) => {
|
|
143
|
+
const id = `${skillName}-${String(ordinal).padStart(3, '0')}`
|
|
144
|
+
const record = {
|
|
145
|
+
id,
|
|
146
|
+
ordinal,
|
|
147
|
+
destination: destination.replaceAll('\\', '/'),
|
|
148
|
+
sha256: hash(raw),
|
|
149
|
+
lines: lineCount(raw),
|
|
150
|
+
heading: headingOf(raw, skillName),
|
|
151
|
+
}
|
|
152
|
+
chunkRecords.push(record)
|
|
153
|
+
ordinal += 1
|
|
154
|
+
return `<!-- microi-progressive:chunk id=${id} sha256=${record.sha256} -->${eol}${raw}<!-- /microi-progressive:chunk -->${eol}`
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const entryChunks = kept.map((section) => wrapChunk(section.raw, `${skillName}/SKILL.md`)).join('')
|
|
158
|
+
const referenceRecords = []
|
|
159
|
+
referenceGroups.forEach((group, index) => {
|
|
160
|
+
const fileName = `progressive-${String(index + 1).padStart(2, '0')}-${slug(group[0].heading)}.md`
|
|
161
|
+
const relative = `references/${fileName}`
|
|
162
|
+
const destination = `${skillName}/${relative}`
|
|
163
|
+
const body = group.map((fragment) => wrapChunk(fragment.raw, destination)).join('')
|
|
164
|
+
const title = `# ${skillName} 详细参考 ${index + 1}${eol}${eol}`
|
|
165
|
+
const note = `> 按需读取;本文件由 SKILL.md 的原章节无损拆分。${eol}${eol}`
|
|
166
|
+
fs.writeFileSync(path.join(referencesDirectory, fileName), title + note + body, 'utf8')
|
|
167
|
+
referenceRecords.push({
|
|
168
|
+
path: relative,
|
|
169
|
+
headings: group.map((fragment) => fragment.heading),
|
|
170
|
+
})
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
const routerLines = [
|
|
174
|
+
'## 详细参考路由(渐进披露)',
|
|
175
|
+
'',
|
|
176
|
+
'仅在当前任务涉及对应主题时读取;下列文件合计保留了原 SKILL.md 的全部详细知识。',
|
|
177
|
+
'',
|
|
178
|
+
...referenceRecords.map((reference) =>
|
|
179
|
+
`- [${reference.path}](${reference.path}):${reference.headings.join(';')}`),
|
|
180
|
+
'',
|
|
181
|
+
].join(eol)
|
|
182
|
+
const rewritten = prefix
|
|
183
|
+
+ `<!-- microi-progressive:begin -->${eol}`
|
|
184
|
+
+ entryChunks
|
|
185
|
+
+ routerLines
|
|
186
|
+
+ `<!-- microi-progressive:end -->${eol}`
|
|
187
|
+
if (lineCount(rewritten) > maxEntryLines) {
|
|
188
|
+
throw new Error(`${skillName} entry remains ${lineCount(rewritten)} lines; lower keepBudgetLines`)
|
|
189
|
+
}
|
|
190
|
+
fs.writeFileSync(skillPath, rewritten, 'utf8')
|
|
191
|
+
|
|
192
|
+
manifest.skills[skillName] = {
|
|
193
|
+
originalSha256: hash(original),
|
|
194
|
+
originalLines: lineCount(original),
|
|
195
|
+
prefixSha256: hash(prefix),
|
|
196
|
+
prefixBytes: Buffer.byteLength(prefix),
|
|
197
|
+
entryLines: lineCount(rewritten),
|
|
198
|
+
chunks: chunkRecords,
|
|
199
|
+
references: referenceRecords,
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
fs.writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`, 'utf8')
|
|
204
|
+
console.log(`Optimized ${Object.keys(manifest.skills).length} skills; manifest: ${manifestPath}`)
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import crypto from 'node:crypto'
|
|
2
|
+
import fs from 'node:fs'
|
|
3
|
+
import path from 'node:path'
|
|
4
|
+
import { fileURLToPath } from 'node:url'
|
|
5
|
+
|
|
6
|
+
const skillsRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..')
|
|
7
|
+
const manifestPath = path.join(skillsRoot, '.progressive-disclosure-manifest.json')
|
|
8
|
+
const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'))
|
|
9
|
+
const requested = process.argv.slice(2)
|
|
10
|
+
if (requested.length === 0) {
|
|
11
|
+
throw new Error('Pass each intentionally changed skill name explicitly.')
|
|
12
|
+
}
|
|
13
|
+
const hash = (value) => crypto.createHash('sha256').update(value).digest('hex')
|
|
14
|
+
|
|
15
|
+
for (const skillName of requested) {
|
|
16
|
+
const skill = manifest.skills[skillName]
|
|
17
|
+
if (!skill) throw new Error(`${skillName} is not a progressive-disclosure skill`)
|
|
18
|
+
const sources = new Map()
|
|
19
|
+
const entryPath = path.join(skillsRoot, skillName, 'SKILL.md')
|
|
20
|
+
sources.set(`${skillName}/SKILL.md`, fs.readFileSync(entryPath, 'utf8'))
|
|
21
|
+
for (const reference of skill.references) {
|
|
22
|
+
const destination = `${skillName}/${reference.path}`
|
|
23
|
+
sources.set(destination, fs.readFileSync(path.join(skillsRoot, destination), 'utf8'))
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const ordered = []
|
|
27
|
+
for (const chunk of skill.chunks) {
|
|
28
|
+
let source = sources.get(chunk.destination)
|
|
29
|
+
const openPattern = new RegExp(`<!-- microi-progressive:chunk id=${chunk.id} sha256=[a-f0-9]{64} -->`)
|
|
30
|
+
const match = source.match(openPattern)
|
|
31
|
+
if (!match) throw new Error(`${skillName}: missing chunk ${chunk.id}`)
|
|
32
|
+
const markerStart = match.index
|
|
33
|
+
const markerEnd = markerStart + match[0].length
|
|
34
|
+
const contentStart = markerEnd + (source.startsWith('\r\n', markerEnd) ? 2 : 1)
|
|
35
|
+
const close = '<!-- /microi-progressive:chunk -->'
|
|
36
|
+
const contentEnd = source.indexOf(close, contentStart)
|
|
37
|
+
const raw = source.slice(contentStart, contentEnd)
|
|
38
|
+
const digest = hash(raw)
|
|
39
|
+
source = source.slice(0, markerStart)
|
|
40
|
+
+ `<!-- microi-progressive:chunk id=${chunk.id} sha256=${digest} -->`
|
|
41
|
+
+ source.slice(markerEnd)
|
|
42
|
+
sources.set(chunk.destination, source)
|
|
43
|
+
chunk.sha256 = digest
|
|
44
|
+
chunk.lines = raw.split(/\r?\n/).length
|
|
45
|
+
ordered[chunk.ordinal] = raw
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
for (const [destination, source] of sources) {
|
|
49
|
+
fs.writeFileSync(path.join(skillsRoot, destination), source, 'utf8')
|
|
50
|
+
}
|
|
51
|
+
const entry = sources.get(`${skillName}/SKILL.md`)
|
|
52
|
+
const begin = entry.indexOf('<!-- microi-progressive:begin -->')
|
|
53
|
+
const prefix = entry.slice(0, begin)
|
|
54
|
+
skill.prefixSha256 = hash(prefix)
|
|
55
|
+
skill.prefixBytes = Buffer.byteLength(prefix)
|
|
56
|
+
skill.originalSha256 = hash(prefix + ordered.join(''))
|
|
57
|
+
skill.originalLines = (prefix + ordered.join('')).split(/\r?\n/).length
|
|
58
|
+
skill.entryLines = entry.split(/\r?\n/).length
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
manifest.generatedAt = new Date().toISOString()
|
|
62
|
+
fs.writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`, 'utf8')
|
|
63
|
+
console.log(`Accepted intentional knowledge updates for: ${requested.join(', ')}`)
|
|
64
|
+
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import crypto from 'node:crypto'
|
|
2
|
+
import fs from 'node:fs'
|
|
3
|
+
import path from 'node:path'
|
|
4
|
+
import { fileURLToPath } from 'node:url'
|
|
5
|
+
|
|
6
|
+
const skillsRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..')
|
|
7
|
+
const manifest = JSON.parse(fs.readFileSync(path.join(skillsRoot, '.progressive-disclosure-manifest.json'), 'utf8'))
|
|
8
|
+
const hash = (value) => crypto.createHash('sha256').update(value).digest('hex')
|
|
9
|
+
const lineCount = (value) => value.length === 0 ? 0 : value.split(/\r?\n/).length
|
|
10
|
+
|
|
11
|
+
let checkedChunks = 0
|
|
12
|
+
for (const [skillName, skill] of Object.entries(manifest.skills)) {
|
|
13
|
+
const entryPath = path.join(skillsRoot, skillName, 'SKILL.md')
|
|
14
|
+
const entry = fs.readFileSync(entryPath, 'utf8')
|
|
15
|
+
const begin = entry.indexOf('<!-- microi-progressive:begin -->')
|
|
16
|
+
if (begin < 0) throw new Error(`${skillName}: missing progressive begin marker`)
|
|
17
|
+
const prefix = entry.slice(0, begin)
|
|
18
|
+
if (hash(prefix) !== skill.prefixSha256) throw new Error(`${skillName}: entry prefix changed`)
|
|
19
|
+
if (lineCount(entry) > manifest.policy.maxEntryLines) throw new Error(`${skillName}: entry exceeds line budget`)
|
|
20
|
+
|
|
21
|
+
const sources = new Map([[`${skillName}/SKILL.md`, entry]])
|
|
22
|
+
for (const reference of skill.references) {
|
|
23
|
+
const relative = `${skillName}/${reference.path}`
|
|
24
|
+
const content = fs.readFileSync(path.join(skillsRoot, relative), 'utf8')
|
|
25
|
+
if (lineCount(content) > 300) throw new Error(`${relative}: reference exceeds 300 lines`)
|
|
26
|
+
sources.set(relative, content)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const ordered = []
|
|
30
|
+
for (const chunk of skill.chunks) {
|
|
31
|
+
const source = sources.get(chunk.destination)
|
|
32
|
+
if (source == null) throw new Error(`${skillName}: missing ${chunk.destination}`)
|
|
33
|
+
const open = `<!-- microi-progressive:chunk id=${chunk.id} sha256=${chunk.sha256} -->`
|
|
34
|
+
const startMarker = source.indexOf(open)
|
|
35
|
+
if (startMarker < 0) throw new Error(`${skillName}: missing chunk ${chunk.id}`)
|
|
36
|
+
const contentStart = startMarker + open.length + (source.startsWith('\r\n', startMarker + open.length) ? 2 : 1)
|
|
37
|
+
const close = '<!-- /microi-progressive:chunk -->'
|
|
38
|
+
const contentEnd = source.indexOf(close, contentStart)
|
|
39
|
+
if (contentEnd < 0) throw new Error(`${skillName}: unterminated chunk ${chunk.id}`)
|
|
40
|
+
const raw = source.slice(contentStart, contentEnd)
|
|
41
|
+
if (hash(raw) !== chunk.sha256) throw new Error(`${skillName}: chunk ${chunk.id} changed`)
|
|
42
|
+
ordered[chunk.ordinal] = raw
|
|
43
|
+
checkedChunks += 1
|
|
44
|
+
}
|
|
45
|
+
const reconstructed = prefix + ordered.join('')
|
|
46
|
+
if (hash(reconstructed) !== skill.originalSha256) {
|
|
47
|
+
throw new Error(`${skillName}: reconstructed knowledge differs from original`)
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
console.log(`Validated ${Object.keys(manifest.skills).length} skills and ${checkedChunks} lossless chunks.`)
|
|
52
|
+
|