@stacksjs/buddy 0.70.258 → 0.70.259
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/dist/cli.d.ts +11 -1
- package/dist/cli.js +5 -164
- package/dist/commands/about.js +1 -35
- package/dist/commands/add.js +1 -25
- package/dist/commands/ai-context.js +4 -27
- package/dist/commands/auth.js +1 -68
- package/dist/commands/build.js +1 -221
- package/dist/commands/cd.js +8 -39
- package/dist/commands/changelog.js +1 -32
- package/dist/commands/clean.js +1 -44
- package/dist/commands/cloud.js +2 -519
- package/dist/commands/commit.js +1 -16
- package/dist/commands/completion.js +6 -42
- package/dist/commands/config-migrate.js +6 -94
- package/dist/commands/configure.js +2 -45
- package/dist/commands/create.js +1 -162
- package/dist/commands/deploy.js +13 -1676
- package/dist/commands/desktop-apple.js +12 -399
- package/dist/commands/dev.js +6 -1083
- package/dist/commands/dns.js +3 -103
- package/dist/commands/docs/buddy-commands.js +10 -132
- package/dist/commands/docs/buddy-commands.test.js +1 -38
- package/dist/commands/docs/framework-repo.js +1 -14
- package/dist/commands/docs/framework-repo.test.js +1 -68
- package/dist/commands/docs/generated-artifacts.js +3 -70
- package/dist/commands/docs/generated-artifacts.test.js +1 -19
- package/dist/commands/docs/links.js +2 -85
- package/dist/commands/docs/links.test.js +4 -66
- package/dist/commands/docs.js +1 -24
- package/dist/commands/doctor.js +2 -478
- package/dist/commands/domains.js +2 -152
- package/dist/commands/email.js +31 -503
- package/dist/commands/env.js +1 -312
- package/dist/commands/extension.js +1 -239
- package/dist/commands/features.js +9 -345
- package/dist/commands/fresh.js +1 -46
- package/dist/commands/generate.js +2 -152
- package/dist/commands/http.js +1 -33
- package/dist/commands/index.js +1 -57
- package/dist/commands/install.js +1 -22
- package/dist/commands/key.js +1 -23
- package/dist/commands/link.js +2 -147
- package/dist/commands/lint.js +2 -84
- package/dist/commands/list.js +1 -140
- package/dist/commands/mail.js +15 -1477
- package/dist/commands/maintenance.js +1 -141
- package/dist/commands/make.js +1 -392
- package/dist/commands/migrate-project.js +1 -49
- package/dist/commands/migrate.js +27 -625
- package/dist/commands/outdated.js +1 -19
- package/dist/commands/package.js +1 -17
- package/dist/commands/phone.js +17 -181
- package/dist/commands/ports.js +2 -118
- package/dist/commands/prepublish.js +1 -17
- package/dist/commands/projects.js +1 -29
- package/dist/commands/protocol/craft-evidence.js +4 -98
- package/dist/commands/protocol/craft-evidence.test.js +1 -20
- package/dist/commands/protocol/desktop-lifecycle-report.js +3 -57
- package/dist/commands/protocol/desktop-lifecycle-report.test.js +1 -32
- package/dist/commands/protocol/desktop-support.js +2 -32
- package/dist/commands/protocol/desktop-workflow.test.js +3 -35
- package/dist/commands/protocol/driver-registry.js +2 -71
- package/dist/commands/protocol/pantry-evidence.js +4 -144
- package/dist/commands/protocol/pantry-evidence.test.js +1 -29
- package/dist/commands/protocol/release-manifest.js +3 -102
- package/dist/commands/protocol/release-manifest.test.js +2 -34
- package/dist/commands/protocol/run-conformance.js +4 -346
- package/dist/commands/protocol/run-conformance.test.js +1 -52
- package/dist/commands/protocol/run-driver-contracts.js +4 -83
- package/dist/commands/protocol/run-driver-contracts.test.js +1 -18
- package/dist/commands/protocol/source-manifest.js +3 -113
- package/dist/commands/protocol/sync-suite.js +3 -136
- package/dist/commands/protocol/sync-suite.test.js +1 -44
- package/dist/commands/protocol.js +1 -60
- package/dist/commands/publish.js +8 -500
- package/dist/commands/queue.js +1 -248
- package/dist/commands/release.js +1 -42
- package/dist/commands/route.js +1 -21
- package/dist/commands/run-tool.js +1 -9
- package/dist/commands/saas.js +1 -25
- package/dist/commands/schedule.js +1 -61
- package/dist/commands/search.js +1 -84
- package/dist/commands/seed.js +1 -47
- package/dist/commands/serve.js +1 -55
- package/dist/commands/setup-ai.js +2 -121
- package/dist/commands/setup.js +2 -305
- package/dist/commands/share.js +1 -214
- package/dist/commands/sms.js +32 -319
- package/dist/commands/stacks.js +1 -72
- package/dist/commands/telemetry.js +1 -74
- package/dist/commands/test.js +1 -130
- package/dist/commands/tinker.js +1 -37
- package/dist/commands/types.js +1 -18
- package/dist/commands/upgrade.js +1 -98
- package/dist/commands/user.js +3 -84
- package/dist/commands/version.js +1 -14
- package/dist/config.js +1 -231
- package/dist/custom-cli.js +1 -23
- package/dist/database-preflight.js +1 -88
- package/dist/global-options.js +1 -4
- package/dist/index.js +1 -1
- package/dist/lazy-commands.js +1 -241
- package/dist/migrators/index.js +2 -62
- package/dist/migrators/laravel/index.js +1 -148
- package/dist/migrators/laravel/migrations.js +4 -231
- package/dist/migrators/laravel/models.js +8 -111
- package/dist/migrators/rails/index.js +1 -11
- package/dist/production-server.js +1 -257
- package/dist/project-setup.js +1 -36
- package/dist/serve-entry.js +1 -5
- package/dist/version-info.js +1 -5
- package/package.json +53 -46
|
@@ -1,113 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import { dirname, extname, resolve } from "node:path";
|
|
5
|
-
const root = resolve(import.meta.dir, "../../../../../../.."), outputPath = resolve(root, ".github/protocol/evidence/source-manifest.json");
|
|
6
|
-
function runGit(...arguments_) {
|
|
7
|
-
try {
|
|
8
|
-
return execFileSync("git", arguments_, { cwd: root, maxBuffer: 67108864 });
|
|
9
|
-
} catch (error) {
|
|
10
|
-
throw Error(`git ${arguments_.join(" ")} failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
function revision(value) {
|
|
14
|
-
return runGit("rev-parse", `${value}^{commit}`).toString().trim();
|
|
15
|
-
}
|
|
16
|
-
function showJson(sourceRevision, path) {
|
|
17
|
-
return JSON.parse(runGit("show", `${sourceRevision}:${path}`).toString());
|
|
18
|
-
}
|
|
19
|
-
function category(path) {
|
|
20
|
-
if (/(^|\/)(test|tests|__tests__)(\/|$)|\.(test|spec)\.[^.]+$/.test(path))
|
|
21
|
-
return "tests";
|
|
22
|
-
if (path.startsWith(".github/protocol/suite/"))
|
|
23
|
-
return "vendored-protocol";
|
|
24
|
-
if (/(^|\/)(dist|generated|coverage)(\/|$)|\.d\.ts$/.test(path))
|
|
25
|
-
return "generated";
|
|
26
|
-
if (/\.(md|mdx|rst|txt)$/.test(path) || /(^|\/)docs\//.test(path))
|
|
27
|
-
return "documentation";
|
|
28
|
-
if (/(^|\/)(config|configs|\.github)(\/|$)|(^|\/)(tsconfig|package|bun\.lock|pantry)\b/.test(path))
|
|
29
|
-
return "configuration";
|
|
30
|
-
if (/\.(ts|tsx|js|jsx|vue|svelte|zig|rs|go|py|sh)$/.test(path))
|
|
31
|
-
return "source";
|
|
32
|
-
return "assets-and-data";
|
|
33
|
-
}
|
|
34
|
-
function addCount(record, key, bytes) {
|
|
35
|
-
const current = record[key] || { files: 0, bytes: 0 };
|
|
36
|
-
record[key] = { files: current.files + 1, bytes: current.bytes + bytes };
|
|
37
|
-
}
|
|
38
|
-
export function buildSourceManifest(requestedRevision) {
|
|
39
|
-
const sourceRevision = revision(requestedRevision), sourceTree = runGit("rev-parse", `${sourceRevision}^{tree}`).toString().trim(), treeListing = runGit("ls-tree", "-r", "-l", sourceRevision).toString(), lines = treeListing.trim().split(`
|
|
40
|
-
`).filter(Boolean), categories = {}, extensions = {};
|
|
41
|
-
let totalBytes = 0;
|
|
42
|
-
const paths = [];
|
|
43
|
-
for (const line of lines) {
|
|
44
|
-
const match = line.match(/^\d+\s+blob\s+[0-9a-f]+\s+(\d+)\t(.+)$/);
|
|
45
|
-
if (!match)
|
|
46
|
-
continue;
|
|
47
|
-
const bytes = Number(match[1]), path = match[2];
|
|
48
|
-
if (path == null)
|
|
49
|
-
continue;
|
|
50
|
-
paths.push(path);
|
|
51
|
-
totalBytes += bytes;
|
|
52
|
-
addCount(categories, category(path), bytes);
|
|
53
|
-
const extension = extname(path).toLowerCase() || "[none]";
|
|
54
|
-
extensions[extension] = (extensions[extension] || 0) + 1;
|
|
55
|
-
}
|
|
56
|
-
const packages = paths.filter((path) => path === "package.json" || path.endsWith("/package.json")).flatMap((path) => {
|
|
57
|
-
const pkg = showJson(sourceRevision, path);
|
|
58
|
-
if (!pkg.name || !pkg.version)
|
|
59
|
-
return [];
|
|
60
|
-
return [{ name: pkg.name, path, version: pkg.version, publishable: pkg.private !== !0 }];
|
|
61
|
-
}).sort((a, b) => a.name.localeCompare(b.name) || a.path.localeCompare(b.path)), rootPackage = showJson(sourceRevision, "package.json"), suiteLock = showJson(sourceRevision, ".github/protocol/suite.lock.json");
|
|
62
|
-
return {
|
|
63
|
-
schemaVersion: "1.0.0",
|
|
64
|
-
repository: "https://github.com/stacksjs/stacks",
|
|
65
|
-
sourceRevision,
|
|
66
|
-
sourceTree,
|
|
67
|
-
sourceDigest: `sha256:${createHash("sha256").update(treeListing).digest("hex")}`,
|
|
68
|
-
generatedAt: "derived-from-immutable-git-objects",
|
|
69
|
-
classification: {
|
|
70
|
-
status: "reference-implementation",
|
|
71
|
-
conformance: "unverified",
|
|
72
|
-
notes: "Reference implementation status does not imply a protocol profile claim; consult the report for per-requirement evidence."
|
|
73
|
-
},
|
|
74
|
-
prerequisites: rootPackage.system || {},
|
|
75
|
-
packages,
|
|
76
|
-
inventory: {
|
|
77
|
-
totalFiles: lines.length,
|
|
78
|
-
totalBytes,
|
|
79
|
-
categories: Object.fromEntries(Object.entries(categories).sort(([a], [b]) => a.localeCompare(b))),
|
|
80
|
-
extensions: Object.fromEntries(Object.entries(extensions).sort(([a], [b]) => a.localeCompare(b)))
|
|
81
|
-
},
|
|
82
|
-
protocolSuite: { version: suiteLock.protocolVersion, rfcsRevision: suiteLock.rfcsRevision }
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
function render(manifest) {
|
|
86
|
-
return `${JSON.stringify(manifest, null, 2)}
|
|
87
|
-
`;
|
|
88
|
-
}
|
|
89
|
-
export async function run() {
|
|
90
|
-
const mode = process.argv.includes("--write") ? "write" : process.argv.includes("--check") ? "check" : null;
|
|
91
|
-
if (!mode) {
|
|
92
|
-
console.error("usage: bun storage/framework/core/buddy/src/commands/protocol/source-manifest.ts --write [--revision <ref>] | --check");
|
|
93
|
-
process.exit(2);
|
|
94
|
-
}
|
|
95
|
-
if (mode === "write") {
|
|
96
|
-
const index = process.argv.indexOf("--revision"), requestedRevision = index === -1 ? "HEAD" : process.argv[index + 1];
|
|
97
|
-
if (!requestedRevision)
|
|
98
|
-
throw Error("--revision requires a Git ref");
|
|
99
|
-
const manifest = buildSourceManifest(requestedRevision);
|
|
100
|
-
mkdirSync(dirname(outputPath), { recursive: !0 });
|
|
101
|
-
writeFileSync(outputPath, render(manifest));
|
|
102
|
-
console.log(`Wrote source manifest for ${manifest.sourceRevision} (${manifest.inventory.totalFiles} files, ${manifest.packages.length} packages)`);
|
|
103
|
-
} else {
|
|
104
|
-
if (!existsSync(outputPath))
|
|
105
|
-
throw Error("source manifest is missing; run bun run protocol:manifest");
|
|
106
|
-
const current = JSON.parse(readFileSync(outputPath, "utf8")), expected = render(buildSourceManifest(current.sourceRevision));
|
|
107
|
-
if (readFileSync(outputPath, "utf8") !== expected)
|
|
108
|
-
throw Error(`source manifest is stale or modified; run bun storage/framework/core/buddy/src/commands/protocol/source-manifest.ts --write --revision ${current.sourceRevision}`);
|
|
109
|
-
console.log(`Source manifest matches ${current.sourceRevision}`);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
if (import.meta.main)
|
|
113
|
-
await run();
|
|
1
|
+
import{createHash}from"node:crypto";import{execFileSync}from"node:child_process";import{existsSync,mkdirSync,readFileSync,writeFileSync}from"node:fs";import{dirname,extname,resolve}from"node:path";const root=resolve(import.meta.dir,"../../../../../../.."),outputPath=resolve(root,".github/protocol/evidence/source-manifest.json");function runGit(...arguments_){try{return execFileSync("git",arguments_,{cwd:root,maxBuffer:67108864})}catch(error){throw Error(`git ${arguments_.join(" ")} failed: ${error instanceof Error?error.message:String(error)}`)}}function revision(value){return runGit("rev-parse",`${value}^{commit}`).toString().trim()}function showJson(sourceRevision,path){return JSON.parse(runGit("show",`${sourceRevision}:${path}`).toString())}function category(path){if(/(^|\/)(test|tests|__tests__)(\/|$)|\.(test|spec)\.[^.]+$/.test(path))return"tests";if(path.startsWith(".github/protocol/suite/"))return"vendored-protocol";if(/(^|\/)(dist|generated|coverage)(\/|$)|\.d\.ts$/.test(path))return"generated";if(/\.(md|mdx|rst|txt)$/.test(path)||/(^|\/)docs\//.test(path))return"documentation";if(/(^|\/)(config|configs|\.github)(\/|$)|(^|\/)(tsconfig|package|bun\.lock|pantry)\b/.test(path))return"configuration";if(/\.(ts|tsx|js|jsx|vue|svelte|zig|rs|go|py|sh)$/.test(path))return"source";return"assets-and-data"}function addCount(record,key,bytes){const current=record[key]||{files:0,bytes:0};record[key]={files:current.files+1,bytes:current.bytes+bytes}}export function buildSourceManifest(requestedRevision){const sourceRevision=revision(requestedRevision),sourceTree=runGit("rev-parse",`${sourceRevision}^{tree}`).toString().trim(),treeListing=runGit("ls-tree","-r","-l",sourceRevision).toString(),lines=treeListing.trim().split(`
|
|
2
|
+
`).filter(Boolean),categories={},extensions={};let totalBytes=0;const paths=[];for(const line of lines){const match=line.match(/^\d+\s+blob\s+[0-9a-f]+\s+(\d+)\t(.+)$/);if(!match)continue;const bytes=Number(match[1]),path=match[2];if(path==null)continue;paths.push(path);totalBytes+=bytes;addCount(categories,category(path),bytes);const extension=extname(path).toLowerCase()||"[none]";extensions[extension]=(extensions[extension]||0)+1}const packages=paths.filter((path)=>path==="package.json"||path.endsWith("/package.json")).flatMap((path)=>{const pkg=showJson(sourceRevision,path);if(!pkg.name||!pkg.version)return[];return[{name:pkg.name,path,version:pkg.version,publishable:pkg.private!==!0}]}).sort((a,b)=>a.name.localeCompare(b.name)||a.path.localeCompare(b.path)),rootPackage=showJson(sourceRevision,"package.json"),suiteLock=showJson(sourceRevision,".github/protocol/suite.lock.json");return{schemaVersion:"1.0.0",repository:"https://github.com/stacksjs/stacks",sourceRevision,sourceTree,sourceDigest:`sha256:${createHash("sha256").update(treeListing).digest("hex")}`,generatedAt:"derived-from-immutable-git-objects",classification:{status:"reference-implementation",conformance:"unverified",notes:"Reference implementation status does not imply a protocol profile claim; consult the report for per-requirement evidence."},prerequisites:rootPackage.system||{},packages,inventory:{totalFiles:lines.length,totalBytes,categories:Object.fromEntries(Object.entries(categories).sort(([a],[b])=>a.localeCompare(b))),extensions:Object.fromEntries(Object.entries(extensions).sort(([a],[b])=>a.localeCompare(b)))},protocolSuite:{version:suiteLock.protocolVersion,rfcsRevision:suiteLock.rfcsRevision}}}function render(manifest){return`${JSON.stringify(manifest,null,2)}
|
|
3
|
+
`}export async function run(){const mode=process.argv.includes("--write")?"write":process.argv.includes("--check")?"check":null;if(!mode){console.error("usage: bun storage/framework/core/buddy/src/commands/protocol/source-manifest.ts --write [--revision <ref>] | --check");process.exit(2)}if(mode==="write"){const index=process.argv.indexOf("--revision"),requestedRevision=index===-1?"HEAD":process.argv[index+1];if(!requestedRevision)throw Error("--revision requires a Git ref");const manifest=buildSourceManifest(requestedRevision);mkdirSync(dirname(outputPath),{recursive:!0});writeFileSync(outputPath,render(manifest));console.log(`Wrote source manifest for ${manifest.sourceRevision} (${manifest.inventory.totalFiles} files, ${manifest.packages.length} packages)`)}else{if(!existsSync(outputPath))throw Error("source manifest is missing; run bun run protocol:manifest");const current=JSON.parse(readFileSync(outputPath,"utf8")),expected=render(buildSourceManifest(current.sourceRevision));if(readFileSync(outputPath,"utf8")!==expected)throw Error(`source manifest is stale or modified; run bun storage/framework/core/buddy/src/commands/protocol/source-manifest.ts --write --revision ${current.sourceRevision}`);console.log(`Source manifest matches ${current.sourceRevision}`)}}if(import.meta.main)await run();
|
|
@@ -1,137 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
import { basename, dirname, relative, resolve } from "node:path";
|
|
4
|
-
const root = resolve(import.meta.dir, "../../../../../../.."), suiteRoot = resolve(root, ".github/protocol/suite/1.0-draft"), lockPath = resolve(root, ".github/protocol/suite.lock.json");
|
|
5
|
-
function digest(data) {
|
|
6
|
-
return `sha256:${createHash("sha256").update(data).digest("hex")}`;
|
|
7
|
-
}
|
|
8
|
-
function filesBelow(directory) {
|
|
9
|
-
return readdirSync(directory, { withFileTypes: !0 }).flatMap((entry) => {
|
|
10
|
-
const path = resolve(directory, entry.name);
|
|
11
|
-
return entry.isDirectory() ? filesBelow(path) : [path];
|
|
12
|
-
}).sort();
|
|
13
|
-
}
|
|
14
|
-
function argument(name) {
|
|
15
|
-
const index = process.argv.indexOf(name);
|
|
16
|
-
return index === -1 ? void 0 : process.argv[index + 1];
|
|
17
|
-
}
|
|
18
|
-
function gitRevision(repository) {
|
|
19
|
-
const result = Bun.spawnSync(["git", "-C", repository, "rev-parse", "HEAD"]);
|
|
20
|
-
if (result.exitCode !== 0)
|
|
21
|
-
throw Error(`Could not resolve the RFC repository revision: ${result.stderr.toString().trim()}`);
|
|
22
|
-
return result.stdout.toString().trim();
|
|
23
|
-
}
|
|
24
|
-
function writeSnapshot(sourceRepository) {
|
|
25
|
-
const sourceRoot = resolve(sourceRepository, "protocol/1.0-draft");
|
|
26
|
-
if (!existsSync(resolve(sourceRoot, "catalog.json")))
|
|
27
|
-
throw Error(`No protocol suite found at ${sourceRoot}`);
|
|
28
|
-
rmSync(suiteRoot, { force: !0, recursive: !0 });
|
|
29
|
-
const files = {}, sourceFiles = [
|
|
30
|
-
...filesBelow(sourceRoot).map((sourcePath) => ({ sourcePath, path: relative(sourceRoot, sourcePath) })),
|
|
31
|
-
...["LICENSE-SPECIFICATION.md", "LICENSE-FIXTURES.md"].map((path) => ({ sourcePath: resolve(sourceRepository, path), path }))
|
|
32
|
-
];
|
|
33
|
-
for (const { sourcePath, path } of sourceFiles) {
|
|
34
|
-
const outputPath = resolve(suiteRoot, path), contents = readFileSync(sourcePath);
|
|
35
|
-
mkdirSync(dirname(outputPath), { recursive: !0 });
|
|
36
|
-
writeFileSync(outputPath, contents);
|
|
37
|
-
files[path] = digest(contents);
|
|
38
|
-
}
|
|
39
|
-
const lock = {
|
|
40
|
-
protocolVersion: "1.0-draft",
|
|
41
|
-
rfcsRevision: gitRevision(sourceRepository),
|
|
42
|
-
sourceRepository: "https://github.com/stacksjs/rfcs",
|
|
43
|
-
files
|
|
44
|
-
};
|
|
45
|
-
mkdirSync(dirname(lockPath), { recursive: !0 });
|
|
46
|
-
writeFileSync(lockPath, `${JSON.stringify(lock, null, 2)}
|
|
47
|
-
`);
|
|
48
|
-
console.log(`Pinned ${Object.keys(files).length} protocol files at ${lock.rfcsRevision}`);
|
|
49
|
-
}
|
|
50
|
-
function checkSnapshot() {
|
|
51
|
-
if (!existsSync(lockPath))
|
|
52
|
-
throw Error(".github/protocol/suite.lock.json is missing; run bun run protocol:sync");
|
|
53
|
-
const lock = JSON.parse(readFileSync(lockPath, "utf8"));
|
|
54
|
-
if (!/^[0-9a-f]{40}$/.test(lock.rfcsRevision))
|
|
55
|
-
throw Error("suite lock has an invalid RFC revision");
|
|
56
|
-
const actualFiles = filesBelow(suiteRoot).map((path) => relative(suiteRoot, path)), expectedFiles = Object.keys(lock.files).sort(), unexpected = actualFiles.filter((path) => !lock.files[path]), missing = expectedFiles.filter((path) => !actualFiles.includes(path)), changed = expectedFiles.filter((path) => {
|
|
57
|
-
const absolutePath = resolve(suiteRoot, path);
|
|
58
|
-
return existsSync(absolutePath) && digest(readFileSync(absolutePath)) !== lock.files[path];
|
|
59
|
-
}), errors = [
|
|
60
|
-
...missing.map((path) => `missing: ${path}`),
|
|
61
|
-
...unexpected.map((path) => `unexpected: ${path}`),
|
|
62
|
-
...changed.map((path) => `modified: ${path}`)
|
|
63
|
-
];
|
|
64
|
-
if (errors.length > 0)
|
|
65
|
-
throw Error(`Vendored protocol suite does not match its lock:
|
|
1
|
+
import{createHash}from"node:crypto";import{existsSync,mkdirSync,readFileSync,readdirSync,rmSync,writeFileSync}from"node:fs";import{basename,dirname,relative,resolve}from"node:path";const root=resolve(import.meta.dir,"../../../../../../.."),suiteRoot=resolve(root,".github/protocol/suite/1.0-draft"),lockPath=resolve(root,".github/protocol/suite.lock.json");function digest(data){return`sha256:${createHash("sha256").update(data).digest("hex")}`}function filesBelow(directory){return readdirSync(directory,{withFileTypes:!0}).flatMap((entry)=>{const path=resolve(directory,entry.name);return entry.isDirectory()?filesBelow(path):[path]}).sort()}function argument(name){const index=process.argv.indexOf(name);return index===-1?void 0:process.argv[index+1]}function gitRevision(repository){const result=Bun.spawnSync(["git","-C",repository,"rev-parse","HEAD"]);if(result.exitCode!==0)throw Error(`Could not resolve the RFC repository revision: ${result.stderr.toString().trim()}`);return result.stdout.toString().trim()}function writeSnapshot(sourceRepository){const sourceRoot=resolve(sourceRepository,"protocol/1.0-draft");if(!existsSync(resolve(sourceRoot,"catalog.json")))throw Error(`No protocol suite found at ${sourceRoot}`);rmSync(suiteRoot,{force:!0,recursive:!0});const files={},sourceFiles=[...filesBelow(sourceRoot).map((sourcePath)=>({sourcePath,path:relative(sourceRoot,sourcePath)})),...["LICENSE-SPECIFICATION.md","LICENSE-FIXTURES.md"].map((path)=>({sourcePath:resolve(sourceRepository,path),path}))];for(const{sourcePath,path}of sourceFiles){const outputPath=resolve(suiteRoot,path),contents=readFileSync(sourcePath);mkdirSync(dirname(outputPath),{recursive:!0});writeFileSync(outputPath,contents);files[path]=digest(contents)}const lock={protocolVersion:"1.0-draft",rfcsRevision:gitRevision(sourceRepository),sourceRepository:"https://github.com/stacksjs/rfcs",files};mkdirSync(dirname(lockPath),{recursive:!0});writeFileSync(lockPath,`${JSON.stringify(lock,null,2)}
|
|
2
|
+
`);console.log(`Pinned ${Object.keys(files).length} protocol files at ${lock.rfcsRevision}`)}function checkSnapshot(){if(!existsSync(lockPath))throw Error(".github/protocol/suite.lock.json is missing; run bun run protocol:sync");const lock=JSON.parse(readFileSync(lockPath,"utf8"));if(!/^[0-9a-f]{40}$/.test(lock.rfcsRevision))throw Error("suite lock has an invalid RFC revision");const actualFiles=filesBelow(suiteRoot).map((path)=>relative(suiteRoot,path)),expectedFiles=Object.keys(lock.files).sort(),unexpected=actualFiles.filter((path)=>!lock.files[path]),missing=expectedFiles.filter((path)=>!actualFiles.includes(path)),changed=expectedFiles.filter((path)=>{const absolutePath=resolve(suiteRoot,path);return existsSync(absolutePath)&&digest(readFileSync(absolutePath))!==lock.files[path]}),errors=[...missing.map((path)=>`missing: ${path}`),...unexpected.map((path)=>`unexpected: ${path}`),...changed.map((path)=>`modified: ${path}`)];if(errors.length>0)throw Error(`Vendored protocol suite does not match its lock:
|
|
66
3
|
${errors.join(`
|
|
67
|
-
`)}`);
|
|
68
|
-
console.log(`Protocol suite matches ${basename(lock.sourceRepository)}@${lock.rfcsRevision} (${actualFiles.length} files)`);
|
|
69
|
-
}
|
|
70
|
-
export function duplicateRequirementIds(ids) {
|
|
71
|
-
const seen = new Set, duplicates = new Set;
|
|
72
|
-
for (const id of ids)
|
|
73
|
-
if (seen.has(id))
|
|
74
|
-
duplicates.add(id);
|
|
75
|
-
else
|
|
76
|
-
seen.add(id);
|
|
77
|
-
return [...duplicates].sort();
|
|
78
|
-
}
|
|
79
|
-
function checkCatalog() {
|
|
80
|
-
const catalogPath = resolve(suiteRoot, "catalog.json");
|
|
81
|
-
if (!existsSync(catalogPath))
|
|
82
|
-
throw Error(`protocol catalog missing at ${relative(root, catalogPath)}; run bun run protocol:sync`);
|
|
83
|
-
const catalog = JSON.parse(readFileSync(catalogPath, "utf8")), requirements = Array.isArray(catalog.requirements) ? catalog.requirements : [];
|
|
84
|
-
if (requirements.length === 0)
|
|
85
|
-
throw Error("protocol catalog has no requirements");
|
|
86
|
-
const ids = requirements.map((requirement) => requirement?.id), missing = ids.filter((id) => typeof id !== "string" || id.length === 0).length;
|
|
87
|
-
if (missing > 0)
|
|
88
|
-
throw Error(`protocol catalog has ${missing} requirement(s) without a string id`);
|
|
89
|
-
const duplicates = duplicateRequirementIds(ids);
|
|
90
|
-
if (duplicates.length > 0)
|
|
91
|
-
throw Error(`protocol catalog has duplicate requirement id(s): ${duplicates.join(", ")}`);
|
|
92
|
-
console.log(`Protocol catalog: ${ids.length} requirement ids, all unique`);
|
|
93
|
-
}
|
|
94
|
-
export function danglingFixtureRequirements(fixtures, catalogIds) {
|
|
95
|
-
const dangling = [];
|
|
96
|
-
for (const fixture of fixtures)
|
|
97
|
-
for (const requirement of fixture.requirements ?? [])
|
|
98
|
-
if (!catalogIds.has(requirement))
|
|
99
|
-
dangling.push(`${fixture.id} -> ${requirement}`);
|
|
100
|
-
return dangling;
|
|
101
|
-
}
|
|
102
|
-
function checkFixtures() {
|
|
103
|
-
const fixturesPath = resolve(suiteRoot, "fixtures/conformance.json");
|
|
104
|
-
if (!existsSync(fixturesPath))
|
|
105
|
-
throw Error(`protocol fixture corpus missing at ${relative(root, fixturesPath)}; run bun run protocol:sync`);
|
|
106
|
-
const corpus = JSON.parse(readFileSync(fixturesPath, "utf8")), fixtures = Array.isArray(corpus.fixtures) ? corpus.fixtures : [];
|
|
107
|
-
if (fixtures.length === 0)
|
|
108
|
-
throw Error("protocol fixture corpus has no fixtures");
|
|
109
|
-
const ids = fixtures.map((fixture) => fixture?.id), missing = ids.filter((id) => typeof id !== "string" || id.length === 0).length;
|
|
110
|
-
if (missing > 0)
|
|
111
|
-
throw Error(`protocol fixture corpus has ${missing} fixture(s) without a string id`);
|
|
112
|
-
const duplicates = duplicateRequirementIds(ids);
|
|
113
|
-
if (duplicates.length > 0)
|
|
114
|
-
throw Error(`protocol fixture corpus has duplicate fixture id(s): ${duplicates.join(", ")}`);
|
|
115
|
-
const catalog = JSON.parse(readFileSync(resolve(suiteRoot, "catalog.json"), "utf8")), catalogIds = new Set((catalog.requirements ?? []).map((requirement) => requirement?.id).filter((id) => typeof id === "string")), normalized = fixtures.map((fixture) => ({
|
|
116
|
-
id: String(fixture?.id),
|
|
117
|
-
requirements: Array.isArray(fixture?.requirements) ? fixture.requirements.filter((requirement) => typeof requirement === "string") : []
|
|
118
|
-
})), dangling = danglingFixtureRequirements(normalized, catalogIds);
|
|
119
|
-
if (dangling.length > 0)
|
|
120
|
-
throw Error(`protocol fixtures reference unknown requirement id(s): ${dangling.slice(0, 10).join(", ")}`);
|
|
121
|
-
console.log(`Protocol fixtures: ${ids.length} fixtures, ids unique, all requirement refs resolve`);
|
|
122
|
-
}
|
|
123
|
-
export async function run() {
|
|
124
|
-
if (process.argv.includes("--write")) {
|
|
125
|
-
const source = resolve(argument("--source") || process.env.STACKS_RFC_SOURCE || resolve(root, "../rfcs"));
|
|
126
|
-
writeSnapshot(source);
|
|
127
|
-
} else if (process.argv.includes("--check")) {
|
|
128
|
-
checkSnapshot();
|
|
129
|
-
checkCatalog();
|
|
130
|
-
checkFixtures();
|
|
131
|
-
} else {
|
|
132
|
-
console.error("usage: bun storage/framework/core/buddy/src/commands/protocol/sync-suite.ts --write [--source ../rfcs] | --check");
|
|
133
|
-
process.exit(2);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
if (import.meta.main)
|
|
137
|
-
await run();
|
|
4
|
+
`)}`);console.log(`Protocol suite matches ${basename(lock.sourceRepository)}@${lock.rfcsRevision} (${actualFiles.length} files)`)}export function duplicateRequirementIds(ids){const seen=new Set,duplicates=new Set;for(const id of ids)if(seen.has(id))duplicates.add(id);else seen.add(id);return[...duplicates].sort()}function checkCatalog(){const catalogPath=resolve(suiteRoot,"catalog.json");if(!existsSync(catalogPath))throw Error(`protocol catalog missing at ${relative(root,catalogPath)}; run bun run protocol:sync`);const catalog=JSON.parse(readFileSync(catalogPath,"utf8")),requirements=Array.isArray(catalog.requirements)?catalog.requirements:[];if(requirements.length===0)throw Error("protocol catalog has no requirements");const ids=requirements.map((requirement)=>requirement?.id),missing=ids.filter((id)=>typeof id!=="string"||id.length===0).length;if(missing>0)throw Error(`protocol catalog has ${missing} requirement(s) without a string id`);const duplicates=duplicateRequirementIds(ids);if(duplicates.length>0)throw Error(`protocol catalog has duplicate requirement id(s): ${duplicates.join(", ")}`);console.log(`Protocol catalog: ${ids.length} requirement ids, all unique`)}export function danglingFixtureRequirements(fixtures,catalogIds){const dangling=[];for(const fixture of fixtures)for(const requirement of fixture.requirements??[])if(!catalogIds.has(requirement))dangling.push(`${fixture.id} -> ${requirement}`);return dangling}function checkFixtures(){const fixturesPath=resolve(suiteRoot,"fixtures/conformance.json");if(!existsSync(fixturesPath))throw Error(`protocol fixture corpus missing at ${relative(root,fixturesPath)}; run bun run protocol:sync`);const corpus=JSON.parse(readFileSync(fixturesPath,"utf8")),fixtures=Array.isArray(corpus.fixtures)?corpus.fixtures:[];if(fixtures.length===0)throw Error("protocol fixture corpus has no fixtures");const ids=fixtures.map((fixture)=>fixture?.id),missing=ids.filter((id)=>typeof id!=="string"||id.length===0).length;if(missing>0)throw Error(`protocol fixture corpus has ${missing} fixture(s) without a string id`);const duplicates=duplicateRequirementIds(ids);if(duplicates.length>0)throw Error(`protocol fixture corpus has duplicate fixture id(s): ${duplicates.join(", ")}`);const catalog=JSON.parse(readFileSync(resolve(suiteRoot,"catalog.json"),"utf8")),catalogIds=new Set((catalog.requirements??[]).map((requirement)=>requirement?.id).filter((id)=>typeof id==="string")),normalized=fixtures.map((fixture)=>({id:String(fixture?.id),requirements:Array.isArray(fixture?.requirements)?fixture.requirements.filter((requirement)=>typeof requirement==="string"):[]})),dangling=danglingFixtureRequirements(normalized,catalogIds);if(dangling.length>0)throw Error(`protocol fixtures reference unknown requirement id(s): ${dangling.slice(0,10).join(", ")}`);console.log(`Protocol fixtures: ${ids.length} fixtures, ids unique, all requirement refs resolve`)}export async function run(){if(process.argv.includes("--write")){const source=resolve(argument("--source")||process.env.STACKS_RFC_SOURCE||resolve(root,"../rfcs"));writeSnapshot(source)}else if(process.argv.includes("--check")){checkSnapshot();checkCatalog();checkFixtures()}else{console.error("usage: bun storage/framework/core/buddy/src/commands/protocol/sync-suite.ts --write [--source ../rfcs] | --check");process.exit(2)}}if(import.meta.main)await run();
|
|
@@ -1,44 +1 @@
|
|
|
1
|
-
import { readFileSync }
|
|
2
|
-
import { resolve } from "node:path";
|
|
3
|
-
import { describe, expect, it } from "bun:test";
|
|
4
|
-
import { danglingFixtureRequirements, duplicateRequirementIds } from "./sync-suite";
|
|
5
|
-
describe("protocol requirement-id uniqueness (stacksjs/stacks#2050)", () => {
|
|
6
|
-
it("reports no duplicates for a unique list", () => {
|
|
7
|
-
expect(duplicateRequirementIds(["CORE-CONV-01", "CORE-CONV-02", "CORE-MVA-01"])).toEqual([]);
|
|
8
|
-
});
|
|
9
|
-
it("reports each duplicated id once, sorted", () => {
|
|
10
|
-
expect(duplicateRequirementIds(["B-1", "A-1", "B-1", "A-1", "A-1", "C-1"])).toEqual(["A-1", "B-1"]);
|
|
11
|
-
});
|
|
12
|
-
it("handles an empty list", () => {
|
|
13
|
-
expect(duplicateRequirementIds([])).toEqual([]);
|
|
14
|
-
});
|
|
15
|
-
it("the vendored catalog.json has unique requirement ids", () => {
|
|
16
|
-
const ids = JSON.parse(readFileSync(resolve(import.meta.dir, "../../../../../../../.github/protocol/suite/1.0-draft/catalog.json"), "utf8")).requirements.map((requirement) => requirement.id);
|
|
17
|
-
expect(ids.length).toBeGreaterThan(0);
|
|
18
|
-
expect(duplicateRequirementIds(ids)).toEqual([]);
|
|
19
|
-
});
|
|
20
|
-
});
|
|
21
|
-
describe("protocol fixture-corpus integrity (stacksjs/stacks#2051)", () => {
|
|
22
|
-
const catalogIds = new Set(["CORE-CONV-01", "CORE-CONV-02", "CORE-MVA-01"]);
|
|
23
|
-
it("reports no dangling refs when every requirement resolves", () => {
|
|
24
|
-
expect(danglingFixtureRequirements([
|
|
25
|
-
{ id: "fixture.a", requirements: ["CORE-CONV-01", "CORE-CONV-02"] },
|
|
26
|
-
{ id: "fixture.b", requirements: ["CORE-MVA-01"] }
|
|
27
|
-
], catalogIds)).toEqual([]);
|
|
28
|
-
});
|
|
29
|
-
it("reports each unknown requirement ref as `fixture -> requirement`", () => {
|
|
30
|
-
expect(danglingFixtureRequirements([
|
|
31
|
-
{ id: "fixture.a", requirements: ["CORE-CONV-01", "CORE-GONE-99"] },
|
|
32
|
-
{ id: "fixture.b", requirements: ["NOPE-01"] }
|
|
33
|
-
], catalogIds)).toEqual(["fixture.a -> CORE-GONE-99", "fixture.b -> NOPE-01"]);
|
|
34
|
-
});
|
|
35
|
-
it("tolerates fixtures with no requirements", () => {
|
|
36
|
-
expect(danglingFixtureRequirements([{ id: "fixture.a" }], catalogIds)).toEqual([]);
|
|
37
|
-
});
|
|
38
|
-
it("the vendored fixture corpus has unique ids and no dangling requirement refs", () => {
|
|
39
|
-
const base = resolve(import.meta.dir, "../../../../../../../.github/protocol/suite/1.0-draft"), corpus = JSON.parse(readFileSync(resolve(base, "fixtures/conformance.json"), "utf8")), catalog = JSON.parse(readFileSync(resolve(base, "catalog.json"), "utf8")), realIds = new Set(catalog.requirements.map((requirement) => requirement.id));
|
|
40
|
-
expect(corpus.fixtures.length).toBeGreaterThan(0);
|
|
41
|
-
expect(duplicateRequirementIds(corpus.fixtures.map((fixture) => fixture.id))).toEqual([]);
|
|
42
|
-
expect(danglingFixtureRequirements(corpus.fixtures, realIds)).toEqual([]);
|
|
43
|
-
});
|
|
44
|
-
});
|
|
1
|
+
import{readFileSync}from"node:fs";import{resolve}from"node:path";import{describe,expect,it}from"bun:test";import{danglingFixtureRequirements,duplicateRequirementIds}from"./sync-suite";describe("protocol requirement-id uniqueness (stacksjs/stacks#2050)",()=>{it("reports no duplicates for a unique list",()=>{expect(duplicateRequirementIds(["CORE-CONV-01","CORE-CONV-02","CORE-MVA-01"])).toEqual([])});it("reports each duplicated id once, sorted",()=>{expect(duplicateRequirementIds(["B-1","A-1","B-1","A-1","A-1","C-1"])).toEqual(["A-1","B-1"])});it("handles an empty list",()=>{expect(duplicateRequirementIds([])).toEqual([])});it("the vendored catalog.json has unique requirement ids",()=>{const ids=JSON.parse(readFileSync(resolve(import.meta.dir,"../../../../../../../.github/protocol/suite/1.0-draft/catalog.json"),"utf8")).requirements.map((requirement)=>requirement.id);expect(ids.length).toBeGreaterThan(0);expect(duplicateRequirementIds(ids)).toEqual([])})});describe("protocol fixture-corpus integrity (stacksjs/stacks#2051)",()=>{const catalogIds=new Set(["CORE-CONV-01","CORE-CONV-02","CORE-MVA-01"]);it("reports no dangling refs when every requirement resolves",()=>{expect(danglingFixtureRequirements([{id:"fixture.a",requirements:["CORE-CONV-01","CORE-CONV-02"]},{id:"fixture.b",requirements:["CORE-MVA-01"]}],catalogIds)).toEqual([])});it("reports each unknown requirement ref as `fixture -> requirement`",()=>{expect(danglingFixtureRequirements([{id:"fixture.a",requirements:["CORE-CONV-01","CORE-GONE-99"]},{id:"fixture.b",requirements:["NOPE-01"]}],catalogIds)).toEqual(["fixture.a -> CORE-GONE-99","fixture.b -> NOPE-01"])});it("tolerates fixtures with no requirements",()=>{expect(danglingFixtureRequirements([{id:"fixture.a"}],catalogIds)).toEqual([])});it("the vendored fixture corpus has unique ids and no dangling requirement refs",()=>{const base=resolve(import.meta.dir,"../../../../../../../.github/protocol/suite/1.0-draft"),corpus=JSON.parse(readFileSync(resolve(base,"fixtures/conformance.json"),"utf8")),catalog=JSON.parse(readFileSync(resolve(base,"catalog.json"),"utf8")),realIds=new Set(catalog.requirements.map((requirement)=>requirement.id));expect(corpus.fixtures.length).toBeGreaterThan(0);expect(duplicateRequirementIds(corpus.fixtures.map((fixture)=>fixture.id))).toEqual([]);expect(danglingFixtureRequirements(corpus.fixtures,realIds)).toEqual([])})});
|
|
@@ -1,60 +1 @@
|
|
|
1
|
-
import { run as
|
|
2
|
-
import { run as runCraft } from "./protocol/craft-evidence";
|
|
3
|
-
import { run as runDesktop } from "./protocol/desktop-support";
|
|
4
|
-
import { run as runDrivers } from "./protocol/driver-registry";
|
|
5
|
-
import { run as runDriverContracts } from "./protocol/run-driver-contracts";
|
|
6
|
-
import { run as runPantry } from "./protocol/pantry-evidence";
|
|
7
|
-
import { run as runRelease } from "./protocol/release-manifest";
|
|
8
|
-
import { run as runManifest } from "./protocol/source-manifest";
|
|
9
|
-
import { run as runSync } from "./protocol/sync-suite";
|
|
10
|
-
import { runTool } from "./run-tool";
|
|
11
|
-
export function protocol(buddy) {
|
|
12
|
-
buddy.command("protocol:conformance", "Generate the Stacks protocol conformance report").action(async () => {
|
|
13
|
-
await runConformance();
|
|
14
|
-
});
|
|
15
|
-
buddy.command("protocol:sync", "Sync the vendored protocol suite from stacksjs/rfcs").option("--source <path>", "Path to a local rfcs checkout", { default: void 0 }).action(async (options) => {
|
|
16
|
-
await runTool(runSync, "--write", ...options.source ? ["--source", options.source] : []);
|
|
17
|
-
});
|
|
18
|
-
buddy.command("protocol:check", "Verify the vendored protocol suite is pinned + internally consistent").action(async () => {
|
|
19
|
-
await runTool(runSync, "--check");
|
|
20
|
-
});
|
|
21
|
-
buddy.command("protocol:manifest", "Write the protocol source manifest").option("--revision <ref>", "Source revision to pin (default HEAD)", { default: void 0 }).action(async (options) => {
|
|
22
|
-
await runTool(runManifest, "--write", ...options.revision ? ["--revision", options.revision] : []);
|
|
23
|
-
});
|
|
24
|
-
buddy.command("protocol:manifest:check", "Verify the protocol source manifest is current").action(async () => {
|
|
25
|
-
await runTool(runManifest, "--check");
|
|
26
|
-
});
|
|
27
|
-
buddy.command("protocol:release", "Write the protocol release manifest").option("--tag <tag>", "Release tag", { default: void 0 }).action(async (options) => {
|
|
28
|
-
await runTool(runRelease, "--write", ...options.tag ? ["--tag", options.tag] : []);
|
|
29
|
-
});
|
|
30
|
-
buddy.command("protocol:release:check", "Verify the protocol release manifest is current").action(async () => {
|
|
31
|
-
await runTool(runRelease, "--check");
|
|
32
|
-
});
|
|
33
|
-
buddy.command("protocol:drivers", "Write the driver capability registry evidence").action(async () => {
|
|
34
|
-
await runTool(runDrivers, "--write");
|
|
35
|
-
});
|
|
36
|
-
buddy.command("protocol:drivers:check", "Verify the driver capability registry evidence").action(async () => {
|
|
37
|
-
await runTool(runDrivers, "--check");
|
|
38
|
-
});
|
|
39
|
-
buddy.command("protocol:drivers:test", "Run the driver contract suite").action(async () => {
|
|
40
|
-
await runTool(runDriverContracts);
|
|
41
|
-
});
|
|
42
|
-
buddy.command("protocol:desktop", "Write the desktop support matrix evidence").action(async () => {
|
|
43
|
-
await runTool(runDesktop, "--write");
|
|
44
|
-
});
|
|
45
|
-
buddy.command("protocol:desktop:check", "Verify the desktop support matrix evidence").action(async () => {
|
|
46
|
-
await runTool(runDesktop, "--check");
|
|
47
|
-
});
|
|
48
|
-
buddy.command("protocol:pantry", "Write the pantry evidence").action(async () => {
|
|
49
|
-
await runTool(runPantry, "--write");
|
|
50
|
-
});
|
|
51
|
-
buddy.command("protocol:pantry:check", "Verify the pantry evidence").action(async () => {
|
|
52
|
-
await runTool(runPantry, "--check");
|
|
53
|
-
});
|
|
54
|
-
buddy.command("protocol:craft", "Write the Craft evidence").action(async () => {
|
|
55
|
-
await runTool(runCraft, "--write");
|
|
56
|
-
});
|
|
57
|
-
buddy.command("protocol:craft:check", "Verify the Craft evidence").action(async () => {
|
|
58
|
-
await runTool(runCraft, "--check");
|
|
59
|
-
});
|
|
60
|
-
}
|
|
1
|
+
import{run as runConformance}from"./protocol/run-conformance";import{run as runCraft}from"./protocol/craft-evidence";import{run as runDesktop}from"./protocol/desktop-support";import{run as runDrivers}from"./protocol/driver-registry";import{run as runDriverContracts}from"./protocol/run-driver-contracts";import{run as runPantry}from"./protocol/pantry-evidence";import{run as runRelease}from"./protocol/release-manifest";import{run as runManifest}from"./protocol/source-manifest";import{run as runSync}from"./protocol/sync-suite";import{runTool}from"./run-tool";export function protocol(buddy){buddy.command("protocol:conformance","Generate the Stacks protocol conformance report").action(async()=>{await runConformance()});buddy.command("protocol:sync","Sync the vendored protocol suite from stacksjs/rfcs").option("--source <path>","Path to a local rfcs checkout",{default:void 0}).action(async(options)=>{await runTool(runSync,"--write",...options.source?["--source",options.source]:[])});buddy.command("protocol:check","Verify the vendored protocol suite is pinned + internally consistent").action(async()=>{await runTool(runSync,"--check")});buddy.command("protocol:manifest","Write the protocol source manifest").option("--revision <ref>","Source revision to pin (default HEAD)",{default:void 0}).action(async(options)=>{await runTool(runManifest,"--write",...options.revision?["--revision",options.revision]:[])});buddy.command("protocol:manifest:check","Verify the protocol source manifest is current").action(async()=>{await runTool(runManifest,"--check")});buddy.command("protocol:release","Write the protocol release manifest").option("--tag <tag>","Release tag",{default:void 0}).action(async(options)=>{await runTool(runRelease,"--write",...options.tag?["--tag",options.tag]:[])});buddy.command("protocol:release:check","Verify the protocol release manifest is current").action(async()=>{await runTool(runRelease,"--check")});buddy.command("protocol:drivers","Write the driver capability registry evidence").action(async()=>{await runTool(runDrivers,"--write")});buddy.command("protocol:drivers:check","Verify the driver capability registry evidence").action(async()=>{await runTool(runDrivers,"--check")});buddy.command("protocol:drivers:test","Run the driver contract suite").action(async()=>{await runTool(runDriverContracts)});buddy.command("protocol:desktop","Write the desktop support matrix evidence").action(async()=>{await runTool(runDesktop,"--write")});buddy.command("protocol:desktop:check","Verify the desktop support matrix evidence").action(async()=>{await runTool(runDesktop,"--check")});buddy.command("protocol:pantry","Write the pantry evidence").action(async()=>{await runTool(runPantry,"--write")});buddy.command("protocol:pantry:check","Verify the pantry evidence").action(async()=>{await runTool(runPantry,"--check")});buddy.command("protocol:craft","Write the Craft evidence").action(async()=>{await runTool(runCraft,"--write")});buddy.command("protocol:craft:check","Verify the Craft evidence").action(async()=>{await runTool(runCraft,"--check")})}
|