agentsmesh 0.41.0 → 0.42.0
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/CHANGELOG.md +36 -0
- package/README.md +2 -2
- package/dist/canonical.js +369 -194
- package/dist/canonical.js.map +1 -1
- package/dist/cli.js +267 -258
- package/dist/engine.d.ts +6 -1
- package/dist/engine.js +505 -262
- package/dist/engine.js.map +1 -1
- package/dist/index.js +625 -320
- package/dist/index.js.map +1 -1
- package/dist/lessons.d.ts +5 -0
- package/dist/lessons.js +170 -107
- package/dist/lessons.js.map +1 -1
- package/dist/targets.js +437 -252
- package/dist/targets.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { readFileSync, existsSync, mkdirSync, writeFileSync, constants, rmSync, readdirSync, statSync, chmodSync, renameSync, accessSync,
|
|
2
|
-
import { join,
|
|
1
|
+
import { readFileSync, existsSync, mkdirSync, writeFileSync, constants, rmSync, realpathSync, readdirSync, statSync, chmodSync, renameSync, accessSync, lstatSync, rmdirSync, unlinkSync } from 'fs';
|
|
2
|
+
import { join, relative, sep, resolve, dirname, basename, extname, win32, posix } from 'path';
|
|
3
3
|
import { stringify, parse, parseDocument, YAMLSeq, isMap, Document, isSeq, YAMLMap, isScalar, Scalar, Pair } from 'yaml';
|
|
4
4
|
import { z } from 'zod';
|
|
5
|
-
import { access, readdir, mkdir, readFile, rm, writeFile,
|
|
5
|
+
import { access, readdir, mkdir, readFile, lstat, rm, writeFile, open, stat, realpath, rmdir, unlink, rename, mkdtemp, cp } from 'fs/promises';
|
|
6
6
|
import { setTimeout } from 'timers/promises';
|
|
7
7
|
import { createHash, randomUUID } from 'crypto';
|
|
8
8
|
import picomatch from 'picomatch';
|
|
@@ -1579,25 +1579,6 @@ var init_no_outputs = __esm({
|
|
|
1579
1579
|
function escapeRegExp(value) {
|
|
1580
1580
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1581
1581
|
}
|
|
1582
|
-
function managedBlockPattern(start, end) {
|
|
1583
|
-
return new RegExp(`${escapeRegExp(start)}[\\s\\S]*?${escapeRegExp(end)}`, "g");
|
|
1584
|
-
}
|
|
1585
|
-
function stripManagedBlock(content, start, end) {
|
|
1586
|
-
return content.replace(managedBlockPattern(start, end), "").trim();
|
|
1587
|
-
}
|
|
1588
|
-
function splitFrontmatterPrefix(content) {
|
|
1589
|
-
const split = splitFrontmatter(content);
|
|
1590
|
-
return split === null ? { prefix: "", body: content.trim() } : { prefix: split.prefix, body: split.body };
|
|
1591
|
-
}
|
|
1592
|
-
function insertAtBodyTop(content, block) {
|
|
1593
|
-
const { prefix, body } = splitFrontmatterPrefix(content);
|
|
1594
|
-
const placed = body ? `${block}
|
|
1595
|
-
|
|
1596
|
-
${body}` : block;
|
|
1597
|
-
return prefix ? `${prefix}
|
|
1598
|
-
|
|
1599
|
-
${placed}` : placed;
|
|
1600
|
-
}
|
|
1601
1582
|
function ruleSource(source) {
|
|
1602
1583
|
const normalized = source.replace(/\\/g, "/");
|
|
1603
1584
|
const meshIndex = normalized.lastIndexOf(".agentsmesh/");
|
|
@@ -1605,36 +1586,22 @@ function ruleSource(source) {
|
|
|
1605
1586
|
if (normalized.startsWith("rules/")) return normalized;
|
|
1606
1587
|
return join("rules", basename(normalized)).replace(/\\/g, "/");
|
|
1607
1588
|
}
|
|
1608
|
-
function
|
|
1609
|
-
|
|
1589
|
+
function renderEmbeddedRule(rule) {
|
|
1590
|
+
const marker = {
|
|
1610
1591
|
source: ruleSource(rule.source),
|
|
1611
1592
|
description: rule.description,
|
|
1612
1593
|
globs: rule.globs,
|
|
1613
1594
|
targets: rule.targets
|
|
1614
1595
|
};
|
|
1615
|
-
}
|
|
1616
|
-
function embeddedRuleStart(rule) {
|
|
1617
|
-
return `${EMBEDDED_RULE_START_PREFIX}${JSON.stringify(markerForRule(rule))}${EMBEDDED_RULE_START_SUFFIX}`;
|
|
1618
|
-
}
|
|
1619
|
-
function renderRule(rule) {
|
|
1620
|
-
const parts = [embeddedRuleStart(rule)];
|
|
1596
|
+
const parts = [`${START_PREFIX}${JSON.stringify(marker)}${START_SUFFIX}`];
|
|
1621
1597
|
if (rule.description.trim()) {
|
|
1622
1598
|
parts.push(`## ${rule.description.trim()}`, "");
|
|
1623
1599
|
}
|
|
1624
1600
|
parts.push(rule.body.trim(), EMBEDDED_RULE_END);
|
|
1625
1601
|
return parts.filter((part) => part.length > 0).join("\n");
|
|
1626
1602
|
}
|
|
1627
|
-
function
|
|
1628
|
-
|
|
1629
|
-
return [EMBEDDED_RULES_START, ...rules.map(renderRule), EMBEDDED_RULES_END].join("\n");
|
|
1630
|
-
}
|
|
1631
|
-
function appendEmbeddedRulesBlock(content, rules) {
|
|
1632
|
-
const block = renderEmbeddedRulesBlock(rules);
|
|
1633
|
-
const withoutExisting = stripManagedBlock(content, EMBEDDED_RULES_START, EMBEDDED_RULES_END);
|
|
1634
|
-
if (!block) return withoutExisting;
|
|
1635
|
-
return withoutExisting ? `${withoutExisting}
|
|
1636
|
-
|
|
1637
|
-
${block}` : block;
|
|
1603
|
+
function renderEmbeddedRuleEntries(rules) {
|
|
1604
|
+
return rules.map(renderEmbeddedRule).join("\n\n");
|
|
1638
1605
|
}
|
|
1639
1606
|
function toStringArray2(value) {
|
|
1640
1607
|
return Array.isArray(value) ? value.filter((entry) => typeof entry === "string") : [];
|
|
@@ -1661,26 +1628,67 @@ function stripGeneratedHeading(body, description) {
|
|
|
1661
1628
|
const heading = `## ${description.trim()}`;
|
|
1662
1629
|
return trimmed.startsWith(heading) ? trimmed.slice(heading.length).trim() : trimmed;
|
|
1663
1630
|
}
|
|
1631
|
+
function takeEmbeddedRuleEntries(text) {
|
|
1632
|
+
const rules = [];
|
|
1633
|
+
const entry = new RegExp(
|
|
1634
|
+
`${escapeRegExp(START_PREFIX)}([\\s\\S]*?)${escapeRegExp(START_SUFFIX)}([\\s\\S]*?)${escapeRegExp(EMBEDDED_RULE_END)}`,
|
|
1635
|
+
"g"
|
|
1636
|
+
);
|
|
1637
|
+
const rest = text.replace(entry, (whole, markerText, body) => {
|
|
1638
|
+
const marker = parseMarker(markerText);
|
|
1639
|
+
if (!marker) return whole;
|
|
1640
|
+
rules.push({ ...marker, body: stripGeneratedHeading(body, marker.description) });
|
|
1641
|
+
return "";
|
|
1642
|
+
});
|
|
1643
|
+
return { rest: rest.trim(), rules };
|
|
1644
|
+
}
|
|
1645
|
+
var EMBEDDED_RULE_END, START_PREFIX, START_SUFFIX;
|
|
1646
|
+
var init_embedded_rule_entries = __esm({
|
|
1647
|
+
"src/targets/projection/embedded-rule-entries.ts"() {
|
|
1648
|
+
EMBEDDED_RULE_END = "<!-- agentsmesh:embedded-rule:end -->";
|
|
1649
|
+
START_PREFIX = "<!-- agentsmesh:embedded-rule:start ";
|
|
1650
|
+
START_SUFFIX = " -->";
|
|
1651
|
+
}
|
|
1652
|
+
});
|
|
1653
|
+
|
|
1654
|
+
// src/targets/projection/managed-blocks.ts
|
|
1655
|
+
function managedBlockPattern(start, end) {
|
|
1656
|
+
return new RegExp(`${escapeRegExp(start)}[\\s\\S]*?${escapeRegExp(end)}`, "g");
|
|
1657
|
+
}
|
|
1658
|
+
function stripManagedBlock(content, start, end) {
|
|
1659
|
+
return content.replace(managedBlockPattern(start, end), "").trim();
|
|
1660
|
+
}
|
|
1661
|
+
function splitFrontmatterPrefix(content) {
|
|
1662
|
+
const split = splitFrontmatter(content);
|
|
1663
|
+
return split === null ? { prefix: "", body: content.trim() } : { prefix: split.prefix, body: split.body };
|
|
1664
|
+
}
|
|
1665
|
+
function insertAtBodyTop(content, block) {
|
|
1666
|
+
const { prefix, body } = splitFrontmatterPrefix(content);
|
|
1667
|
+
const placed = body ? `${block}
|
|
1668
|
+
|
|
1669
|
+
${body}` : block;
|
|
1670
|
+
return prefix ? `${prefix}
|
|
1671
|
+
|
|
1672
|
+
${placed}` : placed;
|
|
1673
|
+
}
|
|
1674
|
+
function renderEmbeddedRulesBlock(rules) {
|
|
1675
|
+
if (rules.length === 0) return "";
|
|
1676
|
+
return [EMBEDDED_RULES_START, ...rules.map(renderEmbeddedRule), EMBEDDED_RULES_END].join("\n");
|
|
1677
|
+
}
|
|
1678
|
+
function appendEmbeddedRulesBlock(content, rules) {
|
|
1679
|
+
const block = renderEmbeddedRulesBlock(rules);
|
|
1680
|
+
const withoutExisting = stripManagedBlock(content, EMBEDDED_RULES_START, EMBEDDED_RULES_END);
|
|
1681
|
+
if (!block) return withoutExisting;
|
|
1682
|
+
return withoutExisting ? `${withoutExisting}
|
|
1683
|
+
|
|
1684
|
+
${block}` : block;
|
|
1685
|
+
}
|
|
1664
1686
|
function extractEmbeddedRules(content) {
|
|
1665
1687
|
const rules = [];
|
|
1666
1688
|
const outerPattern = managedBlockPattern(EMBEDDED_RULES_START, EMBEDDED_RULES_END);
|
|
1667
1689
|
const rootContent = content.replace(outerPattern, (block) => {
|
|
1668
|
-
const inner = block.replace(EMBEDDED_RULES_START, "").replace(EMBEDDED_RULES_END, "")
|
|
1669
|
-
|
|
1670
|
-
`${escapeRegExp(EMBEDDED_RULE_START_PREFIX)}([\\s\\S]*?)${escapeRegExp(EMBEDDED_RULE_START_SUFFIX)}([\\s\\S]*?)${escapeRegExp(EMBEDDED_RULE_END)}`,
|
|
1671
|
-
"g"
|
|
1672
|
-
);
|
|
1673
|
-
for (const match of inner.matchAll(entryPattern)) {
|
|
1674
|
-
const markerText = match[1];
|
|
1675
|
-
const body = match[2];
|
|
1676
|
-
if (markerText === void 0 || body === void 0) continue;
|
|
1677
|
-
const marker = parseMarker(markerText);
|
|
1678
|
-
if (!marker) continue;
|
|
1679
|
-
rules.push({
|
|
1680
|
-
...marker,
|
|
1681
|
-
body: stripGeneratedHeading(body, marker.description)
|
|
1682
|
-
});
|
|
1683
|
-
}
|
|
1690
|
+
const inner = block.replace(EMBEDDED_RULES_START, "").replace(EMBEDDED_RULES_END, "");
|
|
1691
|
+
rules.push(...takeEmbeddedRuleEntries(inner).rules);
|
|
1684
1692
|
return "";
|
|
1685
1693
|
});
|
|
1686
1694
|
return { rootContent: rootContent.trim(), rules };
|
|
@@ -1693,19 +1701,18 @@ function embeddedRootRule(canonical, target34, rootFile) {
|
|
|
1693
1701
|
const content = appendEmbeddedRulesBlock(rootBody, nonRootRules);
|
|
1694
1702
|
return content ? [{ path: rootFile, content }] : [];
|
|
1695
1703
|
}
|
|
1696
|
-
var ROOT_CONTRACT_START, ROOT_CONTRACT_END, LESSONS_CONTRACT_START, LESSONS_CONTRACT_END, EMBEDDED_RULES_START, EMBEDDED_RULES_END
|
|
1704
|
+
var ROOT_CONTRACT_START, ROOT_CONTRACT_END, LESSONS_CONTRACT_START, LESSONS_CONTRACT_END, EMBEDDED_RULES_START, EMBEDDED_RULES_END;
|
|
1697
1705
|
var init_managed_blocks = __esm({
|
|
1698
1706
|
"src/targets/projection/managed-blocks.ts"() {
|
|
1699
1707
|
init_markdown();
|
|
1708
|
+
init_embedded_rule_entries();
|
|
1709
|
+
init_embedded_rule_entries();
|
|
1700
1710
|
ROOT_CONTRACT_START = "<!-- agentsmesh:root-generation-contract:start -->";
|
|
1701
1711
|
ROOT_CONTRACT_END = "<!-- agentsmesh:root-generation-contract:end -->";
|
|
1702
1712
|
LESSONS_CONTRACT_START = "<!-- agentsmesh:lessons-contract:start -->";
|
|
1703
1713
|
LESSONS_CONTRACT_END = "<!-- agentsmesh:lessons-contract:end -->";
|
|
1704
1714
|
EMBEDDED_RULES_START = "<!-- agentsmesh:embedded-rules:start -->";
|
|
1705
1715
|
EMBEDDED_RULES_END = "<!-- agentsmesh:embedded-rules:end -->";
|
|
1706
|
-
EMBEDDED_RULE_END = "<!-- agentsmesh:embedded-rule:end -->";
|
|
1707
|
-
EMBEDDED_RULE_START_PREFIX = "<!-- agentsmesh:embedded-rule:start ";
|
|
1708
|
-
EMBEDDED_RULE_START_SUFFIX = " -->";
|
|
1709
1716
|
}
|
|
1710
1717
|
});
|
|
1711
1718
|
|
|
@@ -2997,6 +3004,8 @@ function rewriteFileLinks(input) {
|
|
|
2997
3004
|
const lineNumSuffix = lineNumMatch ? lineNumMatch[0] : "";
|
|
2998
3005
|
if (!rawCandidate) return match;
|
|
2999
3006
|
const tokenContext = getTokenContext(fullContent, offset, offset + rawCandidate.length);
|
|
3007
|
+
if (input.markdownLinksOnly === true && tokenContext.role !== "markdown-link-dest")
|
|
3008
|
+
return match;
|
|
3000
3009
|
const candidate = decodeLinkPath(rawCandidate, tokenContext.role);
|
|
3001
3010
|
if (tokenContext.role !== "markdown-link-dest" && WINDOWS_ABSOLUTE_PATH.test(candidate)) {
|
|
3002
3011
|
return match;
|
|
@@ -3171,13 +3180,12 @@ var init_import_rewriter = __esm({
|
|
|
3171
3180
|
});
|
|
3172
3181
|
async function writeMcpWithMerge(projectRoot, canonicalPath, imported) {
|
|
3173
3182
|
const destPath = join(projectRoot, canonicalPath);
|
|
3174
|
-
const existing = await
|
|
3183
|
+
const existing = parseMcpServers(await readFileSafe(destPath));
|
|
3175
3184
|
const merged = { ...existing, ...imported };
|
|
3176
3185
|
await mkdirp(dirname(destPath));
|
|
3177
3186
|
await writeFileAtomic(destPath, JSON.stringify({ mcpServers: merged }, null, 2));
|
|
3178
3187
|
}
|
|
3179
|
-
|
|
3180
|
-
const content = await readFileSafe(path);
|
|
3188
|
+
function parseMcpServers(content) {
|
|
3181
3189
|
if (content === null) return {};
|
|
3182
3190
|
let parsed;
|
|
3183
3191
|
try {
|
|
@@ -7215,12 +7223,14 @@ function canonicalRulePath(source) {
|
|
|
7215
7223
|
}
|
|
7216
7224
|
async function splitEmbeddedRulesToCanonical(input) {
|
|
7217
7225
|
const extracted = extractEmbeddedRules(input.content);
|
|
7226
|
+
const results = await writeEmbeddedRules(extracted.rules, input);
|
|
7227
|
+
return { rootContent: extracted.rootContent, results };
|
|
7228
|
+
}
|
|
7229
|
+
async function writeEmbeddedRules(rules, input) {
|
|
7218
7230
|
const results = [];
|
|
7219
|
-
if (
|
|
7220
|
-
return { rootContent: extracted.rootContent, results };
|
|
7221
|
-
}
|
|
7231
|
+
if (rules.length === 0) return results;
|
|
7222
7232
|
await mkdirp(join(input.projectRoot, input.rulesDir));
|
|
7223
|
-
for (const rule of
|
|
7233
|
+
for (const rule of rules) {
|
|
7224
7234
|
const canonicalSource = canonicalRulePath(rule.source);
|
|
7225
7235
|
if (canonicalSource === null || canonicalSource === "rules/_root.md") continue;
|
|
7226
7236
|
const destPath = join(input.projectRoot, ".agentsmesh", canonicalSource);
|
|
@@ -7230,6 +7240,7 @@ async function splitEmbeddedRulesToCanonical(input) {
|
|
|
7230
7240
|
destPath,
|
|
7231
7241
|
{
|
|
7232
7242
|
...frontmatter,
|
|
7243
|
+
...input.frontmatter,
|
|
7233
7244
|
root: false,
|
|
7234
7245
|
description: rule.description || void 0,
|
|
7235
7246
|
globs: rule.globs.length > 0 ? rule.globs : void 0,
|
|
@@ -7245,13 +7256,19 @@ async function splitEmbeddedRulesToCanonical(input) {
|
|
|
7245
7256
|
feature: "rules"
|
|
7246
7257
|
});
|
|
7247
7258
|
}
|
|
7248
|
-
return
|
|
7259
|
+
return results;
|
|
7260
|
+
}
|
|
7261
|
+
async function splitNestedAgentsFile(input, into) {
|
|
7262
|
+
const { rest, rules } = takeEmbeddedRuleEntries(input.content);
|
|
7263
|
+
into.push(...await writeEmbeddedRules(rules, input));
|
|
7264
|
+
return rest.length > 0 ? rest : null;
|
|
7249
7265
|
}
|
|
7250
7266
|
var init_embedded_rules = __esm({
|
|
7251
7267
|
"src/targets/import/embedded-rules.ts"() {
|
|
7252
7268
|
init_fs();
|
|
7253
7269
|
init_markdown();
|
|
7254
7270
|
init_managed_blocks();
|
|
7271
|
+
init_embedded_rule_entries();
|
|
7255
7272
|
init_import_metadata();
|
|
7256
7273
|
}
|
|
7257
7274
|
});
|
|
@@ -8679,7 +8696,7 @@ function generateRules6(canonical) {
|
|
|
8679
8696
|
const slug = basename(rule.source, ".md");
|
|
8680
8697
|
const frontmatter = {};
|
|
8681
8698
|
if (rule.description) frontmatter.description = rule.description;
|
|
8682
|
-
if (rule.globs.length > 0) frontmatter.
|
|
8699
|
+
if (rule.globs.length > 0) frontmatter.paths = rule.globs;
|
|
8683
8700
|
const content = serializeFrontmatter(frontmatter, rule.body.trim() || "");
|
|
8684
8701
|
outputs.push({ path: `${CLAUDE_RULES_DIR}/${slug}.md`, content });
|
|
8685
8702
|
}
|
|
@@ -9061,12 +9078,14 @@ var init_import_mappers2 = __esm({
|
|
|
9061
9078
|
}) => {
|
|
9062
9079
|
const destPath = join(destDir, relativePath);
|
|
9063
9080
|
const { frontmatter, body } = parseFrontmatter(normalizeTo(destPath));
|
|
9081
|
+
const { paths: paths2, ...rest } = frontmatter;
|
|
9082
|
+
const scoped = paths2 === void 0 ? {} : { globs: toToolsArray(paths2) };
|
|
9064
9083
|
return {
|
|
9065
9084
|
destPath,
|
|
9066
9085
|
toPath: `${AB_RULES}/${relativePath}`,
|
|
9067
9086
|
content: await serializeImportedRuleWithFallback(
|
|
9068
9087
|
destPath,
|
|
9069
|
-
{ ...
|
|
9088
|
+
{ ...rest, ...scoped, root: false },
|
|
9070
9089
|
body
|
|
9071
9090
|
)
|
|
9072
9091
|
};
|
|
@@ -10571,7 +10590,7 @@ function generateRules8(canonical) {
|
|
|
10571
10590
|
const rootBody = canonical.rules.find((rule) => rule.root)?.body.trim() ?? "";
|
|
10572
10591
|
if (rootBody) outputs.push({ path: CODEBUFF_ROOT_FILE, content: rootBody });
|
|
10573
10592
|
for (const [path, rules] of groupByNestedPath(eligibleRules(canonical))) {
|
|
10574
|
-
const content = rules.
|
|
10593
|
+
const content = renderEmbeddedRuleEntries(rules.filter((rule) => rule.body.trim().length > 0));
|
|
10575
10594
|
if (content) outputs.push({ path, content });
|
|
10576
10595
|
}
|
|
10577
10596
|
return outputs;
|
|
@@ -10599,6 +10618,7 @@ var init_generator8 = __esm({
|
|
|
10599
10618
|
init_no_outputs();
|
|
10600
10619
|
init_embedded_skill();
|
|
10601
10620
|
init_managed_blocks();
|
|
10621
|
+
init_embedded_rule_entries();
|
|
10602
10622
|
init_command_skill();
|
|
10603
10623
|
init_nested_rules();
|
|
10604
10624
|
init_mcp_format2();
|
|
@@ -10648,33 +10668,47 @@ function isVendored(relDir) {
|
|
|
10648
10668
|
}
|
|
10649
10669
|
async function importNestedRules(projectRoot, normalize) {
|
|
10650
10670
|
const destDir = join(projectRoot, AB_RULES);
|
|
10651
|
-
|
|
10671
|
+
const embedded = [];
|
|
10672
|
+
const results = await importFileDirectory({
|
|
10652
10673
|
srcDir: projectRoot,
|
|
10653
10674
|
destDir,
|
|
10654
10675
|
extensions: [CODEBUFF_ROOT_FILE],
|
|
10655
10676
|
fromTool: CODEBUFF_TARGET,
|
|
10656
10677
|
normalize,
|
|
10657
|
-
mapEntry: ({ srcPath, normalizeTo }) => {
|
|
10678
|
+
mapEntry: async ({ srcPath, content, normalizeTo }) => {
|
|
10658
10679
|
if (basename(srcPath) !== CODEBUFF_ROOT_FILE) return null;
|
|
10659
10680
|
const relDir = relative(projectRoot, dirname(srcPath)).replace(/\\/g, "/");
|
|
10660
10681
|
if (!relDir || relDir === ".") return null;
|
|
10661
10682
|
if (!shouldImportScopedAgentsRule(relDir)) return null;
|
|
10662
10683
|
if (isVendored(relDir)) return null;
|
|
10684
|
+
const ownText = await splitNestedAgentsFile(
|
|
10685
|
+
{
|
|
10686
|
+
content,
|
|
10687
|
+
projectRoot,
|
|
10688
|
+
rulesDir: AB_RULES,
|
|
10689
|
+
sourcePath: srcPath,
|
|
10690
|
+
fromTool: CODEBUFF_TARGET,
|
|
10691
|
+
normalize
|
|
10692
|
+
},
|
|
10693
|
+
embedded
|
|
10694
|
+
);
|
|
10695
|
+
if (ownText === null) return null;
|
|
10663
10696
|
const ruleName2 = relDir.replace(/\//g, "-");
|
|
10664
10697
|
const destPath = join(destDir, `${ruleName2}.md`);
|
|
10665
|
-
const { frontmatter, body } = parseFrontmatter(normalizeTo(destPath));
|
|
10666
|
-
return
|
|
10667
|
-
destPath,
|
|
10668
|
-
{ ...frontmatter, root: false, globs: [`${relDir}/**`] },
|
|
10669
|
-
body
|
|
10670
|
-
).then((content) => ({
|
|
10698
|
+
const { frontmatter, body } = parseFrontmatter(normalizeTo(destPath, ownText));
|
|
10699
|
+
return {
|
|
10671
10700
|
destPath,
|
|
10672
10701
|
toPath: `${AB_RULES}/${ruleName2}.md`,
|
|
10673
10702
|
feature: "rules",
|
|
10674
|
-
content
|
|
10675
|
-
|
|
10703
|
+
content: await serializeImportedRuleWithFallback(
|
|
10704
|
+
destPath,
|
|
10705
|
+
{ ...frontmatter, root: false, globs: [`${relDir}/**`] },
|
|
10706
|
+
body
|
|
10707
|
+
)
|
|
10708
|
+
};
|
|
10676
10709
|
}
|
|
10677
10710
|
});
|
|
10711
|
+
return [...results, ...embedded];
|
|
10678
10712
|
}
|
|
10679
10713
|
async function importCodebuffRules(projectRoot, scope, normalize) {
|
|
10680
10714
|
const results = await importRootRule2(projectRoot, scope, normalize);
|
|
@@ -11107,7 +11141,7 @@ function generateRules9(canonical) {
|
|
|
11107
11141
|
}
|
|
11108
11142
|
const nested = advisory.filter((rule) => !isRootEmbedded(rule));
|
|
11109
11143
|
for (const [path, rules] of groupByNestedPath2(nested)) {
|
|
11110
|
-
const content = rules.
|
|
11144
|
+
const content = renderEmbeddedRuleEntries(rules.filter((rule) => rule.body.trim().length > 0));
|
|
11111
11145
|
outputs.push({ path, content });
|
|
11112
11146
|
}
|
|
11113
11147
|
return outputs;
|
|
@@ -11120,6 +11154,7 @@ function renderCodexGlobalInstructions(canonical) {
|
|
|
11120
11154
|
var init_rules = __esm({
|
|
11121
11155
|
"src/targets/codex-cli/generator/rules.ts"() {
|
|
11122
11156
|
init_managed_blocks();
|
|
11157
|
+
init_embedded_rule_entries();
|
|
11123
11158
|
init_constants10();
|
|
11124
11159
|
init_codex_rule_paths();
|
|
11125
11160
|
}
|
|
@@ -11749,6 +11784,7 @@ async function importCodexRules(projectRoot, results, normalize, normalizeWindsu
|
|
|
11749
11784
|
await importInstructionMirrors(projectRoot, destDir, results, normalize);
|
|
11750
11785
|
results.push(...await importCodexNonRootRuleFiles(projectRoot, destDir, normalize));
|
|
11751
11786
|
if (layoutScope !== "global") {
|
|
11787
|
+
const embedded = [];
|
|
11752
11788
|
results.push(
|
|
11753
11789
|
...await importFileDirectory({
|
|
11754
11790
|
srcDir: projectRoot,
|
|
@@ -11756,7 +11792,7 @@ async function importCodexRules(projectRoot, results, normalize, normalizeWindsu
|
|
|
11756
11792
|
extensions: ["AGENTS.md", "AGENTS.override.md"],
|
|
11757
11793
|
fromTool: "codex-cli",
|
|
11758
11794
|
normalize,
|
|
11759
|
-
mapEntry: async ({ srcPath, normalizeTo }) => {
|
|
11795
|
+
mapEntry: async ({ srcPath, content: content2, normalizeTo }) => {
|
|
11760
11796
|
const relDir = relative(projectRoot, dirname(srcPath)).replace(/\\/g, "/");
|
|
11761
11797
|
const fileName = basename(srcPath);
|
|
11762
11798
|
const isOverride = fileName === "AGENTS.override.md";
|
|
@@ -11767,26 +11803,36 @@ async function importCodexRules(projectRoot, results, normalize, normalizeWindsu
|
|
|
11767
11803
|
await removePathIfExists(join(destDir, `${ruleName2}.md`));
|
|
11768
11804
|
return null;
|
|
11769
11805
|
}
|
|
11806
|
+
const variant = isOverride ? { codex_instruction: "override" } : {};
|
|
11807
|
+
const ownText = await splitNestedAgentsFile(
|
|
11808
|
+
{
|
|
11809
|
+
content: content2,
|
|
11810
|
+
projectRoot,
|
|
11811
|
+
rulesDir: AB_RULES,
|
|
11812
|
+
sourcePath: srcPath,
|
|
11813
|
+
fromTool: "codex-cli",
|
|
11814
|
+
normalize,
|
|
11815
|
+
frontmatter: variant
|
|
11816
|
+
},
|
|
11817
|
+
embedded
|
|
11818
|
+
);
|
|
11819
|
+
if (ownText === null) return null;
|
|
11770
11820
|
const destPath = join(destDir, `${ruleName2}.md`);
|
|
11771
|
-
const { frontmatter, body } = parseFrontmatter(normalizeTo(destPath));
|
|
11821
|
+
const { frontmatter, body } = parseFrontmatter(normalizeTo(destPath, ownText));
|
|
11772
11822
|
return {
|
|
11773
11823
|
destPath,
|
|
11774
11824
|
toPath: `${AB_RULES}/${ruleName2}.md`,
|
|
11775
11825
|
feature: "rules",
|
|
11776
11826
|
content: await serializeImportedRuleWithFallback(
|
|
11777
11827
|
destPath,
|
|
11778
|
-
{
|
|
11779
|
-
...frontmatter,
|
|
11780
|
-
root: false,
|
|
11781
|
-
globs: [`${relDir}/**`],
|
|
11782
|
-
...isOverride ? { codex_instruction: "override" } : {}
|
|
11783
|
-
},
|
|
11828
|
+
{ ...frontmatter, root: false, globs: [`${relDir}/**`], ...variant },
|
|
11784
11829
|
body
|
|
11785
11830
|
)
|
|
11786
11831
|
};
|
|
11787
11832
|
}
|
|
11788
11833
|
})
|
|
11789
11834
|
);
|
|
11835
|
+
results.push(...embedded);
|
|
11790
11836
|
}
|
|
11791
11837
|
}
|
|
11792
11838
|
async function importInstructionMirrors(projectRoot, destDir, results, normalize) {
|
|
@@ -18410,7 +18456,7 @@ function parseExtensions(content) {
|
|
|
18410
18456
|
}
|
|
18411
18457
|
return out2;
|
|
18412
18458
|
}
|
|
18413
|
-
async function
|
|
18459
|
+
async function readExistingServers(destPath) {
|
|
18414
18460
|
const content = await readFileSafe(destPath);
|
|
18415
18461
|
if (content === null) return {};
|
|
18416
18462
|
let parsed;
|
|
@@ -18433,7 +18479,7 @@ async function gooseMcpMap(ctx) {
|
|
|
18433
18479
|
const imported = ctx.relativePath.endsWith(".mcp.json") ? parsePluginMcpJson(ctx.content) : parseExtensions(ctx.content);
|
|
18434
18480
|
if (Object.keys(imported).length === 0) return null;
|
|
18435
18481
|
const destPath = join(ctx.destDir, "mcp.json");
|
|
18436
|
-
const existing = await
|
|
18482
|
+
const existing = await readExistingServers(destPath);
|
|
18437
18483
|
const merged = { ...existing, ...imported };
|
|
18438
18484
|
return {
|
|
18439
18485
|
destPath,
|
|
@@ -26988,12 +27034,6 @@ function ruleSlug3(source) {
|
|
|
26988
27034
|
const name = basename(source, ".md");
|
|
26989
27035
|
return name === "_root" ? "root" : name;
|
|
26990
27036
|
}
|
|
26991
|
-
function directoryScopedRuleDir(globs) {
|
|
26992
|
-
if (globs.length === 0) return null;
|
|
26993
|
-
const dirs = globs.map((glob) => glob.split("/")[0] ?? "").filter((segment) => /^[A-Za-z0-9._-]+$/.test(segment));
|
|
26994
|
-
if (dirs.length !== globs.length) return null;
|
|
26995
|
-
return dirs.every((dir) => dir === dirs[0]) ? dirs[0] : null;
|
|
26996
|
-
}
|
|
26997
27037
|
function generateRules32(canonical) {
|
|
26998
27038
|
const outputs = [];
|
|
26999
27039
|
const root = canonical.rules.find((r) => r.root);
|
|
@@ -27010,21 +27050,14 @@ function generateRules32(canonical) {
|
|
|
27010
27050
|
const frontmatter = {
|
|
27011
27051
|
description: rule.description || void 0,
|
|
27012
27052
|
trigger: normalizedTrigger,
|
|
27013
|
-
|
|
27014
|
-
globs: rule.globs.length >
|
|
27053
|
+
// Windsurf reads `globs` as one comma-joined string; it ignores `glob`.
|
|
27054
|
+
globs: rule.globs.length > 0 ? rule.globs.join(",") : void 0
|
|
27015
27055
|
};
|
|
27016
27056
|
Object.keys(frontmatter).forEach((k) => {
|
|
27017
27057
|
if (frontmatter[k] === void 0) delete frontmatter[k];
|
|
27018
27058
|
});
|
|
27019
27059
|
const content = Object.keys(frontmatter).length > 0 ? serializeFrontmatter(frontmatter, rule.body.trim() || "") : rule.body.trim() || "";
|
|
27020
27060
|
outputs.push({ path: `${WINDSURF_RULES_DIR}/${slug}.md`, content });
|
|
27021
|
-
const dir = directoryScopedRuleDir(rule.globs);
|
|
27022
|
-
if (dir) {
|
|
27023
|
-
if (dir !== slug) {
|
|
27024
|
-
outputs.push({ path: `${WINDSURF_RULES_DIR}/${dir}.md`, content });
|
|
27025
|
-
}
|
|
27026
|
-
outputs.push({ path: `${dir}/AGENTS.md`, content: rule.body.trim() || "" });
|
|
27027
|
-
}
|
|
27028
27061
|
}
|
|
27029
27062
|
return outputs;
|
|
27030
27063
|
}
|
|
@@ -27224,6 +27257,185 @@ var init_generator36 = __esm({
|
|
|
27224
27257
|
init_generator35();
|
|
27225
27258
|
}
|
|
27226
27259
|
});
|
|
27260
|
+
|
|
27261
|
+
// src/utils/output/color.ts
|
|
27262
|
+
function noColorRequested() {
|
|
27263
|
+
const value = process.env.NO_COLOR;
|
|
27264
|
+
return value !== void 0 && value !== "";
|
|
27265
|
+
}
|
|
27266
|
+
function forceColorRequested() {
|
|
27267
|
+
const value = process.env.FORCE_COLOR;
|
|
27268
|
+
if (value === void 0) return void 0;
|
|
27269
|
+
return value !== "0" && value !== "false";
|
|
27270
|
+
}
|
|
27271
|
+
function colorEnabled(stream = process.stdout) {
|
|
27272
|
+
const forced = forceColorRequested();
|
|
27273
|
+
if (forced !== void 0) return forced;
|
|
27274
|
+
if (noColorRequested()) return false;
|
|
27275
|
+
return stream.isTTY === true;
|
|
27276
|
+
}
|
|
27277
|
+
var init_color = __esm({
|
|
27278
|
+
"src/utils/output/color.ts"() {
|
|
27279
|
+
}
|
|
27280
|
+
});
|
|
27281
|
+
|
|
27282
|
+
// src/utils/output/logger.ts
|
|
27283
|
+
function outStream() {
|
|
27284
|
+
return stdoutRedirectedToStderr ? process.stderr : process.stdout;
|
|
27285
|
+
}
|
|
27286
|
+
function out(text) {
|
|
27287
|
+
outStream().write(text);
|
|
27288
|
+
}
|
|
27289
|
+
function c(code, text, stream) {
|
|
27290
|
+
return colorEnabled(stream) ? `${code}${text}${C.reset}` : text;
|
|
27291
|
+
}
|
|
27292
|
+
var C, muted, stdoutRedirectedToStderr, logger;
|
|
27293
|
+
var init_logger = __esm({
|
|
27294
|
+
"src/utils/output/logger.ts"() {
|
|
27295
|
+
init_color();
|
|
27296
|
+
C = {
|
|
27297
|
+
green: "\x1B[32m",
|
|
27298
|
+
red: "\x1B[31m",
|
|
27299
|
+
yellow: "\x1B[33m",
|
|
27300
|
+
cyan: "\x1B[36m",
|
|
27301
|
+
reset: "\x1B[0m"
|
|
27302
|
+
};
|
|
27303
|
+
muted = false;
|
|
27304
|
+
stdoutRedirectedToStderr = false;
|
|
27305
|
+
logger = {
|
|
27306
|
+
info(msg) {
|
|
27307
|
+
if (muted) return;
|
|
27308
|
+
out(c(C.cyan, msg, outStream()) + "\n");
|
|
27309
|
+
},
|
|
27310
|
+
warn(msg) {
|
|
27311
|
+
if (muted) return;
|
|
27312
|
+
process.stderr.write(c(C.yellow, "\u26A0 ", process.stderr) + msg + "\n");
|
|
27313
|
+
},
|
|
27314
|
+
error(msg) {
|
|
27315
|
+
if (muted) return;
|
|
27316
|
+
process.stderr.write(c(C.red, "\u2717 ", process.stderr) + msg + "\n");
|
|
27317
|
+
},
|
|
27318
|
+
success(msg) {
|
|
27319
|
+
if (muted) return;
|
|
27320
|
+
out(c(C.green, "\u2713 ", outStream()) + msg + "\n");
|
|
27321
|
+
},
|
|
27322
|
+
debug(msg) {
|
|
27323
|
+
if (muted) return;
|
|
27324
|
+
if (process.env.AGENTSMESH_DEBUG === "1") {
|
|
27325
|
+
out(c(C.cyan, "[debug] ", outStream()) + msg + "\n");
|
|
27326
|
+
}
|
|
27327
|
+
}
|
|
27328
|
+
};
|
|
27329
|
+
}
|
|
27330
|
+
});
|
|
27331
|
+
|
|
27332
|
+
// src/targets/windsurf/rule-globs.ts
|
|
27333
|
+
function splitTopLevelCommas(value) {
|
|
27334
|
+
const parts = [];
|
|
27335
|
+
let depth = 0;
|
|
27336
|
+
let current = "";
|
|
27337
|
+
for (const char of value) {
|
|
27338
|
+
if (char === "{") depth++;
|
|
27339
|
+
else if (char === "}") depth = Math.max(0, depth - 1);
|
|
27340
|
+
if (char === "," && depth === 0) {
|
|
27341
|
+
parts.push(current);
|
|
27342
|
+
current = "";
|
|
27343
|
+
} else {
|
|
27344
|
+
current += char;
|
|
27345
|
+
}
|
|
27346
|
+
}
|
|
27347
|
+
parts.push(current);
|
|
27348
|
+
return parts.map((part) => part.trim()).filter(Boolean);
|
|
27349
|
+
}
|
|
27350
|
+
function parseWindsurfGlobs(value) {
|
|
27351
|
+
if (typeof value === "string") return splitTopLevelCommas(value);
|
|
27352
|
+
return Array.isArray(value) ? toToolsArray(value) : [];
|
|
27353
|
+
}
|
|
27354
|
+
function quoteWindsurfGlobValues(content) {
|
|
27355
|
+
const lines = content.split("\n");
|
|
27356
|
+
if (lines[0]?.trim() !== "---") return content;
|
|
27357
|
+
for (let i = 1; i < lines.length; i++) {
|
|
27358
|
+
if (lines[i].trim() === "---") break;
|
|
27359
|
+
const match = UNQUOTED_GLOBS_LINE.exec(lines[i]);
|
|
27360
|
+
if (match !== null) lines[i] = `${match[1]}${JSON.stringify(match[2])}${match[3]}`;
|
|
27361
|
+
}
|
|
27362
|
+
return lines.join("\n");
|
|
27363
|
+
}
|
|
27364
|
+
var UNQUOTED_GLOBS_LINE;
|
|
27365
|
+
var init_rule_globs = __esm({
|
|
27366
|
+
"src/targets/windsurf/rule-globs.ts"() {
|
|
27367
|
+
init_shared_import_helpers();
|
|
27368
|
+
UNQUOTED_GLOBS_LINE = /^(\s*globs?\s*:[ \t]*)([^\s"'[{|>#][^\r\n]*?)[ \t]*(\r?)$/;
|
|
27369
|
+
}
|
|
27370
|
+
});
|
|
27371
|
+
async function windsurfRuleBodies(projectRoot) {
|
|
27372
|
+
const files = await readDirRecursiveNoSymlinks(join(projectRoot, WINDSURF_RULES_DIR));
|
|
27373
|
+
const bodies = /* @__PURE__ */ new Set();
|
|
27374
|
+
for (const file of files.filter((path) => path.endsWith(".md"))) {
|
|
27375
|
+
const content = await readFileSafe(file);
|
|
27376
|
+
if (content !== null) bodies.add(bodyKey(splitFrontmatter(content)?.body ?? content));
|
|
27377
|
+
}
|
|
27378
|
+
return bodies;
|
|
27379
|
+
}
|
|
27380
|
+
async function importWindsurfNestedAgents(projectRoot, normalize) {
|
|
27381
|
+
const destRulesDir = join(projectRoot, AB_RULES);
|
|
27382
|
+
const embedded = [];
|
|
27383
|
+
const ruleBodies = await windsurfRuleBodies(projectRoot);
|
|
27384
|
+
const results = await importFileDirectory({
|
|
27385
|
+
srcDir: projectRoot,
|
|
27386
|
+
destDir: destRulesDir,
|
|
27387
|
+
extensions: ["AGENTS.md"],
|
|
27388
|
+
fromTool: "windsurf",
|
|
27389
|
+
normalize,
|
|
27390
|
+
mapEntry: async ({ srcPath, content, normalizeTo }) => {
|
|
27391
|
+
const relDir = relative(projectRoot, dirname(srcPath)).replace(/\\/g, "/");
|
|
27392
|
+
if (!relDir || relDir === "." || basename(srcPath) !== "AGENTS.md") return null;
|
|
27393
|
+
const ruleName2 = relDir.replace(/\//g, "-");
|
|
27394
|
+
if (!shouldImportScopedAgentsRule(relDir)) {
|
|
27395
|
+
await removePathIfExists(join(destRulesDir, `${ruleName2}.md`));
|
|
27396
|
+
return null;
|
|
27397
|
+
}
|
|
27398
|
+
const ownText = await splitNestedAgentsFile(
|
|
27399
|
+
{
|
|
27400
|
+
content,
|
|
27401
|
+
projectRoot,
|
|
27402
|
+
rulesDir: AB_RULES,
|
|
27403
|
+
sourcePath: srcPath,
|
|
27404
|
+
fromTool: "windsurf",
|
|
27405
|
+
normalize
|
|
27406
|
+
},
|
|
27407
|
+
embedded
|
|
27408
|
+
);
|
|
27409
|
+
if (ownText === null || ruleBodies.has(bodyKey(ownText))) return null;
|
|
27410
|
+
const destPath = join(destRulesDir, `${ruleName2}.md`);
|
|
27411
|
+
return {
|
|
27412
|
+
destPath,
|
|
27413
|
+
toPath: `${AB_RULES}/${ruleName2}.md`,
|
|
27414
|
+
feature: "rules",
|
|
27415
|
+
content: await serializeImportedRuleWithFallback(
|
|
27416
|
+
destPath,
|
|
27417
|
+
{ root: false, globs: [`${relDir}/**`] },
|
|
27418
|
+
normalizeTo(destPath, ownText)
|
|
27419
|
+
)
|
|
27420
|
+
};
|
|
27421
|
+
}
|
|
27422
|
+
});
|
|
27423
|
+
return [...results, ...embedded];
|
|
27424
|
+
}
|
|
27425
|
+
var bodyKey;
|
|
27426
|
+
var init_import_nested_agents = __esm({
|
|
27427
|
+
"src/targets/windsurf/import-nested-agents.ts"() {
|
|
27428
|
+
init_canonical_paths();
|
|
27429
|
+
init_embedded_rules();
|
|
27430
|
+
init_import_metadata();
|
|
27431
|
+
init_import_orchestrator();
|
|
27432
|
+
init_scoped_agents_import();
|
|
27433
|
+
init_fs();
|
|
27434
|
+
init_markdown();
|
|
27435
|
+
init_constants34();
|
|
27436
|
+
bodyKey = (text) => text.replace(/\r\n?/g, "\n").trim();
|
|
27437
|
+
}
|
|
27438
|
+
});
|
|
27227
27439
|
function toStringArray3(value) {
|
|
27228
27440
|
if (Array.isArray(value)) {
|
|
27229
27441
|
return value.filter((entry) => typeof entry === "string").map((entry) => entry.trim()).filter(Boolean);
|
|
@@ -27492,35 +27704,7 @@ async function importFromWindsurf(projectRoot, options) {
|
|
|
27492
27704
|
}
|
|
27493
27705
|
}
|
|
27494
27706
|
if (layoutScope !== "global") {
|
|
27495
|
-
results.push(
|
|
27496
|
-
...await importFileDirectory({
|
|
27497
|
-
srcDir: projectRoot,
|
|
27498
|
-
destDir: destRulesDir,
|
|
27499
|
-
extensions: ["AGENTS.md"],
|
|
27500
|
-
fromTool: "windsurf",
|
|
27501
|
-
normalize,
|
|
27502
|
-
mapEntry: async ({ srcPath, normalizeTo }) => {
|
|
27503
|
-
const relDir = relative(projectRoot, dirname(srcPath)).replace(/\\/g, "/");
|
|
27504
|
-
if (!relDir || relDir === "." || basename(srcPath) !== "AGENTS.md") return null;
|
|
27505
|
-
const ruleName2 = relDir.replace(/\//g, "-");
|
|
27506
|
-
if (!shouldImportScopedAgentsRule(relDir)) {
|
|
27507
|
-
await removePathIfExists(join(destRulesDir, `${ruleName2}.md`));
|
|
27508
|
-
return null;
|
|
27509
|
-
}
|
|
27510
|
-
const destPath = join(destRulesDir, `${ruleName2}.md`);
|
|
27511
|
-
return {
|
|
27512
|
-
destPath,
|
|
27513
|
-
toPath: `${AB_RULES}/${ruleName2}.md`,
|
|
27514
|
-
feature: "rules",
|
|
27515
|
-
content: await serializeImportedRuleWithFallback(
|
|
27516
|
-
destPath,
|
|
27517
|
-
{ root: false, globs: [`${relDir}/**`] },
|
|
27518
|
-
normalizeTo(destPath)
|
|
27519
|
-
)
|
|
27520
|
-
};
|
|
27521
|
-
}
|
|
27522
|
-
})
|
|
27523
|
-
);
|
|
27707
|
+
results.push(...await importWindsurfNestedAgents(projectRoot, normalize));
|
|
27524
27708
|
}
|
|
27525
27709
|
const rulesDir = join(projectRoot, WINDSURF_RULES_DIR);
|
|
27526
27710
|
results.push(
|
|
@@ -27530,15 +27714,22 @@ async function importFromWindsurf(projectRoot, options) {
|
|
|
27530
27714
|
extensions: [".md"],
|
|
27531
27715
|
fromTool: "windsurf",
|
|
27532
27716
|
normalize,
|
|
27533
|
-
mapEntry: async ({ relativePath, normalizeTo }) => {
|
|
27717
|
+
mapEntry: async ({ relativePath, content, normalizeTo }) => {
|
|
27534
27718
|
if (relativePath === "_root.md" && rootContent !== null) return null;
|
|
27535
27719
|
const destPath = join(destRulesDir, relativePath);
|
|
27536
|
-
const
|
|
27537
|
-
const
|
|
27538
|
-
|
|
27539
|
-
|
|
27540
|
-
|
|
27720
|
+
const sourceLabel = `${WINDSURF_RULES_DIR}/${relativePath}`;
|
|
27721
|
+
const parsed = tryParseFrontmatter(
|
|
27722
|
+
normalizeTo(destPath, quoteWindsurfGlobValues(content)),
|
|
27723
|
+
sourceLabel
|
|
27724
|
+
);
|
|
27725
|
+
if (!parsed.ok) {
|
|
27726
|
+
logger.warn(`Skipping ${sourceLabel}: ${parsed.error.message}`);
|
|
27727
|
+
return null;
|
|
27541
27728
|
}
|
|
27729
|
+
const { frontmatter, body } = parsed.value;
|
|
27730
|
+
const { glob, ...normalizedFrontmatter } = frontmatter;
|
|
27731
|
+
const globs = parseWindsurfGlobs(frontmatter.globs ?? glob);
|
|
27732
|
+
if (globs.length > 0) normalizedFrontmatter.globs = globs;
|
|
27542
27733
|
return {
|
|
27543
27734
|
destPath,
|
|
27544
27735
|
toPath: `${AB_RULES}/${relativePath}`,
|
|
@@ -27589,9 +27780,11 @@ var init_importer32 = __esm({
|
|
|
27589
27780
|
init_import_rewriter();
|
|
27590
27781
|
init_fs();
|
|
27591
27782
|
init_markdown();
|
|
27783
|
+
init_logger();
|
|
27784
|
+
init_rule_globs();
|
|
27592
27785
|
init_import_metadata();
|
|
27593
27786
|
init_import_orchestrator();
|
|
27594
|
-
|
|
27787
|
+
init_import_nested_agents();
|
|
27595
27788
|
init_constants34();
|
|
27596
27789
|
init_importer_workflows();
|
|
27597
27790
|
init_skills_adapter5();
|
|
@@ -27696,12 +27889,6 @@ var init_lint31 = __esm({
|
|
|
27696
27889
|
});
|
|
27697
27890
|
|
|
27698
27891
|
// src/targets/windsurf/index.ts
|
|
27699
|
-
function directoryScopedRuleDir2(globs) {
|
|
27700
|
-
if (globs.length === 0) return null;
|
|
27701
|
-
const dirs = globs.map((glob) => glob.split("/")[0] ?? "").filter((segment) => /^[A-Za-z0-9._-]+$/.test(segment));
|
|
27702
|
-
if (dirs.length !== globs.length) return null;
|
|
27703
|
-
return dirs.every((dir) => dir === dirs[0]) ? dirs[0] : null;
|
|
27704
|
-
}
|
|
27705
27892
|
var target32, project24, globalLayout30, globalCapabilities25, descriptor32;
|
|
27706
27893
|
var init_windsurf2 = __esm({
|
|
27707
27894
|
"src/targets/windsurf/index.ts"() {
|
|
@@ -27733,9 +27920,7 @@ var init_windsurf2 = __esm({
|
|
|
27733
27920
|
project24 = {
|
|
27734
27921
|
rootInstructionPath: WINDSURF_AGENTS_MD,
|
|
27735
27922
|
extraRuleOutputPaths(rule) {
|
|
27736
|
-
|
|
27737
|
-
const dir = directoryScopedRuleDir2(rule.globs);
|
|
27738
|
-
return dir !== null ? [`${dir}/AGENTS.md`] : [];
|
|
27923
|
+
return rule.root ? [WINDSURF_AGENTS_MD] : [];
|
|
27739
27924
|
},
|
|
27740
27925
|
skillDir: WINDSURF_SKILLS_DIR,
|
|
27741
27926
|
managedOutputs: {
|
|
@@ -29344,7 +29529,6 @@ function rewriteGeneratedReferences(results, canonical, config, projectRoot, sco
|
|
|
29344
29529
|
const artifactCache = /* @__PURE__ */ new Map();
|
|
29345
29530
|
const sourceCache = /* @__PURE__ */ new Map();
|
|
29346
29531
|
return results.map((result2) => {
|
|
29347
|
-
if (skipPaths?.has(result2.path)) return result2;
|
|
29348
29532
|
const smKey = sourceMapCacheKey(result2.target, activeTargets);
|
|
29349
29533
|
const sourceMap = sourceCache.get(smKey) ?? (() => {
|
|
29350
29534
|
const built = buildOutputSourceMap(result2.target, canonical, config, scope, activeTargets);
|
|
@@ -29353,9 +29537,10 @@ function rewriteGeneratedReferences(results, canonical, config, projectRoot, sco
|
|
|
29353
29537
|
})();
|
|
29354
29538
|
const sourceFile = sourceMap.get(result2.path);
|
|
29355
29539
|
if (!sourceFile) return result2;
|
|
29540
|
+
const shared = skipPaths?.has(result2.path) === true;
|
|
29356
29541
|
const artifactMapTarget = artifactMapTargetForResult(result2, scope, activeTargets);
|
|
29357
29542
|
const cacheKey = artifactCacheKey(result2, scope, activeTargets);
|
|
29358
|
-
const artifactMap = artifactCache.get(cacheKey) ?? (() => {
|
|
29543
|
+
const artifactMap = shared ? /* @__PURE__ */ new Map() : artifactCache.get(cacheKey) ?? (() => {
|
|
29359
29544
|
const built = buildArtifactPathMap(
|
|
29360
29545
|
artifactMapTarget,
|
|
29361
29546
|
canonical,
|
|
@@ -29376,6 +29561,7 @@ function rewriteGeneratedReferences(results, canonical, config, projectRoot, sco
|
|
|
29376
29561
|
pathExists: (absolutePath) => plannedPaths.has(absolutePath) || existsSync(absolutePath),
|
|
29377
29562
|
explicitCurrentDirLinks: true,
|
|
29378
29563
|
rewriteBarePathTokens: true,
|
|
29564
|
+
markdownLinksOnly: shared,
|
|
29379
29565
|
scope,
|
|
29380
29566
|
pathIsDirectory: (absolutePath) => {
|
|
29381
29567
|
try {
|
|
@@ -29393,62 +29579,7 @@ function rewriteGeneratedReferences(results, canonical, config, projectRoot, sco
|
|
|
29393
29579
|
init_path_helpers();
|
|
29394
29580
|
init_link_rebaser_helpers();
|
|
29395
29581
|
init_protected_ranges();
|
|
29396
|
-
|
|
29397
|
-
// src/utils/output/color.ts
|
|
29398
|
-
function noColorRequested() {
|
|
29399
|
-
const value = process.env.NO_COLOR;
|
|
29400
|
-
return value !== void 0 && value !== "";
|
|
29401
|
-
}
|
|
29402
|
-
function forceColorRequested() {
|
|
29403
|
-
const value = process.env.FORCE_COLOR;
|
|
29404
|
-
if (value === void 0) return void 0;
|
|
29405
|
-
return value !== "0" && value !== "false";
|
|
29406
|
-
}
|
|
29407
|
-
function colorEnabled(stream = process.stdout) {
|
|
29408
|
-
const forced = forceColorRequested();
|
|
29409
|
-
if (forced !== void 0) return forced;
|
|
29410
|
-
if (noColorRequested()) return false;
|
|
29411
|
-
return stream.isTTY === true;
|
|
29412
|
-
}
|
|
29413
|
-
|
|
29414
|
-
// src/utils/output/logger.ts
|
|
29415
|
-
var C = {
|
|
29416
|
-
green: "\x1B[32m",
|
|
29417
|
-
red: "\x1B[31m",
|
|
29418
|
-
yellow: "\x1B[33m",
|
|
29419
|
-
cyan: "\x1B[36m",
|
|
29420
|
-
reset: "\x1B[0m"
|
|
29421
|
-
};
|
|
29422
|
-
function outStream() {
|
|
29423
|
-
return process.stdout;
|
|
29424
|
-
}
|
|
29425
|
-
function out(text) {
|
|
29426
|
-
outStream().write(text);
|
|
29427
|
-
}
|
|
29428
|
-
function c(code, text, stream) {
|
|
29429
|
-
return colorEnabled(stream) ? `${code}${text}${C.reset}` : text;
|
|
29430
|
-
}
|
|
29431
|
-
var logger = {
|
|
29432
|
-
info(msg) {
|
|
29433
|
-
out(c(C.cyan, msg, outStream()) + "\n");
|
|
29434
|
-
},
|
|
29435
|
-
warn(msg) {
|
|
29436
|
-
process.stderr.write(c(C.yellow, "\u26A0 ", process.stderr) + msg + "\n");
|
|
29437
|
-
},
|
|
29438
|
-
error(msg) {
|
|
29439
|
-
process.stderr.write(c(C.red, "\u2717 ", process.stderr) + msg + "\n");
|
|
29440
|
-
},
|
|
29441
|
-
success(msg) {
|
|
29442
|
-
out(c(C.green, "\u2713 ", outStream()) + msg + "\n");
|
|
29443
|
-
},
|
|
29444
|
-
debug(msg) {
|
|
29445
|
-
if (process.env.AGENTSMESH_DEBUG === "1") {
|
|
29446
|
-
out(c(C.cyan, "[debug] ", outStream()) + msg + "\n");
|
|
29447
|
-
}
|
|
29448
|
-
}
|
|
29449
|
-
};
|
|
29450
|
-
|
|
29451
|
-
// src/core/reference/validate-generated-markdown-links.ts
|
|
29582
|
+
init_logger();
|
|
29452
29583
|
var INLINE_MD_LINK = /!?\[[^\]]*\]\(([^)]+)\)/g;
|
|
29453
29584
|
var REF_LINK_DEF = /^\s*\[(?!\^)[^\]\n]+\]:\s*(?:<([^>\n]*)>|(\S+))/gm;
|
|
29454
29585
|
function isMarkdownLikeOutput(relativePath) {
|
|
@@ -29680,6 +29811,7 @@ init_fs_text_encoding();
|
|
|
29680
29811
|
|
|
29681
29812
|
// src/core/generate/collision-agents.ts
|
|
29682
29813
|
init_target_ids();
|
|
29814
|
+
init_logger();
|
|
29683
29815
|
var AGENTS_SUFFIX = "AGENTS.md";
|
|
29684
29816
|
var OPTIONAL_AGENTS_BLOCKS = [
|
|
29685
29817
|
/<!-- agentsmesh:embedded-rules:start -->[\s\S]*?<!-- agentsmesh:embedded-rules:end -->\n*/g
|
|
@@ -30040,6 +30172,7 @@ init_errors();
|
|
|
30040
30172
|
|
|
30041
30173
|
// src/config/core/loader.ts
|
|
30042
30174
|
init_fs();
|
|
30175
|
+
init_logger();
|
|
30043
30176
|
init_errors();
|
|
30044
30177
|
|
|
30045
30178
|
// src/config/core/schema.ts
|
|
@@ -30867,6 +31000,7 @@ async function resolveExtendPaths(config, configDir, options = {}) {
|
|
|
30867
31000
|
}
|
|
30868
31001
|
|
|
30869
31002
|
// src/canonical/features/empty-file.ts
|
|
31003
|
+
init_logger();
|
|
30870
31004
|
function isEmptyCanonicalFile(content, path) {
|
|
30871
31005
|
if (content.trim() !== "") return false;
|
|
30872
31006
|
logger.warn(`Skipping empty canonical file ${path.replaceAll("\\", "/")}`);
|
|
@@ -30968,6 +31102,9 @@ function assertNoBasenameCollisions(feature, paths2, stripExt) {
|
|
|
30968
31102
|
seen.set(key, { path: p, slug });
|
|
30969
31103
|
}
|
|
30970
31104
|
}
|
|
31105
|
+
|
|
31106
|
+
// src/canonical/features/unrecognized-files-warning.ts
|
|
31107
|
+
init_logger();
|
|
30971
31108
|
var ALTERNATE_RESOURCE_FORMATS = /* @__PURE__ */ new Set([".toml", ".yaml", ".yml", ".json"]);
|
|
30972
31109
|
function warnIfUnrecognizedResourceFormats(featureLabel, dir, allFiles, parsedFiles, opts = {}) {
|
|
30973
31110
|
if (allFiles.length === 0) return;
|
|
@@ -31176,6 +31313,14 @@ async function readContent(path) {
|
|
|
31176
31313
|
return c2 ?? "";
|
|
31177
31314
|
}
|
|
31178
31315
|
var SKILL_FILE = "SKILL.md";
|
|
31316
|
+
async function readSkillFile(skillPath) {
|
|
31317
|
+
try {
|
|
31318
|
+
if ((await lstat(skillPath)).isSymbolicLink()) return null;
|
|
31319
|
+
} catch {
|
|
31320
|
+
return null;
|
|
31321
|
+
}
|
|
31322
|
+
return readFileSafe(skillPath);
|
|
31323
|
+
}
|
|
31179
31324
|
var DOC_EXTENSIONS = /* @__PURE__ */ new Set([".md", ".mdx", ".rst", ".txt"]);
|
|
31180
31325
|
function isMarkdownLikeDoc(name) {
|
|
31181
31326
|
const dot = name.lastIndexOf(".");
|
|
@@ -31205,7 +31350,7 @@ async function listSupportingFiles(skillDir) {
|
|
|
31205
31350
|
}
|
|
31206
31351
|
async function parseSkillDirectory(skillDir, opts = {}) {
|
|
31207
31352
|
const skillPath = join(skillDir, SKILL_FILE);
|
|
31208
|
-
const content = await
|
|
31353
|
+
const content = await readSkillFile(skillPath);
|
|
31209
31354
|
if (!content) return null;
|
|
31210
31355
|
const parsed = parseOrSkipFrontmatter(content, skillPath, opts.onParseError);
|
|
31211
31356
|
if (!parsed) return null;
|
|
@@ -31236,7 +31381,7 @@ async function parseSkills(skillsDir, opts = {}) {
|
|
|
31236
31381
|
assertCanonicalName("skill", ent.name);
|
|
31237
31382
|
const skillDir = join(skillsDir, ent.name);
|
|
31238
31383
|
const skillPath = join(skillDir, SKILL_FILE);
|
|
31239
|
-
const content = await
|
|
31384
|
+
const content = await readSkillFile(skillPath);
|
|
31240
31385
|
if (!content) continue;
|
|
31241
31386
|
const parsed = parseOrSkipFrontmatter(content, skillPath, opts.onParseError);
|
|
31242
31387
|
if (!parsed) continue;
|
|
@@ -31266,6 +31411,9 @@ function ensureStringArray(val) {
|
|
|
31266
31411
|
async function parsePermissions(permissionsPath, onParseError) {
|
|
31267
31412
|
const content = await readFileSafe(permissionsPath);
|
|
31268
31413
|
if (content === null) return null;
|
|
31414
|
+
return parsePermissionsContent(content, permissionsPath, onParseError);
|
|
31415
|
+
}
|
|
31416
|
+
function parsePermissionsContent(content, permissionsPath, onParseError) {
|
|
31269
31417
|
if (!content.trim()) return { allow: [], deny: [], ask: [] };
|
|
31270
31418
|
let parsed;
|
|
31271
31419
|
try {
|
|
@@ -31398,6 +31546,20 @@ function hookEvents(a, b) {
|
|
|
31398
31546
|
function hookKey(entry) {
|
|
31399
31547
|
return JSON.stringify([entry.type ?? "command", entry.matcher, entry.command]);
|
|
31400
31548
|
}
|
|
31549
|
+
function settleRootRule(merged, local, packs) {
|
|
31550
|
+
const roots = merged.filter((rule) => rule.root);
|
|
31551
|
+
const root = roots.find((rule) => local.includes(rule)) ?? roots.find((rule) => packs.includes(rule)) ?? roots[0];
|
|
31552
|
+
const demoted = roots.filter((rule) => rule !== root);
|
|
31553
|
+
return {
|
|
31554
|
+
rules: merged.map((rule) => demoted.includes(rule) ? { ...rule, root: false } : rule),
|
|
31555
|
+
root,
|
|
31556
|
+
demoted
|
|
31557
|
+
};
|
|
31558
|
+
}
|
|
31559
|
+
function demotedRootMessage(rule, root, baseDir) {
|
|
31560
|
+
const shown = (r) => relative(baseDir, r.source).replaceAll("\\", "/");
|
|
31561
|
+
return `[agentsmesh] Rule "${shown(rule)}" also says root: true, but "${shown(root)}" is the root rule (the project's own root wins over installed packs, and packs over extends), so it is used as a normal rule.`;
|
|
31562
|
+
}
|
|
31401
31563
|
|
|
31402
31564
|
// src/config/resolve/native-format-detector.ts
|
|
31403
31565
|
init_fs();
|
|
@@ -31443,6 +31605,7 @@ var KNOWN_NATIVE_PATHS = BUILTIN_TARGETS.map(
|
|
|
31443
31605
|
|
|
31444
31606
|
// src/canonical/extends/extend-load.ts
|
|
31445
31607
|
init_fs();
|
|
31608
|
+
init_logger();
|
|
31446
31609
|
|
|
31447
31610
|
// src/canonical/extends/native-extends-importer.ts
|
|
31448
31611
|
init_registry();
|
|
@@ -32069,6 +32232,9 @@ Expected one of: .agentsmesh/, ${KNOWN_NATIVE_PATHS.join(", ")}.`
|
|
|
32069
32232
|
throw wrapped;
|
|
32070
32233
|
}
|
|
32071
32234
|
}
|
|
32235
|
+
|
|
32236
|
+
// src/canonical/extends/extend-pick.ts
|
|
32237
|
+
init_logger();
|
|
32072
32238
|
function applyExtendPick(canonical, features, pick, extendName) {
|
|
32073
32239
|
if (!pick) return canonical;
|
|
32074
32240
|
let next = { ...canonical };
|
|
@@ -32261,6 +32427,7 @@ async function loadPacksCanonical(abDir) {
|
|
|
32261
32427
|
}
|
|
32262
32428
|
|
|
32263
32429
|
// src/canonical/extends/extends.ts
|
|
32430
|
+
init_logger();
|
|
32264
32431
|
var FEATURE_TO_KEYS = {
|
|
32265
32432
|
rules: ["rules"],
|
|
32266
32433
|
commands: ["commands"],
|
|
@@ -32309,6 +32476,15 @@ async function loadCanonicalWithExtends(config, configDir, options = {}, canonic
|
|
|
32309
32476
|
merged = mergeCanonicalFiles(merged, packsCanonical, { hooks: "combine" });
|
|
32310
32477
|
const localCanonical = await loadCanonicalFiles(canonicalDir);
|
|
32311
32478
|
merged = mergeCanonicalFiles(merged, localCanonical);
|
|
32479
|
+
const { rules, root, demoted } = settleRootRule(
|
|
32480
|
+
merged.rules,
|
|
32481
|
+
localCanonical.rules,
|
|
32482
|
+
packsCanonical.rules
|
|
32483
|
+
);
|
|
32484
|
+
if (root !== void 0) {
|
|
32485
|
+
for (const rule of demoted) logger.warn(demotedRootMessage(rule, root, configDir));
|
|
32486
|
+
}
|
|
32487
|
+
merged = { ...merged, rules };
|
|
32312
32488
|
merged = { ...merged, hooks: combineHooks(merged.hooks, packsCanonical.hooks) };
|
|
32313
32489
|
return { canonical: merged, resolvedExtends };
|
|
32314
32490
|
}
|
|
@@ -32316,6 +32492,7 @@ async function loadCanonicalWithExtends(config, configDir, options = {}, canonic
|
|
|
32316
32492
|
// src/plugins/load-plugin.ts
|
|
32317
32493
|
init_target_descriptor_schema();
|
|
32318
32494
|
init_registry();
|
|
32495
|
+
init_logger();
|
|
32319
32496
|
function resolveNpmSpecifier(source, projectRoot) {
|
|
32320
32497
|
const pkgDir = join(projectRoot, "node_modules", source);
|
|
32321
32498
|
const pkgJsonPath = join(pkgDir, "package.json");
|
|
@@ -32637,6 +32814,113 @@ function parseGraph(raw) {
|
|
|
32637
32814
|
function emptyGraph() {
|
|
32638
32815
|
return { version: CURRENT_GRAPH_VERSION, lessons: {}, topics: {}, triggers: {} };
|
|
32639
32816
|
}
|
|
32817
|
+
async function canonicalizePath(path) {
|
|
32818
|
+
try {
|
|
32819
|
+
return await realpath(path);
|
|
32820
|
+
} catch (error) {
|
|
32821
|
+
if (error.code !== "ENOENT") throw error;
|
|
32822
|
+
const parent = dirname(path);
|
|
32823
|
+
if (parent === path) return resolve(path);
|
|
32824
|
+
return join(await canonicalizePath(parent), basename(path));
|
|
32825
|
+
}
|
|
32826
|
+
}
|
|
32827
|
+
function canonicalizePathSync(path) {
|
|
32828
|
+
try {
|
|
32829
|
+
return realpathSync(path);
|
|
32830
|
+
} catch (error) {
|
|
32831
|
+
if (error.code !== "ENOENT") return null;
|
|
32832
|
+
}
|
|
32833
|
+
try {
|
|
32834
|
+
lstatSync(path);
|
|
32835
|
+
return null;
|
|
32836
|
+
} catch {
|
|
32837
|
+
const parent = dirname(path);
|
|
32838
|
+
if (parent === path) return resolve(path);
|
|
32839
|
+
const realParent = canonicalizePathSync(parent);
|
|
32840
|
+
return realParent === null ? null : join(realParent, basename(path));
|
|
32841
|
+
}
|
|
32842
|
+
}
|
|
32843
|
+
function resolvesInsideRootSync(root, target34) {
|
|
32844
|
+
const realRoot = canonicalizePathSync(resolve(root));
|
|
32845
|
+
const realTarget = canonicalizePathSync(resolve(target34));
|
|
32846
|
+
return realRoot !== null && realTarget !== null && isPathInside(realTarget, realRoot);
|
|
32847
|
+
}
|
|
32848
|
+
function isPathInside(target34, root) {
|
|
32849
|
+
return target34 === root || target34.startsWith(root.endsWith(sep) ? root : `${root}${sep}`);
|
|
32850
|
+
}
|
|
32851
|
+
var display = (path) => path.replaceAll("\\", "/");
|
|
32852
|
+
async function assertPathInsideRoot(root, target34) {
|
|
32853
|
+
const rootAbs = resolve(root);
|
|
32854
|
+
const targetAbs = resolve(target34);
|
|
32855
|
+
if (!isPathInside(targetAbs, rootAbs)) {
|
|
32856
|
+
throw new Error(`Unsafe filesystem path: ${display(target34)} is outside ${display(rootAbs)}`);
|
|
32857
|
+
}
|
|
32858
|
+
let realTarget;
|
|
32859
|
+
let realRoot;
|
|
32860
|
+
try {
|
|
32861
|
+
[realTarget, realRoot] = await Promise.all([
|
|
32862
|
+
canonicalizePath(targetAbs),
|
|
32863
|
+
canonicalizePath(rootAbs)
|
|
32864
|
+
]);
|
|
32865
|
+
} catch (cause) {
|
|
32866
|
+
const detail = cause instanceof Error ? cause.message : String(cause);
|
|
32867
|
+
throw new Error(
|
|
32868
|
+
`Unsafe filesystem path: ${display(target34)} could not be resolved (${detail})`,
|
|
32869
|
+
{ cause }
|
|
32870
|
+
);
|
|
32871
|
+
}
|
|
32872
|
+
if (isPathInside(realTarget, realRoot)) return;
|
|
32873
|
+
throw new Error(
|
|
32874
|
+
`Unsafe filesystem path: ${display(target34)} resolves to ${display(realTarget)} outside ${display(realRoot)}`
|
|
32875
|
+
);
|
|
32876
|
+
}
|
|
32877
|
+
var BASE_REL = ".agentsmesh/lessons";
|
|
32878
|
+
function lessonsPaths(projectRoot) {
|
|
32879
|
+
const base = join(projectRoot, BASE_REL);
|
|
32880
|
+
return {
|
|
32881
|
+
base,
|
|
32882
|
+
graph: join(base, "lessons.json"),
|
|
32883
|
+
config: join(base, "config.json"),
|
|
32884
|
+
journal: join(base, "journal.md"),
|
|
32885
|
+
index: join(base, "index.yaml"),
|
|
32886
|
+
topicsDir: join(base, "topics")
|
|
32887
|
+
};
|
|
32888
|
+
}
|
|
32889
|
+
function toRelPath(projectRoot, absolute) {
|
|
32890
|
+
return relative(projectRoot, absolute).split(sep).join("/");
|
|
32891
|
+
}
|
|
32892
|
+
var LESSONS_PROCEDURAL_RULE = `## Lessons (BLOCKING)
|
|
32893
|
+
|
|
32894
|
+
Graph \`.agentsmesh/lessons/lessons.json\` is canonical; never hand-edit it. Manual: \`lessons\` skill.
|
|
32895
|
+
|
|
32896
|
+
**Recall:** before every file edit or state-changing command, MUST run \`agentsmesh lessons query --file <path> --cmd <command> --session auto\` and obey matches; at task start, ALSO run \`agentsmesh lessons query --keyword "<task terms>" --always --session auto\` for conceptual + universal rules no path/command names. Pure-read commands and recall itself are exempt.
|
|
32897
|
+
|
|
32898
|
+
**Capture:** after any failure, user correction, regression, wrong assumption, useful surprise, repeated friction, or non-obvious fix, MUST self-critique and run \`agentsmesh lessons add "<imperative rule>" --topic <id> --trigger-file <glob> --evidence <sha|lesson-id>\`.
|
|
32899
|
+
|
|
32900
|
+
**Before final:** report \`Lesson: captured <id>\` or \`Lesson: none\`. No recall/capture gate = task incomplete. No shell: use \`lessons_query\` / \`lessons_add\`.`;
|
|
32901
|
+
|
|
32902
|
+
// src/lessons/lessons-dir-guard.ts
|
|
32903
|
+
function lessonsDirInsideProject(projectRoot) {
|
|
32904
|
+
return resolvesInsideRootSync(projectRoot, lessonsPaths(projectRoot).base);
|
|
32905
|
+
}
|
|
32906
|
+
var LessonsDirOutsideProjectError = class extends Error {
|
|
32907
|
+
code = "LESSONS_DIR_OUTSIDE_PROJECT";
|
|
32908
|
+
constructor(projectRoot) {
|
|
32909
|
+
const base = lessonsPaths(projectRoot).base;
|
|
32910
|
+
let where = "a path that does not exist";
|
|
32911
|
+
try {
|
|
32912
|
+
where = realpathSync(base).replaceAll("\\", "/");
|
|
32913
|
+
} catch {
|
|
32914
|
+
}
|
|
32915
|
+
super(
|
|
32916
|
+
`${base.replaceAll("\\", "/")} resolves to ${where}, outside the project ${projectRoot.replaceAll("\\", "/")}. agentsmesh only writes lessons inside the project; replace the link with a real folder.`
|
|
32917
|
+
);
|
|
32918
|
+
this.name = "LessonsDirOutsideProjectError";
|
|
32919
|
+
}
|
|
32920
|
+
};
|
|
32921
|
+
function assertLessonsDirInsideProject(projectRoot) {
|
|
32922
|
+
if (!lessonsDirInsideProject(projectRoot)) throw new LessonsDirOutsideProjectError(projectRoot);
|
|
32923
|
+
}
|
|
32640
32924
|
|
|
32641
32925
|
// src/lessons/graph-store.ts
|
|
32642
32926
|
var LESSONS_GRAPH_PATH = ".agentsmesh/lessons/lessons.json";
|
|
@@ -32675,6 +32959,7 @@ function isWritable(path) {
|
|
|
32675
32959
|
}
|
|
32676
32960
|
}
|
|
32677
32961
|
function saveLessonsGraph(projectRoot, graph) {
|
|
32962
|
+
assertLessonsDirInsideProject(projectRoot);
|
|
32678
32963
|
const path = graphFilePath(projectRoot);
|
|
32679
32964
|
mkdirSync(dirname(path), { recursive: true });
|
|
32680
32965
|
const mode = fileMode(path);
|
|
@@ -32701,30 +32986,6 @@ function canonicalize2(value) {
|
|
|
32701
32986
|
}
|
|
32702
32987
|
return value;
|
|
32703
32988
|
}
|
|
32704
|
-
var BASE_REL = ".agentsmesh/lessons";
|
|
32705
|
-
function lessonsPaths(projectRoot) {
|
|
32706
|
-
const base = join(projectRoot, BASE_REL);
|
|
32707
|
-
return {
|
|
32708
|
-
base,
|
|
32709
|
-
graph: join(base, "lessons.json"),
|
|
32710
|
-
config: join(base, "config.json"),
|
|
32711
|
-
journal: join(base, "journal.md"),
|
|
32712
|
-
index: join(base, "index.yaml"),
|
|
32713
|
-
topicsDir: join(base, "topics")
|
|
32714
|
-
};
|
|
32715
|
-
}
|
|
32716
|
-
function toRelPath(projectRoot, absolute) {
|
|
32717
|
-
return relative(projectRoot, absolute).split(sep).join("/");
|
|
32718
|
-
}
|
|
32719
|
-
var LESSONS_PROCEDURAL_RULE = `## Lessons (BLOCKING)
|
|
32720
|
-
|
|
32721
|
-
Graph \`.agentsmesh/lessons/lessons.json\` is canonical; never hand-edit it. Manual: \`lessons\` skill.
|
|
32722
|
-
|
|
32723
|
-
**Recall:** before every file edit or state-changing command, MUST run \`agentsmesh lessons query --file <path> --cmd <command> --session auto\` and obey matches; at task start, ALSO run \`agentsmesh lessons query --keyword "<task terms>" --always --session auto\` for conceptual + universal rules no path/command names. Pure-read commands and recall itself are exempt.
|
|
32724
|
-
|
|
32725
|
-
**Capture:** after any failure, user correction, regression, wrong assumption, useful surprise, repeated friction, or non-obvious fix, MUST self-critique and run \`agentsmesh lessons add "<imperative rule>" --topic <id> --trigger-file <glob> --evidence <sha|lesson-id>\`.
|
|
32726
|
-
|
|
32727
|
-
**Before final:** report \`Lesson: captured <id>\` or \`Lesson: none\`. No recall/capture gate = task incomplete. No shell: use \`lessons_query\` / \`lessons_add\`.`;
|
|
32728
32989
|
var MAX_OUTPUT_BYTES = 64 * 1024 * 1024;
|
|
32729
32990
|
function runGit2(cwd, args, timeoutMs) {
|
|
32730
32991
|
const r = spawnSync("git", [...args], {
|
|
@@ -34541,6 +34802,13 @@ async function hashFileForManifest(path) {
|
|
|
34541
34802
|
}
|
|
34542
34803
|
}
|
|
34543
34804
|
|
|
34805
|
+
// src/config/core/lock-stale-targets.ts
|
|
34806
|
+
function parseStaleTargets(raw) {
|
|
34807
|
+
if (!Array.isArray(raw)) return void 0;
|
|
34808
|
+
const targets = raw.filter((target34) => typeof target34 === "string");
|
|
34809
|
+
return targets.length > 0 ? targets : void 0;
|
|
34810
|
+
}
|
|
34811
|
+
|
|
34544
34812
|
// src/config/core/lock.ts
|
|
34545
34813
|
var LOCK_FILENAME = ".lock";
|
|
34546
34814
|
var CANONICAL_PATTERNS = [
|
|
@@ -34582,7 +34850,8 @@ async function readLock(abDir) {
|
|
|
34582
34850
|
extends: raw.extends && typeof raw.extends === "object" ? raw.extends : {},
|
|
34583
34851
|
packs: raw.packs && typeof raw.packs === "object" ? raw.packs : {},
|
|
34584
34852
|
// undefined (not {}) when absent → old-format lock; skips output check.
|
|
34585
|
-
outputs: raw.outputs && typeof raw.outputs === "object" ? raw.outputs : void 0
|
|
34853
|
+
outputs: raw.outputs && typeof raw.outputs === "object" ? raw.outputs : void 0,
|
|
34854
|
+
staleTargets: parseStaleTargets(raw.stale_targets)
|
|
34586
34855
|
};
|
|
34587
34856
|
} catch {
|
|
34588
34857
|
return null;
|
|
@@ -34651,47 +34920,6 @@ async function diffOutputChecksums(rootBase, lockOutputs) {
|
|
|
34651
34920
|
|
|
34652
34921
|
// src/core/generate/stale-cleanup.ts
|
|
34653
34922
|
init_fs();
|
|
34654
|
-
async function canonicalizePath(path) {
|
|
34655
|
-
try {
|
|
34656
|
-
return await realpath(path);
|
|
34657
|
-
} catch (error) {
|
|
34658
|
-
if (error.code !== "ENOENT") throw error;
|
|
34659
|
-
const parent = dirname(path);
|
|
34660
|
-
if (parent === path) return resolve(path);
|
|
34661
|
-
return join(await canonicalizePath(parent), basename(path));
|
|
34662
|
-
}
|
|
34663
|
-
}
|
|
34664
|
-
function isPathInside(target34, root) {
|
|
34665
|
-
return target34 === root || target34.startsWith(root.endsWith(sep) ? root : `${root}${sep}`);
|
|
34666
|
-
}
|
|
34667
|
-
var display = (path) => path.replaceAll("\\", "/");
|
|
34668
|
-
async function assertPathInsideRoot(root, target34) {
|
|
34669
|
-
const rootAbs = resolve(root);
|
|
34670
|
-
const targetAbs = resolve(target34);
|
|
34671
|
-
if (!isPathInside(targetAbs, rootAbs)) {
|
|
34672
|
-
throw new Error(`Unsafe filesystem path: ${display(target34)} is outside ${display(rootAbs)}`);
|
|
34673
|
-
}
|
|
34674
|
-
let realTarget;
|
|
34675
|
-
let realRoot;
|
|
34676
|
-
try {
|
|
34677
|
-
[realTarget, realRoot] = await Promise.all([
|
|
34678
|
-
canonicalizePath(targetAbs),
|
|
34679
|
-
canonicalizePath(rootAbs)
|
|
34680
|
-
]);
|
|
34681
|
-
} catch (cause) {
|
|
34682
|
-
const detail = cause instanceof Error ? cause.message : String(cause);
|
|
34683
|
-
throw new Error(
|
|
34684
|
-
`Unsafe filesystem path: ${display(target34)} could not be resolved (${detail})`,
|
|
34685
|
-
{ cause }
|
|
34686
|
-
);
|
|
34687
|
-
}
|
|
34688
|
-
if (isPathInside(realTarget, realRoot)) return;
|
|
34689
|
-
throw new Error(
|
|
34690
|
-
`Unsafe filesystem path: ${display(target34)} resolves to ${display(realTarget)} outside ${display(realRoot)}`
|
|
34691
|
-
);
|
|
34692
|
-
}
|
|
34693
|
-
|
|
34694
|
-
// src/core/generate/stale-cleanup.ts
|
|
34695
34923
|
init_builtin_targets();
|
|
34696
34924
|
init_registry();
|
|
34697
34925
|
init_builtin_targets();
|
|
@@ -34806,6 +35034,7 @@ async function checkLockSync(opts) {
|
|
|
34806
35034
|
outputsModified: [],
|
|
34807
35035
|
outputsRemoved: [],
|
|
34808
35036
|
outputsStale: [],
|
|
35037
|
+
staleTargets: [],
|
|
34809
35038
|
outputsUntracked: [],
|
|
34810
35039
|
outputsChecked: false
|
|
34811
35040
|
};
|
|
@@ -34859,8 +35088,10 @@ async function checkLockSync(opts) {
|
|
|
34859
35088
|
generatedOutputs: Object.keys(lock.outputs),
|
|
34860
35089
|
scope
|
|
34861
35090
|
}) : [];
|
|
35091
|
+
const configured = [...config.targets, ...config.pluginTargets ?? []];
|
|
35092
|
+
const staleTargets = (lock.staleTargets ?? []).filter((target34) => configured.includes(target34));
|
|
34862
35093
|
const canonicalDrift = modified.length > 0 || added.length > 0 || removed.length > 0 || extendsModified.length > 0;
|
|
34863
|
-
const outputDrift = outputsModified.length > 0 || outputsRemoved.length > 0 || outputsStale.length > 0;
|
|
35094
|
+
const outputDrift = outputsModified.length > 0 || outputsRemoved.length > 0 || outputsStale.length > 0 || staleTargets.length > 0;
|
|
34864
35095
|
const inSync = !canonicalDrift && !outputDrift;
|
|
34865
35096
|
return {
|
|
34866
35097
|
inSync,
|
|
@@ -34876,6 +35107,7 @@ async function checkLockSync(opts) {
|
|
|
34876
35107
|
outputsModified,
|
|
34877
35108
|
outputsRemoved,
|
|
34878
35109
|
outputsStale,
|
|
35110
|
+
staleTargets,
|
|
34879
35111
|
outputsUntracked,
|
|
34880
35112
|
outputsChecked
|
|
34881
35113
|
};
|
|
@@ -34884,6 +35116,62 @@ async function checkLockSync(opts) {
|
|
|
34884
35116
|
// src/public/engine.ts
|
|
34885
35117
|
init_registry();
|
|
34886
35118
|
init_target_ids();
|
|
35119
|
+
init_canonical_paths();
|
|
35120
|
+
init_fs();
|
|
35121
|
+
init_mcp_merge();
|
|
35122
|
+
var PERMISSION_LISTS = ["allow", "deny", "ask"];
|
|
35123
|
+
async function keepPermissions(path, before) {
|
|
35124
|
+
const after = await readFileSafe(path) ?? "";
|
|
35125
|
+
const skipBroken = () => void 0;
|
|
35126
|
+
const earlier = parsePermissionsContent(before, path, skipBroken);
|
|
35127
|
+
const now = parsePermissionsContent(after, path, skipBroken);
|
|
35128
|
+
if (earlier === null || now === null) return;
|
|
35129
|
+
const doc = parseDocument(after);
|
|
35130
|
+
let changed = false;
|
|
35131
|
+
for (const list of PERMISSION_LISTS) {
|
|
35132
|
+
const old = earlier[list];
|
|
35133
|
+
const cur = now[list];
|
|
35134
|
+
if (old.every((entry) => cur.includes(entry))) continue;
|
|
35135
|
+
doc.set(list, [...old, ...cur.filter((entry) => !old.includes(entry))]);
|
|
35136
|
+
changed = true;
|
|
35137
|
+
}
|
|
35138
|
+
if (changed) await writeFileAtomic(path, doc.toString());
|
|
35139
|
+
}
|
|
35140
|
+
async function keepIgnorePatterns(path, before) {
|
|
35141
|
+
const lines = (text) => text.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
35142
|
+
const earlier = lines(before);
|
|
35143
|
+
const now = lines(await readFileSafe(path) ?? "");
|
|
35144
|
+
if (earlier.every((line) => now.includes(line))) return;
|
|
35145
|
+
const added = now.filter((line) => !earlier.includes(line));
|
|
35146
|
+
await writeFileAtomic(path, `${[before.trimEnd(), ...added].join("\n")}
|
|
35147
|
+
`);
|
|
35148
|
+
}
|
|
35149
|
+
async function keepMcpServers(path, before) {
|
|
35150
|
+
const earlier = parseMcpServers(before);
|
|
35151
|
+
const now = parseMcpServers(await readFileSafe(path));
|
|
35152
|
+
if (Object.keys(earlier).every((name) => Object.hasOwn(now, name))) return;
|
|
35153
|
+
await writeFileAtomic(path, JSON.stringify({ mcpServers: { ...earlier, ...now } }, null, 2));
|
|
35154
|
+
}
|
|
35155
|
+
var KEEPERS = [
|
|
35156
|
+
[AB_PERMISSIONS, keepPermissions],
|
|
35157
|
+
[AB_IGNORE, keepIgnorePatterns],
|
|
35158
|
+
[AB_MCP, keepMcpServers]
|
|
35159
|
+
];
|
|
35160
|
+
async function runTargetImport(descriptor34, rootBase, scope) {
|
|
35161
|
+
const snapshots = await Promise.all(
|
|
35162
|
+
KEEPERS.map(async ([rel2, keep]) => {
|
|
35163
|
+
const path = join(rootBase, rel2);
|
|
35164
|
+
return { path, keep, before: await readFileSafe(path) };
|
|
35165
|
+
})
|
|
35166
|
+
);
|
|
35167
|
+
const results = await descriptor34.generators.importFrom(rootBase, { scope });
|
|
35168
|
+
for (const { path, keep, before } of snapshots) {
|
|
35169
|
+
if (before !== null) await keep(path, before);
|
|
35170
|
+
}
|
|
35171
|
+
return results;
|
|
35172
|
+
}
|
|
35173
|
+
|
|
35174
|
+
// src/public/engine.ts
|
|
34887
35175
|
async function importFrom(target34, opts) {
|
|
34888
35176
|
const descriptor34 = getDescriptor(target34);
|
|
34889
35177
|
if (!descriptor34) {
|
|
@@ -34891,7 +35179,7 @@ async function importFrom(target34, opts) {
|
|
|
34891
35179
|
supported: [...TARGET_IDS, ...getAllDescriptors().map((d) => d.id)]
|
|
34892
35180
|
});
|
|
34893
35181
|
}
|
|
34894
|
-
return descriptor34
|
|
35182
|
+
return runTargetImport(descriptor34, opts.root, opts.scope ?? "project");
|
|
34895
35183
|
}
|
|
34896
35184
|
async function loadConfig2(projectRoot) {
|
|
34897
35185
|
return loadConfigFromDir(projectRoot);
|
|
@@ -35064,42 +35352,8 @@ function makeTriggerId2(spec) {
|
|
|
35064
35352
|
const hash = createHash("sha1").update(`${spec.kind}|${spec.pattern}`).digest("hex").slice(0, 8);
|
|
35065
35353
|
return `t-${TRIGGER_PREFIX2[spec.kind]}-${hash}`;
|
|
35066
35354
|
}
|
|
35067
|
-
var RULE_HEADING_RE = /^##\s+Rules\b.*$/i;
|
|
35068
|
-
var NEXT_HEADING_RE = /^##\s+/;
|
|
35069
|
-
var RULE_LINE_RE = /^(\d+)\.\s+(.+?)\s*$/;
|
|
35070
|
-
var EVIDENCE_TAIL_RE = /\s*\(Evidence:?\s+([^)]+)\)\s*$/;
|
|
35071
|
-
var EVIDENCE_REF_RE = /L\d+/g;
|
|
35072
|
-
function parseRulesSection(markdown) {
|
|
35073
|
-
const lines = markdown.split(/\r?\n/);
|
|
35074
|
-
let inRules = false;
|
|
35075
|
-
const rules = [];
|
|
35076
|
-
for (const line of lines) {
|
|
35077
|
-
if (!inRules) {
|
|
35078
|
-
if (RULE_HEADING_RE.test(line)) inRules = true;
|
|
35079
|
-
continue;
|
|
35080
|
-
}
|
|
35081
|
-
if (NEXT_HEADING_RE.test(line)) break;
|
|
35082
|
-
const m = RULE_LINE_RE.exec(line);
|
|
35083
|
-
if (m === null) continue;
|
|
35084
|
-
const ruleIndex = Number(m[1]);
|
|
35085
|
-
let body = m[2];
|
|
35086
|
-
const evidence = [];
|
|
35087
|
-
let tail = EVIDENCE_TAIL_RE.exec(body);
|
|
35088
|
-
while (tail !== null) {
|
|
35089
|
-
const refs = tail[1];
|
|
35090
|
-
const matches = refs.match(EVIDENCE_REF_RE);
|
|
35091
|
-
if (matches !== null) evidence.unshift(...matches);
|
|
35092
|
-
body = body.slice(0, tail.index).trimEnd();
|
|
35093
|
-
tail = EVIDENCE_TAIL_RE.exec(body);
|
|
35094
|
-
}
|
|
35095
|
-
rules.push({ index: ruleIndex, body, evidence });
|
|
35096
|
-
}
|
|
35097
|
-
return rules;
|
|
35098
|
-
}
|
|
35099
35355
|
var LEGACY_ARTIFACT_REL = [
|
|
35100
35356
|
"index.yaml",
|
|
35101
|
-
"journal.md",
|
|
35102
|
-
"journal.legacy.md",
|
|
35103
35357
|
"topics",
|
|
35104
35358
|
"distill-ledger.yaml",
|
|
35105
35359
|
"distill-proposal.md"
|
|
@@ -35794,6 +36048,7 @@ function holdLock(lockPath, token) {
|
|
|
35794
36048
|
}
|
|
35795
36049
|
|
|
35796
36050
|
// src/lessons/lessons-lock.ts
|
|
36051
|
+
init_logger();
|
|
35797
36052
|
var LESSONS_LOCK_FILENAME = ".lessons.lock";
|
|
35798
36053
|
var LESSONS_LOCK_OPTIONS = Object.freeze({
|
|
35799
36054
|
retries: 500,
|
|
@@ -35806,6 +36061,7 @@ function lessonsLockPath(projectRoot) {
|
|
|
35806
36061
|
return resolve(projectRoot, ".agentsmesh/lessons", LESSONS_LOCK_FILENAME);
|
|
35807
36062
|
}
|
|
35808
36063
|
async function acquireLessonsLock(projectRoot, opts = {}) {
|
|
36064
|
+
assertLessonsDirInsideProject(projectRoot);
|
|
35809
36065
|
return acquireProcessLock(lessonsLockPath(projectRoot), {
|
|
35810
36066
|
retries: opts.retries ?? LESSONS_LOCK_OPTIONS.retries,
|
|
35811
36067
|
retryDelayMs: opts.retryDelayMs ?? LESSONS_LOCK_OPTIONS.retryDelayMs,
|
|
@@ -35972,6 +36228,50 @@ async function mergeLegacy(projectRoot, paths2, specs, summaryByTopic, options)
|
|
|
35972
36228
|
triggerCount: addedTriggers.size
|
|
35973
36229
|
};
|
|
35974
36230
|
}
|
|
36231
|
+
|
|
36232
|
+
// src/lessons/import-legacy-rules.ts
|
|
36233
|
+
var HEADING = /^#{1,6}\s/;
|
|
36234
|
+
var SECTION_HEADING = /^#{1,2}\s/;
|
|
36235
|
+
var RULES_HEADING = /^##\s+(?:Rules|Lessons)\b/i;
|
|
36236
|
+
var ITEM = /^\s{0,3}(?:\d+[.)]|[-*+])\s+(.+?)\s*$/;
|
|
36237
|
+
var EVIDENCE_TAIL = /\s*\(Evidence:?\s+([^)]+)\)\s*$/;
|
|
36238
|
+
var EVIDENCE_REF = /L\d+/g;
|
|
36239
|
+
function withEvidence(index, text) {
|
|
36240
|
+
let body = text;
|
|
36241
|
+
const evidence = [];
|
|
36242
|
+
let tail = EVIDENCE_TAIL.exec(body);
|
|
36243
|
+
while (tail !== null) {
|
|
36244
|
+
evidence.unshift(...tail[1].match(EVIDENCE_REF) ?? []);
|
|
36245
|
+
body = body.slice(0, tail.index).trimEnd();
|
|
36246
|
+
tail = EVIDENCE_TAIL.exec(body);
|
|
36247
|
+
}
|
|
36248
|
+
return { index, body, evidence };
|
|
36249
|
+
}
|
|
36250
|
+
function parseRulesSection(markdown) {
|
|
36251
|
+
const items = [];
|
|
36252
|
+
let inRules = false;
|
|
36253
|
+
let open2 = false;
|
|
36254
|
+
let strayLine = null;
|
|
36255
|
+
markdown.split(/\r?\n/).forEach((line, i) => {
|
|
36256
|
+
if (HEADING.test(line)) {
|
|
36257
|
+
if (SECTION_HEADING.test(line)) inRules = RULES_HEADING.test(line);
|
|
36258
|
+
open2 = false;
|
|
36259
|
+
return;
|
|
36260
|
+
}
|
|
36261
|
+
const item = ITEM.exec(line);
|
|
36262
|
+
if (item !== null) {
|
|
36263
|
+
if (inRules) items.push(item[1]);
|
|
36264
|
+
else strayLine ??= i + 1;
|
|
36265
|
+
open2 = inRules;
|
|
36266
|
+
return;
|
|
36267
|
+
}
|
|
36268
|
+
if (line.trim() === "") open2 = false;
|
|
36269
|
+
else if (open2) items[items.length - 1] += ` ${line.trim()}`;
|
|
36270
|
+
});
|
|
36271
|
+
return { rules: items.map((text, i) => withEvidence(i + 1, text)), strayLine };
|
|
36272
|
+
}
|
|
36273
|
+
|
|
36274
|
+
// src/lessons/import-legacy-read.ts
|
|
35975
36275
|
var LESSONS_DIR = ".agentsmesh/lessons";
|
|
35976
36276
|
var LegacyTopicPathError = class extends Error {
|
|
35977
36277
|
code = "LEGACY_TOPIC_PATH_OUTSIDE";
|
|
@@ -35985,8 +36285,8 @@ var LegacyTopicPathError = class extends Error {
|
|
|
35985
36285
|
async function resolveLegacyTopicPath(projectRoot, file) {
|
|
35986
36286
|
const forward = file.replaceAll("\\", "/");
|
|
35987
36287
|
const normalized = posix.normalize(forward);
|
|
35988
|
-
const
|
|
35989
|
-
if (!
|
|
36288
|
+
const relative28 = !/^[A-Za-z]:/.test(forward) && !forward.startsWith("/") && normalized.startsWith(`${LESSONS_DIR}/`);
|
|
36289
|
+
if (!relative28) throw new LegacyTopicPathError(file);
|
|
35990
36290
|
const target34 = join(projectRoot, normalized);
|
|
35991
36291
|
try {
|
|
35992
36292
|
await assertPathInsideRoot(join(projectRoot, LESSONS_DIR), target34);
|
|
@@ -36015,9 +36315,13 @@ async function readLegacySource(projectRoot, migratedAt) {
|
|
|
36015
36315
|
`Legacy topic file is missing: ${cluster.file}. Refusing to migrate (legacy artifacts left intact).`
|
|
36016
36316
|
);
|
|
36017
36317
|
}
|
|
36018
|
-
|
|
36019
|
-
|
|
36020
|
-
|
|
36318
|
+
const parsed = parseRulesSection(readFileSync(topicFile, "utf8"));
|
|
36319
|
+
if (parsed.strayLine !== null) {
|
|
36320
|
+
throw new Error(
|
|
36321
|
+
`Legacy lessons were not migrated: ${cluster.file} line ${parsed.strayLine} is a list item outside a "## Rules" or "## Lessons" section. Move it under one of them or delete it, then run \`agentsmesh lessons import-md\`. Nothing was changed.`
|
|
36322
|
+
);
|
|
36323
|
+
}
|
|
36324
|
+
for (const { index: ruleIndex, body, evidence } of parsed.rules) {
|
|
36021
36325
|
const lessonEvidence = [
|
|
36022
36326
|
`legacy:${cluster.file}#rule-${ruleIndex}`,
|
|
36023
36327
|
...evidence.map((e) => `legacy:${e}`)
|
|
@@ -36718,6 +37022,7 @@ async function scaffoldLessons(projectRoot) {
|
|
|
36718
37022
|
const created = [];
|
|
36719
37023
|
const updated = [];
|
|
36720
37024
|
const skipped = [];
|
|
37025
|
+
assertLessonsDirInsideProject(projectRoot);
|
|
36721
37026
|
mkdirSync(paths2.base, { recursive: true });
|
|
36722
37027
|
await maybeAutoMigrateLessons(projectRoot);
|
|
36723
37028
|
if (existsSync(paths2.graph)) {
|