Compare commits
No commits in common. "503a9f80246c4f9aba1c8d508247377df5db499a" and "53b21a76ab362a9871c05de4f1ddf70d47ae3d6d" have entirely different histories.
503a9f8024
...
53b21a76ab
File diff suppressed because it is too large
Load Diff
12
package.json
12
package.json
|
|
@ -71,12 +71,6 @@
|
||||||
"markdownlint-cli2"
|
"markdownlint-cli2"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"overrides": {
|
|
||||||
"esbuild": "^0.28.1",
|
|
||||||
"markdownlint-cli2": {
|
|
||||||
"markdown-it": "^14.2.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@clack/core": "^1.3.1",
|
"@clack/core": "^1.3.1",
|
||||||
"@clack/prompts": "^1.4.0",
|
"@clack/prompts": "^1.4.0",
|
||||||
|
|
@ -93,10 +87,10 @@
|
||||||
"yaml": "^2.7.0"
|
"yaml": "^2.7.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@astrojs/sitemap": "^3.7.3",
|
"@astrojs/sitemap": "^3.6.0",
|
||||||
"@astrojs/starlight": "^0.40.0",
|
"@astrojs/starlight": "^0.37.5",
|
||||||
"@eslint/js": "^9.33.0",
|
"@eslint/js": "^9.33.0",
|
||||||
"astro": "^6.4.6",
|
"astro": "^5.16.0",
|
||||||
"c8": "^10.1.3",
|
"c8": "^10.1.3",
|
||||||
"eslint": "^9.33.0",
|
"eslint": "^9.33.0",
|
||||||
"eslint-config-prettier": "^10.1.8",
|
"eslint-config-prettier": "^10.1.8",
|
||||||
|
|
|
||||||
|
|
@ -62,13 +62,7 @@ function parseArgs(argv) {
|
||||||
|
|
||||||
export async function main() {
|
export async function main() {
|
||||||
const argv = process.argv.slice(2);
|
const argv = process.argv.slice(2);
|
||||||
// An explicit help request is a successful invocation → exit 0. A bare call
|
if (argv.length === 0 || argv[0] === '--help' || argv[0] === '-h') {
|
||||||
// with no verb is an incomplete usage → EXIT.USAGE (2).
|
|
||||||
if (argv[0] === '--help' || argv[0] === '-h') {
|
|
||||||
printUsage();
|
|
||||||
process.exit(0);
|
|
||||||
}
|
|
||||||
if (argv.length === 0) {
|
|
||||||
printUsage();
|
printUsage();
|
||||||
process.exit(EXIT.USAGE);
|
process.exit(EXIT.USAGE);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,29 +39,19 @@ export function formatTomlValue(value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Minimal reverse of formatTomlValue for the scalars we read back (core values).
|
// Minimal reverse of formatTomlValue for the scalars we read back (core values).
|
||||||
// Exported for round-trip unit tests (test/test-bmad-module-source.mjs).
|
function parseTomlScalar(raw) {
|
||||||
export function parseTomlScalar(raw) {
|
|
||||||
const s = raw.trim();
|
const s = raw.trim();
|
||||||
if (s === 'true') return true;
|
if (s === 'true') return true;
|
||||||
if (s === 'false') return false;
|
if (s === 'false') return false;
|
||||||
if (/^-?\d+(\.\d+)?$/.test(s)) return Number(s);
|
if (/^-?\d+(\.\d+)?$/.test(s)) return Number(s);
|
||||||
if (s.startsWith('"') && s.endsWith('"')) {
|
if (s.startsWith('"') && s.endsWith('"')) {
|
||||||
// Single left-to-right pass: each backslash consumes exactly one following
|
return s
|
||||||
// char. A chained replaceAll would mis-handle round-tripped literal
|
.slice(1, -1)
|
||||||
// backslashes (e.g. `\\n` → `\` + newline instead of `\` + `n`), since an
|
.replaceAll('\\n', '\n')
|
||||||
// earlier pass can rewrite the escape introduced by a later one. The escape
|
.replaceAll('\\r', '\r')
|
||||||
// set here is the exact inverse of formatTomlValue (\\ \" \n \r \t).
|
.replaceAll('\\t', '\t')
|
||||||
const inner = s.slice(1, -1);
|
.replaceAll('\\"', '"')
|
||||||
let out = '';
|
.replaceAll('\\\\', '\\');
|
||||||
for (let i = 0; i < inner.length; i++) {
|
|
||||||
if (inner[i] === '\\' && i + 1 < inner.length) {
|
|
||||||
const n = inner[++i];
|
|
||||||
out += n === 'n' ? '\n' : n === 'r' ? '\r' : n === 't' ? '\t' : n === '"' ? '"' : n === '\\' ? '\\' : '\\' + n;
|
|
||||||
} else {
|
|
||||||
out += inner[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -126,16 +126,7 @@ export async function atomicSwapDir(stagedDir, targetDir) {
|
||||||
if (hadTarget) await fsp.rm(backup, { recursive: true, force: true });
|
if (hadTarget) await fsp.rm(backup, { recursive: true, force: true });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
await fsp.rm(sibling, { recursive: true, force: true });
|
await fsp.rm(sibling, { recursive: true, force: true });
|
||||||
// Keep `backup` if it still exists — on a failed swap+rollback it is the
|
await fsp.rm(backup, { recursive: true, force: true });
|
||||||
// only surviving copy of the previous install. Surface its location so the
|
|
||||||
// user can recover manually rather than silently destroying it here.
|
|
||||||
const backupSurvives = await fsp
|
|
||||||
.stat(backup)
|
|
||||||
.then(() => true)
|
|
||||||
.catch(() => false);
|
|
||||||
if (backupSurvives) {
|
|
||||||
process.stderr.write(`[bmad-module] previous install preserved at ${backup}\n`);
|
|
||||||
}
|
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -140,10 +140,6 @@ if (checkMode) {
|
||||||
` The committed bundle no longer matches tools/installer/ide/*.\n` +
|
` The committed bundle no longer matches tools/installer/ide/*.\n` +
|
||||||
` Fix: run \`npm run vendor:build\` and commit the regenerated files.\n`,
|
` Fix: run \`npm run vendor:build\` and commit the regenerated files.\n`,
|
||||||
);
|
);
|
||||||
// Pinpoint the first divergence so a CI-only mismatch is diagnosable from the
|
|
||||||
// log instead of just "they differ".
|
|
||||||
reportFirstDiff('ide-sync.mjs', currentBundle, built);
|
|
||||||
reportFirstDiff('platform-codes.yaml', currentSidecar, sidecar);
|
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -153,26 +149,6 @@ process.stdout.write(`built ide-sync.mjs + platform-codes.yaml (self-check OK, e
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
// On a --check mismatch, print the committed vs freshly-built lengths and a
|
|
||||||
// window around the first differing character. Keeps CI logs actionable when a
|
|
||||||
// drift is environment-specific and can't be reproduced locally.
|
|
||||||
function reportFirstDiff(label, committed, fresh) {
|
|
||||||
if (committed === fresh) return;
|
|
||||||
if (committed == null) {
|
|
||||||
process.stderr.write(` [diff] ${label}: committed file missing\n`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const n = Math.min(committed.length, fresh.length);
|
|
||||||
let i = 0;
|
|
||||||
while (i < n && committed[i] === fresh[i]) i++;
|
|
||||||
const win = (s) => JSON.stringify(s.slice(Math.max(0, i - 40), i + 40));
|
|
||||||
process.stderr.write(
|
|
||||||
` [diff] ${label}: committed=${committed.length}B fresh=${fresh.length}B firstDiff@${i}\n` +
|
|
||||||
` committed: ${win(committed)}\n` +
|
|
||||||
` fresh : ${win(fresh)}\n`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function selfCheck(bundleText, sidecarText) {
|
async function selfCheck(bundleText, sidecarText) {
|
||||||
const dir = await fs.mkdtemp(path.join(os.tmpdir(), 'bmad-ide-sync-check-'));
|
const dir = await fs.mkdtemp(path.join(os.tmpdir(), 'bmad-ide-sync-check-'));
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
// Self-contained bundle of BMAD's IDE-distribution engine
|
// Self-contained bundle of BMAD's IDE-distribution engine
|
||||||
// (tools/installer/ide/* via tools/installer/core/ide-sync.js).
|
// (tools/installer/ide/* via tools/installer/core/ide-sync.js).
|
||||||
//
|
//
|
||||||
// bundler : esbuild 0.28.1
|
// bundler : esbuild 0.25.12
|
||||||
// yaml : 2.8.4
|
// yaml : 2.8.4
|
||||||
// csv-parse : 6.1.0
|
// csv-parse : 6.1.0
|
||||||
//
|
//
|
||||||
|
|
@ -30,11 +30,7 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
||||||
throw Error('Dynamic require of "' + x + '" is not supported');
|
throw Error('Dynamic require of "' + x + '" is not supported');
|
||||||
});
|
});
|
||||||
var __commonJS = (cb, mod) => function __require2() {
|
var __commonJS = (cb, mod) => function __require2() {
|
||||||
try {
|
|
||||||
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
||||||
} catch (e) {
|
|
||||||
throw mod = 0, e;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
var __copyProps = (to, from, except, desc) => {
|
var __copyProps = (to, from, except, desc) => {
|
||||||
if (from && typeof from === "object" || typeof from === "function") {
|
if (from && typeof from === "object" || typeof from === "function") {
|
||||||
|
|
@ -336,13 +332,13 @@ var require_prompts = __commonJS({
|
||||||
var require_identity = __commonJS({
|
var require_identity = __commonJS({
|
||||||
"node_modules/yaml/dist/nodes/identity.js"(exports) {
|
"node_modules/yaml/dist/nodes/identity.js"(exports) {
|
||||||
"use strict";
|
"use strict";
|
||||||
var ALIAS = /* @__PURE__ */ Symbol.for("yaml.alias");
|
var ALIAS = Symbol.for("yaml.alias");
|
||||||
var DOC = /* @__PURE__ */ Symbol.for("yaml.document");
|
var DOC = Symbol.for("yaml.document");
|
||||||
var MAP = /* @__PURE__ */ Symbol.for("yaml.map");
|
var MAP = Symbol.for("yaml.map");
|
||||||
var PAIR = /* @__PURE__ */ Symbol.for("yaml.pair");
|
var PAIR = Symbol.for("yaml.pair");
|
||||||
var SCALAR = /* @__PURE__ */ Symbol.for("yaml.scalar");
|
var SCALAR = Symbol.for("yaml.scalar");
|
||||||
var SEQ = /* @__PURE__ */ Symbol.for("yaml.seq");
|
var SEQ = Symbol.for("yaml.seq");
|
||||||
var NODE_TYPE = /* @__PURE__ */ Symbol.for("yaml.node.type");
|
var NODE_TYPE = Symbol.for("yaml.node.type");
|
||||||
var isAlias = (node) => !!node && typeof node === "object" && node[NODE_TYPE] === ALIAS;
|
var isAlias = (node) => !!node && typeof node === "object" && node[NODE_TYPE] === ALIAS;
|
||||||
var isDocument = (node) => !!node && typeof node === "object" && node[NODE_TYPE] === DOC;
|
var isDocument = (node) => !!node && typeof node === "object" && node[NODE_TYPE] === DOC;
|
||||||
var isMap = (node) => !!node && typeof node === "object" && node[NODE_TYPE] === MAP;
|
var isMap = (node) => !!node && typeof node === "object" && node[NODE_TYPE] === MAP;
|
||||||
|
|
@ -394,9 +390,9 @@ var require_visit = __commonJS({
|
||||||
"node_modules/yaml/dist/visit.js"(exports) {
|
"node_modules/yaml/dist/visit.js"(exports) {
|
||||||
"use strict";
|
"use strict";
|
||||||
var identity = require_identity();
|
var identity = require_identity();
|
||||||
var BREAK = /* @__PURE__ */ Symbol("break visit");
|
var BREAK = Symbol("break visit");
|
||||||
var SKIP = /* @__PURE__ */ Symbol("skip children");
|
var SKIP = Symbol("skip children");
|
||||||
var REMOVE = /* @__PURE__ */ Symbol("remove node");
|
var REMOVE = Symbol("remove node");
|
||||||
function visit(node, visitor) {
|
function visit(node, visitor) {
|
||||||
const visitor_ = initVisitor(visitor);
|
const visitor_ = initVisitor(visitor);
|
||||||
if (identity.isDocument(node)) {
|
if (identity.isDocument(node)) {
|
||||||
|
|
@ -5854,9 +5850,9 @@ var require_cst_stringify = __commonJS({
|
||||||
var require_cst_visit = __commonJS({
|
var require_cst_visit = __commonJS({
|
||||||
"node_modules/yaml/dist/parse/cst-visit.js"(exports) {
|
"node_modules/yaml/dist/parse/cst-visit.js"(exports) {
|
||||||
"use strict";
|
"use strict";
|
||||||
var BREAK = /* @__PURE__ */ Symbol("break visit");
|
var BREAK = Symbol("break visit");
|
||||||
var SKIP = /* @__PURE__ */ Symbol("skip children");
|
var SKIP = Symbol("skip children");
|
||||||
var REMOVE = /* @__PURE__ */ Symbol("remove item");
|
var REMOVE = Symbol("remove item");
|
||||||
function visit(cst, visitor) {
|
function visit(cst, visitor) {
|
||||||
if ("type" in cst && cst.type === "document")
|
if ("type" in cst && cst.type === "document")
|
||||||
cst = { start: cst.start, value: cst.value };
|
cst = { start: cst.start, value: cst.value };
|
||||||
|
|
|
||||||
|
|
@ -162,13 +162,6 @@ platforms:
|
||||||
target_dir: .agents/skills
|
target_dir: .agents/skills
|
||||||
global_target_dir: ~/.config/agents/skills
|
global_target_dir: ~/.config/agents/skills
|
||||||
|
|
||||||
hermes:
|
|
||||||
name: "Hermes Agent"
|
|
||||||
preferred: false
|
|
||||||
installer:
|
|
||||||
target_dir: .agents/skills
|
|
||||||
global_target_dir: ~/.hermes/skills
|
|
||||||
|
|
||||||
iflow:
|
iflow:
|
||||||
name: "iFlow"
|
name: "iFlow"
|
||||||
preferred: false
|
preferred: false
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
// Vendored, self-contained bundle of the `yaml` npm package (eemeli/yaml).
|
// Vendored, self-contained bundle of the `yaml` npm package (eemeli/yaml).
|
||||||
//
|
//
|
||||||
// yaml : 2.8.4
|
// yaml : 2.8.4
|
||||||
// bundler : esbuild 0.28.1
|
// bundler : esbuild 0.25.12
|
||||||
//
|
//
|
||||||
// Shipped because the skill is copied into projects without node_modules; see
|
// Shipped because the skill is copied into projects without node_modules; see
|
||||||
// build-vendor.mjs and vendor/README.md for the rationale. Only `parse` and
|
// build-vendor.mjs and vendor/README.md for the rationale. Only `parse` and
|
||||||
|
|
@ -25,11 +25,7 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
||||||
throw Error('Dynamic require of "' + x + '" is not supported');
|
throw Error('Dynamic require of "' + x + '" is not supported');
|
||||||
});
|
});
|
||||||
var __commonJS = (cb, mod) => function __require2() {
|
var __commonJS = (cb, mod) => function __require2() {
|
||||||
try {
|
|
||||||
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
||||||
} catch (e) {
|
|
||||||
throw mod = 0, e;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
var __copyProps = (to, from, except, desc) => {
|
var __copyProps = (to, from, except, desc) => {
|
||||||
if (from && typeof from === "object" || typeof from === "function") {
|
if (from && typeof from === "object" || typeof from === "function") {
|
||||||
|
|
@ -52,13 +48,13 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
||||||
var require_identity = __commonJS({
|
var require_identity = __commonJS({
|
||||||
"node_modules/yaml/dist/nodes/identity.js"(exports) {
|
"node_modules/yaml/dist/nodes/identity.js"(exports) {
|
||||||
"use strict";
|
"use strict";
|
||||||
var ALIAS = /* @__PURE__ */ Symbol.for("yaml.alias");
|
var ALIAS = Symbol.for("yaml.alias");
|
||||||
var DOC = /* @__PURE__ */ Symbol.for("yaml.document");
|
var DOC = Symbol.for("yaml.document");
|
||||||
var MAP = /* @__PURE__ */ Symbol.for("yaml.map");
|
var MAP = Symbol.for("yaml.map");
|
||||||
var PAIR = /* @__PURE__ */ Symbol.for("yaml.pair");
|
var PAIR = Symbol.for("yaml.pair");
|
||||||
var SCALAR = /* @__PURE__ */ Symbol.for("yaml.scalar");
|
var SCALAR = Symbol.for("yaml.scalar");
|
||||||
var SEQ = /* @__PURE__ */ Symbol.for("yaml.seq");
|
var SEQ = Symbol.for("yaml.seq");
|
||||||
var NODE_TYPE = /* @__PURE__ */ Symbol.for("yaml.node.type");
|
var NODE_TYPE = Symbol.for("yaml.node.type");
|
||||||
var isAlias = (node) => !!node && typeof node === "object" && node[NODE_TYPE] === ALIAS;
|
var isAlias = (node) => !!node && typeof node === "object" && node[NODE_TYPE] === ALIAS;
|
||||||
var isDocument = (node) => !!node && typeof node === "object" && node[NODE_TYPE] === DOC;
|
var isDocument = (node) => !!node && typeof node === "object" && node[NODE_TYPE] === DOC;
|
||||||
var isMap = (node) => !!node && typeof node === "object" && node[NODE_TYPE] === MAP;
|
var isMap = (node) => !!node && typeof node === "object" && node[NODE_TYPE] === MAP;
|
||||||
|
|
@ -110,9 +106,9 @@ var require_visit = __commonJS({
|
||||||
"node_modules/yaml/dist/visit.js"(exports) {
|
"node_modules/yaml/dist/visit.js"(exports) {
|
||||||
"use strict";
|
"use strict";
|
||||||
var identity = require_identity();
|
var identity = require_identity();
|
||||||
var BREAK = /* @__PURE__ */ Symbol("break visit");
|
var BREAK = Symbol("break visit");
|
||||||
var SKIP = /* @__PURE__ */ Symbol("skip children");
|
var SKIP = Symbol("skip children");
|
||||||
var REMOVE = /* @__PURE__ */ Symbol("remove node");
|
var REMOVE = Symbol("remove node");
|
||||||
function visit(node, visitor) {
|
function visit(node, visitor) {
|
||||||
const visitor_ = initVisitor(visitor);
|
const visitor_ = initVisitor(visitor);
|
||||||
if (identity.isDocument(node)) {
|
if (identity.isDocument(node)) {
|
||||||
|
|
@ -5570,9 +5566,9 @@ var require_cst_stringify = __commonJS({
|
||||||
var require_cst_visit = __commonJS({
|
var require_cst_visit = __commonJS({
|
||||||
"node_modules/yaml/dist/parse/cst-visit.js"(exports) {
|
"node_modules/yaml/dist/parse/cst-visit.js"(exports) {
|
||||||
"use strict";
|
"use strict";
|
||||||
var BREAK = /* @__PURE__ */ Symbol("break visit");
|
var BREAK = Symbol("break visit");
|
||||||
var SKIP = /* @__PURE__ */ Symbol("skip children");
|
var SKIP = Symbol("skip children");
|
||||||
var REMOVE = /* @__PURE__ */ Symbol("remove item");
|
var REMOVE = Symbol("remove item");
|
||||||
function visit(cst, visitor) {
|
function visit(cst, visitor) {
|
||||||
if ("type" in cst && cst.type === "document")
|
if ("type" in cst && cst.type === "document")
|
||||||
cst = { start: cst.start, value: cst.value };
|
cst = { start: cst.start, value: cst.value };
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,8 @@
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
import fsp from 'node:fs/promises';
|
|
||||||
import { EXIT, BmadModuleError } from './lib/exit.mjs';
|
import { EXIT, BmadModuleError } from './lib/exit.mjs';
|
||||||
import { findBmadDir } from './lib/bmad-dir.mjs';
|
import { findBmadDir } from './lib/bmad-dir.mjs';
|
||||||
import { parseSource, materializeSource } from './lib/source.mjs';
|
import { parseSource, materializeSource } from './lib/source.mjs';
|
||||||
import { readAndValidateManifest, validateManifestObject, hasBmadPluginJson } from './lib/plugin-json.mjs';
|
import { readAndValidateManifest } from './lib/plugin-json.mjs';
|
||||||
import { resolveLegacyModule } from './lib/legacy-resolver.mjs';
|
|
||||||
import { readUserIgnores, buildIgnoreMatcher, buildCopyPlan, rewriteManifestPaths, validateDeclaredPaths } from './lib/install-plan.mjs';
|
import { readUserIgnores, buildIgnoreMatcher, buildCopyPlan, rewriteManifestPaths, validateDeclaredPaths } from './lib/install-plan.mjs';
|
||||||
import { stageCopyPlan, atomicSwapDir, sha256File, pruneEmptyDirs, safePathInsideRoot } from './lib/fs-safe.mjs';
|
import { stageCopyPlan, atomicSwapDir, sha256File, pruneEmptyDirs, safePathInsideRoot } from './lib/fs-safe.mjs';
|
||||||
import {
|
import {
|
||||||
|
|
@ -72,29 +70,7 @@ async function updateOne(bmadDir, projectDir, entry, opts) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Re-read the manifest the same way install does: new-spec modules carry a
|
const manifest = await readAndValidateManifest(materialized.dir);
|
||||||
// `.claude-plugin/plugin.json#bmad`; legacy modules carry a
|
|
||||||
// `.claude-plugin/marketplace.json` resolved into a synthetic manifest. A
|
|
||||||
// legacy-installed module re-clones to the legacy format, so update must
|
|
||||||
// handle both — otherwise readAndValidateManifest throws BAD_MANIFEST and
|
|
||||||
// every legacy community module becomes un-updatable.
|
|
||||||
let manifest;
|
|
||||||
let synthesized = null;
|
|
||||||
if (await hasBmadPluginJson(materialized.dir)) {
|
|
||||||
manifest = await readAndValidateManifest(materialized.dir);
|
|
||||||
} else {
|
|
||||||
const legacy = await resolveLegacyModule(materialized.dir, { selector: code });
|
|
||||||
if (!legacy) {
|
|
||||||
throw new BmadModuleError(
|
|
||||||
EXIT.BAD_MANIFEST,
|
|
||||||
`no .claude-plugin/plugin.json#bmad and no .claude-plugin/marketplace.json at ${materialized.dir}`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
// Legacy first-party modules (gds, bmm, …) legitimately use reserved codes.
|
|
||||||
validateManifestObject(legacy.manifest, { allowReserved: true });
|
|
||||||
manifest = legacy.manifest;
|
|
||||||
synthesized = legacy.synthesized;
|
|
||||||
}
|
|
||||||
if (manifest.bmad.code !== code) {
|
if (manifest.bmad.code !== code) {
|
||||||
throw new BmadModuleError(
|
throw new BmadModuleError(
|
||||||
EXIT.PREFIX_COLLISION,
|
EXIT.PREFIX_COLLISION,
|
||||||
|
|
@ -127,18 +103,6 @@ async function updateOne(bmadDir, projectDir, entry, opts) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Strategy-5 legacy modules have no module.yaml/module-help.csv on disk —
|
|
||||||
// the resolver synthesized them. Write them into the throwaway temp source so
|
|
||||||
// buildCopyPlan/validateDeclaredPaths discover them via the normal path.
|
|
||||||
if (synthesized) {
|
|
||||||
if (synthesized['module.yaml']) {
|
|
||||||
await fsp.writeFile(path.join(materialized.dir, 'module.yaml'), synthesized['module.yaml'], 'utf8');
|
|
||||||
}
|
|
||||||
if (synthesized['module-help.csv']) {
|
|
||||||
await fsp.writeFile(path.join(materialized.dir, 'module-help.csv'), synthesized['module-help.csv'], 'utf8');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build new copy plan, stage, swap.
|
// Build new copy plan, stage, swap.
|
||||||
validateDeclaredPaths(materialized.dir, manifest);
|
validateDeclaredPaths(materialized.dir, manifest);
|
||||||
const userIgnores = await readUserIgnores(materialized.dir, manifest);
|
const userIgnores = await readUserIgnores(materialized.dir, manifest);
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@
|
||||||
import { parseSource } from '../src/core-skills/bmad-module/scripts/lib/source.mjs';
|
import { parseSource } from '../src/core-skills/bmad-module/scripts/lib/source.mjs';
|
||||||
import { valid, prerelease, compare, rcompare, validRange } from '../src/core-skills/bmad-module/scripts/lib/semver-lite.mjs';
|
import { valid, prerelease, compare, rcompare, validRange } from '../src/core-skills/bmad-module/scripts/lib/semver-lite.mjs';
|
||||||
import { parseGitHubRepo, normalizeStableTag } from '../src/core-skills/bmad-module/scripts/lib/channel-resolver.mjs';
|
import { parseGitHubRepo, normalizeStableTag } from '../src/core-skills/bmad-module/scripts/lib/channel-resolver.mjs';
|
||||||
import { formatTomlValue, parseTomlScalar } from '../src/core-skills/bmad-module/scripts/lib/config-gen.mjs';
|
|
||||||
|
|
||||||
const colors = { reset: '[0m', green: '[32m', red: '[31m', cyan: '[36m', dim: '[2m' };
|
const colors = { reset: '[0m', green: '[32m', red: '[31m', cyan: '[36m', dim: '[2m' };
|
||||||
let passed = 0;
|
let passed = 0;
|
||||||
|
|
@ -153,18 +152,6 @@ eq(
|
||||||
'normalizeStableTag excludes prereleases/invalid',
|
'normalizeStableTag excludes prereleases/invalid',
|
||||||
);
|
);
|
||||||
|
|
||||||
// ─── config-gen TOML scalar round-trip ────────────────────────────────────────
|
|
||||||
// parseTomlScalar must be the exact inverse of formatTomlValue. Regression guard
|
|
||||||
// for the unescape bug where a literal backslash followed by `n` (e.g. a Windows
|
|
||||||
// path segment `\new`) was corrupted into a backslash + newline on read-back.
|
|
||||||
console.log(`\n${colors.cyan}config-gen TOML scalars${colors.reset}\n`);
|
|
||||||
|
|
||||||
for (const v of [String.raw`a\new`, 'x\ty', 'l1\nl2', 'say "hi"', String.raw`back\\slash`, 'trailing\\', 'plain', '']) {
|
|
||||||
eq(parseTomlScalar(formatTomlValue(v)), v, `TOML round-trip: ${JSON.stringify(v)}`);
|
|
||||||
}
|
|
||||||
eq(parseTomlScalar('true'), true, 'parseTomlScalar bare true');
|
|
||||||
eq(parseTomlScalar('42'), 42, 'parseTomlScalar bare number');
|
|
||||||
|
|
||||||
// ─── Summary ──────────────────────────────────────────────────────────────────
|
// ─── Summary ──────────────────────────────────────────────────────────────────
|
||||||
console.log(`\n${colors.cyan}Results: ${passed} passed, ${failed} failed${colors.reset}\n`);
|
console.log(`\n${colors.cyan}Results: ${passed} passed, ${failed} failed${colors.reset}\n`);
|
||||||
process.exit(failed > 0 ? 1 : 0);
|
process.exit(failed > 0 ? 1 : 0);
|
||||||
|
|
|
||||||
|
|
@ -162,13 +162,6 @@ platforms:
|
||||||
target_dir: .agents/skills
|
target_dir: .agents/skills
|
||||||
global_target_dir: ~/.config/agents/skills
|
global_target_dir: ~/.config/agents/skills
|
||||||
|
|
||||||
hermes:
|
|
||||||
name: "Hermes Agent"
|
|
||||||
preferred: false
|
|
||||||
installer:
|
|
||||||
target_dir: .agents/skills
|
|
||||||
global_target_dir: ~/.hermes/skills
|
|
||||||
|
|
||||||
iflow:
|
iflow:
|
||||||
name: "iFlow"
|
name: "iFlow"
|
||||||
preferred: false
|
preferred: false
|
||||||
|
|
|
||||||
|
|
@ -106,25 +106,25 @@ export default defineConfig({
|
||||||
label: 'Tutorials',
|
label: 'Tutorials',
|
||||||
translations: { 'vi-VN': 'Hướng dẫn nhập môn', 'zh-CN': '教程', 'fr-FR': 'Tutoriels', 'cs-CZ': 'Tutoriály' },
|
translations: { 'vi-VN': 'Hướng dẫn nhập môn', 'zh-CN': '教程', 'fr-FR': 'Tutoriels', 'cs-CZ': 'Tutoriály' },
|
||||||
collapsed: false,
|
collapsed: false,
|
||||||
items: [{ autogenerate: { directory: 'tutorials' } }],
|
autogenerate: { directory: 'tutorials' },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'How-To Guides',
|
label: 'How-To Guides',
|
||||||
translations: { 'vi-VN': 'Hướng dẫn tác vụ', 'zh-CN': '操作指南', 'fr-FR': 'Guides pratiques', 'cs-CZ': 'Praktické návody' },
|
translations: { 'vi-VN': 'Hướng dẫn tác vụ', 'zh-CN': '操作指南', 'fr-FR': 'Guides pratiques', 'cs-CZ': 'Praktické návody' },
|
||||||
collapsed: true,
|
collapsed: true,
|
||||||
items: [{ autogenerate: { directory: 'how-to' } }],
|
autogenerate: { directory: 'how-to' },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Explanation',
|
label: 'Explanation',
|
||||||
translations: { 'vi-VN': 'Giải thích', 'zh-CN': '概念说明', 'fr-FR': 'Explications', 'cs-CZ': 'Vysvětlení' },
|
translations: { 'vi-VN': 'Giải thích', 'zh-CN': '概念说明', 'fr-FR': 'Explications', 'cs-CZ': 'Vysvětlení' },
|
||||||
collapsed: true,
|
collapsed: true,
|
||||||
items: [{ autogenerate: { directory: 'explanation' } }],
|
autogenerate: { directory: 'explanation' },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Reference',
|
label: 'Reference',
|
||||||
translations: { 'vi-VN': 'Tham chiếu', 'zh-CN': '参考', 'fr-FR': 'Référence', 'cs-CZ': 'Reference' },
|
translations: { 'vi-VN': 'Tham chiếu', 'zh-CN': '参考', 'fr-FR': 'Référence', 'cs-CZ': 'Reference' },
|
||||||
collapsed: true,
|
collapsed: true,
|
||||||
items: [{ autogenerate: { directory: 'reference' } }],
|
autogenerate: { directory: 'reference' },
|
||||||
},
|
},
|
||||||
// TEA docs moved to standalone module site; keep BMM sidebar focused.
|
// TEA docs moved to standalone module site; keep BMM sidebar focused.
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
import { defineCollection } from 'astro:content';
|
|
||||||
import { docsLoader, i18nLoader } from '@astrojs/starlight/loaders';
|
|
||||||
import { docsSchema, i18nSchema } from '@astrojs/starlight/schema';
|
|
||||||
|
|
||||||
export const collections = {
|
|
||||||
docs: defineCollection({ loader: docsLoader(), schema: docsSchema() }),
|
|
||||||
i18n: defineCollection({ loader: i18nLoader(), schema: i18nSchema() }),
|
|
||||||
};
|
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
import { defineCollection } from 'astro:content';
|
||||||
|
import { docsSchema, i18nSchema } from '@astrojs/starlight/schema';
|
||||||
|
|
||||||
|
export const collections = {
|
||||||
|
docs: defineCollection({ schema: docsSchema() }),
|
||||||
|
i18n: defineCollection({ type: 'data', schema: i18nSchema() }),
|
||||||
|
};
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
---
|
---
|
||||||
import StarlightPage from '@astrojs/starlight/components/StarlightPage.astro';
|
import StarlightPage from '@astrojs/starlight/components/StarlightPage.astro';
|
||||||
import { getEntry, render } from 'astro:content';
|
import { getEntry } from 'astro:content';
|
||||||
import { translatedLocales } from '../lib/locales.mjs';
|
import { translatedLocales } from '../lib/locales.mjs';
|
||||||
|
|
||||||
const entry = await getEntry('docs', '404');
|
const entry = await getEntry('docs', '404');
|
||||||
const { Content } = await render(entry);
|
const { Content } = await entry.render();
|
||||||
---
|
---
|
||||||
|
|
||||||
<StarlightPage frontmatter={{ title: entry.data.title, template: entry.data.template }}>
|
<StarlightPage frontmatter={{ title: entry.data.title, template: entry.data.template }}>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue