@stacksjs/buddy 0.70.261 → 0.70.262
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/commands/index.d.ts +0 -1
- package/dist/commands/index.js +1 -1
- package/dist/lazy-commands.js +1 -1
- package/package.json +44 -44
- package/dist/commands/protocol/craft-evidence.d.ts +0 -76
- package/dist/commands/protocol/craft-evidence.js +0 -4
- package/dist/commands/protocol/craft-evidence.test.d.ts +0 -1
- package/dist/commands/protocol/craft-evidence.test.js +0 -1
- package/dist/commands/protocol/desktop-lifecycle-report.d.ts +0 -16
- package/dist/commands/protocol/desktop-lifecycle-report.js +0 -3
- package/dist/commands/protocol/desktop-lifecycle-report.test.d.ts +0 -1
- package/dist/commands/protocol/desktop-lifecycle-report.test.js +0 -1
- package/dist/commands/protocol/desktop-support.d.ts +0 -1
- package/dist/commands/protocol/desktop-support.js +0 -2
- package/dist/commands/protocol/desktop-workflow.test.d.ts +0 -1
- package/dist/commands/protocol/desktop-workflow.test.js +0 -3
- package/dist/commands/protocol/driver-registry.d.ts +0 -1
- package/dist/commands/protocol/driver-registry.js +0 -2
- package/dist/commands/protocol/pantry-evidence.d.ts +0 -67
- package/dist/commands/protocol/pantry-evidence.js +0 -4
- package/dist/commands/protocol/pantry-evidence.test.d.ts +0 -1
- package/dist/commands/protocol/pantry-evidence.test.js +0 -1
- package/dist/commands/protocol/release-manifest.d.ts +0 -30
- package/dist/commands/protocol/release-manifest.js +0 -3
- package/dist/commands/protocol/release-manifest.test.d.ts +0 -1
- package/dist/commands/protocol/release-manifest.test.js +0 -2
- package/dist/commands/protocol/run-conformance.d.ts +0 -21
- package/dist/commands/protocol/run-conformance.js +0 -16
- package/dist/commands/protocol/run-conformance.test.d.ts +0 -1
- package/dist/commands/protocol/run-conformance.test.js +0 -1
- package/dist/commands/protocol/run-driver-contracts.d.ts +0 -7
- package/dist/commands/protocol/run-driver-contracts.js +0 -15
- package/dist/commands/protocol/run-driver-contracts.test.d.ts +0 -1
- package/dist/commands/protocol/run-driver-contracts.test.js +0 -1
- package/dist/commands/protocol/source-manifest.d.ts +0 -25
- package/dist/commands/protocol/source-manifest.js +0 -3
- package/dist/commands/protocol/sync-suite.d.ts +0 -8
- package/dist/commands/protocol/sync-suite.js +0 -4
- package/dist/commands/protocol/sync-suite.test.d.ts +0 -1
- package/dist/commands/protocol/sync-suite.test.js +0 -1
- package/dist/commands/protocol.d.ts +0 -8
- package/dist/commands/protocol.js +0 -1
package/dist/commands/index.d.ts
CHANGED
package/dist/commands/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export*from"./about";export*from"./auth";export*from"./build";export*from"./cd";export*from"./changelog";export*from"./clean";export*from"./cloud";export*from"./commit";export*from"./completion";export*from"./config-migrate";export*from"./configure";export*from"./create";export*from"./deploy";export*from"./dev";export*from"./dns";export*from"./docs";export*from"./doctor";export*from"./domains";export*from"./email";export*from"./env";export*from"./features";export*from"./fresh";export*from"./generate";export*from"./http";export*from"./install";export*from"./key";export*from"./lint";export*from"./list";export*from"./mail";export*from"./make";export*from"./migrate";export*from"./migrate-project";export*from"./outdated";export*from"./phone";export*from"./ports";export*from"./link";export*from"./user";export*from"./prepublish";export*from"./projects";export*from"./
|
|
1
|
+
export*from"./about";export*from"./auth";export*from"./build";export*from"./cd";export*from"./changelog";export*from"./clean";export*from"./cloud";export*from"./commit";export*from"./completion";export*from"./config-migrate";export*from"./configure";export*from"./create";export*from"./deploy";export*from"./dev";export*from"./dns";export*from"./docs";export*from"./doctor";export*from"./domains";export*from"./email";export*from"./env";export*from"./features";export*from"./fresh";export*from"./generate";export*from"./http";export*from"./install";export*from"./key";export*from"./lint";export*from"./list";export*from"./mail";export*from"./make";export*from"./migrate";export*from"./migrate-project";export*from"./outdated";export*from"./phone";export*from"./ports";export*from"./link";export*from"./user";export*from"./prepublish";export*from"./projects";export*from"./publish";export*from"./queue";export*from"./release";export*from"./route";export*from"./saas";export*from"./schedule";export*from"./search";export*from"./seed";export*from"./serve";export*from"./setup";export*from"./sms";export*from"./telemetry";export*from"./test";export*from"./tinker";export*from"./types";export*from"./upgrade";export*from"./version";
|
package/dist/lazy-commands.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const commandRegistry={about:{path:"./commands/about.js",exportName:"about"},add:{path:"./commands/add.js",exportName:"add"},"ai:context":{path:"./commands/ai-context.js",exportName:"aiContext"},auth:{path:"./commands/auth.js",exportName:"auth"},build:{path:"./commands/build.js",exportName:"build"},cd:{path:"./commands/cd.js",exportName:"cd"},changelog:{path:"./commands/changelog.js",exportName:"changelog"},clean:{path:"./commands/clean.js",exportName:"clean"},cloud:{path:"./commands/cloud.js",exportName:"cloud"},commit:{path:"./commands/commit.js",exportName:"commit"},completion:{path:"./commands/completion.js",exportName:"completion"},"config:migrate":{path:"./commands/config-migrate.js",exportName:"configMigrate"},configure:{path:"./commands/configure.js",exportName:"configure"},create:{path:"./commands/create.js",exportName:"create"},new:{path:"./commands/create.js",exportName:"create"},deploy:{path:"./commands/deploy.js",exportName:"deploy"},dev:{path:"./commands/dev.js",exportName:"dev"},"desktop:apple:doctor":{path:"./commands/desktop-apple.js",exportName:"desktopApple"},"desktop:apple:csr":{path:"./commands/desktop-apple.js",exportName:"desktopApple"},"desktop:apple:init":{path:"./commands/desktop-apple.js",exportName:"desktopApple"},"desktop:apple:package":{path:"./commands/desktop-apple.js",exportName:"desktopApple"},"desktop:apple:provision":{path:"./commands/desktop-apple.js",exportName:"desktopApple"},"desktop:apple:publish":{path:"./commands/desktop-apple.js",exportName:"desktopApple"},dns:{path:"./commands/dns.js",exportName:"dns"},"dns:pull":{path:"./commands/dns.js",exportName:"dns"},"dns:diff":{path:"./commands/dns.js",exportName:"dns"},"dns:sync":{path:"./commands/dns.js",exportName:"dns"},doctor:{path:"./commands/doctor.js",exportName:"doctor"},domains:{path:"./commands/domains.js",exportName:"domains"},email:{path:"./commands/email.js",exportName:"email"},env:{path:"./commands/env.js",exportName:"env"},"extension:init":{path:"./commands/extension.js",exportName:"extension"},"extension:build":{path:"./commands/extension.js",exportName:"extension"},"extension:package":{path:"./commands/extension.js",exportName:"extension"},"extension:chrome:publish":{path:"./commands/extension.js",exportName:"extension"},"extension:chrome:status":{path:"./commands/extension.js",exportName:"extension"},"extension:firefox:publish":{path:"./commands/extension.js",exportName:"extension"},"extension:safari:init":{path:"./commands/extension.js",exportName:"extension"},"extension:safari:provision":{path:"./commands/extension.js",exportName:"extension"},"extension:safari:app":{path:"./commands/extension.js",exportName:"extension"},"extension:safari:publish":{path:"./commands/extension.js",exportName:"extension"},"dashboard:install":{path:"./commands/features.js",exportName:"features"},"dashboard:uninstall":{path:"./commands/features.js",exportName:"features"},"commerce:install":{path:"./commands/features.js",exportName:"features"},"commerce:uninstall":{path:"./commands/features.js",exportName:"features"},"cms:install":{path:"./commands/features.js",exportName:"features"},"cms:uninstall":{path:"./commands/features.js",exportName:"features"},"marketing:install":{path:"./commands/features.js",exportName:"features"},"marketing:uninstall":{path:"./commands/features.js",exportName:"features"},"monitoring:install":{path:"./commands/features.js",exportName:"features"},"monitoring:uninstall":{path:"./commands/features.js",exportName:"features"},"realtime:install":{path:"./commands/features.js",exportName:"features"},"realtime:uninstall":{path:"./commands/features.js",exportName:"features"},"queue:install":{path:"./commands/features.js",exportName:"features"},"queue:uninstall":{path:"./commands/features.js",exportName:"features"},fresh:{path:"./commands/fresh.js",exportName:"fresh"},generate:{path:"./commands/generate.js",exportName:"generate"},http:{path:"./commands/http.js",exportName:"http"},install:{path:"./commands/install.js",exportName:"install"},key:{path:"./commands/key.js",exportName:"key"},lint:{path:"./commands/lint.js",exportName:"lint"},format:{path:"./commands/lint.js",exportName:"lint"},"format:check":{path:"./commands/lint.js",exportName:"lint"},list:{path:"./commands/list.js",exportName:"list"},mail:{path:"./commands/mail.js",exportName:"mailCommands"},"mail:preview":{path:"./commands/mail.js",exportName:"mailCommands"},maintenance:{path:"./commands/maintenance.js",exportName:"maintenance"},down:{path:"./commands/maintenance.js",exportName:"maintenance"},up:{path:"./commands/maintenance.js",exportName:"maintenance"},status:{path:"./commands/maintenance.js",exportName:"maintenance"},"coming-soon":{path:"./commands/maintenance.js",exportName:"maintenance"},"coming-soon:status":{path:"./commands/maintenance.js",exportName:"maintenance"},launch:{path:"./commands/maintenance.js",exportName:"maintenance"},make:{path:"./commands/make.js",exportName:"make"},"scaffold:crud":{path:"./commands/make.js",exportName:"make"},migrate:{path:"./commands/migrate.js",exportName:"migrate"},"migrate:fresh":{path:"./commands/migrate.js",exportName:"migrate"},"migrate:switch":{path:"./commands/migrate.js",exportName:"migrate"},"migrate:dns":{path:"./commands/migrate.js",exportName:"migrate"},"migrate:project":{path:"./commands/migrate-project.js",exportName:"migrateProject"},outdated:{path:"./commands/outdated.js",exportName:"outdated"},package:{path:"./commands/package.js",exportName:"packageCommands"},phone:{path:"./commands/phone.js",exportName:"phone"},ports:{path:"./commands/ports.js",exportName:"ports"},"link:core":{path:"./commands/link.js",exportName:"link"},"user:add":{path:"./commands/user.js",exportName:"user"},"user:list":{path:"./commands/user.js",exportName:"user"},"unlink:core":{path:"./commands/link.js",exportName:"link"},prepublish:{path:"./commands/prepublish.js",exportName:"prepublish"},projects:{path:"./commands/projects.js",exportName:"projects"},publish:{path:"./commands/publish.js",exportName:"publish"},"publish:model":{path:"./commands/publish.js",exportName:"publish"},"publish:controller":{path:"./commands/publish.js",exportName:"publish"},"publish:middleware":{path:"./commands/publish.js",exportName:"publish"},"publish:action":{path:"./commands/publish.js",exportName:"publish"},"publish:core":{path:"./commands/publish.js",exportName:"publish"},"core:status":{path:"./commands/publish.js",exportName:"publish"},queue:{path:"./commands/queue.js",exportName:"queue"},release:{path:"./commands/release.js",exportName:"release"},route:{path:"./commands/route.js",exportName:"route"},saas:{path:"./commands/saas.js",exportName:"saas"},"stripe:setup":{path:"./commands/saas.js",exportName:"saas"},schedule:{path:"./commands/schedule.js",exportName:"schedule"},search:{path:"./commands/search.js",exportName:"search"},"search-engine:update":{path:"./commands/search.js",exportName:"search"},"search-engine:settings":{path:"./commands/search.js",exportName:"search"},seed:{path:"./commands/seed.js",exportName:"seed"},"seed:roles":{path:"./commands/seed.js",exportName:"seed"},"roles:seed":{path:"./commands/seed.js",exportName:"seed"},preview:{path:"./commands/serve.js",exportName:"preview"},serve:{path:"./commands/serve.js",exportName:"serve"},"serve:api":{path:"./commands/serve.js",exportName:"serveApi"},setup:{path:"./commands/setup.js",exportName:"setup"},"setup:ai":{path:"./commands/setup.js",exportName:"setup"},"setup:ssl":{path:"./commands/setup.js",exportName:"setup"},"setup:oh-my-zsh":{path:"./commands/setup.js",exportName:"setup"},"ai:setup":{path:"./commands/setup.js",exportName:"setup"},share:{path:"./commands/share.js",exportName:"share"},stack:{path:"./commands/stacks.js",exportName:"stacks"},sms:{path:"./commands/sms.js",exportName:"sms"},telemetry:{path:"./commands/telemetry.js",exportName:"telemetryCommand"},test:{path:"./commands/test.js",exportName:"test"},tinker:{path:"./commands/tinker.js",exportName:"tinker"},types:{path:"./commands/types.js",exportName:"types"},undeploy:{path:"./commands/cloud.js",exportName:"cloud"},upgrade:{path:"./commands/upgrade.js",exportName:"upgrade"},version:{path:"./commands/version.js",exportName:"version"},"protocol:conformance":{path:"./commands/protocol.js",exportName:"protocol"},"protocol:sync":{path:"./commands/protocol.js",exportName:"protocol"},"protocol:check":{path:"./commands/protocol.js",exportName:"protocol"},"protocol:manifest":{path:"./commands/protocol.js",exportName:"protocol"},"protocol:manifest:check":{path:"./commands/protocol.js",exportName:"protocol"},"protocol:release":{path:"./commands/protocol.js",exportName:"protocol"},"protocol:release:check":{path:"./commands/protocol.js",exportName:"protocol"},"protocol:drivers":{path:"./commands/protocol.js",exportName:"protocol"},"protocol:drivers:check":{path:"./commands/protocol.js",exportName:"protocol"},"protocol:drivers:test":{path:"./commands/protocol.js",exportName:"protocol"},"protocol:desktop":{path:"./commands/protocol.js",exportName:"protocol"},"protocol:desktop:check":{path:"./commands/protocol.js",exportName:"protocol"},"protocol:pantry":{path:"./commands/protocol.js",exportName:"protocol"},"protocol:pantry:check":{path:"./commands/protocol.js",exportName:"protocol"},"protocol:craft":{path:"./commands/protocol.js",exportName:"protocol"},"protocol:craft:check":{path:"./commands/protocol.js",exportName:"protocol"},"docs:buddy":{path:"./commands/docs.js",exportName:"docs"},"docs:buddy:check":{path:"./commands/docs.js",exportName:"docs"},"docs:artifacts":{path:"./commands/docs.js",exportName:"docs"},"docs:artifacts:check":{path:"./commands/docs.js",exportName:"docs"},"docs:links":{path:"./commands/docs.js",exportName:"docs"},"docs:links:check":{path:"./commands/docs.js",exportName:"docs"}},commandGroups={minimal:["version","help"],development:["dev","build","test","lint"],database:["migrate","seed","fresh"],scaffolding:["make","generate"],deployment:["deploy","release","cloud"],info:["about","doctor","list"]},loadedRegistrars=new WeakMap;function loaderKey(loader){return`${loader.path}#${loader.exportName}`}export function markLoaded(buddy,commandName){const loader=commandRegistry[commandName];if(!loader)return;let set=loadedRegistrars.get(buddy);if(!set){set=new Set;loadedRegistrars.set(buddy,set)}set.add(loaderKey(loader))}export async function loadCommand(commandName,buddy){const loader=commandRegistry[commandName];if(!loader)return!1;let set=loadedRegistrars.get(buddy);if(!set){set=new Set;loadedRegistrars.set(buddy,set)}const key=loaderKey(loader);if(set.has(key))return!0;set.add(key);try{const commandFunction=(await import(loader.path))[loader.exportName];if(typeof commandFunction==="function"){commandFunction(buddy);return!0}else return!1}catch{return!1}}export async function loadCommands(commandNames,buddy){const timeout=(ms)=>new Promise((_,reject)=>setTimeout(()=>reject(Error("timeout")),ms)),seen=new Set,unique=[];for(const name of commandNames){const loader=commandRegistry[name],key=loader?`${loader.path}#${loader.exportName}`:`name:${name}`;if(seen.has(key))continue;seen.add(key);unique.push(name)}await Promise.all(unique.map(async(name)=>{try{await Promise.race([loadCommand(name,buddy),timeout(5000)])}catch{}}))}export async function loadCommandGroup(groupName,buddy){const commands=commandGroups[groupName];if(commands)await loadCommands(commands,buddy)}export async function loadAllCommands(buddy){const allCommands=Object.keys(commandRegistry);await loadCommands(allCommands,buddy)}export function getCommandNames(){return Object.keys(commandRegistry)}export function getCommandsToLoad(args){const requestedCommand=args[0],isVersionFlag=requestedCommand==="--version"||requestedCommand==="-v",isHelpFlag=requestedCommand==="--help"||requestedCommand==="-h",isHelpWord=requestedCommand==="help";if(isVersionFlag)return["version"];if(!requestedCommand||isHelpFlag||isHelpWord)return Object.keys(commandRegistry);const baseCommand=requestedCommand.split(":")[0];if(baseCommand==="list")return["list",...Object.keys(commandRegistry).filter((k)=>k!=="list")];if(commandRegistry[requestedCommand])return[requestedCommand];if(commandRegistry[baseCommand])return[baseCommand];return Object.keys(commandRegistry)}
|
|
1
|
+
const commandRegistry={about:{path:"./commands/about.js",exportName:"about"},add:{path:"./commands/add.js",exportName:"add"},"ai:context":{path:"./commands/ai-context.js",exportName:"aiContext"},auth:{path:"./commands/auth.js",exportName:"auth"},build:{path:"./commands/build.js",exportName:"build"},cd:{path:"./commands/cd.js",exportName:"cd"},changelog:{path:"./commands/changelog.js",exportName:"changelog"},clean:{path:"./commands/clean.js",exportName:"clean"},cloud:{path:"./commands/cloud.js",exportName:"cloud"},commit:{path:"./commands/commit.js",exportName:"commit"},completion:{path:"./commands/completion.js",exportName:"completion"},"config:migrate":{path:"./commands/config-migrate.js",exportName:"configMigrate"},configure:{path:"./commands/configure.js",exportName:"configure"},create:{path:"./commands/create.js",exportName:"create"},new:{path:"./commands/create.js",exportName:"create"},deploy:{path:"./commands/deploy.js",exportName:"deploy"},dev:{path:"./commands/dev.js",exportName:"dev"},"desktop:apple:doctor":{path:"./commands/desktop-apple.js",exportName:"desktopApple"},"desktop:apple:csr":{path:"./commands/desktop-apple.js",exportName:"desktopApple"},"desktop:apple:init":{path:"./commands/desktop-apple.js",exportName:"desktopApple"},"desktop:apple:package":{path:"./commands/desktop-apple.js",exportName:"desktopApple"},"desktop:apple:provision":{path:"./commands/desktop-apple.js",exportName:"desktopApple"},"desktop:apple:publish":{path:"./commands/desktop-apple.js",exportName:"desktopApple"},dns:{path:"./commands/dns.js",exportName:"dns"},"dns:pull":{path:"./commands/dns.js",exportName:"dns"},"dns:diff":{path:"./commands/dns.js",exportName:"dns"},"dns:sync":{path:"./commands/dns.js",exportName:"dns"},doctor:{path:"./commands/doctor.js",exportName:"doctor"},domains:{path:"./commands/domains.js",exportName:"domains"},email:{path:"./commands/email.js",exportName:"email"},env:{path:"./commands/env.js",exportName:"env"},"extension:init":{path:"./commands/extension.js",exportName:"extension"},"extension:build":{path:"./commands/extension.js",exportName:"extension"},"extension:package":{path:"./commands/extension.js",exportName:"extension"},"extension:chrome:publish":{path:"./commands/extension.js",exportName:"extension"},"extension:chrome:status":{path:"./commands/extension.js",exportName:"extension"},"extension:firefox:publish":{path:"./commands/extension.js",exportName:"extension"},"extension:safari:init":{path:"./commands/extension.js",exportName:"extension"},"extension:safari:provision":{path:"./commands/extension.js",exportName:"extension"},"extension:safari:app":{path:"./commands/extension.js",exportName:"extension"},"extension:safari:publish":{path:"./commands/extension.js",exportName:"extension"},"dashboard:install":{path:"./commands/features.js",exportName:"features"},"dashboard:uninstall":{path:"./commands/features.js",exportName:"features"},"commerce:install":{path:"./commands/features.js",exportName:"features"},"commerce:uninstall":{path:"./commands/features.js",exportName:"features"},"cms:install":{path:"./commands/features.js",exportName:"features"},"cms:uninstall":{path:"./commands/features.js",exportName:"features"},"marketing:install":{path:"./commands/features.js",exportName:"features"},"marketing:uninstall":{path:"./commands/features.js",exportName:"features"},"monitoring:install":{path:"./commands/features.js",exportName:"features"},"monitoring:uninstall":{path:"./commands/features.js",exportName:"features"},"realtime:install":{path:"./commands/features.js",exportName:"features"},"realtime:uninstall":{path:"./commands/features.js",exportName:"features"},"queue:install":{path:"./commands/features.js",exportName:"features"},"queue:uninstall":{path:"./commands/features.js",exportName:"features"},fresh:{path:"./commands/fresh.js",exportName:"fresh"},generate:{path:"./commands/generate.js",exportName:"generate"},http:{path:"./commands/http.js",exportName:"http"},install:{path:"./commands/install.js",exportName:"install"},key:{path:"./commands/key.js",exportName:"key"},lint:{path:"./commands/lint.js",exportName:"lint"},format:{path:"./commands/lint.js",exportName:"lint"},"format:check":{path:"./commands/lint.js",exportName:"lint"},list:{path:"./commands/list.js",exportName:"list"},mail:{path:"./commands/mail.js",exportName:"mailCommands"},"mail:preview":{path:"./commands/mail.js",exportName:"mailCommands"},maintenance:{path:"./commands/maintenance.js",exportName:"maintenance"},down:{path:"./commands/maintenance.js",exportName:"maintenance"},up:{path:"./commands/maintenance.js",exportName:"maintenance"},status:{path:"./commands/maintenance.js",exportName:"maintenance"},"coming-soon":{path:"./commands/maintenance.js",exportName:"maintenance"},"coming-soon:status":{path:"./commands/maintenance.js",exportName:"maintenance"},launch:{path:"./commands/maintenance.js",exportName:"maintenance"},make:{path:"./commands/make.js",exportName:"make"},"scaffold:crud":{path:"./commands/make.js",exportName:"make"},migrate:{path:"./commands/migrate.js",exportName:"migrate"},"migrate:fresh":{path:"./commands/migrate.js",exportName:"migrate"},"migrate:switch":{path:"./commands/migrate.js",exportName:"migrate"},"migrate:dns":{path:"./commands/migrate.js",exportName:"migrate"},"migrate:project":{path:"./commands/migrate-project.js",exportName:"migrateProject"},outdated:{path:"./commands/outdated.js",exportName:"outdated"},package:{path:"./commands/package.js",exportName:"packageCommands"},phone:{path:"./commands/phone.js",exportName:"phone"},ports:{path:"./commands/ports.js",exportName:"ports"},"link:core":{path:"./commands/link.js",exportName:"link"},"user:add":{path:"./commands/user.js",exportName:"user"},"user:list":{path:"./commands/user.js",exportName:"user"},"unlink:core":{path:"./commands/link.js",exportName:"link"},prepublish:{path:"./commands/prepublish.js",exportName:"prepublish"},projects:{path:"./commands/projects.js",exportName:"projects"},publish:{path:"./commands/publish.js",exportName:"publish"},"publish:model":{path:"./commands/publish.js",exportName:"publish"},"publish:controller":{path:"./commands/publish.js",exportName:"publish"},"publish:middleware":{path:"./commands/publish.js",exportName:"publish"},"publish:action":{path:"./commands/publish.js",exportName:"publish"},"publish:core":{path:"./commands/publish.js",exportName:"publish"},"core:status":{path:"./commands/publish.js",exportName:"publish"},queue:{path:"./commands/queue.js",exportName:"queue"},release:{path:"./commands/release.js",exportName:"release"},route:{path:"./commands/route.js",exportName:"route"},saas:{path:"./commands/saas.js",exportName:"saas"},"stripe:setup":{path:"./commands/saas.js",exportName:"saas"},schedule:{path:"./commands/schedule.js",exportName:"schedule"},search:{path:"./commands/search.js",exportName:"search"},"search-engine:update":{path:"./commands/search.js",exportName:"search"},"search-engine:settings":{path:"./commands/search.js",exportName:"search"},seed:{path:"./commands/seed.js",exportName:"seed"},"seed:roles":{path:"./commands/seed.js",exportName:"seed"},"roles:seed":{path:"./commands/seed.js",exportName:"seed"},preview:{path:"./commands/serve.js",exportName:"preview"},serve:{path:"./commands/serve.js",exportName:"serve"},"serve:api":{path:"./commands/serve.js",exportName:"serveApi"},setup:{path:"./commands/setup.js",exportName:"setup"},"setup:ai":{path:"./commands/setup.js",exportName:"setup"},"setup:ssl":{path:"./commands/setup.js",exportName:"setup"},"setup:oh-my-zsh":{path:"./commands/setup.js",exportName:"setup"},"ai:setup":{path:"./commands/setup.js",exportName:"setup"},share:{path:"./commands/share.js",exportName:"share"},stack:{path:"./commands/stacks.js",exportName:"stacks"},sms:{path:"./commands/sms.js",exportName:"sms"},telemetry:{path:"./commands/telemetry.js",exportName:"telemetryCommand"},test:{path:"./commands/test.js",exportName:"test"},tinker:{path:"./commands/tinker.js",exportName:"tinker"},types:{path:"./commands/types.js",exportName:"types"},undeploy:{path:"./commands/cloud.js",exportName:"cloud"},upgrade:{path:"./commands/upgrade.js",exportName:"upgrade"},version:{path:"./commands/version.js",exportName:"version"},"docs:buddy":{path:"./commands/docs.js",exportName:"docs"},"docs:buddy:check":{path:"./commands/docs.js",exportName:"docs"},"docs:artifacts":{path:"./commands/docs.js",exportName:"docs"},"docs:artifacts:check":{path:"./commands/docs.js",exportName:"docs"},"docs:links":{path:"./commands/docs.js",exportName:"docs"},"docs:links:check":{path:"./commands/docs.js",exportName:"docs"}},commandGroups={minimal:["version","help"],development:["dev","build","test","lint"],database:["migrate","seed","fresh"],scaffolding:["make","generate"],deployment:["deploy","release","cloud"],info:["about","doctor","list"]},loadedRegistrars=new WeakMap;function loaderKey(loader){return`${loader.path}#${loader.exportName}`}export function markLoaded(buddy,commandName){const loader=commandRegistry[commandName];if(!loader)return;let set=loadedRegistrars.get(buddy);if(!set){set=new Set;loadedRegistrars.set(buddy,set)}set.add(loaderKey(loader))}export async function loadCommand(commandName,buddy){const loader=commandRegistry[commandName];if(!loader)return!1;let set=loadedRegistrars.get(buddy);if(!set){set=new Set;loadedRegistrars.set(buddy,set)}const key=loaderKey(loader);if(set.has(key))return!0;set.add(key);try{const commandFunction=(await import(loader.path))[loader.exportName];if(typeof commandFunction==="function"){commandFunction(buddy);return!0}else return!1}catch{return!1}}export async function loadCommands(commandNames,buddy){const timeout=(ms)=>new Promise((_,reject)=>setTimeout(()=>reject(Error("timeout")),ms)),seen=new Set,unique=[];for(const name of commandNames){const loader=commandRegistry[name],key=loader?`${loader.path}#${loader.exportName}`:`name:${name}`;if(seen.has(key))continue;seen.add(key);unique.push(name)}await Promise.all(unique.map(async(name)=>{try{await Promise.race([loadCommand(name,buddy),timeout(5000)])}catch{}}))}export async function loadCommandGroup(groupName,buddy){const commands=commandGroups[groupName];if(commands)await loadCommands(commands,buddy)}export async function loadAllCommands(buddy){const allCommands=Object.keys(commandRegistry);await loadCommands(allCommands,buddy)}export function getCommandNames(){return Object.keys(commandRegistry)}export function getCommandsToLoad(args){const requestedCommand=args[0],isVersionFlag=requestedCommand==="--version"||requestedCommand==="-v",isHelpFlag=requestedCommand==="--help"||requestedCommand==="-h",isHelpWord=requestedCommand==="help";if(isVersionFlag)return["version"];if(!requestedCommand||isHelpFlag||isHelpWord)return Object.keys(commandRegistry);const baseCommand=requestedCommand.split(":")[0];if(baseCommand==="list")return["list",...Object.keys(commandRegistry).filter((k)=>k!=="list")];if(commandRegistry[requestedCommand])return[requestedCommand];if(commandRegistry[baseCommand])return[baseCommand];return Object.keys(commandRegistry)}
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@stacksjs/buddy",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"sideEffects": false,
|
|
5
|
-
"version": "0.70.
|
|
5
|
+
"version": "0.70.262",
|
|
6
6
|
"description": "Meet Buddy. The Stacks runtime.",
|
|
7
7
|
"author": "Chris Breuer",
|
|
8
8
|
"contributors": [
|
|
@@ -95,54 +95,54 @@
|
|
|
95
95
|
"prepublishOnly": "bun run build"
|
|
96
96
|
},
|
|
97
97
|
"dependencies": {
|
|
98
|
-
"@stacksjs/actions": "^0.70.
|
|
99
|
-
"@stacksjs/ai": "^0.70.
|
|
100
|
-
"@stacksjs/alias": "^0.70.
|
|
101
|
-
"@stacksjs/arrays": "^0.70.
|
|
102
|
-
"@stacksjs/auth": "^0.70.
|
|
103
|
-
"@stacksjs/build": "^0.70.
|
|
104
|
-
"@stacksjs/cache": "^0.70.
|
|
105
|
-
"@stacksjs/cli": "^0.70.
|
|
98
|
+
"@stacksjs/actions": "^0.70.262",
|
|
99
|
+
"@stacksjs/ai": "^0.70.262",
|
|
100
|
+
"@stacksjs/alias": "^0.70.262",
|
|
101
|
+
"@stacksjs/arrays": "^0.70.262",
|
|
102
|
+
"@stacksjs/auth": "^0.70.262",
|
|
103
|
+
"@stacksjs/build": "^0.70.262",
|
|
104
|
+
"@stacksjs/cache": "^0.70.262",
|
|
105
|
+
"@stacksjs/cli": "^0.70.262",
|
|
106
106
|
"@stacksjs/clapp": "^0.2.12",
|
|
107
|
-
"@stacksjs/cloud": "^0.70.
|
|
108
|
-
"@stacksjs/collections": "^0.70.
|
|
109
|
-
"@stacksjs/config": "^0.70.
|
|
110
|
-
"@stacksjs/database": "^0.70.
|
|
111
|
-
"@stacksjs/desktop-build": "^0.70.
|
|
112
|
-
"@stacksjs/dns": "^0.70.
|
|
113
|
-
"@stacksjs/email": "^0.70.
|
|
114
|
-
"@stacksjs/enums": "^0.70.
|
|
115
|
-
"@stacksjs/error-handling": "^0.70.
|
|
116
|
-
"@stacksjs/events": "^0.70.
|
|
117
|
-
"@stacksjs/git": "^0.70.
|
|
107
|
+
"@stacksjs/cloud": "^0.70.262",
|
|
108
|
+
"@stacksjs/collections": "^0.70.262",
|
|
109
|
+
"@stacksjs/config": "^0.70.262",
|
|
110
|
+
"@stacksjs/database": "^0.70.262",
|
|
111
|
+
"@stacksjs/desktop-build": "^0.70.262",
|
|
112
|
+
"@stacksjs/dns": "^0.70.262",
|
|
113
|
+
"@stacksjs/email": "^0.70.262",
|
|
114
|
+
"@stacksjs/enums": "^0.70.262",
|
|
115
|
+
"@stacksjs/error-handling": "^0.70.262",
|
|
116
|
+
"@stacksjs/events": "^0.70.262",
|
|
117
|
+
"@stacksjs/git": "^0.70.262",
|
|
118
118
|
"@stacksjs/gitit": "^0.2.5",
|
|
119
|
-
"@stacksjs/health": "^0.70.
|
|
119
|
+
"@stacksjs/health": "^0.70.262",
|
|
120
120
|
"@stacksjs/dnsx": "^0.2.3",
|
|
121
121
|
"@stacksjs/httx": "^0.1.10",
|
|
122
|
-
"@stacksjs/image": "^0.70.
|
|
123
|
-
"@stacksjs/lint": "^0.70.
|
|
124
|
-
"@stacksjs/logging": "^0.70.
|
|
125
|
-
"@stacksjs/notifications": "^0.70.
|
|
126
|
-
"@stacksjs/objects": "^0.70.
|
|
127
|
-
"@stacksjs/orm": "^0.70.
|
|
128
|
-
"@stacksjs/path": "^0.70.
|
|
129
|
-
"@stacksjs/skills": "^0.70.
|
|
130
|
-
"@stacksjs/payments": "^0.70.
|
|
131
|
-
"@stacksjs/realtime": "^0.70.
|
|
132
|
-
"@stacksjs/router": "^0.70.
|
|
122
|
+
"@stacksjs/image": "^0.70.262",
|
|
123
|
+
"@stacksjs/lint": "^0.70.262",
|
|
124
|
+
"@stacksjs/logging": "^0.70.262",
|
|
125
|
+
"@stacksjs/notifications": "^0.70.262",
|
|
126
|
+
"@stacksjs/objects": "^0.70.262",
|
|
127
|
+
"@stacksjs/orm": "^0.70.262",
|
|
128
|
+
"@stacksjs/path": "^0.70.262",
|
|
129
|
+
"@stacksjs/skills": "^0.70.262",
|
|
130
|
+
"@stacksjs/payments": "^0.70.262",
|
|
131
|
+
"@stacksjs/realtime": "^0.70.262",
|
|
132
|
+
"@stacksjs/router": "^0.70.262",
|
|
133
133
|
"@stacksjs/rpx": "^0.11.42",
|
|
134
|
-
"@stacksjs/search-engine": "^0.70.
|
|
135
|
-
"@stacksjs/security": "^0.70.
|
|
136
|
-
"@stacksjs/server": "^0.70.
|
|
137
|
-
"@stacksjs/storage": "^0.70.
|
|
138
|
-
"@stacksjs/strings": "^0.70.
|
|
139
|
-
"@stacksjs/testing": "^0.70.
|
|
140
|
-
"@stacksjs/tunnel": "^0.70.
|
|
141
|
-
"@stacksjs/types": "^0.70.
|
|
142
|
-
"@stacksjs/ui": "^0.70.
|
|
143
|
-
"@stacksjs/utils": "^0.70.
|
|
144
|
-
"@stacksjs/validation": "^0.70.
|
|
145
|
-
"@stacksjs/ts-cloud": "^0.7.
|
|
134
|
+
"@stacksjs/search-engine": "^0.70.262",
|
|
135
|
+
"@stacksjs/security": "^0.70.262",
|
|
136
|
+
"@stacksjs/server": "^0.70.262",
|
|
137
|
+
"@stacksjs/storage": "^0.70.262",
|
|
138
|
+
"@stacksjs/strings": "^0.70.262",
|
|
139
|
+
"@stacksjs/testing": "^0.70.262",
|
|
140
|
+
"@stacksjs/tunnel": "^0.70.262",
|
|
141
|
+
"@stacksjs/types": "^0.70.262",
|
|
142
|
+
"@stacksjs/ui": "^0.70.262",
|
|
143
|
+
"@stacksjs/utils": "^0.70.262",
|
|
144
|
+
"@stacksjs/validation": "^0.70.262",
|
|
145
|
+
"@stacksjs/ts-cloud": "^0.7.96",
|
|
146
146
|
"ajv": "^8.20.0",
|
|
147
147
|
"ajv-formats": "^3.0.1",
|
|
148
148
|
"ts-pantry": "^0.11.0"
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
export declare function validateCraftEvidence(evidence: typeof craftEvidence): string[];
|
|
2
|
-
export declare function run(): Promise<void>;
|
|
3
|
-
export declare const craftEvidence: {
|
|
4
|
-
schemaVersion: 1;
|
|
5
|
-
status: 'source-verified-ci-retained';
|
|
6
|
-
source: {
|
|
7
|
-
repository: 'https://github.com/home-lang/craft';
|
|
8
|
-
version: '0.0.48';
|
|
9
|
-
tag: 'v0.0.48';
|
|
10
|
-
revision: 'bf75807669e3af6cfb4ae34724be5c613442aee2'
|
|
11
|
-
};
|
|
12
|
-
issues: {
|
|
13
|
-
support: 'https://github.com/stacksjs/stacks/issues/2059';
|
|
14
|
-
signing: 'https://github.com/stacksjs/stacks/issues/2062';
|
|
15
|
-
lifecycle: 'https://github.com/stacksjs/stacks/issues/2063';
|
|
16
|
-
upstreamActions: 'https://github.com/home-lang/craft/issues/11';
|
|
17
|
-
dmgContention: 'https://github.com/home-lang/craft/issues/16'
|
|
18
|
-
};
|
|
19
|
-
contracts: readonly [{
|
|
20
|
-
path: 'packages/typescript/src/package.ts';
|
|
21
|
-
sha256: 'a7522f8c79dbd50a0f3bbc113525fb46eb8d6d1bab711d434cae85dc892ccdc1'
|
|
22
|
-
}, {
|
|
23
|
-
path: 'packages/typescript/src/package.test.ts';
|
|
24
|
-
sha256: '673338f3793e397a83590daf84815869b0698b4afe97eaad8039426418554b7a'
|
|
25
|
-
}, {
|
|
26
|
-
path: 'scripts/native-lifecycle.ts';
|
|
27
|
-
sha256: 'a2c0af2c2165981ca7fbd31880adeec64db64fc305d4ca3efe62a11483b289b4'
|
|
28
|
-
}, {
|
|
29
|
-
path: 'scripts/native-lifecycle-plan.ts';
|
|
30
|
-
sha256: 'ac8e8f101246e94c0c26fdcbf9202536426bf192a303606079273d9689e4e27d'
|
|
31
|
-
}, {
|
|
32
|
-
path: 'scripts/native-lifecycle-plan.test.ts';
|
|
33
|
-
sha256: '5cc839b60f7c8e32716f29201b159af817f4ac40b2c7963131124b3ac5de0638'
|
|
34
|
-
}, {
|
|
35
|
-
path: '.github/workflows/native-lifecycle.yml';
|
|
36
|
-
sha256: '493b614554f03dc669724ff31bd56ae8361851dd2a9b32ac37560d9c0bb1b85e'
|
|
37
|
-
}, {
|
|
38
|
-
path: '.github/workflows/release.yml';
|
|
39
|
-
sha256: 'e3c7edd45841a7260fb4dfe810f0ff3f63f3117f7d0f4d14984e4dfb36b1f638'
|
|
40
|
-
}];
|
|
41
|
-
lifecycleMatrix: readonly [{
|
|
42
|
-
runner: 'macos-15';
|
|
43
|
-
platform: 'darwin';
|
|
44
|
-
architecture: 'arm64';
|
|
45
|
-
formats: readonly ['dmg', 'pkg']
|
|
46
|
-
}, {
|
|
47
|
-
runner: 'macos-15-intel';
|
|
48
|
-
platform: 'darwin';
|
|
49
|
-
architecture: 'x64';
|
|
50
|
-
formats: readonly ['dmg', 'pkg']
|
|
51
|
-
}, {
|
|
52
|
-
runner: 'ubuntu-24.04';
|
|
53
|
-
platform: 'linux';
|
|
54
|
-
architecture: 'x64';
|
|
55
|
-
formats: readonly ['deb']
|
|
56
|
-
}, {
|
|
57
|
-
runner: 'windows-2025';
|
|
58
|
-
platform: 'win32';
|
|
59
|
-
architecture: 'x64';
|
|
60
|
-
formats: readonly ['msi', 'zip']
|
|
61
|
-
}];
|
|
62
|
-
lifecycleOperations: readonly ['install', 'launch', 'update', 'rollback', 'uninstall'];
|
|
63
|
-
stacksWorkflow: 'https://github.com/stacksjs/stacks/actions/workflows/desktop-lifecycle.yml';
|
|
64
|
-
release: {
|
|
65
|
-
sourceTagged: true;
|
|
66
|
-
githubRelease: null;
|
|
67
|
-
packagePublished: false;
|
|
68
|
-
signing: 'pending';
|
|
69
|
-
notarization: 'pending';
|
|
70
|
-
blockedBy: 'https://github.com/home-lang/craft/issues/11'
|
|
71
|
-
};
|
|
72
|
-
verification: {
|
|
73
|
-
local: readonly ['bun test packages/typescript/src/package.test.ts scripts/native-lifecycle-plan.test.ts', 'bun run typecheck', 'bun .github/scripts/native-lifecycle.ts'];
|
|
74
|
-
retained: 'https://github.com/stacksjs/stacks/actions/runs/29890804159'
|
|
75
|
-
}
|
|
76
|
-
};
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import{existsSync,readFileSync,writeFileSync}from"node:fs";import{resolve}from"node:path";const root=resolve(import.meta.dir,"../../../../../../.."),outputPath=resolve(root,".github/protocol/evidence/craft.json");export const craftEvidence={schemaVersion:1,status:"source-verified-ci-retained",source:{repository:"https://github.com/home-lang/craft",version:"0.0.48",tag:"v0.0.48",revision:"bf75807669e3af6cfb4ae34724be5c613442aee2"},issues:{support:"https://github.com/stacksjs/stacks/issues/2059",signing:"https://github.com/stacksjs/stacks/issues/2062",lifecycle:"https://github.com/stacksjs/stacks/issues/2063",upstreamActions:"https://github.com/home-lang/craft/issues/11",dmgContention:"https://github.com/home-lang/craft/issues/16"},contracts:[{path:"packages/typescript/src/package.ts",sha256:"a7522f8c79dbd50a0f3bbc113525fb46eb8d6d1bab711d434cae85dc892ccdc1"},{path:"packages/typescript/src/package.test.ts",sha256:"673338f3793e397a83590daf84815869b0698b4afe97eaad8039426418554b7a"},{path:"scripts/native-lifecycle.ts",sha256:"a2c0af2c2165981ca7fbd31880adeec64db64fc305d4ca3efe62a11483b289b4"},{path:"scripts/native-lifecycle-plan.ts",sha256:"ac8e8f101246e94c0c26fdcbf9202536426bf192a303606079273d9689e4e27d"},{path:"scripts/native-lifecycle-plan.test.ts",sha256:"5cc839b60f7c8e32716f29201b159af817f4ac40b2c7963131124b3ac5de0638"},{path:".github/workflows/native-lifecycle.yml",sha256:"493b614554f03dc669724ff31bd56ae8361851dd2a9b32ac37560d9c0bb1b85e"},{path:".github/workflows/release.yml",sha256:"e3c7edd45841a7260fb4dfe810f0ff3f63f3117f7d0f4d14984e4dfb36b1f638"}],lifecycleMatrix:[{runner:"macos-15",platform:"darwin",architecture:"arm64",formats:["dmg","pkg"]},{runner:"macos-15-intel",platform:"darwin",architecture:"x64",formats:["dmg","pkg"]},{runner:"ubuntu-24.04",platform:"linux",architecture:"x64",formats:["deb"]},{runner:"windows-2025",platform:"win32",architecture:"x64",formats:["msi","zip"]}],lifecycleOperations:["install","launch","update","rollback","uninstall"],stacksWorkflow:"https://github.com/stacksjs/stacks/actions/workflows/desktop-lifecycle.yml",release:{sourceTagged:!0,githubRelease:null,packagePublished:!1,signing:"pending",notarization:"pending",blockedBy:"https://github.com/home-lang/craft/issues/11"},verification:{local:["bun test packages/typescript/src/package.test.ts scripts/native-lifecycle-plan.test.ts","bun run typecheck","bun .github/scripts/native-lifecycle.ts"],retained:"https://github.com/stacksjs/stacks/actions/runs/29890804159"}};export function validateCraftEvidence(evidence){const errors=[];if(evidence.source.tag!==`v${evidence.source.version}`)errors.push("Craft tag does not match its version");if(!/^[a-f0-9]{40}$/.test(evidence.source.revision))errors.push("Craft revision is not a full commit SHA");if(evidence.contracts.length!==7)errors.push("all Craft packaging/release contracts must be pinned");for(const contract of evidence.contracts)if(!/^[a-f0-9]{64}$/.test(contract.sha256))errors.push(`${contract.path}: invalid SHA-256 digest`);const targets=new Set(evidence.lifecycleMatrix.map((row)=>`${row.platform}/${row.architecture}`));for(const target of["darwin/arm64","darwin/x64","linux/x64","win32/x64"])if(!targets.has(target))errors.push(`Craft lifecycle matrix is missing ${target}`);if(evidence.release.signing!=="pending"||evidence.release.notarization!=="pending")errors.push("Craft signing/notarization cannot be promoted without retained release evidence");if(!evidence.release.blockedBy)errors.push("Craft release blocker must be linked");return errors}function serializedEvidence(){return`${JSON.stringify(craftEvidence,null,2)}
|
|
2
|
-
`}export async function run(){const errors=validateCraftEvidence(craftEvidence);if(process.argv.includes("--write")){if(errors.length)throw Error(errors.join(`
|
|
3
|
-
`));writeFileSync(outputPath,serializedEvidence());console.log(`Wrote Craft evidence for ${craftEvidence.source.tag}`)}else if(process.argv.includes("--check")){if(!existsSync(outputPath))errors.push(".github/protocol/evidence/craft.json is missing");else if(readFileSync(outputPath,"utf8")!==serializedEvidence())errors.push("Craft evidence is stale; run bun run protocol:craft");if(errors.length)throw Error(errors.join(`
|
|
4
|
-
`));console.log(`Craft evidence pins ${craftEvidence.source.tag} at ${craftEvidence.source.revision}`)}else{console.error("usage: bun storage/framework/core/buddy/src/commands/protocol/craft-evidence.ts --write | --check");process.exit(2)}}if(import.meta.main)await run();
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{describe,expect,it}from"bun:test";import{craftEvidence,validateCraftEvidence}from"./craft-evidence";describe("Craft protocol evidence",()=>{it("pins the full native lifecycle and release contract",()=>{expect(validateCraftEvidence(craftEvidence)).toEqual([]);expect(craftEvidence.lifecycleMatrix).toHaveLength(4);expect(craftEvidence.lifecycleOperations).toEqual(["install","launch","update","rollback","uninstall"])});it("rejects untraceable source and premature signing claims",()=>{const invalid=structuredClone(craftEvidence);Object.assign(invalid.source,{tag:"latest",revision:"short"});Object.assign(invalid.release,{signing:"enforced",notarization:"enforced",blockedBy:""});expect(validateCraftEvidence(invalid)).toEqual(expect.arrayContaining(["Craft tag does not match its version","Craft revision is not a full commit SHA","Craft signing/notarization cannot be promoted without retained release evidence","Craft release blocker must be linked"]))})});
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
export declare function validateLifecycleReport(report: LifecycleReport, expected: {
|
|
2
|
-
revision: string
|
|
3
|
-
platform: string
|
|
4
|
-
architecture: string
|
|
5
|
-
formats: string[]
|
|
6
|
-
}): string[];
|
|
7
|
-
export declare function run(): Promise<void>;
|
|
8
|
-
declare type LifecycleReport = {
|
|
9
|
-
revision?: string
|
|
10
|
-
orchestratorRevision?: string | null
|
|
11
|
-
status?: string
|
|
12
|
-
installLifecycleExercised?: boolean
|
|
13
|
-
runner?: { os?: string, arch?: string }
|
|
14
|
-
artifacts?: Array<{ format?: string, sha256?: string }>
|
|
15
|
-
steps?: Array<{ name?: string, status?: string }>
|
|
16
|
-
}
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
import{mkdirSync,readFileSync,writeFileSync}from"node:fs";import{dirname,resolve}from"node:path";export function validateLifecycleReport(report,expected){const errors=[];if(report.revision!==expected.revision)errors.push(`Craft source revision mismatch: ${report.revision||"missing"}`);if(report.status!=="passed")errors.push(`Craft lifecycle status is ${report.status||"missing"}`);if(report.installLifecycleExercised!==!0)errors.push("privileged install lifecycle was not exercised");if(report.runner?.os!==expected.platform||report.runner?.arch!==expected.architecture)errors.push(`runner mismatch: ${report.runner?.os||"missing"}/${report.runner?.arch||"missing"}`);const steps=new Map((report.steps||[]).map((step)=>[step.name,step.status]));for(const name of["install v1","launch v1","update to v2","launch v2","rollback to v1","launch rollback","uninstall","verify uninstall"])if(steps.get(name)!=="passed")errors.push(`lifecycle step did not pass: ${name}`);const artifacts=report.artifacts||[];for(const format of expected.formats){const matching=artifacts.filter((artifact)=>artifact.format===format);if(matching.length!==2)errors.push(`expected two ${format} artifacts, found ${matching.length}`);if(matching.some((artifact)=>!/^[a-f0-9]{64}$/.test(artifact.sha256||"")))errors.push(`${format} artifact has an invalid digest`)}return errors}export async function run(){const value=(name)=>{const index=process.argv.indexOf(name),result=index===-1?void 0:process.argv[index+1];if(!result)throw Error(`${name} requires a value`);return result},reportPath=resolve(value("--report")),outputPath=resolve(value("--output")),expected={revision:value("--revision"),platform:value("--platform"),architecture:value("--architecture"),formats:value("--formats").split(",")},report=JSON.parse(readFileSync(reportPath,"utf8")),errors=validateLifecycleReport(report,expected);if(errors.length)throw Error(errors.join(`
|
|
2
|
-
`));const attestation={schemaVersion:1,status:"passed",stacksRevision:process.env.GITHUB_SHA||"local",craftRevision:expected.revision,sourceReport:reportPath,target:{platform:expected.platform,architecture:expected.architecture,formats:expected.formats},checks:{lifecycle:"passed",artifactDigests:"passed",sourcePin:"passed"}};mkdirSync(dirname(outputPath),{recursive:!0});writeFileSync(outputPath,`${JSON.stringify(attestation,null,2)}
|
|
3
|
-
`);console.log(`Validated Craft lifecycle for ${expected.platform}/${expected.architecture}`)}if(import.meta.main)await run();
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{describe,expect,it}from"bun:test";import{validateLifecycleReport}from"./desktop-lifecycle-report";const steps=["install v1","launch v1","update to v2","launch v2","rollback to v1","launch rollback","uninstall","verify uninstall"],revision="d".repeat(40);describe("desktop lifecycle report validation",()=>{it("requires a complete source-pinned lifecycle and two versioned artifacts per format",()=>{const report={revision,status:"passed",installLifecycleExercised:!0,runner:{os:"linux",arch:"x64"},steps:steps.map((name)=>({name,status:"passed"})),artifacts:[{format:"deb",sha256:"a".repeat(64)},{format:"deb",sha256:"b".repeat(64)}]};expect(validateLifecycleReport(report,{revision,platform:"linux",architecture:"x64",formats:["deb"]})).toEqual([])});it("rejects missing rollback, wrong source, and invalid artifact evidence",()=>{const errors=validateLifecycleReport({revision:"wrong",status:"passed",installLifecycleExercised:!0,runner:{os:"linux",arch:"x64"},steps:steps.filter((name)=>name!=="rollback to v1").map((name)=>({name,status:"passed"})),artifacts:[{format:"deb",sha256:"short"}]},{revision,platform:"linux",architecture:"x64",formats:["deb"]});expect(errors).toEqual(expect.arrayContaining(["Craft source revision mismatch: wrong","lifecycle step did not pass: rollback to v1","expected two deb artifacts, found 1","deb artifact has an invalid digest"]))})});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function run(): void;
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{existsSync,readFileSync,writeFileSync}from"node:fs";import{resolve}from"node:path";import{desktopSupportMatrix}from"../../../../desktop/src/support";const root=resolve(import.meta.dir,"../../../../../../.."),outputPath=resolve(root,".github/protocol/evidence/desktop-support.json"),document={schemaVersion:"1.0.0",generatedFrom:"storage/framework/core/desktop/src/support.ts",stableTargets:desktopSupportMatrix.filter((row)=>row.status==="stable").length,externalGates:["https://github.com/stacksjs/stacks/issues/2059","https://github.com/stacksjs/stacks/issues/2062","https://github.com/stacksjs/stacks/issues/2063"],targets:desktopSupportMatrix},expected=`${JSON.stringify(document,null,2)}
|
|
2
|
-
`;export function run(){if(process.argv.includes("--write")){writeFileSync(outputPath,expected);console.log(`Wrote desktop support matrix (${document.stableTargets} stable targets)`)}else if(process.argv.includes("--check")){if(!existsSync(outputPath)||readFileSync(outputPath,"utf8")!==expected)throw Error("desktop support evidence is stale; run buddy protocol:desktop");if(document.targets.some((row)=>row.status==="stable"&&(!row.installLaunchEvidence||!row.updateRollbackEvidence||row.signing!=="enforced")))throw Error("stable desktop target lacks required evidence");console.log(`Desktop support matrix is current (${document.stableTargets} stable targets)`)}else{console.error("usage: buddy protocol:desktop --write | --check");process.exit(2)}}if(import.meta.main)run();
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
import{describe,expect,it}from"bun:test";import{readdirSync,readFileSync}from"node:fs";import{resolve}from"node:path";const root=resolve(import.meta.dir,"../../../../../../.."),workflow=readFileSync(resolve(root,".github/workflows/desktop-lifecycle.yml"),"utf8"),workflowDirectory=resolve(root,".github/workflows"),repositoryWorkflows=readdirSync(workflowDirectory).filter((path)=>path.endsWith(".yml")||path.endsWith(".yaml")).map((path)=>readFileSync(resolve(workflowDirectory,path),"utf8")).join(`
|
|
2
|
-
`);describe("desktop lifecycle workflow",()=>{it("packages Craft before allocating the Stacks dependency graph",()=>{const craftInstall=workflow.indexOf("- name: Install Craft dependencies"),lifecycle=workflow.indexOf("- name: Exercise native package lifecycle"),reclaim=workflow.indexOf("- name: Reclaim Craft dependency space"),stacksInstall=workflow.indexOf("- name: Install Stacks dependencies"),stacksTests=workflow.indexOf("- name: Verify Stacks update security contracts");expect([craftInstall,lifecycle,reclaim,stacksInstall,stacksTests].every((index)=>index>=0)).toBe(!0);expect(craftInstall).toBeLessThan(lifecycle);expect(lifecycle).toBeLessThan(reclaim);expect(reclaim).toBeLessThan(stacksInstall);expect(stacksInstall).toBeLessThan(stacksTests);expect(workflow).toContain(`working-directory: .craft-contract
|
|
3
|
-
run: bun scripts/native-lifecycle.ts --install`);expect(workflow).toContain("rm -rf .craft-contract/node_modules")});it("provisions explicit macOS descriptor capacity for Bun installs",()=>{expect(workflow.match(/ulimit -n 65536/g)).toHaveLength(2);expect(workflow).toContain('if [ "$RUNNER_OS" = "macOS" ]')});it("uses a compatible preinstalled WiX 3.14 before installing it",()=>{const discovery=workflow.indexOf("$bin = Get-ChildItem"),install=workflow.indexOf("choco install wixtoolset");expect(discovery).toBeGreaterThan(0);expect(discovery).toBeLessThan(install);expect(workflow).toContain("$version.StartsWith('3.14')");expect(workflow).toContain("--allow-downgrade")});it("retains artifacts through maintained Node 24 action runtimes",()=>{expect(repositoryWorkflows).not.toMatch(/actions\/upload-artifact@v[1-6]\b/);expect(repositoryWorkflows).not.toMatch(/actions\/download-artifact@v[1-7]\b/);expect(repositoryWorkflows.match(/actions\/upload-artifact@v7\b/g)).toHaveLength(4);expect(repositoryWorkflows.match(/actions\/download-artifact@v8\b/g)).toHaveLength(1)})});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function run(): Promise<void>;
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{existsSync,readFileSync,writeFileSync}from"node:fs";import{resolve}from"node:path";import{capabilityRegistry}from"../../../../config/src/capabilities";const root=resolve(import.meta.dir,"../../../../../../.."),outputPath=resolve(root,".github/protocol/evidence/drivers.json");function validate(){const errors=[],seen=new Set,categories=new Set(["database","queue","cache","storage","mail","realtime","deploy"]);for(const driver of capabilityRegistry){const id=`${driver.category}/${driver.name}`;if(seen.has(id))errors.push(`${id}: duplicate registry entry`);seen.add(id);if(!categories.has(driver.category))errors.push(`${id}: unknown category`);if(driver.status==="supported"&&driver.testEvidence.length===0)errors.push(`${id}: supported driver has no test evidence`);if(driver.status==="supported"&&/client-server|managed|smtp|redis/.test(driver.topology)&&!driver.liveServiceContract)errors.push(`${id}: externally hosted driver cannot be supported without a retained live-service contract`);if(driver.liveServiceContract&&!existsSync(resolve(root,driver.liveServiceContract.workflow)))errors.push(`${id}: live-service workflow does not exist: ${driver.liveServiceContract.workflow}`);if(driver.status!=="supported"&&driver.limitations.length===0)errors.push(`${id}: non-supported driver must explain its evidence gap`);if(driver.status!=="unsupported"&&!driver.implementation)errors.push(`${id}: operational driver has no implementation`);if(driver.implementation&&!existsSync(resolve(root,driver.implementation)))errors.push(`${id}: implementation path does not exist`);for(const testPath of driver.testEvidence)if(!existsSync(resolve(root,testPath)))errors.push(`${id}: test evidence does not exist: ${testPath}`)}for(const category of categories)if(!capabilityRegistry.some((driver)=>driver.category===category))errors.push(`${category}: no drivers registered`);return errors}function render(){const document={schemaVersion:"1.0.0",generatedFrom:"storage/framework/core/config/src/capabilities.ts",resultSemantics:{supported:"Implemented, selected by configuration, and backed by checked-in automated evidence.",partial:"Implemented, but missing live-service or feature-parity evidence.",experimental:"Implemented for evaluation without a compatibility commitment or complete matrix.",unsupported:"Reserved, planned, or intentionally unavailable; selection must fail loudly."},drivers:[...capabilityRegistry].sort((a,b)=>a.category.localeCompare(b.category)||a.name.localeCompare(b.name))};return`${JSON.stringify(document,null,2)}
|
|
2
|
-
`}export async function run(){const errors=validate();if(errors.length>0){for(const error of errors)console.error(`error: ${error}`);process.exit(1)}const expected=render();if(process.argv.includes("--write")){writeFileSync(outputPath,expected);console.log(`Wrote ${capabilityRegistry.length} driver capability records`)}else if(process.argv.includes("--check")){if(!existsSync(outputPath)||readFileSync(outputPath,"utf8")!==expected)throw Error("driver registry evidence is stale; run bun run protocol:drivers");console.log(`Driver registry is current (${capabilityRegistry.length} records)`)}else{console.error("usage: bun storage/framework/core/buddy/src/commands/protocol/driver-registry.ts --write | --check");process.exit(2)}}if(import.meta.main)await run();
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
export declare function validatePantryEvidence(evidence: typeof pantryEvidence): string[];
|
|
2
|
-
export declare function run(): Promise<void>;
|
|
3
|
-
export declare const pantryEvidence: {
|
|
4
|
-
schemaVersion: 1;
|
|
5
|
-
status: 'pinned';
|
|
6
|
-
issue: 'https://github.com/stacksjs/stacks/issues/2066';
|
|
7
|
-
source: {
|
|
8
|
-
repository: 'https://github.com/pantry-pm/pantry';
|
|
9
|
-
version: '0.10.47';
|
|
10
|
-
tag: 'v0.10.47';
|
|
11
|
-
revision: 'd738d5fd2e543e3b8380e5fbd5d01ba8936c1790'
|
|
12
|
-
};
|
|
13
|
-
whitepaper: {
|
|
14
|
-
repository: 'https://github.com/stacksjs/white-paper';
|
|
15
|
-
revision: 'ac6d1dfba8cb96cf6e888f3369cbcc3e17cdf202';
|
|
16
|
-
evidenceLock: 'evidence/pantry/evidence.lock.json'
|
|
17
|
-
};
|
|
18
|
-
contracts: readonly [{
|
|
19
|
-
id: 'package-manager';
|
|
20
|
-
sourcePath: 'docs/package-manager.md';
|
|
21
|
-
sha256: '03bab0e0373e2405a4f0656745786702a19c3b3a0ffb9be09ca0931f85a5158e';
|
|
22
|
-
referencePath: 'docs/reference/package-manager.md'
|
|
23
|
-
}, {
|
|
24
|
-
id: 'registry';
|
|
25
|
-
sourcePath: 'docs/registry.md';
|
|
26
|
-
sha256: 'c16a2ef8855d99b34398bddfd6f574e0e3001ce8a769dc6dd6792af418c4724b';
|
|
27
|
-
referencePath: 'docs/reference/registry.md'
|
|
28
|
-
}];
|
|
29
|
-
serviceContracts: readonly [{
|
|
30
|
-
id: 'github-actions-service-interface';
|
|
31
|
-
sourcePath: 'packages/action/action.yml';
|
|
32
|
-
sha256: '06f4ac3f3307a474e493abe56f1e8f7d99f7af8ce49cecbf3dfdd2e55333ea13'
|
|
33
|
-
}, {
|
|
34
|
-
id: 'github-actions-redis-lifecycle';
|
|
35
|
-
sourcePath: 'packages/action/src/services.ts';
|
|
36
|
-
sha256: '7e88c89880bf1dc42cfee44f5a741b7659b2c2a1aced7da9c23520ed28a8afe9'
|
|
37
|
-
}, {
|
|
38
|
-
id: 'github-actions-redis-orchestration';
|
|
39
|
-
sourcePath: 'packages/action/src/index.ts';
|
|
40
|
-
sha256: '3fd905facb4109f0a3e65d743c522eb72b934dea466531aeb24c468ab4fc76ab'
|
|
41
|
-
}, {
|
|
42
|
-
id: 'github-actions-install-mode';
|
|
43
|
-
sourcePath: 'packages/action/src/install-mode.ts';
|
|
44
|
-
sha256: 'e3ff33f0197eb9607d9a74efd946d34c76aad21ed4af4b2a89169aa04db30581'
|
|
45
|
-
}, {
|
|
46
|
-
id: 'github-actions-redis-cleanup';
|
|
47
|
-
sourcePath: 'packages/action/src/post.ts';
|
|
48
|
-
sha256: '9dbfa452e86a61ec75da8c461d69d10a4f493765c19523ba999ee4f916ccde54'
|
|
49
|
-
}, {
|
|
50
|
-
id: 'native-service-readiness';
|
|
51
|
-
sourcePath: 'packages/zig/src/cli/commands/services.zig';
|
|
52
|
-
sha256: '7da9d6271b8dc755865db26a366202448cc408e0d2e3b0daa0a3b8cb917fd748'
|
|
53
|
-
}, {
|
|
54
|
-
id: 'native-redis-definition';
|
|
55
|
-
sourcePath: 'packages/zig/src/services/definitions.zig';
|
|
56
|
-
sha256: 'faf362b6a9f037350b6baf7204f424e78b9bfe8704dfdfcf26e1daa1b5dce678'
|
|
57
|
-
}];
|
|
58
|
-
verification: {
|
|
59
|
-
documentationContracts: 'bun run docs:contracts:check (54 source-linked markers)';
|
|
60
|
-
targetedBunTests: '332 passed, 6 skipped, 0 failed';
|
|
61
|
-
typecheck: 'bun run typecheck';
|
|
62
|
-
nativeTests: '29 semver tests passed; zig build test completed 32/32 steps';
|
|
63
|
-
actionRedisService: 'Pantry CI action-redis-service job (Redis 8.8.0)';
|
|
64
|
-
whitepaperCheck: 'bun run evidence:check'
|
|
65
|
-
};
|
|
66
|
-
boundaries: readonly ['Pantry system packages, npm-compatible packages, and workspace/local packages use distinct resolution paths.', 'npm fallback is read-only and does not publish npm packages into Pantry.', 'Configured storage and authentication modes do not by themselves prove production readiness.', 'Stacks consumes Pantry as a versioned toolchain boundary and does not redefine Pantry behavior.']
|
|
67
|
-
};
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import{existsSync,readFileSync,writeFileSync}from"node:fs";import{resolve}from"node:path";const root=resolve(import.meta.dir,"../../../../../../.."),outputPath=resolve(root,".github/protocol/evidence/pantry.json");export const pantryEvidence={schemaVersion:1,status:"pinned",issue:"https://github.com/stacksjs/stacks/issues/2066",source:{repository:"https://github.com/pantry-pm/pantry",version:"0.10.47",tag:"v0.10.47",revision:"d738d5fd2e543e3b8380e5fbd5d01ba8936c1790"},whitepaper:{repository:"https://github.com/stacksjs/white-paper",revision:"ac6d1dfba8cb96cf6e888f3369cbcc3e17cdf202",evidenceLock:"evidence/pantry/evidence.lock.json"},contracts:[{id:"package-manager",sourcePath:"docs/package-manager.md",sha256:"03bab0e0373e2405a4f0656745786702a19c3b3a0ffb9be09ca0931f85a5158e",referencePath:"docs/reference/package-manager.md"},{id:"registry",sourcePath:"docs/registry.md",sha256:"c16a2ef8855d99b34398bddfd6f574e0e3001ce8a769dc6dd6792af418c4724b",referencePath:"docs/reference/registry.md"}],serviceContracts:[{id:"github-actions-service-interface",sourcePath:"packages/action/action.yml",sha256:"06f4ac3f3307a474e493abe56f1e8f7d99f7af8ce49cecbf3dfdd2e55333ea13"},{id:"github-actions-redis-lifecycle",sourcePath:"packages/action/src/services.ts",sha256:"7e88c89880bf1dc42cfee44f5a741b7659b2c2a1aced7da9c23520ed28a8afe9"},{id:"github-actions-redis-orchestration",sourcePath:"packages/action/src/index.ts",sha256:"3fd905facb4109f0a3e65d743c522eb72b934dea466531aeb24c468ab4fc76ab"},{id:"github-actions-install-mode",sourcePath:"packages/action/src/install-mode.ts",sha256:"e3ff33f0197eb9607d9a74efd946d34c76aad21ed4af4b2a89169aa04db30581"},{id:"github-actions-redis-cleanup",sourcePath:"packages/action/src/post.ts",sha256:"9dbfa452e86a61ec75da8c461d69d10a4f493765c19523ba999ee4f916ccde54"},{id:"native-service-readiness",sourcePath:"packages/zig/src/cli/commands/services.zig",sha256:"7da9d6271b8dc755865db26a366202448cc408e0d2e3b0daa0a3b8cb917fd748"},{id:"native-redis-definition",sourcePath:"packages/zig/src/services/definitions.zig",sha256:"faf362b6a9f037350b6baf7204f424e78b9bfe8704dfdfcf26e1daa1b5dce678"}],verification:{documentationContracts:"bun run docs:contracts:check (54 source-linked markers)",targetedBunTests:"332 passed, 6 skipped, 0 failed",typecheck:"bun run typecheck",nativeTests:"29 semver tests passed; zig build test completed 32/32 steps",actionRedisService:"Pantry CI action-redis-service job (Redis 8.8.0)",whitepaperCheck:"bun run evidence:check"},boundaries:["Pantry system packages, npm-compatible packages, and workspace/local packages use distinct resolution paths.","npm fallback is read-only and does not publish npm packages into Pantry.","Configured storage and authentication modes do not by themselves prove production readiness.","Stacks consumes Pantry as a versioned toolchain boundary and does not redefine Pantry behavior."]};export function validatePantryEvidence(evidence){const errors=[];if(evidence.source.tag!==`v${evidence.source.version}`)errors.push("Pantry tag does not match its version");if(!/^[a-f0-9]{40}$/.test(evidence.source.revision))errors.push("Pantry revision is not a full commit SHA");if(!/^[a-f0-9]{40}$/.test(evidence.whitepaper.revision))errors.push("whitepaper revision is not a full commit SHA");if(evidence.contracts.length!==2)errors.push("both canonical Pantry contracts must be pinned");for(const contract of evidence.contracts){if(!/^[a-f0-9]{64}$/.test(contract.sha256))errors.push(`${contract.id}: invalid SHA-256 digest`);if(!contract.sourcePath.endsWith(".md"))errors.push(`${contract.id}: source contract is not Markdown`);if(!contract.referencePath.startsWith("docs/reference/"))errors.push(`${contract.id}: whitepaper reference path is invalid`)}if(evidence.serviceContracts.length!==7)errors.push("all Pantry Redis service contracts must be pinned");for(const contract of evidence.serviceContracts){if(!/^[a-f0-9]{64}$/.test(contract.sha256))errors.push(`${contract.id}: invalid SHA-256 digest`);if(!contract.sourcePath.startsWith("packages/"))errors.push(`${contract.id}: source path is outside Pantry packages`)}return errors}function serializedEvidence(){return`${JSON.stringify(pantryEvidence,null,2)}
|
|
2
|
-
`}function check(){const errors=validatePantryEvidence(pantryEvidence);if(!existsSync(outputPath))errors.push(".github/protocol/evidence/pantry.json is missing");else if(readFileSync(outputPath,"utf8")!==serializedEvidence())errors.push("Pantry evidence is stale; run bun run protocol:pantry");if(errors.length)throw Error(errors.join(`
|
|
3
|
-
`));console.log(`Pantry evidence pins ${pantryEvidence.source.tag} at ${pantryEvidence.source.revision}`)}export async function run(){if(process.argv.includes("--write")){const errors=validatePantryEvidence(pantryEvidence);if(errors.length)throw Error(errors.join(`
|
|
4
|
-
`));writeFileSync(outputPath,serializedEvidence());console.log(`Wrote Pantry evidence for ${pantryEvidence.source.tag}`)}else if(process.argv.includes("--check"))check();else{console.error("usage: bun storage/framework/core/buddy/src/commands/protocol/pantry-evidence.ts --write | --check");process.exit(2)}}if(import.meta.main)await run();
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{describe,expect,it}from"bun:test";import{pantryEvidence,validatePantryEvidence}from"./pantry-evidence";describe("Pantry protocol evidence",()=>{it("pins both verified upstream contracts",()=>{expect(validatePantryEvidence(pantryEvidence)).toEqual([]);expect(pantryEvidence.contracts.map((contract)=>contract.id)).toEqual(["package-manager","registry"]);expect(pantryEvidence.serviceContracts.map((contract)=>contract.id)).toEqual(["github-actions-service-interface","github-actions-redis-lifecycle","github-actions-redis-orchestration","github-actions-install-mode","github-actions-redis-cleanup","native-service-readiness","native-redis-definition"])});it("rejects an untraceable release or contract digest",()=>{const invalid=structuredClone(pantryEvidence);Object.assign(invalid.source,{tag:"latest",revision:"short"});Object.assign(invalid.contracts[0],{sha256:"not-a-digest"});Object.assign(invalid.serviceContracts[0],{sha256:"not-a-digest"});expect(validatePantryEvidence(invalid)).toEqual(expect.arrayContaining(["Pantry tag does not match its version","Pantry revision is not a full commit SHA","package-manager: invalid SHA-256 digest","github-actions-service-interface: invalid SHA-256 digest"]))})});
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
export declare function assertReleaseMapping(tag: string, releasePackageVersion?: string): void;
|
|
2
|
-
export declare function buildReleaseManifest(tag: string): ReleaseManifest;
|
|
3
|
-
export declare function renderReleaseManifest(manifest: ReleaseManifest): string;
|
|
4
|
-
export declare function run(): Promise<void>;
|
|
5
|
-
export declare interface ReleasePackageEntry {
|
|
6
|
-
name: string
|
|
7
|
-
path: string
|
|
8
|
-
version: string
|
|
9
|
-
publishable: boolean
|
|
10
|
-
}
|
|
11
|
-
export declare interface ReleaseManifest {
|
|
12
|
-
schemaVersion: '1.0.0'
|
|
13
|
-
repository: string
|
|
14
|
-
tag: string
|
|
15
|
-
tagType: 'annotated' | 'lightweight'
|
|
16
|
-
releaseVersion: string
|
|
17
|
-
releasePackage: string
|
|
18
|
-
sourceRevision: string
|
|
19
|
-
sourceTree: string
|
|
20
|
-
sourceDigest: string
|
|
21
|
-
generatedAt: 'derived-from-immutable-git-objects'
|
|
22
|
-
rootPackage: { name: string, version: string, private: boolean }
|
|
23
|
-
prerequisites: Record<string, string>
|
|
24
|
-
packages: ReleasePackageEntry[]
|
|
25
|
-
policy: {
|
|
26
|
-
tagMatchesReleasePackageVersion: true
|
|
27
|
-
rootVersionIsIndependent: true
|
|
28
|
-
notes: string
|
|
29
|
-
}
|
|
30
|
-
}
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
import{createHash}from"node:crypto";import{execFileSync}from"node:child_process";import{existsSync,mkdirSync,readFileSync,writeFileSync}from"node:fs";import{dirname,resolve}from"node:path";const root=resolve(import.meta.dir,"../../../../../../.."),outputPath=resolve(root,".github/protocol/evidence/release-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 showJson(sourceRevision,path){return JSON.parse(runGit("show",`${sourceRevision}:${path}`).toString())}function assertReleaseTag(tag){assertReleaseMapping(tag);try{runGit("show-ref","--verify","--quiet",`refs/tags/${tag}`)}catch{throw Error(`release tag does not exist: ${tag}`)}return runGit("rev-parse",`refs/tags/${tag}^{commit}`).toString().trim()}export function assertReleaseMapping(tag,releasePackageVersion){if(!/^v\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/.test(tag))throw Error(`release tag must be an exact semantic version tag, received: ${tag}`);if(releasePackageVersion!==void 0&&releasePackageVersion!==tag.slice(1))throw Error(`release tag ${tag} does not match storage/framework/package.json version ${releasePackageVersion}`)}export function buildReleaseManifest(tag){const sourceRevision=assertReleaseTag(tag),tagObjectType=runGit("cat-file","-t",`refs/tags/${tag}`).toString().trim(),tagType=tagObjectType==="tag"?"annotated":tagObjectType==="commit"?"lightweight":null;if(!tagType)throw Error(`release tag ${tag} points to unsupported Git object type: ${tagObjectType}`);const sourceTree=runGit("rev-parse",`${sourceRevision}^{tree}`).toString().trim(),treeListing=runGit("ls-tree","-r","-l",sourceRevision).toString(),packages=treeListing.trim().split(`
|
|
2
|
-
`).filter(Boolean).flatMap((line)=>{const path=line.match(/^\d+\s+blob\s+[0-9a-f]+\s+\d+\t(.+)$/)?.[1];return path!=null?[path]:[]}).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"),releasePackagePath="storage/framework/package.json",releasePackage=packages.find((pkg)=>pkg.path===releasePackagePath);if(!releasePackage)throw Error(`${releasePackagePath} is missing a name or version at ${sourceRevision}`);const releaseVersion=tag.slice(1);assertReleaseMapping(tag,releasePackage.version);return{schemaVersion:"1.0.0",repository:"https://github.com/stacksjs/stacks",tag,tagType,releaseVersion,releasePackage:releasePackage.name,sourceRevision,sourceTree,sourceDigest:`sha256:${createHash("sha256").update(treeListing).digest("hex")}`,generatedAt:"derived-from-immutable-git-objects",rootPackage:{name:rootPackage.name,version:rootPackage.version,private:rootPackage.private===!0},prerequisites:rootPackage.system||{},packages,policy:{tagMatchesReleasePackageVersion:!0,rootVersionIsIndependent:!0,notes:"The release tag versions stacks-framework. The private root package orchestrates the monorepo and has an independent version. Every versioned package is recorded at the exact tagged commit."}}}export function renderReleaseManifest(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/release-manifest.ts --write --tag <tag> | --check");process.exit(2)}if(mode==="write"){const index=process.argv.indexOf("--tag"),tag=index===-1?null:process.argv[index+1];if(!tag)throw Error("--tag requires an exact release tag");const manifest=buildReleaseManifest(tag);mkdirSync(dirname(outputPath),{recursive:!0});writeFileSync(outputPath,renderReleaseManifest(manifest));console.log(`Wrote release manifest for ${manifest.tag} at ${manifest.sourceRevision} (${manifest.packages.length} packages)`)}else{if(!existsSync(outputPath))throw Error("release manifest is missing; run bun run protocol:release -- --tag <tag>");const current=JSON.parse(readFileSync(outputPath,"utf8")),expected=renderReleaseManifest(buildReleaseManifest(current.tag));if(readFileSync(outputPath,"utf8")!==expected)throw Error(`release manifest is stale or modified; run bun run protocol:release -- --tag ${current.tag}`);console.log(`Release manifest matches ${current.tag} at ${current.sourceRevision}`)}}if(import.meta.main)await run();
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{describe,expect,it}from"bun:test";import{assertReleaseMapping,renderReleaseManifest}from"./release-manifest";describe("release manifest",()=>{it("requires the framework release version to match the tag",()=>{expect(()=>assertReleaseMapping("v0.70.161","0.70.161")).not.toThrow();expect(()=>assertReleaseMapping("v0.70.161","0.70.160")).toThrow("does not match");expect(()=>assertReleaseMapping("main")).toThrow("exact semantic version tag")});it("renders deterministically without wall-clock state",()=>{const manifest={schemaVersion:"1.0.0",repository:"https://github.com/stacksjs/stacks",tag:"v0.70.161",tagType:"lightweight",releaseVersion:"0.70.161",releasePackage:"stacks-framework",sourceRevision:"a9eaab647858ee12d891a74341c99923074a6faf",sourceTree:"99ebce98969603c1fa0b0f743efcc04c9de02b98",sourceDigest:"sha256:f20e1dabc57b8b9c0422d6574d756a0fc8ba40b1df2598171e28dcade07e3535",generatedAt:"derived-from-immutable-git-objects",rootPackage:{name:"stacks",version:"0.70.52",private:!0},prerequisites:{bun:"^1.3.0"},packages:[],policy:{tagMatchesReleasePackageVersion:!0,rootVersionIsIndependent:!0,notes:"test policy"}};expect(manifest.generatedAt).toBe("derived-from-immutable-git-objects");expect(renderReleaseManifest(manifest)).toBe(`${JSON.stringify(manifest,null,2)}
|
|
2
|
-
`)})});
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { string } from '../../../../validation/src/index';
|
|
2
|
-
export declare function executeSecurityEvidence(revision: string): Evidence;
|
|
3
|
-
export declare function executeConfigEvidence(revision: string): Evidence;
|
|
4
|
-
export declare function executeValidationEvidence(revision: string): Promise<Evidence>;
|
|
5
|
-
export declare function executeConventionsEvidence(revision: string): Evidence;
|
|
6
|
-
export declare function executeLifecycleEvidence(revision: string): Promise<Evidence>;
|
|
7
|
-
export declare function executeQueryEvidence(revision: string): Promise<Evidence>;
|
|
8
|
-
export declare function executeDatabaseEvidence(revision: string): Promise<Evidence>;
|
|
9
|
-
export declare function buildReport(): Promise<Record<string, unknown>>;
|
|
10
|
-
export declare function run(): Promise<void>;
|
|
11
|
-
declare interface Result {
|
|
12
|
-
requirementId: string
|
|
13
|
-
status: ResultStatus
|
|
14
|
-
fixtureId: string | null
|
|
15
|
-
evidenceUrl: string | null
|
|
16
|
-
durationMs: number
|
|
17
|
-
notes?: string
|
|
18
|
-
}
|
|
19
|
-
declare type ResultStatus = 'pass' | 'fail' | 'skipped' | 'unsupported' | 'exception' | 'experimental';
|
|
20
|
-
/** Executable-check evidence keyed by requirement id, merged into the report. */
|
|
21
|
-
declare type Evidence = Map<string, Omit<Result, 'requirementId' | 'fixtureId'>>;
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import{createHash}from"node:crypto";import{existsSync,mkdirSync,readFileSync,writeFileSync}from"node:fs";import{arch,platform}from"node:os";import{resolve}from"node:path";import Ajv2020 from"ajv/dist/2020.js";import addFormats from"ajv-formats";import{Action}from"../../../../actions/src/index";import{assertCapabilityAvailable,capabilityRegistry}from"../../../../config/src/capabilities";import{decryptValue,encryptValue,generateKeypair}from"../../../../env/src/crypto";import{escapeHtml}from"../../../../error-handling/src/error-page-template";import{appPath,defaultsAppPath}from"../../../../path/src/index";import{createValidationErrorResponse}from"../../../../router/src/error-handler";import{timingSafeEqualString}from"../../../../security/src/hash";import{object,string}from"../../../../validation/src/index";const root=resolve(import.meta.dir,"../../../../../../.."),suiteRoot=resolve(root,".github/protocol/suite/1.0-draft");function git(...arguments_){const result=Bun.spawnSync(["git",...arguments_],{cwd:root});if(result.exitCode!==0)throw Error(result.stderr.toString().trim());return result.stdout.toString().trim()}function exactSourceDigest(){const tree=git("rev-parse","HEAD^{tree}");return`sha256:${createHash("sha256").update(tree).digest("hex")}`}function tamper(ciphertext){const prefix="encrypted:",payload=Buffer.from(ciphertext.slice(prefix.length),"base64"),last=payload.length-1;if(last>=0)payload[last]=(payload[last]??0)^1;return`${prefix}${payload.toString("base64")}`}function blob(revision,path){return`https://github.com/stacksjs/stacks/blob/${revision}/${path}`}export function executeSecurityEvidence(revision){const evidence=new Map,cryptoUrl=blob(revision,"storage/framework/core/env/src/crypto.ts"),comparisonUrl=blob(revision,"storage/framework/core/security/src/hash.ts"),renderUrl=blob(revision,"storage/framework/core/error-handling/src/error-page-template.ts"),started=performance.now();try{const{publicKey,privateKey}=generateKeypair(),encrypted=encryptValue("secret",publicKey),roundTrip=decryptValue(encrypted,privateKey);let tamperRejected=!1;try{decryptValue(tamper(encrypted),privateKey)}catch{tamperRejected=!0}const passed=roundTrip==="secret"&&!encrypted.includes("secret")&&tamperRejected;evidence.set("CORE-SEC-05",{status:passed?"pass":"fail",evidenceUrl:cryptoUrl,durationMs:Math.max(0,performance.now()-started),notes:passed?"Authenticated-encryption round trip passed and modified ciphertext was rejected.":"Authenticated-encryption fixture failed."})}catch(error){evidence.set("CORE-SEC-05",{status:"fail",evidenceUrl:cryptoUrl,durationMs:Math.max(0,performance.now()-started),notes:`Authenticated-encryption fixture threw: ${error instanceof Error?error.message:String(error)}`})}const comparisonStarted=performance.now(),unequal=timingSafeEqualString("token-a","token-b")===!1;evidence.set("CORE-SEC-07",{status:unequal?"pass":"fail",evidenceUrl:comparisonUrl,durationMs:Math.max(0,performance.now()-comparisonStarted),notes:unequal?"The public authenticator comparison helper uses the runtime timing-safe primitive.":"Timing-safe comparison fixture failed."});const renderStarted=performance.now(),renderOk=escapeHtml("<script>alert(1)</script>")==="<script>alert(1)</script>";evidence.set("CORE-SEC-02",{status:renderOk?"pass":"fail",evidenceUrl:renderUrl,durationMs:Math.max(0,performance.now()-renderStarted),notes:renderOk?"Untrusted markup is converted to HTML entities by the default escaper.":"Default render-escaping fixture failed."});return evidence}export function executeConfigEvidence(revision){const evidence=new Map,url=blob(revision,"storage/framework/core/config/src/capabilities.ts"),started=performance.now();let failedClosed=!1,message="";try{assertCapabilityAvailable("queue","planned")}catch(error){failedClosed=!0;message=error instanceof Error?error.message:String(error)}evidence.set("CORE-CONFIG-02",{status:failedClosed?"pass":"fail",evidenceUrl:url,durationMs:Math.max(0,performance.now()-started),notes:failedClosed?`Selecting an unavailable driver is rejected before use: ${message}`:"Fail-closed capability guard accepted an unavailable driver."});const drvStarted=performance.now();let drvFailedClosed=!1;try{assertCapabilityAvailable("queue","planned-driver")}catch{drvFailedClosed=!0}evidence.set("STD-DRV-01",{status:drvFailedClosed?"pass":"fail",evidenceUrl:url,durationMs:Math.max(0,performance.now()-drvStarted),notes:drvFailedClosed?"A planned driver is rejected loudly with no silent fallback.":"Driver-failure fixture did not reject a planned driver."});return evidence}export async function executeValidationEvidence(revision){const evidence=new Map,validationUrl=blob(revision,"storage/framework/core/validation/src/validator.ts"),envelopeUrl=blob(revision,"storage/framework/core/router/src/error-handler.ts"),started=performance.now(),result=await object({profile:object({email:string().email()})}).validate({profile:{email:"bad"}}),valOk=result.valid===!1&&Object.keys(result.errors).includes("profile.email");evidence.set("CORE-VAL-01",{status:valOk?"pass":"fail",evidenceUrl:validationUrl,durationMs:Math.max(0,performance.now()-started),notes:valOk?"Nested invalid input produced a stable field-keyed error at profile.email.":"Field-keyed validation fixture failed."});const envStarted=performance.now(),fieldErrors={};for(const[field,errors]of Object.entries(result.errors))fieldErrors[field]=errors.map((entry)=>entry.message??String(entry));const response=createValidationErrorResponse(fieldErrors,new Request("http://conformance.local/profile",{method:"POST"})),body=await response.text(),durationEnv=Math.max(0,performance.now()-envStarted),envelopeOk=response.status===422&&body.includes('"message":"Validation failed"')&&body.includes("profile.email");evidence.set("CORE-ERR-01",{status:envelopeOk?"pass":"fail",evidenceUrl:envelopeUrl,durationMs:durationEnv,notes:envelopeOk?"Validation failure serialized to a stable 422 envelope with error, message, status, and field errors.":"Error-envelope fixture failed."});const leaks=["stack","password","SELECT","/home/"].filter((token)=>body.includes(token));evidence.set("CORE-ERR-02",{status:envelopeOk&&leaks.length===0?"pass":"fail",evidenceUrl:envelopeUrl,durationMs:durationEnv,notes:leaks.length===0?"Production error envelope contained no stack trace, credentials, raw query, or filesystem path.":`Production error envelope leaked: ${leaks.join(", ")}.`});return evidence}export function executeConventionsEvidence(revision){const evidence=new Map,rolesUrl=blob(revision,"storage/framework/core/path/src/index.ts"),overrideUrl=blob(revision,"storage/framework/core/router/src/stacks-router.ts"),started=performance.now(),conv01Ok=appPath("Actions/Greet").endsWith("/app/Actions/Greet");evidence.set("CORE-CONV-01",{status:conv01Ok?"pass":"fail",evidenceUrl:rolesUrl,durationMs:Math.max(0,performance.now()-started),notes:conv01Ok?"The Action role maps to its documented app/Actions/<name> path.":"Role-to-path mapping fixture failed."});const overrideStarted=performance.now(),logical="Actions/NotifyUser.ts",userCandidate=appPath(logical),defaultCandidate=defaultsAppPath(logical),resolved=existsSync(userCandidate)?userCandidate:defaultCandidate,conv02Ok=existsSync(userCandidate)&&existsSync(defaultCandidate)&&resolved===userCandidate;evidence.set("CORE-CONV-02",{status:conv02Ok?"pass":"fail",evidenceUrl:overrideUrl,durationMs:Math.max(0,performance.now()-overrideStarted),notes:conv02Ok?"With the same logical path present in both app/ and framework defaults, resolution selects the app-owned file.":"Override-precedence fixture failed."});return evidence}export async function executeLifecycleEvidence(revision){const evidence=new Map,url=blob(revision,"storage/framework/core/actions/src/action.ts"),started=performance.now(),mvaOk=(await new Action({name:"Increment",handle(request){return{value:request.body.value+1}}}).handle({body:{value:1}}))?.value===2;evidence.set("CORE-MVA-01",{status:mvaOk?"pass":"fail",evidenceUrl:url,durationMs:Math.max(0,performance.now()-started),notes:mvaOk?"An Action was invoked directly with no HTTP transport and returned its computed result.":"Direct Action invocation fixture failed."});return evidence}export async function executeQueryEvidence(revision){const evidence=new Map,url=blob(revision,"storage/framework/core/database/src/types.ts"),started=performance.now();try{const{sql}=await import("../../../../database/src/types"),attack="' OR 1=1 --",query=sql`SELECT * FROM users WHERE email = ${attack}`,parameterized=query.sql==="SELECT * FROM users WHERE email = ?"&&Array.isArray(query.parameters)&&query.parameters.length===1&&query.parameters[0]===attack;evidence.set("CORE-SEC-01",{status:parameterized?"pass":"fail",evidenceUrl:url,durationMs:Math.max(0,performance.now()-started),notes:parameterized?"Untrusted input is bound as a positional parameter and never inlined into the SQL text.":"Query-parameterization fixture failed."})}catch(error){evidence.set("CORE-SEC-01",{status:"skipped",evidenceUrl:null,durationMs:Math.max(0,performance.now()-started),notes:`Query builder unavailable in this environment: ${error instanceof Error?error.message.slice(0,100):String(error)}`})}return evidence}export async function executeDatabaseEvidence(revision){const evidence=new Map,url=blob(revision,"storage/framework/core/query-builder/src/index.ts"),started=performance.now();try{const{createQueryBuilder,setConfig}=await import("../../../../query-builder/src/index");setConfig({dialect:"sqlite",database:":memory:"});const db=createQueryBuilder();await db.raw`DROP TABLE IF EXISTS conformance_widgets`.execute();await db.raw`CREATE TABLE conformance_widgets (id INTEGER PRIMARY KEY, name TEXT)`.execute();await db.insertInto("conformance_widgets").values({id:1,name:"a"}).execute();const created=await db.selectFrom("conformance_widgets").selectAll().execute();await db.updateTable("conformance_widgets").set({name:"b"}).where("id","=",1).execute();const updated=await db.selectFrom("conformance_widgets").select(["name"]).where("id","=",1).execute();await db.deleteFrom("conformance_widgets").where("id","=",1).execute();const afterDelete=await db.selectFrom("conformance_widgets").selectAll().execute(),crudOk=created.length===1&&created[0]?.name==="a"&&updated[0]?.name==="b"&&afterDelete.length===0;evidence.set("CORE-DATA-01",{status:crudOk?"pass":"fail",evidenceUrl:url,durationMs:Math.max(0,performance.now()-started),notes:crudOk?"Create, read, update, and delete round-trip succeeded against SQLite.":"CRUD fixture failed."});const txStarted=performance.now();await db.insertInto("conformance_widgets").values({id:1,name:"keep"}).execute();let rolledBack=!1;try{await db.transaction(async(trx)=>{await trx.insertInto("conformance_widgets").values({id:2,name:"temp"}).execute();throw Error("force rollback")})}catch{rolledBack=!0}const rows=await db.selectFrom("conformance_widgets").selectAll().execute(),txOk=rolledBack&&rows.length===1&&rows[0]?.id===1;evidence.set("CORE-DATA-03",{status:txOk?"pass":"fail",evidenceUrl:url,durationMs:Math.max(0,performance.now()-txStarted),notes:txOk?"A failing transaction rolled back its writes, leaving prior state intact.":"Transaction-rollback fixture failed."});const relStarted=performance.now();await db.raw`DROP TABLE IF EXISTS conformance_books`.execute();await db.raw`DROP TABLE IF EXISTS conformance_authors`.execute();await db.raw`CREATE TABLE conformance_authors (id INTEGER PRIMARY KEY, name TEXT)`.execute();await db.raw`CREATE TABLE conformance_books (id INTEGER PRIMARY KEY, author_id INTEGER, title TEXT)`.execute();await db.insertInto("conformance_authors").values({id:1,name:"Ada"}).execute();await db.insertInto("conformance_books").values([{id:1,author_id:1,title:"B1"},{id:2,author_id:1,title:"B2"}]).execute();const related=await db.selectFrom("conformance_books").innerJoin("conformance_authors","conformance_authors.id","=","conformance_books.author_id").select(["conformance_books.title","conformance_authors.name"]).where("conformance_authors.id","=",1).execute(),relationOk=related.length===2&&related.every((row)=>row.name==="Ada");evidence.set("CORE-DATA-02",{status:relationOk?"pass":"fail",evidenceUrl:url,durationMs:Math.max(0,performance.now()-relStarted),notes:relationOk?"A relation query joined related rows across two tables.":"Relation fixture failed."})}catch(error){const note=`Query builder unavailable in this environment: ${error instanceof Error?error.message.slice(0,100):String(error)}`;for(const id of["CORE-DATA-01","CORE-DATA-02","CORE-DATA-03"])if(!evidence.has(id))evidence.set(id,{status:"skipped",evidenceUrl:null,durationMs:Math.max(0,performance.now()-started),notes:note})}return evidence}function validateSemantics(report,catalog,fixtures){const errors=[],expected=new Set(catalog.requirements.map((requirement)=>requirement.id)),seen=new Set,fixtureIds=new Set(fixtures.fixtures.map((fixture)=>fixture.id));for(const result of report.results){if(seen.has(result.requirementId))errors.push(`${result.requirementId}: duplicate result`);if(!expected.has(result.requirementId))errors.push(`${result.requirementId}: unknown requirement`);if(result.fixtureId&&!fixtureIds.has(result.fixtureId))errors.push(`${result.requirementId}: unknown fixture`);if(result.status==="pass"&&!result.evidenceUrl)errors.push(`${result.requirementId}: pass requires evidence`);seen.add(result.requirementId)}for(const id of expected)if(!seen.has(id))errors.push(`${id}: missing result`);if(report.profileClaim!==null)errors.push("The Stacks adapter must remain unverified until profile calculation is implemented");return errors}function renderSummary(report){const counts=new Map;for(const result of report.results)counts.set(result.status,(counts.get(result.status)||0)+1);const rows=[...counts].sort(([a],[b])=>a.localeCompare(b)).map(([status,count])=>`| ${status} | ${count} |`).join(`
|
|
2
|
-
`);return`# Stacks protocol conformance report
|
|
3
|
-
|
|
4
|
-
**Profile claim:** Unverified
|
|
5
|
-
**Implementation:** \`${report.implementation.revision}\` (${report.implementation.version})
|
|
6
|
-
**Protocol:** ${report.protocol.version}, catalog ${report.protocol.catalogRevision}, suite ${report.protocol.suiteVersion}
|
|
7
|
-
**Runtime/platform:** Bun ${report.execution.runtime.version} on ${report.execution.platform.os}/${report.execution.platform.architecture}
|
|
8
|
-
**CI:** [run](${report.execution.ci.runUrl}) \xB7 [artifact](${report.execution.ci.artifactUrl})
|
|
9
|
-
|
|
10
|
-
| Status | Count |
|
|
11
|
-
| --- | ---: |
|
|
12
|
-
${rows}
|
|
13
|
-
|
|
14
|
-
Only executable adapter checks are marked \`pass\`. All remaining requirements stay \`skipped\` until their fixtures are wired to Stacks public APIs.
|
|
15
|
-
`}export async function buildReport(){const startedAt=new Date,catalog=JSON.parse(readFileSync(resolve(suiteRoot,"catalog.json"),"utf8")),fixtures=JSON.parse(readFileSync(resolve(suiteRoot,"fixtures/conformance.json"),"utf8")),lock=JSON.parse(readFileSync(resolve(root,".github/protocol/suite.lock.json"),"utf8")),packageJson=JSON.parse(readFileSync(resolve(root,"package.json"),"utf8")),revision=process.env.GITHUB_SHA||git("rev-parse","HEAD"),runUrl=process.env.GITHUB_SERVER_URL&&process.env.GITHUB_REPOSITORY&&process.env.GITHUB_RUN_ID?`${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}/actions/runs/${process.env.GITHUB_RUN_ID}`:`https://github.com/stacksjs/stacks/commit/${revision}`,evidence=executeSecurityEvidence(revision);for(const[id,value]of executeConfigEvidence(revision))evidence.set(id,value);for(const[id,value]of executeConventionsEvidence(revision))evidence.set(id,value);for(const[id,value]of await executeValidationEvidence(revision))evidence.set(id,value);for(const[id,value]of await executeLifecycleEvidence(revision))evidence.set(id,value);for(const[id,value]of await executeQueryEvidence(revision))evidence.set(id,value);for(const[id,value]of await executeDatabaseEvidence(revision))evidence.set(id,value);const fixtureByRequirement=new Map(fixtures.fixtures.flatMap((fixture)=>fixture.requirements.map((id)=>[id,fixture.id]))),results=catalog.requirements.map((requirement)=>({requirementId:requirement.id,fixtureId:fixtureByRequirement.get(requirement.id)||null,...evidence.get(requirement.id)||{status:"skipped",evidenceUrl:null,durationMs:0,notes:requirement.evidence==="behavior"?"Fixture adapter is not implemented yet.":"Inspection evidence is not linked yet."}})),drivers=capabilityRegistry.map((driver)=>({category:driver.category,name:driver.name,version:packageJson.version,serviceVersion:null,topology:driver.topology,status:driver.status,evidenceUrl:driver.testEvidence[0]?`https://github.com/stacksjs/stacks/blob/${revision}/${driver.testEvidence[0]}`:null,prerequisites:driver.prerequisites}));return{reportVersion:"1.0.0-draft.1",protocol:{version:catalog.protocolVersion,catalogRevision:catalog.catalogRevision,suiteVersion:fixtures.suiteVersion,rfcsRevision:lock.rfcsRevision},implementation:{name:"Stacks",version:packageJson.version,revision,repository:"https://github.com/stacksjs/stacks",sourceDigest:exactSourceDigest()},execution:{startedAt:startedAt.toISOString(),completedAt:new Date().toISOString(),runtime:{name:"bun",version:Bun.version},platform:{os:platform(),architecture:arch()},ci:{provider:process.env.GITHUB_ACTIONS?"github-actions":"local",runUrl,artifactUrl:`${runUrl}#artifacts`}},profileClaim:null,results,drivers,extensions:catalog.extensions.map((extension)=>extension.id==="EXT-DESKTOP-01"?{id:extension.id,status:"experimental",evidenceUrl:`https://github.com/stacksjs/stacks/blob/${revision}/protocol/evidence/desktop-support.json`,notes:"Craft targets are explicitly experimental pending native release evidence and signing infrastructure."}:{id:extension.id,status:"unsupported",evidenceUrl:null,notes:"Not evaluated by this adapter."}),exceptions:[],generator:{name:"@stacksjs/protocol-adapter",version:"1.0.0-draft.1",revision}}}export async function run(){const report=await buildReport(),schema=JSON.parse(readFileSync(resolve(suiteRoot,"schemas/conformance-report.schema.json"),"utf8")),catalog=JSON.parse(readFileSync(resolve(suiteRoot,"catalog.json"),"utf8")),fixtures=JSON.parse(readFileSync(resolve(suiteRoot,"fixtures/conformance.json"),"utf8")),ajv=new Ajv2020({allErrors:!0,strict:!1});addFormats(ajv);const validate=ajv.compile(schema),errors=[...validate(report)?[]:(validate.errors||[]).map((error)=>`${error.instancePath||"/"} ${error.message||"is invalid"}`),...validateSemantics(report,catalog,fixtures)];if(errors.length>0){for(const error of errors)console.error(`error: ${error}`);process.exit(1)}const outputDirectory=resolve(process.env.PROTOCOL_REPORT_DIR||resolve(root,".github/protocol/reports"));mkdirSync(outputDirectory,{recursive:!0});writeFileSync(resolve(outputDirectory,"stacks-conformance.json"),`${JSON.stringify(report,null,2)}
|
|
16
|
-
`);writeFileSync(resolve(outputDirectory,"stacks-conformance.md"),renderSummary(report));console.log(`Protocol report generated in ${outputDirectory}`)}if(import.meta.main)await run();
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{describe,expect,it}from"bun:test";import{buildReport,executeConfigEvidence,executeConventionsEvidence,executeDatabaseEvidence,executeLifecycleEvidence,executeQueryEvidence,executeSecurityEvidence,executeValidationEvidence}from"./run-conformance";const REVISION="0".repeat(40);describe("protocol adapter evidence",()=>{it("executes authenticated encryption, timing-safe comparison, and default escaping checks",()=>{const evidence=executeSecurityEvidence(REVISION);expect(evidence.get("CORE-SEC-05")?.status).toBe("pass");expect(evidence.get("CORE-SEC-07")?.status).toBe("pass");expect(evidence.get("CORE-SEC-02")?.status).toBe("pass")});it("rejects unavailable and planned drivers loudly, before any work begins",()=>{const evidence=executeConfigEvidence(REVISION);expect(evidence.get("CORE-CONFIG-02")?.status).toBe("pass");expect(evidence.get("STD-DRV-01")?.status).toBe("pass")});it("invokes an Action directly, independent of any HTTP transport",async()=>{const evidence=await executeLifecycleEvidence(REVISION);expect(evidence.get("CORE-MVA-01")?.status).toBe("pass")});it("parameterizes untrusted values instead of inlining them into SQL",async()=>{const evidence=await executeQueryEvidence(REVISION);expect(evidence.get("CORE-SEC-01")?.status).toBe("pass")});it("performs a CRUD round-trip, a relation join, and rolls back a failed transaction",async()=>{const evidence=await executeDatabaseEvidence(REVISION);expect(evidence.get("CORE-DATA-01")?.status).toBe("pass");expect(evidence.get("CORE-DATA-02")?.status).toBe("pass");expect(evidence.get("CORE-DATA-03")?.status).toBe("pass")});it("produces field-keyed validation errors and a redacted 422 envelope",async()=>{const evidence=await executeValidationEvidence(REVISION);expect(evidence.get("CORE-VAL-01")?.status).toBe("pass");expect(evidence.get("CORE-ERR-01")?.status).toBe("pass");expect(evidence.get("CORE-ERR-02")?.status).toBe("pass")});it("maps canonical roles to paths and prefers app-owned overrides",()=>{const evidence=executeConventionsEvidence(REVISION);expect(evidence.get("CORE-CONV-01")?.status).toBe("pass");expect(evidence.get("CORE-CONV-02")?.status).toBe("pass")});it("reports each registered driver independently",async()=>{const report=await buildReport();expect(report.drivers.length).toBeGreaterThan(7);expect(report.drivers).toContainEqual(expect.objectContaining({category:"database",name:"sqlite"}));expect(report.drivers).toContainEqual(expect.objectContaining({category:"queue",name:"sqs"}))});it("marks every passing requirement with a source evidence url",async()=>{const passing=(await buildReport()).results.filter((result)=>result.status==="pass");expect(passing.length).toBeGreaterThanOrEqual(15);expect(passing.every((result)=>typeof result.evidenceUrl==="string"&&result.evidenceUrl.startsWith("https://"))).toBe(!0)})});
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import type { CapabilityDriver } from '../../../../config/src/capabilities';
|
|
2
|
-
export declare function planDriverContracts(drivers: readonly CapabilityDriver[]): {
|
|
3
|
-
tests: string[]
|
|
4
|
-
records: Array<CapabilityDriver & { execution: 'run' | 'not-run', reason: string | null }>
|
|
5
|
-
};
|
|
6
|
-
export declare function runDriverContracts(): void;
|
|
7
|
-
export declare function run(): Promise<void>;
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import{Database}from"bun:sqlite";import{mkdirSync,writeFileSync}from"node:fs";import{arch,platform}from"node:os";import{resolve}from"node:path";import{capabilityRegistry}from"../../../../config/src/capabilities";const root=resolve(import.meta.dir,"../../../../../../.."),reportRoot=resolve(process.env.PROTOCOL_REPORT_DIR||resolve(root,".github/protocol/reports"));export function planDriverContracts(drivers){const tests=[...new Set(drivers.filter((driver)=>driver.status==="supported").flatMap((driver)=>driver.testEvidence))].sort(),records=drivers.map((driver)=>({...driver,execution:driver.status==="supported"?"run":"not-run",reason:driver.status==="supported"?null:`Maturity is ${driver.status}; prerequisites and missing evidence are reported without promotion.`}));return{tests,records}}function sqliteVersion(){const database=new Database(":memory:");try{return database.query("select sqlite_version() as version").get().version}finally{database.close()}}function markdown(report){const rows=report.drivers.map((driver)=>`| ${driver.category} | ${driver.name} | ${driver.maturity} | ${driver.execution} | ${driver.topology} | ${driver.reason||"Retained test paths passed."} |`).join(`
|
|
2
|
-
`);return`# Stacks driver contract matrix
|
|
3
|
-
|
|
4
|
-
- Source: \`${report.sourceRevision}\`
|
|
5
|
-
- Runtime: Bun \`${report.environment.runtime.version}\` on \`${report.environment.platform.os}/${report.environment.platform.architecture}\`
|
|
6
|
-
- SQLite: \`${report.environment.services.sqlite}\`
|
|
7
|
-
- Redis: \`${report.environment.services.redis.version}\` at \`${report.environment.services.redis.topology}\`
|
|
8
|
-
- Test files: ${report.testRun.files.length}
|
|
9
|
-
- Result: **${report.testRun.status}**
|
|
10
|
-
|
|
11
|
-
| Category | Driver | Maturity | Execution | Topology | Evidence boundary |
|
|
12
|
-
| --- | --- | --- | --- | --- | --- |
|
|
13
|
-
${rows}
|
|
14
|
-
`}export function runDriverContracts(){const plan=planDriverContracts(capabilityRegistry);if(!plan.tests.length)throw Error("No supported driver contracts were selected");const revisionResult=Bun.spawnSync(["git","rev-parse","HEAD"],{cwd:root});if(revisionResult.exitCode!==0)throw Error("Could not resolve the Stacks revision");const started=performance.now(),result=Bun.spawnSync(["bun","test",...plan.tests],{cwd:root,stdout:"inherit",stderr:"inherit"}),durationMs=Math.round(performance.now()-started),status=result.exitCode===0?"pass":"fail",report={schemaVersion:"1.0.0",sourceRevision:revisionResult.stdout.toString().trim(),environment:{runtime:{name:"bun",version:Bun.version},platform:{os:platform(),architecture:arch()},ci:process.env.GITHUB_ACTIONS==="true"?"github-actions":"local",services:{sqlite:sqliteVersion(),redis:{version:process.env.REDIS_SERVICE_VERSION||"unreported",url:process.env.REDIS_URL?"redis://127.0.0.1:6379/0":"not provisioned",topology:"single-node loopback process provisioned by Pantry Action"},otherExternal:"not provisioned; partial/experimental drivers are not promoted"}},testRun:{status,durationMs,files:plan.tests},drivers:plan.records.map((driver)=>({category:driver.category,name:driver.name,maturity:driver.status,execution:driver.execution==="run"?status:driver.execution,topology:driver.topology,prerequisites:driver.prerequisites,evidence:driver.testEvidence,limitations:driver.limitations,reason:driver.reason}))};mkdirSync(reportRoot,{recursive:!0});writeFileSync(resolve(reportRoot,"driver-matrix.json"),`${JSON.stringify(report,null,2)}
|
|
15
|
-
`);writeFileSync(resolve(reportRoot,"driver-matrix.md"),markdown(report));if(status==="fail")throw Error("Supported driver contract tests failed");console.log(`Driver contract matrix passed ${plan.tests.length} retained test files`)}export async function run(){try{runDriverContracts()}catch(error){console.error(error instanceof Error?error.message:String(error));process.exit(1)}}if(import.meta.main)await run();
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{describe,expect,it}from"bun:test";import{planDriverContracts}from"./run-driver-contracts";describe("driver contract matrix planning",()=>{it("runs only supported evidence and reports all other maturity states explicitly",()=>{const plan=planDriverContracts([{category:"cache",name:"memory",status:"supported",implementation:"memory.ts",testEvidence:["memory.test.ts"],topology:"memory",prerequisites:[],limitations:[]},{category:"cache",name:"redis",status:"partial",implementation:"redis.ts",testEvidence:["redis.test.ts"],topology:"redis",prerequisites:["Redis"],limitations:["No live evidence"]},{category:"queue",name:"sqs",status:"unsupported",implementation:null,testEvidence:[],topology:"sqs",prerequisites:["AWS"],limitations:["Reserved"]}]);expect(plan.tests).toEqual(["memory.test.ts"]);expect(plan.records.map((record)=>[record.name,record.execution])).toEqual([["memory","run"],["redis","not-run"],["sqs","not-run"]]);expect(plan.records[1].reason).toContain("partial")})});
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
export declare function buildSourceManifest(requestedRevision: string): SourceManifest;
|
|
2
|
-
export declare function run(): Promise<void>;
|
|
3
|
-
declare interface PackageEntry { name: string, path: string, version: string, publishable: boolean }
|
|
4
|
-
declare interface SourceManifest {
|
|
5
|
-
schemaVersion: '1.0.0'
|
|
6
|
-
repository: string
|
|
7
|
-
sourceRevision: string
|
|
8
|
-
sourceTree: string
|
|
9
|
-
sourceDigest: string
|
|
10
|
-
generatedAt: string
|
|
11
|
-
classification: {
|
|
12
|
-
status: 'reference-implementation'
|
|
13
|
-
conformance: 'unverified'
|
|
14
|
-
notes: string
|
|
15
|
-
}
|
|
16
|
-
prerequisites: Record<string, string>
|
|
17
|
-
packages: PackageEntry[]
|
|
18
|
-
inventory: {
|
|
19
|
-
totalFiles: number
|
|
20
|
-
totalBytes: number
|
|
21
|
-
categories: Record<string, { files: number, bytes: number }>
|
|
22
|
-
extensions: Record<string, number>
|
|
23
|
-
}
|
|
24
|
-
protocolSuite: { version: string, rfcsRevision: string }
|
|
25
|
-
}
|
|
@@ -1,3 +0,0 @@
|
|
|
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,8 +0,0 @@
|
|
|
1
|
-
/** Requirement ids that appear more than once in `ids` (sorted, deduped). */
|
|
2
|
-
export declare function duplicateRequirementIds(ids: string[]): string[];
|
|
3
|
-
/**
|
|
4
|
-
* Requirement ids referenced by a fixture that are absent from `catalogIds`,
|
|
5
|
-
* formatted `fixtureId -> requirementId`.
|
|
6
|
-
*/
|
|
7
|
-
export declare function danglingFixtureRequirements(fixtures: Array<{ id: string, requirements?: string[] }>, catalogIds: Set<string>): string[];
|
|
8
|
-
export declare function run(): Promise<void>;
|
|
@@ -1,4 +0,0 @@
|
|
|
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:
|
|
3
|
-
${errors.join(`
|
|
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 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1 +0,0 @@
|
|
|
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,8 +0,0 @@
|
|
|
1
|
-
import type { CLI } from '@stacksjs/types';
|
|
2
|
-
/**
|
|
3
|
-
* Framework-repo `buddy protocol:*` commands. The governance tooling itself
|
|
4
|
-
* lives beside this file under `commands/protocol/`; the protocol suite +
|
|
5
|
-
* evidence DATA stays under `.github/protocol/`. These wrap the tooling so it
|
|
6
|
-
* is discoverable via the CLI (`buddy protocol:conformance`).
|
|
7
|
-
*/
|
|
8
|
-
export declare function protocol(buddy: CLI): void;
|
|
@@ -1 +0,0 @@
|
|
|
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")})}
|