Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 29 additions & 12 deletions core/src/standards/atlas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,34 @@ interface AtlasYamlDoc {
}

/**
* Resolve the ATLAS YAML. Two layouts are supported:
* - Published package: `<core>/atlas-data/ATLAS.yaml` (vendored into the tarball at pack time).
* - Monorepo dev: `<repo>/third_party/atlas-data/dist/ATLAS.yaml` (the git submodule).
*
* This module is at `core/{src,dist}/standards/atlas.{ts,js}`, so the package root is 2 levels
* up and the repo root is 3 levels up — true whether run from `src` (tsx) or `dist` (compiled).
* Resolve the ATLAS YAML. Three layouts are supported, tried in order:
* - Bundled runner (cli/mcp/sdk): the runner's esbuild/tsup bundle flattens this module to
* `<pkg>/dist/*.js`, so `atlas-data/` (vendored at pack time) is 1 level up: `<pkg>/atlas-data/ATLAS.yaml`.
* - Published core package: this module is at `core/dist/standards/atlas.js`, so `atlas-data/`
* (vendored at pack time) is 2 levels up: `<core>/atlas-data/ATLAS.yaml`.
* - Monorepo dev: `<repo>/third_party/atlas-data/dist/ATLAS.yaml` (the git submodule), 3 levels up
* from `core/{src,dist}/standards/`.
*/
function atlasYamlPath(): string {
function atlasYamlPath(): string | undefined {
const here = path.dirname(fileURLToPath(import.meta.url));
const packageLocal = path.resolve(here, "..", "..", "atlas-data", "ATLAS.yaml");
if (existsSync(packageLocal)) {
return packageLocal;
}
return path.resolve(here, "..", "..", "..", "third_party", "atlas-data", "dist", "ATLAS.yaml");
const candidates = [
path.resolve(here, "..", "atlas-data", "ATLAS.yaml"),
path.resolve(here, "..", "..", "atlas-data", "ATLAS.yaml"),
path.resolve(here, "..", "..", "..", "third_party", "atlas-data", "dist", "ATLAS.yaml"),
];
return candidates.find((p) => existsSync(p));
}

function missingAtlasHelp(): string {
return [
"MITRE ATLAS data not found.",
"",
"Published package (cli / mcp / sdk): atlas-data/ is bundled at install time.",
" Try reinstalling: npm install @keyvaluesystems/agent-opfor-cli (or -mcp / -sdk)",
"",
"Monorepo checkout: initialize the atlas-data submodule with:",
" git submodule update --init --recursive",
].join("\n");
}

function missingSubmoduleHelp(atlasPath: string): string {
Expand All @@ -57,6 +71,9 @@ function missingSubmoduleHelp(atlasPath: string): string {
*/
export async function loadAtlasTechniqueIndex(): Promise<Map<string, AtlasTechniqueMeta>> {
const atlasPath = atlasYamlPath();
if (atlasPath === undefined) {
throw new Error(missingAtlasHelp());
}
let raw: string;
try {
raw = await readFile(atlasPath, "utf8");
Expand Down
3 changes: 3 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions runners/sdk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@
"publishConfig": {
"access": "public"
},
"dependencies": {
"@modelcontextprotocol/sdk": "^1.29.0"
},
"devDependencies": {
"@keyvaluesystems/agent-opfor-core": "^0.9.0",
"@types/node": "^24.0.0",
Expand Down
9 changes: 9 additions & 0 deletions runners/sdk/tsup.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,13 @@ export default defineConfig({
target: "node20",
external: ["node:*"],
sourcemap: true,
// ESM output bundling CJS deps (yaml, etc.) that call require() at runtime needs a
// real require — without this shim esbuild's stub throws "Dynamic require ... not supported".
// Mirrors the createRequire banner in the cli/mcp esbuild bundles.
banner: {
js: [
"import { createRequire } from 'module';",
"const require = createRequire(import.meta.url);",
].join("\n"),
},
});
Loading