mirror of
https://github.com/morluto/rea.git
synced 2026-10-11 21:39:55 +00:00
fix(skills): expose authored skill to repository discovery
This commit is contained in:
@@ -28,7 +28,7 @@ intentionally not included. -->
|
||||
- Provider, bridge, target-format, or platform compatibility:
|
||||
- Evidence, artifact, provenance, or reconstruction contract:
|
||||
- Process execution, authorization, cleanup, or containment impact:
|
||||
- Generated metadata (`docs/public/product-catalog.json`), package, or installation impact (CI generates and validates ignored catalogs and `skills/`; edit authored instructions in `skill-src/` and never commit build outputs):
|
||||
- Generated metadata (`docs/public/product-catalog.json`), package, or installation impact (CI generates and validates ignored catalogs and `skills/`; edit authored instructions in `.agents/skills/reverse-engineer-anything/` and never commit build outputs):
|
||||
|
||||
## Evidence and regression coverage
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ Use [.nvmrc](.nvmrc) and `package.json#packageManager` for the pinned toolchain.
|
||||
|
||||
Use relevant checks for the change. The complete local gate, `npm run check:pr`, is optional for broad changes or CI diagnosis. See [CONTRIBUTING.md](CONTRIBUTING.md) for development, generated-file ownership, and release conventions.
|
||||
|
||||
`docs/public/product-catalog.json`, `docs/verification/managed-conformance-*.json`, and `skills/` are ignored outputs. Edit source contracts and `skill-src/`, then regenerate as needed. `.cache/mcp-tool-catalog.json` is test metadata; runtime builds and source checking do not consume it. Never commit binaries, provider project documents, credentials, `dist/`, `node_modules/`, or local planning artifacts.
|
||||
`docs/public/product-catalog.json`, `docs/verification/managed-conformance-*.json`, and `skills/` are ignored outputs. Edit source contracts and `.agents/skills/reverse-engineer-anything/`, then regenerate as needed. `.cache/mcp-tool-catalog.json` is test metadata; runtime builds and source checking do not consume it. Never commit binaries, provider project documents, credentials, `dist/`, `node_modules/`, or local planning artifacts.
|
||||
|
||||
## Tool and Test Changes
|
||||
|
||||
|
||||
+6
-2
@@ -95,8 +95,12 @@ Pre-commit formats and lints staged files; pre-push runs `check:fast`.
|
||||
`evidence:generate` prepares only the managed commitment and its runtime/skill
|
||||
dependencies. The ignored outputs are `docs/public/product-catalog.json`,
|
||||
`docs/verification/managed-conformance-*.json`, and `skills/`. Edit authored
|
||||
skill instructions in `skill-src/`. CI validates generated outputs and retains
|
||||
them as artifacts; do not commit them. Reviewed source metadata, including
|
||||
skill instructions in `.agents/skills/reverse-engineer-anything/`, where Skills
|
||||
can discover the public bundle directly from a clean checkout. `verify:package`
|
||||
installs that bundle with Skills 1.7.2 using default repository-root discovery
|
||||
and checks every installed file, alongside the packaged setup checks.
|
||||
CI validates generated outputs and retains them as artifacts; do not commit
|
||||
them. Reviewed source metadata, including
|
||||
`src/generatedPackageMetadata.ts` and `docs/error-contract.schema.json`, remains
|
||||
tracked and checked for freshness.
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ npx skills add morluto/rea --skill reverse-engineer-anything
|
||||
|
||||
This installs agent instructions and bundled references, not REA MCP
|
||||
registration or analysis engines. Follow the skill's
|
||||
[conditional connection guide](https://github.com/morluto/rea/blob/main/skill-src/reverse-engineer-anything/SKILL.md#connect-only-when-needed).
|
||||
[conditional connection guide](https://github.com/morluto/rea/blob/main/.agents/skills/reverse-engineer-anything/SKILL.md#connect-only-when-needed).
|
||||
Working tools can be used immediately. If tools are missing, inspect the current
|
||||
client's registration with `doctor --client codex --json` (substitute its client
|
||||
ID), then plan repairs with `setup --client codex --dry-run --json`. Show and
|
||||
|
||||
@@ -17,7 +17,7 @@ const lock = JSON.parse(
|
||||
await readFile(join(root, "package-lock.json"), "utf8"),
|
||||
);
|
||||
const skill = await readFile(
|
||||
join(root, "skill-src/reverse-engineer-anything/SKILL.md"),
|
||||
join(root, ".agents/skills/reverse-engineer-anything/SKILL.md"),
|
||||
"utf8",
|
||||
);
|
||||
const skillVersion = /^\s{2}version:\s*"([^"]+)"\s*$/mu.exec(skill)?.[1];
|
||||
|
||||
@@ -10,7 +10,7 @@ for (const argument of arguments_)
|
||||
throw new Error(`Unknown skill metadata option: ${argument}`);
|
||||
|
||||
const root = join(dirname(fileURLToPath(import.meta.url)), "..");
|
||||
const sourceRoot = join(root, "skill-src/reverse-engineer-anything");
|
||||
const sourceRoot = join(root, ".agents/skills/reverse-engineer-anything");
|
||||
const outputRoot = join(root, "skills/reverse-engineer-anything");
|
||||
const check = arguments_.has("--check");
|
||||
const current = (
|
||||
@@ -25,7 +25,7 @@ const { PRODUCT_IDENTITY } = await import(
|
||||
);
|
||||
if (/^\s{2}(?:tool_count|catalog_digest):/mu.test(current))
|
||||
throw new Error(
|
||||
"Catalog metadata belongs in the generated skill, not skill-src",
|
||||
"Catalog metadata belongs in the generated skill, not the authored source",
|
||||
);
|
||||
const versionLine = /^ {2}version: "[^"\r\n]+"$/mu;
|
||||
if (!versionLine.test(current))
|
||||
|
||||
@@ -38,7 +38,7 @@ export async function verifyPackagePack({ root, workspace }) {
|
||||
throw new Error("package did not expose both rea command entry points");
|
||||
if (packedManifest.mcpName !== "io.github.morluto/rea")
|
||||
throw new Error("package did not retain its MCP Registry ownership marker");
|
||||
if (packedFiles.some((path) => path.startsWith("package/skill-src/")))
|
||||
if (packedFiles.some((path) => path.startsWith("package/.agents/")))
|
||||
throw new Error(
|
||||
"package included authored skill sources instead of only the generated bundle",
|
||||
);
|
||||
|
||||
@@ -17,6 +17,7 @@ import { verifyPackageMcp } from "./verify-package-mcp.mjs";
|
||||
import { verifyPackagePack } from "./verify-package-pack.mjs";
|
||||
import { verifyPackagePlatform } from "./verify-package-platform.mjs";
|
||||
import { verifyPackageSetup } from "./verify-package-setup.mjs";
|
||||
import { verifyRepositorySkill } from "./verify-repository-skill.mjs";
|
||||
import { verifyManaged } from "./verify-package-managed.mjs";
|
||||
import { verifyUnknownProvider } from "./verify-package-unknown-provider.mjs";
|
||||
import { completeVerifierRun, createVerifierRun } from "./lib/verifier-run.mjs";
|
||||
@@ -34,9 +35,11 @@ let tarball;
|
||||
let mcpStartup;
|
||||
let mcpModuleLoading;
|
||||
let update;
|
||||
let repositorySkill;
|
||||
let report;
|
||||
|
||||
try {
|
||||
repositorySkill = await verifyRepositorySkill({ root, workspace });
|
||||
({ tarball } = await verifyPackagePack({ root, workspace }));
|
||||
const environmentData = await verifyPackageEnvironment({
|
||||
root,
|
||||
@@ -156,6 +159,7 @@ try {
|
||||
configSymlinkLifecycle: supportedSetupHost,
|
||||
skill: supportedSetupHost,
|
||||
skillReferences: supportedSetupHost,
|
||||
repositorySkill,
|
||||
mcpTools: TOOL_CONTRACTS.length,
|
||||
mcpPrompts: prompts.names.length,
|
||||
promptCompletion: true,
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
import { cp, mkdir, readFile, readdir } from "node:fs/promises";
|
||||
import { dirname, join, relative } from "node:path";
|
||||
|
||||
import { exec, pathExists } from "./lib/verify-package-core.mjs";
|
||||
|
||||
/** Exercise Skills' default root discovery without ignored build outputs. */
|
||||
export async function verifyRepositorySkill({ root, workspace }) {
|
||||
const snapshot = join(workspace, "repository");
|
||||
const consumer = join(workspace, "skill-consumer");
|
||||
const home = join(workspace, "skill-consumer-home");
|
||||
const tracked = (
|
||||
await exec(
|
||||
"git",
|
||||
["ls-files", "--cached", "--format=%(objectmode) %(path)", "-z"],
|
||||
{ cwd: root },
|
||||
)
|
||||
).stdout
|
||||
.split("\0")
|
||||
.filter(Boolean);
|
||||
for (const entry of tracked) {
|
||||
const mode = entry.slice(0, 6);
|
||||
const path = entry.slice(7);
|
||||
const destination = join(snapshot, path);
|
||||
// A GitHub clone without submodule initialization has only these directories.
|
||||
if (mode === "160000") {
|
||||
await mkdir(destination, { recursive: true });
|
||||
continue;
|
||||
}
|
||||
await mkdir(dirname(destination), { recursive: true });
|
||||
await cp(join(root, path), destination, { verbatimSymlinks: true });
|
||||
}
|
||||
if (await pathExists(join(snapshot, "skills")))
|
||||
throw new Error("repository skill check must run without generated skills");
|
||||
await mkdir(consumer, { recursive: true });
|
||||
await mkdir(home, { recursive: true });
|
||||
const skillsVersion = "1.7.2";
|
||||
await exec(
|
||||
"npm",
|
||||
[
|
||||
"exec",
|
||||
"--yes",
|
||||
"--package",
|
||||
`skills@${skillsVersion}`,
|
||||
"--",
|
||||
"skills",
|
||||
"add",
|
||||
snapshot,
|
||||
"--skill",
|
||||
"reverse-engineer-anything",
|
||||
"--agent",
|
||||
"codex",
|
||||
"--yes",
|
||||
],
|
||||
{
|
||||
cwd: consumer,
|
||||
env: {
|
||||
...process.env,
|
||||
HOME: home,
|
||||
USERPROFILE: home,
|
||||
XDG_CONFIG_HOME: join(home, ".config"),
|
||||
CODEX_HOME: join(home, ".codex"),
|
||||
DO_NOT_TRACK: "1",
|
||||
SKILLS_NO_TELEMETRY: "1",
|
||||
CI: "1",
|
||||
},
|
||||
timeout: 120_000,
|
||||
},
|
||||
);
|
||||
const authoredRoot = join(
|
||||
snapshot,
|
||||
".agents/skills/reverse-engineer-anything",
|
||||
);
|
||||
const installedSkills = join(consumer, ".agents/skills");
|
||||
const installedRoot = join(installedSkills, "reverse-engineer-anything");
|
||||
const files = await filePaths(authoredRoot);
|
||||
if (
|
||||
JSON.stringify(await readdir(installedSkills)) !==
|
||||
JSON.stringify(["reverse-engineer-anything"]) ||
|
||||
JSON.stringify(await filePaths(installedRoot)) !== JSON.stringify(files)
|
||||
)
|
||||
throw new Error(
|
||||
"Skills did not install exactly the selected public bundle",
|
||||
);
|
||||
for (const path of files) {
|
||||
const authored = await readFile(join(authoredRoot, path));
|
||||
if (!authored.equals(await readFile(join(installedRoot, path))))
|
||||
throw new Error(`Skills changed authored skill content: ${path}`);
|
||||
}
|
||||
return { skillsVersion, files };
|
||||
}
|
||||
|
||||
async function filePaths(root) {
|
||||
return (await readdir(root, { recursive: true, withFileTypes: true }))
|
||||
.filter((entry) => entry.isFile())
|
||||
.map((entry) => relative(root, join(entry.parentPath, entry.name)))
|
||||
.sort();
|
||||
}
|
||||
@@ -169,7 +169,7 @@ const createBuildCacheFixture = async (): Promise<string> => {
|
||||
"scripts/clean-build-output.mjs",
|
||||
"scripts/generate-package-metadata.mjs",
|
||||
"scripts/lib/generated-file.mjs",
|
||||
"skill-src/reverse-engineer-anything/SKILL.md",
|
||||
".agents/skills/reverse-engineer-anything/SKILL.md",
|
||||
"src/generatedPackageMetadata.ts",
|
||||
];
|
||||
await Promise.all(
|
||||
|
||||
@@ -21,7 +21,7 @@ async function fixture(eol = "\n") {
|
||||
await mkdir(dirname(join(root, path)), { recursive: true });
|
||||
await copyFile(join(repositoryRoot, path), join(root, path));
|
||||
}
|
||||
const sourceRoot = join(root, "skill-src/reverse-engineer-anything");
|
||||
const sourceRoot = join(root, ".agents/skills/reverse-engineer-anything");
|
||||
const outputRoot = join(root, "skills/reverse-engineer-anything");
|
||||
await mkdir(join(sourceRoot, "references"), { recursive: true });
|
||||
await mkdir(join(root, "dist"));
|
||||
|
||||
+3
-3
@@ -39,7 +39,7 @@
|
||||
"package-lock.json",
|
||||
"scripts/generate-package-metadata.mjs",
|
||||
"scripts/lib/generated-file.mjs",
|
||||
"skill-src/reverse-engineer-anything/SKILL.md",
|
||||
".agents/skills/reverse-engineer-anything/SKILL.md",
|
||||
"src/generatedPackageMetadata.ts"
|
||||
]
|
||||
},
|
||||
@@ -138,7 +138,7 @@
|
||||
"docs/**",
|
||||
"!docs/public/product-catalog.json",
|
||||
"!docs/verification/managed-conformance-*.json",
|
||||
"skill-src/**",
|
||||
".agents/skills/reverse-engineer-anything/**",
|
||||
"README.md",
|
||||
{
|
||||
"mode": "dependencyOutputs",
|
||||
@@ -170,7 +170,7 @@
|
||||
"package-lock.json",
|
||||
"scripts/generate-skill-metadata.mjs",
|
||||
"scripts/lib/generated-file.mjs",
|
||||
"skill-src/**"
|
||||
".agents/skills/reverse-engineer-anything/**"
|
||||
],
|
||||
"outputs": ["skills/**"]
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user