@vegastack/skills 0.1.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/LICENSE +21 -0
- package/README.md +46 -0
- package/dist/index.js +512 -0
- package/package.json +35 -0
- package/skill/vegastack-arch-guardian/SKILL.md +96 -0
- package/skill/vegastack-arch-guardian/agents/openai.yaml +4 -0
- package/skill/vegastack-arch-guardian/assets/adr-template.md +40 -0
- package/skill/vegastack-arch-guardian/assets/answers-example.json +20 -0
- package/skill/vegastack-arch-guardian/assets/architecture-profile.json +25 -0
- package/skill/vegastack-arch-guardian/assets/architecture-profile.schema.json +213 -0
- package/skill/vegastack-arch-guardian/assets/deployment-review-template.md +24 -0
- package/skill/vegastack-arch-guardian/assets/service-design-template.md +33 -0
- package/skill/vegastack-arch-guardian/assets/threat-model-template.md +34 -0
- package/skill/vegastack-arch-guardian/references/architecture/agent-product.md +22 -0
- package/skill/vegastack-arch-guardian/references/architecture/ai-cost.md +22 -0
- package/skill/vegastack-arch-guardian/references/architecture/ai-data-boundaries.md +19 -0
- package/skill/vegastack-arch-guardian/references/architecture/ai-evals.md +26 -0
- package/skill/vegastack-arch-guardian/references/architecture/connectors-sandbox.md +39 -0
- package/skill/vegastack-arch-guardian/references/architecture/data-memory.md +25 -0
- package/skill/vegastack-arch-guardian/references/architecture/delivery-operations.md +34 -0
- package/skill/vegastack-arch-guardian/references/architecture/durable-execution.md +43 -0
- package/skill/vegastack-arch-guardian/references/architecture/flutter.md +26 -0
- package/skill/vegastack-arch-guardian/references/architecture/foundation.md +33 -0
- package/skill/vegastack-arch-guardian/references/architecture/hosting-reliability.md +37 -0
- package/skill/vegastack-arch-guardian/references/architecture/identity-tenancy.md +37 -0
- package/skill/vegastack-arch-guardian/references/architecture/model-lifecycle.md +18 -0
- package/skill/vegastack-arch-guardian/references/architecture/models-observability.md +23 -0
- package/skill/vegastack-arch-guardian/references/architecture/realtime-channels.md +16 -0
- package/skill/vegastack-arch-guardian/references/architecture/security-privacy.md +23 -0
- package/skill/vegastack-arch-guardian/references/architecture/topology-monorepo.md +47 -0
- package/skill/vegastack-arch-guardian/references/architecture/web.md +29 -0
- package/skill/vegastack-arch-guardian/references/control-catalog.json +55 -0
- package/skill/vegastack-arch-guardian/references/foundation-compatibility.json +44 -0
- package/skill/vegastack-arch-guardian/references/golden-patterns.md +43 -0
- package/skill/vegastack-arch-guardian/references/profile-governance.md +54 -0
- package/skill/vegastack-arch-guardian/references/rule-model.json +36 -0
- package/skill/vegastack-arch-guardian/references/workflows.md +45 -0
- package/skill/vegastack-arch-guardian/refresh/REFRESH.md +40 -0
- package/skill/vegastack-arch-guardian/refresh/sources.json +1159 -0
- package/skill/vegastack-arch-guardian/scripts/architecture-check.mjs +323 -0
- package/skill/vegastack-arch-guardian/scripts/lib.mjs +57 -0
- package/skill/vegastack-arch-guardian/scripts/profile-tool.mjs +223 -0
- package/skill/vegastack-arch-guardian/scripts/refresh-evidence.mjs +325 -0
- package/skill/vegastack-arch-guardian/scripts/schema-validate.mjs +63 -0
- package/skill/vegastack-arch-guardian/scripts/validate-profile.mjs +241 -0
- package/skill/vegastack-arch-guardian/scripts/verify-corpus.mjs +148 -0
- package/skill-integrity.json +48 -0
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { readFile } from 'node:fs/promises'
|
|
3
|
+
import { basename, dirname, join, relative, resolve } from 'node:path'
|
|
4
|
+
import { fileURLToPath } from 'node:url'
|
|
5
|
+
import { listFiles, pathExists, readJsonYaml } from './lib.mjs'
|
|
6
|
+
import { canonicalRuleIds } from './validate-profile.mjs'
|
|
7
|
+
|
|
8
|
+
let mermaid = null
|
|
9
|
+
try {
|
|
10
|
+
const { JSDOM } = await import('jsdom')
|
|
11
|
+
const dom = new JSDOM('<!doctype html><html><body></body></html>')
|
|
12
|
+
globalThis.window = dom.window
|
|
13
|
+
globalThis.document = dom.window.document
|
|
14
|
+
mermaid = (await import('mermaid')).default
|
|
15
|
+
mermaid.initialize({ startOnLoad: false, securityLevel: 'strict' })
|
|
16
|
+
} catch {
|
|
17
|
+
// Installed copies have no development dependencies and use structural checks.
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const skillRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..')
|
|
21
|
+
const references = join(skillRoot, 'references')
|
|
22
|
+
const architectureRoot = join(references, 'architecture')
|
|
23
|
+
const skillPath = join(skillRoot, 'SKILL.md')
|
|
24
|
+
const skillBody = await readFile(skillPath, 'utf8')
|
|
25
|
+
const chapters = await listFiles(architectureRoot, path => path.endsWith('.md'))
|
|
26
|
+
const registry = await readJsonYaml(join(skillRoot, 'refresh', 'sources.json'))
|
|
27
|
+
const sourceIds = new Set(registry.sources.map(source => source.id))
|
|
28
|
+
const ruleIds = await canonicalRuleIds()
|
|
29
|
+
const controlCatalog = await readJsonYaml(join(references, 'control-catalog.json'))
|
|
30
|
+
const ruleModel = await readJsonYaml(join(references, 'rule-model.json'))
|
|
31
|
+
const errors = []
|
|
32
|
+
let diagrams = 0
|
|
33
|
+
let normativeLines = 0
|
|
34
|
+
|
|
35
|
+
const expectedReferences = new Set(['agent-product.md', 'ai-cost.md', 'ai-data-boundaries.md', 'ai-evals.md', 'connectors-sandbox.md', 'data-memory.md', 'delivery-operations.md', 'durable-execution.md', 'flutter.md', 'foundation.md', 'hosting-reliability.md', 'identity-tenancy.md', 'model-lifecycle.md', 'models-observability.md', 'realtime-channels.md', 'security-privacy.md', 'topology-monorepo.md', 'web.md'])
|
|
36
|
+
if (chapters.length !== expectedReferences.size) errors.push(`expected ${expectedReferences.size} normative references, found ${chapters.length}`)
|
|
37
|
+
for (const path of chapters) if (!expectedReferences.delete(basename(path))) errors.push(`unexpected architecture reference ${basename(path)}`)
|
|
38
|
+
for (const missing of expectedReferences) errors.push(`missing architecture reference ${missing}`)
|
|
39
|
+
|
|
40
|
+
const skillLines = skillBody.split('\n').length
|
|
41
|
+
if (skillLines > 120) errors.push(`SKILL.md exceeds 120 lines (${skillLines})`)
|
|
42
|
+
const routed = new Set([...skillBody.matchAll(/\(references\/architecture\/([^)]+\.md)\)/g)].map(match => match[1]))
|
|
43
|
+
|
|
44
|
+
const citedSources = new Set()
|
|
45
|
+
for (const path of chapters) {
|
|
46
|
+
const body = await readFile(path, 'utf8')
|
|
47
|
+
normativeLines += body.split('\n').length
|
|
48
|
+
if (!routed.has(basename(path))) errors.push(`${path}: not routed directly from SKILL.md`)
|
|
49
|
+
for (const match of body.matchAll(/\[([A-Z0-9]+(?:-[A-Z0-9]+)*)\]|<!-- source: ([A-Z0-9]+(?:-[A-Z0-9]+)*) -->/g)) {
|
|
50
|
+
const id = match[1] ?? match[2]
|
|
51
|
+
citedSources.add(id)
|
|
52
|
+
if (!sourceIds.has(id)) errors.push(`${path}: unknown source ${id}`)
|
|
53
|
+
}
|
|
54
|
+
for (const [index, line] of body.split('\n').entries()) {
|
|
55
|
+
const definitions = [...line.matchAll(/\*\*([A-Z]+-[0-9]{3}) —/g)]
|
|
56
|
+
if (definitions.length && !/\bMUST(?:\s+NOT)?\b/.test(line)) errors.push(`${path}: rule ${definitions[0][1]} must define a MUST or MUST NOT invariant in its canonical line`)
|
|
57
|
+
if (/\bMUST(?:\s+NOT)?\b/.test(line) && definitions.length !== 1) errors.push(`${path}:${index + 1}: every MUST/MUST NOT must occur in exactly one canonical rule definition`)
|
|
58
|
+
}
|
|
59
|
+
for (const block of body.matchAll(/```mermaid\n([\s\S]*?)```/g)) {
|
|
60
|
+
diagrams += 1
|
|
61
|
+
const text = block[1].trim()
|
|
62
|
+
if (!/^(flowchart|sequenceDiagram|stateDiagram-v2)\b/.test(text)) errors.push(`${path}: unsupported Mermaid declaration`)
|
|
63
|
+
if ((text.match(/\[/g) ?? []).length !== (text.match(/\]/g) ?? []).length) errors.push(`${path}: unbalanced Mermaid brackets`)
|
|
64
|
+
if (mermaid) try { await mermaid.parse(text) } catch (error) { errors.push(`${path}: Mermaid parser: ${error.message}`) }
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
if (normativeLines > 800) errors.push(`normative references exceed 800 lines (${normativeLines})`)
|
|
68
|
+
if (diagrams < 4) errors.push(`expected at least four decision-useful Mermaid diagrams, found ${diagrams}`)
|
|
69
|
+
|
|
70
|
+
// criticalSources in foundation-compatibility must mirror every critical:true registry entry —
|
|
71
|
+
// asserted here so the mirror can never drift silently.
|
|
72
|
+
const compatibility = await readJsonYaml(join(references, 'foundation-compatibility.json'))
|
|
73
|
+
const declaredCritical = new Set(compatibility.sourceDrift?.criticalSources ?? [])
|
|
74
|
+
const actualCritical = new Set(registry.sources.filter(source => source.critical).map(source => source.id))
|
|
75
|
+
for (const id of actualCritical) if (!declaredCritical.has(id)) errors.push(`criticalSources mirror missing critical registry source ${id}`)
|
|
76
|
+
for (const id of declaredCritical) if (!actualCritical.has(id)) errors.push(`criticalSources mirror lists non-critical or unknown source ${id}`)
|
|
77
|
+
|
|
78
|
+
for (const source of registry.sources) {
|
|
79
|
+
if (!citedSources.has(source.id)) errors.push(`orphan source registry entry ${source.id}`)
|
|
80
|
+
if (!source.urls?.primary) errors.push(`source ${source.id} has no primary URL`)
|
|
81
|
+
for (const target of source.affected ?? []) {
|
|
82
|
+
const [kind, value] = String(target).split(':', 2)
|
|
83
|
+
if (!['rule', 'ref', 'profile'].includes(kind)) errors.push(`source ${source.id} has invalid affected mapping ${target}`)
|
|
84
|
+
if (kind === 'rule' && !ruleIds.has(value)) errors.push(`source ${source.id} maps unknown rule ${value}`)
|
|
85
|
+
if (kind === 'ref' && !await pathExists(join(architectureRoot, `${value}.md`))) errors.push(`source ${source.id} maps unknown reference ${value}`)
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const catalogKeys = new Set()
|
|
90
|
+
for (const control of controlCatalog.controls ?? []) {
|
|
91
|
+
if (!ruleIds.has(control.rule)) errors.push(`control catalog maps unknown rule ${control.rule}`)
|
|
92
|
+
if ((!control.id && !control.idPattern) || (control.id && control.idPattern)) errors.push(`control catalog entry for ${control.rule} must have exactly one id or idPattern`)
|
|
93
|
+
const key = `${control.rule}/${control.id ?? control.idPattern}`
|
|
94
|
+
if (catalogKeys.has(key)) errors.push(`duplicate control catalog entry ${key}`)
|
|
95
|
+
catalogKeys.add(key)
|
|
96
|
+
for (const required of ['classification', 'activation', 'verification', 'waiver']) if (!control[required]) errors.push(`control catalog ${key} missing ${required}`)
|
|
97
|
+
}
|
|
98
|
+
const modeledRules = new Set()
|
|
99
|
+
for (const group of ruleModel.groups ?? []) {
|
|
100
|
+
for (const required of ['activation', 'verification', 'rationale']) if (!group[required]) errors.push(`rule model group missing ${required}`)
|
|
101
|
+
for (const rule of group.rules ?? []) {
|
|
102
|
+
if (modeledRules.has(rule)) errors.push(`rule model duplicates ${rule}`)
|
|
103
|
+
modeledRules.add(rule)
|
|
104
|
+
if (!ruleIds.has(rule)) errors.push(`rule model names unknown rule ${rule}`)
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
for (const rule of ruleIds) if (!modeledRules.has(rule)) errors.push(`canonical rule ${rule} has no activation/verification/rationale model`)
|
|
108
|
+
for (const override of ruleModel.overrides ?? []) if (!modeledRules.has(override.rule)) errors.push(`rule model override names unknown rule ${override.rule}`)
|
|
109
|
+
|
|
110
|
+
for (const match of (await readFile(join(skillRoot, 'scripts', 'architecture-check.mjs'), 'utf8')).matchAll(/issue\([^,]+,\s*['"]([A-Z]+-[0-9]{3})['"]/g)) if (!ruleIds.has(match[1])) errors.push(`architecture-check emits unknown rule ${match[1]}`)
|
|
111
|
+
|
|
112
|
+
const bannedNames = ['golden-architecture.md', 'evidence-manifest.json', 'coverage-matrix.md', 'verification-ledger.md', '23-evidence-comparisons.md', '24-roadmap.md', 'compile-guide.mjs']
|
|
113
|
+
const allFiles = await listFiles(skillRoot)
|
|
114
|
+
for (const path of allFiles) if (bannedNames.includes(basename(path))) errors.push(`forbidden runtime artifact remains: ${relative(skillRoot, path)}`)
|
|
115
|
+
const runtimeText = (await Promise.all((await listFiles(skillRoot, path => /\.(?:md|json|yaml|yml|mjs)$/.test(path) && !path.includes('/tests/'))).map(path => readFile(path, 'utf8')))).join('\n')
|
|
116
|
+
const historicalNames = ['C' + 'RM', 'S' + 'IM', 'Fl' + 'ue']
|
|
117
|
+
if (new RegExp(`\\b(?:${historicalNames.join('|')})\\b`).test(runtimeText)) errors.push('historical comparison names remain in runtime skill')
|
|
118
|
+
|
|
119
|
+
const githubSlug = heading => heading.toLowerCase().trim().replace(/<[^>]+>/g, '').replace(/[^\p{L}\p{N}\s-]/gu, '').replace(/\s+/g, '-')
|
|
120
|
+
const headingsFor = body => new Set([...body.matchAll(/^#{1,6}\s+(.+)$/gm)].map(match => githubSlug(match[1])))
|
|
121
|
+
for (const path of await listFiles(skillRoot, path => path.endsWith('.md'))) {
|
|
122
|
+
const body = await readFile(path, 'utf8')
|
|
123
|
+
for (const match of body.matchAll(/\[[^\]]+\]\(([^)]+)\)/g)) {
|
|
124
|
+
const target = match[1]
|
|
125
|
+
if (/^(https?:|mailto:)/.test(target)) continue
|
|
126
|
+
const [filePart, anchor] = target.split('#')
|
|
127
|
+
const targetPath = filePart ? resolve(dirname(path), decodeURIComponent(filePart)) : path
|
|
128
|
+
if (!await pathExists(targetPath)) { errors.push(`${path}: broken link ${target}`); continue }
|
|
129
|
+
if (anchor && !headingsFor(await readFile(targetPath, 'utf8')).has(anchor)) errors.push(`${path}: broken anchor ${target}`)
|
|
130
|
+
}
|
|
131
|
+
const lines = body.split('\n')
|
|
132
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
133
|
+
if (!lines[index].startsWith('|')) continue
|
|
134
|
+
const expected = (lines[index].match(/\|/g) ?? []).length
|
|
135
|
+
let cursor = index + 1
|
|
136
|
+
while (cursor < lines.length && lines[cursor].startsWith('|')) {
|
|
137
|
+
const actual = (lines[cursor].match(/\|/g) ?? []).length
|
|
138
|
+
if (actual !== expected) errors.push(`${path}:${cursor + 1}: malformed Markdown table`)
|
|
139
|
+
cursor += 1
|
|
140
|
+
}
|
|
141
|
+
index = cursor - 1
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (errors.length) {
|
|
146
|
+
for (const error of errors) console.error(error)
|
|
147
|
+
process.exitCode = 1
|
|
148
|
+
} else console.log(`verify-corpus: ${chapters.length} normative references, ${normativeLines} lines, ${ruleIds.size} rules, ${diagrams} Mermaid diagrams, ${sourceIds.size} cited sources, Mermaid mode=${mermaid ? 'formal' : 'structural-fallback'}`)
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"skill": "vegastack-arch-guardian",
|
|
4
|
+
"files": {
|
|
5
|
+
"SKILL.md": "8403b56f972ccbc5ee86a1fcbbe25334cb3d98d0307b117e85f79308cc094d15",
|
|
6
|
+
"agents/openai.yaml": "7c878993a58e718bc1e8e20abe22c6ef0dd6e63816df66b0f50333e68edcead2",
|
|
7
|
+
"assets/adr-template.md": "7a7138cfc7fe39427e60003b83eb41ea8586dc8a9e0d56e6d7dafda044e10ed8",
|
|
8
|
+
"assets/answers-example.json": "5eb2543f1c1d439b8cbb61e15d1634aac1ba92fdd907a1e8592c8a98d75abf56",
|
|
9
|
+
"assets/architecture-profile.json": "c9f776c5d17f8766d0c9b22723f567ac8e3821c4ea63add5d15877652ec98bdd",
|
|
10
|
+
"assets/architecture-profile.schema.json": "6593fdb8f5abb0425a42173dc4ce272331b4d364c12daa29444de88c2090d49b",
|
|
11
|
+
"assets/deployment-review-template.md": "e9be2feb153138d936f9ebd5763c3be10597cee639616f86cc082c498fd60cd2",
|
|
12
|
+
"assets/service-design-template.md": "670798e3bf26a76d593294ff60763e1a6a35866fa84ea74345406b05b4b0b61b",
|
|
13
|
+
"assets/threat-model-template.md": "ffcf22e3fc81c803d976ac6c41cbac4fb0f552d81653b89a5b587a46b59d9aed",
|
|
14
|
+
"references/architecture/agent-product.md": "3b8039ef9ca6aa30fc8781475e005d7bbb9d8d415705a6e8c79b4a602ee1ed5e",
|
|
15
|
+
"references/architecture/ai-cost.md": "2892d1ed68c19561fb4f38956bbbd7b573c6544f220e8cb88be0dc57bf757221",
|
|
16
|
+
"references/architecture/ai-data-boundaries.md": "d5b2e6486ac2662a9bab1e0469c5ff9dcc00ec56cf8d190dd025f62178dc97fa",
|
|
17
|
+
"references/architecture/ai-evals.md": "cfd81abac927292e6fb3dc2bf999754fc6f30a41184dafcf1060ac3a16f0cd30",
|
|
18
|
+
"references/architecture/connectors-sandbox.md": "5d410e4ec06463b6a51b941fdef768f22f8f62f132117d05a10d125822248621",
|
|
19
|
+
"references/architecture/data-memory.md": "3d2ccbcd90a00dddda7096877c874d4fa7b61b96e2e4061c3c82b40bd990cf19",
|
|
20
|
+
"references/architecture/delivery-operations.md": "2988ae173517faaaff325d39c2881f854663a0386f073475b479a66bb8c69008",
|
|
21
|
+
"references/architecture/durable-execution.md": "a26420ca9fac928597e09ad88aefa221034fef597113335537328e8c9c4df8ea",
|
|
22
|
+
"references/architecture/flutter.md": "434365ff03620b192444af2052f723fb2cb05ffe702894292aaeca72b19b3da0",
|
|
23
|
+
"references/architecture/foundation.md": "bd6eb424139e82f84a7787bd1f23e8206c78fd85e80d81a0f57796f55d8c8b6e",
|
|
24
|
+
"references/architecture/hosting-reliability.md": "10d9a3a82f688c1acd1a1c9a3fbcdcb516217ce446ea09b2fe326b0a8e93b015",
|
|
25
|
+
"references/architecture/identity-tenancy.md": "8c6acc3ec474072d92de59465d6d528c8ca247507ca158f492f405f63b863723",
|
|
26
|
+
"references/architecture/model-lifecycle.md": "061f79418e732cd32efca703f0a6f7c04132ddc8063b2719ce2e3af93efd575f",
|
|
27
|
+
"references/architecture/models-observability.md": "d81e0a8e26d9065f8e26b385a52fade1cf5cd9f82549e8586dd8396eabd0d203",
|
|
28
|
+
"references/architecture/realtime-channels.md": "a95738c431f3f4c8c42c153a0b940897bae8d679ed0c2dfced3cb1c4c9c67ca5",
|
|
29
|
+
"references/architecture/security-privacy.md": "68d00b7accf861664bf26acadd7e88af5bc64e78b04a4fe506932366945d39e5",
|
|
30
|
+
"references/architecture/topology-monorepo.md": "18763c997b924dbc915f49a69712cec95bf8a2e32c67901e12b515d90e698436",
|
|
31
|
+
"references/architecture/web.md": "7b1cf9f459de297c2eda6582ecf5af3727010b15cb31069ee5c424023c9109c4",
|
|
32
|
+
"references/control-catalog.json": "6d5135b4cc209bc9321e8946b6b8c46ddc04532dc4cfb798ed4d7eedbb12f64e",
|
|
33
|
+
"references/foundation-compatibility.json": "5f6c278e601f9221c55b049622da33c613ac274116d939dc479e800b09dbb7a5",
|
|
34
|
+
"references/golden-patterns.md": "0b00ece15e0ae20450d5c20409e7be34bab0d9b47c1614fb48cef780ca66605b",
|
|
35
|
+
"references/profile-governance.md": "14821377e0018072e3843da9d26001040c3b771b3ecf18052859ff77a967a97e",
|
|
36
|
+
"references/rule-model.json": "6429a29c3a106a9851f326dfc963483115a62a508a57772c586951f6726cf8e0",
|
|
37
|
+
"references/workflows.md": "e17858b8f41fddf47a40076e7add3fa7f10aa1dad87fb14f07fae108bc97d2de",
|
|
38
|
+
"refresh/REFRESH.md": "5f258f91e2deefcec2c403cff2b3241cdbdbb9e56f2af8b820789a34f0c030de",
|
|
39
|
+
"refresh/sources.json": "f5ada4bd5f9aab9697767b9ed1c35b44ec66603901e9192dda2c36a9f9e6f0f9",
|
|
40
|
+
"scripts/architecture-check.mjs": "37866fdfe4a6a5de3068144536ccfd8b1351c66793b57cf432ce1bf2444c52b4",
|
|
41
|
+
"scripts/lib.mjs": "ae0c8a324c960ba6af95054d0458e276d6122c835c3094500963078b2202c24b",
|
|
42
|
+
"scripts/profile-tool.mjs": "c79862b55935e2c472ea943c7365815a13b18c22d7783b9beee89b6b8cc1bb33",
|
|
43
|
+
"scripts/refresh-evidence.mjs": "04344be11367b1c60fb4ea2b56f50598c97394caae3227cd81560acb9411e85c",
|
|
44
|
+
"scripts/schema-validate.mjs": "329cca29ead284949107a5e0984588373522e9ef6624dffd18d4d207ef51fc99",
|
|
45
|
+
"scripts/validate-profile.mjs": "f823ce2a04b12f33e6c459e179453d988e5b7b1a888fbf00ad3ee36a18fa2ba7",
|
|
46
|
+
"scripts/verify-corpus.mjs": "d33d3f1717f988a45fe50477d5ad357a7c026abc75d3c1c23812d096b7dfe633"
|
|
47
|
+
}
|
|
48
|
+
}
|