@fusengine/harness 0.1.31 → 0.1.32

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.
@@ -1,2 +1,2 @@
1
- import { a as readClaudeInput, i as guard, n as denyResponse, o as toClaudeResponse, r as fileSizeGuard, t as contextResponse } from "../../claude-B9FYp0Yw.mjs";
1
+ import { a as readClaudeInput, i as guard, n as denyResponse, o as toClaudeResponse, r as fileSizeGuard, t as contextResponse } from "../../claude-BWZcrZbS.mjs";
2
2
  export { contextResponse, denyResponse, fileSizeGuard, guard, readClaudeInput, toClaudeResponse };
@@ -1,4 +1,4 @@
1
- import { t as evaluate } from "../../evaluate-j3gRJ_ng.mjs";
1
+ import { t as evaluate } from "../../evaluate-9ch1K2kt.mjs";
2
2
  import { t as formatPrompt } from "../../types-ernB1Dy3.mjs";
3
3
  //#region src/adapters/cline/index.ts
4
4
  /**
@@ -1,2 +1,2 @@
1
- import { a as readClaudeInput, i as guard, n as denyResponse, t as contextResponse } from "../../claude-B9FYp0Yw.mjs";
1
+ import { a as readClaudeInput, i as guard, n as denyResponse, t as contextResponse } from "../../claude-BWZcrZbS.mjs";
2
2
  export { contextResponse, denyResponse, guard, readClaudeInput as readCodexInput };
@@ -1,4 +1,4 @@
1
- import { t as evaluate } from "../../evaluate-j3gRJ_ng.mjs";
1
+ import { t as evaluate } from "../../evaluate-9ch1K2kt.mjs";
2
2
  import { t as formatPrompt } from "../../types-ernB1Dy3.mjs";
3
3
  //#region src/adapters/cursor/index.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { t as evaluate } from "../../evaluate-j3gRJ_ng.mjs";
1
+ import { t as evaluate } from "../../evaluate-9ch1K2kt.mjs";
2
2
  import { t as formatPrompt } from "../../types-ernB1Dy3.mjs";
3
3
  //#region src/adapters/gemini/index.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { t as evaluate } from "./evaluate-j3gRJ_ng.mjs";
1
+ import { t as evaluate } from "./evaluate-9ch1K2kt.mjs";
2
2
  import { t as formatPrompt } from "./types-ernB1Dy3.mjs";
3
3
  //#region src/adapters/claude/index.ts
4
4
  /**
package/dist/cli/bin.mjs CHANGED
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  import { r as resolveTtlSec } from "../ttl-BG55s6HZ.mjs";
3
3
  import { t as detectHarness } from "../harness-C8Nxxyn_.mjs";
4
- import { n as stagedContent, r as stagedFiles, t as checkStaged } from "../run-CXsV-wIJ.mjs";
4
+ import { n as stagedContent, r as stagedFiles, t as checkStaged } from "../run-CQbtlAKa.mjs";
5
5
  import { n as writeInitFile, t as initFor } from "../run-D91N4ul1.mjs";
6
- import { t as handleHook } from "../handle-DW9cWdVt.mjs";
6
+ import { t as handleHook } from "../handle-DJqHZcml.mjs";
7
7
  //#region src/cli/bin.ts
8
8
  /**
9
9
  * harness — CLI for @fusengine/harness.
@@ -33,7 +33,9 @@ if (cmd === "hook") {
33
33
  "carto",
34
34
  "security",
35
35
  "changelog",
36
- "aipilot"
36
+ "aipilot",
37
+ "lessons",
38
+ "seo"
37
39
  ])).has(scopeArg) ? scopeArg : "core";
38
40
  const outcome = await handleHook(id, await readStdin(), {
39
41
  now: Date.now(),
@@ -1,2 +1,2 @@
1
- import { n as stagedContent, r as stagedFiles, t as checkStaged } from "../run-CXsV-wIJ.mjs";
1
+ import { n as stagedContent, r as stagedFiles, t as checkStaged } from "../run-CQbtlAKa.mjs";
2
2
  export { checkStaged, stagedContent, stagedFiles };
@@ -1,5 +1,5 @@
1
1
  import { i as splitTarget, r as resolveMaxLines } from "./limits-CHn8AIL1.mjs";
2
- import { t as isCodeFile } from "./project-root-ff0_poWU.mjs";
2
+ import { t as isCodeFile } from "./project-root-3kk7gCOp.mjs";
3
3
  //#region src/policy/detect-framework.ts
4
4
  /**
5
5
  * Detect the framework from a file path extension + content patterns.
@@ -1,13 +1,15 @@
1
1
  import { r as resolveMaxLines } from "./limits-CHn8AIL1.mjs";
2
2
  import { r as projectLayout } from "./layout-C0jaaCQC.mjs";
3
- import { C as capVerbosity, F as requiredArchSkill, M as detectModularArchitecture, O as evaluateApex, a as parseEntry, b as frameworkSolidGate, c as EXCLUDE_DIRS$1, d as buildApexTaskInjection, h as buildClaudeMdContext, i as parseEnrichment, l as PROJECT_INDICATORS, s as parseField, t as descFromText, v as skillTriggerGate, w as detectCreationIntent } from "./describe-BYqhoV4c.mjs";
4
- import { j as detectFramework, k as countLines, n as FAIL_CLOSED, t as evaluate } from "./evaluate-j3gRJ_ng.mjs";
3
+ import { i as walkUpFor, n as projectRoot, r as projectRootOrNull, t as isCodeFile } from "./project-root-3kk7gCOp.mjs";
4
+ import { A as evaluateApex, E as detectCreationIntent, L as requiredArchSkill, P as detectModularArchitecture, S as frameworkSolidGate, T as capVerbosity, _ as buildClaudeMdContext, b as skillTriggerGate, c as parseBodyDesc, d as PROJECT_INDICATORS, l as parseField, n as missingSeoElements, o as parseEnrichment, p as buildApexTaskInjection, r as descFromText, s as parseEntry, t as isHtmlLike, u as EXCLUDE_DIRS$1 } from "./validate-CccewDwk.mjs";
5
+ import { j as detectFramework, k as countLines, n as FAIL_CLOSED, t as evaluate } from "./evaluate-9ch1K2kt.mjs";
5
6
  import { t as formatPrompt } from "./types-ernB1Dy3.mjs";
7
+ import { a as nowStamp, l as throttleMs, n as readRoots, o as readState, s as setStateField, t as addRoot } from "./registry-BkoEbdec.mjs";
6
8
  import { a as extractText, o as loadIndex, r as cacheStore, t as cacheLookup } from "./store-PrNPm6So.mjs";
7
9
  import { i as writeJsonFile, r as readJsonFile, t as atomicWrite } from "./json-io-CAn72gI4.mjs";
8
10
  import { t as loadRefs } from "./loader-CyAoJv2W.mjs";
9
11
  import { a as recordAgent, c as recordRefRead, l as recordTrivialEdit, n as saveTrack, o as recordBrainstormRequired, r as agentsFresh, s as recordDoc, t as loadTrack, u as trivialCount } from "./store-D-ge2ZPI.mjs";
10
- import { t as contextResponse } from "./claude-B9FYp0Yw.mjs";
12
+ import { n as denyResponse, t as contextResponse } from "./claude-BWZcrZbS.mjs";
11
13
  import { basename, dirname, extname, join, relative, resolve, sep } from "node:path";
12
14
  import { appendFileSync, copyFileSync, existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, rmdirSync, statSync, unlinkSync, writeFileSync } from "node:fs";
13
15
  import { homedir, tmpdir } from "node:os";
@@ -1459,22 +1461,417 @@ function generateProjectMap(cwd, outputDir) {
1459
1461
  return "";
1460
1462
  }
1461
1463
  //#endregion
1464
+ //#region src/runtime/lifecycle/cartographer/detect.ts
1465
+ /**
1466
+ * Plugin discovery (fs). Ports `detect_plugins.py`: marketplace `plugins` dir
1467
+ * resolution + `plugin.json` meta reading.
1468
+ */
1469
+ /** Sorted entry names of `dir` (alpha, byte-order), or `[]` on error. */
1470
+ function sortedNames$1(dir) {
1471
+ try {
1472
+ return readdirSync(dir).sort((a, b) => a.localeCompare(b, "en"));
1473
+ } catch {
1474
+ return [];
1475
+ }
1476
+ }
1477
+ /**
1478
+ * Read `[version, name]` from `<pluginPath>/.claude-plugin/plugin.json`.
1479
+ * @param pluginPath - Absolute plugin directory.
1480
+ * @returns The `[version, name]` pair (both "" when absent/unreadable).
1481
+ */
1482
+ function readPluginMeta(pluginPath) {
1483
+ const pj = join(pluginPath, ".claude-plugin", "plugin.json");
1484
+ if (!existsSync(pj)) return ["", ""];
1485
+ try {
1486
+ const meta = JSON.parse(readFileSync(pj, "utf-8"));
1487
+ return [meta.version ?? "", meta.name ?? ""];
1488
+ } catch {
1489
+ return ["", ""];
1490
+ }
1491
+ }
1492
+ /**
1493
+ * Auto-detect the marketplace `plugins` dir that contains `cartographer`,
1494
+ * falling back to the first marketplace with a `plugins` dir, else `cwd`.
1495
+ * Ports `find_marketplace_plugins`.
1496
+ * @param home - Home directory (defaults to `~`).
1497
+ * @returns The resolved plugins directory.
1498
+ */
1499
+ function findMarketplacePlugins(home = homedir()) {
1500
+ const mp = join(home, ".claude", "plugins", "marketplaces");
1501
+ const markets = sortedNames$1(mp);
1502
+ for (const m of markets) if (existsSync(join(mp, m, "plugins", "cartographer"))) return join(mp, m, "plugins");
1503
+ for (const m of markets) if (existsSync(join(mp, m, "plugins"))) return join(mp, m, "plugins");
1504
+ return process.cwd();
1505
+ }
1506
+ //#endregion
1507
+ //#region src/runtime/lifecycle/cartographer/scan.ts
1508
+ /**
1509
+ * Plugin scanning (fs). Ports `scan_plugins.py`: turns a plugin's
1510
+ * agents/skills/commands/hooks into ordered `[type, name, desc]` rows.
1511
+ */
1512
+ /** Sorted entry names of `dir` (alpha, byte-order), or `[]` on error. */
1513
+ function sortedNames(dir) {
1514
+ try {
1515
+ return readdirSync(dir).sort((a, b) => a.localeCompare(b, "en"));
1516
+ } catch {
1517
+ return [];
1518
+ }
1519
+ }
1520
+ /** Read a `.md` frontmatter field from a file path, "" when missing/unreadable. */
1521
+ function fileField(path, field) {
1522
+ try {
1523
+ return parseField(readFileSync(path, "utf-8"), field);
1524
+ } catch {
1525
+ return "";
1526
+ }
1527
+ }
1528
+ /** Scan `agents/*.md` → `("agent", name, desc[:50])` rows. */
1529
+ function scanAgents(root) {
1530
+ const dir = join(root, "agents");
1531
+ return sortedNames(dir).filter((n) => extname(n) === ".md").map((n) => {
1532
+ const f = join(dir, n);
1533
+ return [
1534
+ "agent",
1535
+ fileField(f, "name") || n.replace(/\.md$/, ""),
1536
+ fileField(f, "description").slice(0, 50)
1537
+ ];
1538
+ });
1539
+ }
1540
+ /** Scan `skills/<dir>/SKILL.md` → `("skill", dir, desc)` rows. */
1541
+ function scanSkills(root) {
1542
+ const dir = join(root, "skills");
1543
+ const rows = [];
1544
+ for (const name of sortedNames(dir)) {
1545
+ try {
1546
+ if (!statSync(join(dir, name)).isDirectory()) continue;
1547
+ } catch {
1548
+ continue;
1549
+ }
1550
+ const skillMd = join(dir, name, "SKILL.md");
1551
+ let desc = "";
1552
+ if (existsSync(skillMd)) {
1553
+ desc = fileField(skillMd, "description");
1554
+ if (!desc) try {
1555
+ desc = parseBodyDesc(readFileSync(skillMd, "utf-8"));
1556
+ } catch {}
1557
+ }
1558
+ rows.push([
1559
+ "skill",
1560
+ name,
1561
+ desc || "(no description)"
1562
+ ]);
1563
+ }
1564
+ return rows;
1565
+ }
1566
+ /** Scan `commands/*.md` → `("command", "/name", desc[:50])` rows. */
1567
+ function scanCommands(root) {
1568
+ const dir = join(root, "commands");
1569
+ return sortedNames(dir).filter((n) => extname(n) === ".md").map((n) => [
1570
+ "command",
1571
+ `/${n.replace(/\.md$/, "")}`,
1572
+ fileField(join(dir, n), "description").slice(0, 50)
1573
+ ]);
1574
+ }
1575
+ /** Scan `hooks/hooks.json` → a single `("hooks", "<events>", "")` row, or none. */
1576
+ function scanHooks(root) {
1577
+ const file = join(root, "hooks", "hooks.json");
1578
+ if (!existsSync(file)) return [];
1579
+ try {
1580
+ const raw = JSON.parse(readFileSync(file, "utf-8"));
1581
+ const data = raw && typeof raw === "object" ? raw : {};
1582
+ const hooks = data.hooks && typeof data.hooks === "object" ? data.hooks : data;
1583
+ const events = Object.keys(hooks).filter((k) => !k.startsWith("_")).sort((a, b) => a.localeCompare(b, "en"));
1584
+ return events.length ? [[
1585
+ "hooks",
1586
+ events.join(", "),
1587
+ ""
1588
+ ]] : [];
1589
+ } catch {
1590
+ return [];
1591
+ }
1592
+ }
1593
+ /**
1594
+ * Scan a single plugin directory into ordered `[type, name, desc]` rows.
1595
+ * @param pluginDir - Absolute plugin directory.
1596
+ * @returns The agents + skills + commands + hooks rows.
1597
+ */
1598
+ function scanPlugin(pluginDir) {
1599
+ return [
1600
+ ...scanAgents(pluginDir),
1601
+ ...scanSkills(pluginDir),
1602
+ ...scanCommands(pluginDir),
1603
+ ...scanHooks(pluginDir)
1604
+ ];
1605
+ }
1606
+ //#endregion
1607
+ //#region src/policy/cartographer/build-tree.ts
1608
+ const SECTION_ORDER = [
1609
+ "agent",
1610
+ "skill",
1611
+ "command"
1612
+ ];
1613
+ /**
1614
+ * Format grouped items with tree connectors and optional markdown links.
1615
+ * Skill sections link to `./skills/<name>/index.md`; other sections to
1616
+ * `./<folder>/<name>.md`; unlinked sections render the bare name.
1617
+ * @param prefix - The line prefix (indent + branch glyphs).
1618
+ * @param items - The `[name, desc]` pairs to render.
1619
+ * @param folder - The link folder ("" disables linking).
1620
+ * @param asDirs - Whether items link to a subdirectory `index.md`.
1621
+ * @returns The rendered lines.
1622
+ */
1623
+ function printItems(prefix, items, folder, asDirs) {
1624
+ return items.map(([name, desc], i) => {
1625
+ const connector = i === items.length - 1 ? "└──" : "├──";
1626
+ const safe = name.replace(/^\/+/, "");
1627
+ let label = name;
1628
+ if (folder && asDirs) label = `[${name}](./${folder}/${safe}/index.md)`;
1629
+ else if (folder) label = `[${name}](./${folder}/${safe}.md)`;
1630
+ const short = desc && desc !== "(no description)" ? ` — ${desc.slice(0, 80)}` : "";
1631
+ return `${prefix}${connector} ${label}${short}`;
1632
+ });
1633
+ }
1634
+ /**
1635
+ * Build an indented tree from scanned items. The `hooks` row renders as a single
1636
+ * trailing `└── hooks: …` line; agents/skills/commands render as folder sections.
1637
+ * @param items - The scanned `[type, name, desc]` rows.
1638
+ * @param linked - When true, leaf names become markdown links.
1639
+ * @returns The joined tree text.
1640
+ */
1641
+ function buildTree(items, linked = false) {
1642
+ const groups = {};
1643
+ let hooksLine = "";
1644
+ for (const [typ, name, desc] of items) if (typ === "hooks") hooksLine = name;
1645
+ else (groups[typ] ??= []).push([name, desc]);
1646
+ const sections = SECTION_ORDER.filter((s) => s in groups);
1647
+ if (hooksLine) sections.push("hooks");
1648
+ const lines = [];
1649
+ const total = sections.length;
1650
+ for (let idx = 0; idx < total; idx++) {
1651
+ const section = sections[idx] ?? "";
1652
+ if (section === "hooks") {
1653
+ lines.push(`└── hooks: ${hooksLine}`);
1654
+ continue;
1655
+ }
1656
+ const isLast = idx === total - 1;
1657
+ const folder = `${section}s`;
1658
+ const prefix = isLast ? "└──" : "├──";
1659
+ const subPrefix = isLast ? " " : "│ ";
1660
+ lines.push(`${prefix} ${folder}/`);
1661
+ const linkFolder = linked ? folder : "";
1662
+ const isDirSection = section === "skill";
1663
+ lines.push(...printItems(subPrefix, groups[section] ?? [], linkFolder, linked && isDirSection));
1664
+ }
1665
+ return lines.join("\n");
1666
+ }
1667
+ //#endregion
1668
+ //#region src/runtime/lifecycle/cartographer/write-plugin-map.ts
1669
+ /**
1670
+ * Per-plugin map writer (fs). Ports `write_plugin_map.py`: writes a level-2
1671
+ * `<plugin>/index.md` (indented linked tree) then recurses agents/skills/
1672
+ * commands into deeper index trees. Reuses `buildTree`, `mergeLines`, `writeTree`.
1673
+ */
1674
+ /** True when `dir` is a real directory. */
1675
+ function isDir(dir) {
1676
+ try {
1677
+ return statSync(dir).isDirectory();
1678
+ } catch {
1679
+ return false;
1680
+ }
1681
+ }
1682
+ /**
1683
+ * Write `<outputDir>/<pluginName>/index.md` (indented linked tree) and recurse
1684
+ * agents/skills/commands into their own index trees rooted there.
1685
+ * @param outputDir - The map root directory.
1686
+ * @param pluginName - Display name of the plugin (the index subfolder).
1687
+ * @param version - Plugin version ("" to omit).
1688
+ * @param items - The scanned `[type, name, desc]` rows.
1689
+ * @param pluginPath - Absolute source plugin directory (for recursion).
1690
+ */
1691
+ function writePluginMap(outputDir, pluginName, version, items, pluginPath) {
1692
+ const pluginDir = join(outputDir, pluginName);
1693
+ mkdirSync(pluginDir, { recursive: true });
1694
+ const newLines = `# ${pluginName}${version ? ` (v${version})` : ""}\n\n${items.length ? buildTree(items, true) : "└── (empty)"}`.split("\n");
1695
+ const indexPath = join(pluginDir, "index.md");
1696
+ writeFileSync(indexPath, mergeLines(newLines, indexPath).join("\n") + "\n", "utf-8");
1697
+ for (const section of [
1698
+ "agents",
1699
+ "skills",
1700
+ "commands"
1701
+ ]) {
1702
+ const src = join(pluginPath, section);
1703
+ if (isDir(src)) writeTree(src, join(pluginDir, section), "../index.md");
1704
+ }
1705
+ }
1706
+ //#endregion
1707
+ //#region src/runtime/lifecycle/cartographer/ecosystem-map.ts
1708
+ /**
1709
+ * Ecosystem (plugin) map generation (fs). Ports `generate_map.py`: scans every
1710
+ * installed plugin into a level-1 `.cartographer/index.md` + per-plugin level-2+
1711
+ * trees, preserving enriched descriptions. Reuses `findMarketplacePlugins`,
1712
+ * `readPluginMeta`, `scanPlugin`, `mergeLines`, `writePluginMap`.
1713
+ */
1714
+ function pluginDirs(dir) {
1715
+ let entries = [];
1716
+ try {
1717
+ entries = readdirSync(dir);
1718
+ } catch {
1719
+ return [];
1720
+ }
1721
+ return entries.filter((n) => !n.startsWith("_") && !n.startsWith(".")).filter((n) => {
1722
+ try {
1723
+ return statSync(join(dir, n)).isDirectory();
1724
+ } catch {
1725
+ return false;
1726
+ }
1727
+ }).sort((a, b) => a.localeCompare(b, "en"));
1728
+ }
1729
+ function utcStamp(now) {
1730
+ return new Date(now).toISOString().slice(0, 16).replace("T", " ");
1731
+ }
1732
+ /**
1733
+ * Generate the plugin ecosystem map under `<pluginsDir>/.cartographer`.
1734
+ * @param now - Clock for the banner timestamp.
1735
+ * @param pluginsDirOverride - Override for the marketplace plugins directory.
1736
+ * @returns The map navigation context, or "".
1737
+ */
1738
+ function generateEcosystemMap(now, pluginsDirOverride) {
1739
+ const pluginsDir = resolve(pluginsDirOverride ?? findMarketplacePlugins());
1740
+ try {
1741
+ if (!statSync(pluginsDir).isDirectory()) return "";
1742
+ } catch {
1743
+ return "";
1744
+ }
1745
+ const outputDir = join(pluginsDir, ".cartographer");
1746
+ mkdirSync(outputDir, { recursive: true });
1747
+ const dirs = pluginDirs(pluginsDir);
1748
+ const lines = [`# Ecosystem Map (${dirs.length} plugins)\n`, `> Auto-generated by cartographer — ${utcStamp(now)}\n`];
1749
+ for (const name of dirs) {
1750
+ const pluginPath = join(pluginsDir, name);
1751
+ const [version, pkgName] = readPluginMeta(pluginPath);
1752
+ const display = pkgName || name;
1753
+ const items = scanPlugin(pluginPath);
1754
+ const agents = items.filter(([t]) => t === "agent").map(([, n]) => n);
1755
+ const ver = version ? ` (v${version})` : "";
1756
+ lines.push(`- [${display}](./${display}/index.md)${ver} → ${agents.length ? agents.join(", ") : "(no agents)"}`);
1757
+ writePluginMap(outputDir, display, version, items, pluginPath);
1758
+ writePluginMap(pluginPath, ".cartographer", version, items, pluginPath);
1759
+ }
1760
+ const indexPath = join(outputDir, "index.md");
1761
+ writeFileSync(indexPath, mergeLines(lines, indexPath).join("\n") + "\n", "utf-8");
1762
+ return `Project map: .cartographer/project/index.md — navigate project files. Plugin skills map: ${outputDir}/index.md — navigate agent skills. Branches link to deeper index.md, leaves link to real files.`;
1763
+ }
1764
+ //#endregion
1462
1765
  //#region src/runtime/lifecycle/cartographer/session-start.ts
1463
1766
  /**
1464
- * Cartographer SessionStart handler. Ports the project-map half of
1465
- * `generate_project_map.py`: regenerates `.cartographer/project` and emits no
1466
- * additionalContext (the plugin ecosystem map from `generate_map.py` is not
1467
- * ported and stays as Python).
1767
+ * Cartographer SessionStart handler. Ports BOTH halves of the Python maps:
1768
+ * `generate_project_map.py` (regenerate `.cartographer/project`) and
1769
+ * `generate_map.py` (regenerate the plugin ecosystem map), emitting the
1770
+ * navigation context from the latter as additionalContext.
1468
1771
  */
1469
1772
  /**
1470
- * Regenerate the project map for `cwd` on SessionStart. Returns "" (side-effect
1471
- * only no additionalContext).
1773
+ * Regenerate the project map + plugin ecosystem map for `cwd` on SessionStart.
1774
+ * Emits the ecosystem navigation context as additionalContext (or "").
1472
1775
  * @param cwd - The working directory.
1473
- * @returns "" always.
1776
+ * @param now - Clock for the ecosystem map banner timestamp.
1777
+ * @returns The SessionStart additionalContext response, or "".
1474
1778
  */
1475
- function cartoSessionStart(cwd) {
1779
+ function cartoSessionStart(cwd, now = Date.now()) {
1476
1780
  generateProjectMap(cwd);
1477
- return "";
1781
+ const ctx = generateEcosystemMap(now);
1782
+ return ctx ? contextResponse("SessionStart", ctx) : "";
1783
+ }
1784
+ //#endregion
1785
+ //#region src/runtime/lifecycle/lessons/state.ts
1786
+ /**
1787
+ * Per-project lessons paths. The `fuse-lessons` plugin stores its lessons under
1788
+ * `<root>/MEMORY/` (NOT the harness `.harness/memory/`), so these two path
1789
+ * helpers override the layout while ALL state/gitignore/throttle logic is
1790
+ * reused from `src/memory` (`setStateField`, `ensureMemoryGitignore`,
1791
+ * `readState`, `nowStamp`, `throttleMs`).
1792
+ */
1793
+ /** Absolute `<root>/MEMORY/LESSON.md` — the curated, committable lessons file. */
1794
+ function lessonsFileFor(root) {
1795
+ return join(root, "MEMORY", "LESSON.md");
1796
+ }
1797
+ /** Absolute `<root>/MEMORY/state.json` — machine-local throttle counter. */
1798
+ function lessonsStateFileFor(root) {
1799
+ return join(root, "MEMORY", "state.json");
1800
+ }
1801
+ //#endregion
1802
+ //#region src/runtime/lifecycle/lessons/dispatch.ts
1803
+ /**
1804
+ * fuse-lessons scope dispatch (TS port of the 4 handler scripts). Routes by
1805
+ * event: SessionStart/SubagentStart inject `MEMORY/LESSON.md`; Stop reminds
1806
+ * across every project with unsaved code edits; PostToolUse marks the write to
1807
+ * arm/silence the per-project throttle. Non-fatal by design.
1808
+ */
1809
+ /** Inject `<root>/MEMORY/LESSON.md` as additionalContext for `event`. */
1810
+ function injectMemory(cwd, event) {
1811
+ const file = lessonsFileFor(projectRoot(cwd));
1812
+ if (!existsSync(file)) return "";
1813
+ let content = "";
1814
+ try {
1815
+ content = readFileSync(file, "utf-8").trim();
1816
+ } catch {
1817
+ return "";
1818
+ }
1819
+ if (!content) return "";
1820
+ return contextResponse(event, `Project lessons — never reproduce these:\n${content}\nYou may append OR refine/merge/dedupe bullets in MEMORY/LESSON.md — keep it terse.`);
1821
+ }
1822
+ /** Select roots with unsaved code edits past the throttle, bumping their state. */
1823
+ function collectPending(now, window) {
1824
+ const pending = [];
1825
+ for (const root of readRoots()) {
1826
+ const stateFile = lessonsStateFileFor(root);
1827
+ const { lastRemindedAt, lastCodeEditAt } = readState(stateFile);
1828
+ if (lastCodeEditAt <= lastRemindedAt) continue;
1829
+ if (now - lastRemindedAt < window) continue;
1830
+ pending.push(root);
1831
+ setStateField(stateFile, "lastRemindedAt", now);
1832
+ }
1833
+ return pending;
1834
+ }
1835
+ /** Stop: emit one reminder covering every project with pending lessons. */
1836
+ function remindWrite(now) {
1837
+ const pending = collectPending(now, throttleMs());
1838
+ if (pending.length === 0) return "";
1839
+ return contextResponse("Stop", `Before ending: if this session hit a mistake/blocker worth never reproducing, append 1-3 COMPACT bullets OR sharpen/merge existing ones (format \`- [${nowStamp()}] what went wrong → do instead\`, use exactly this timestamp) in each project's lessons file below. Skip if nothing notable.\n${pending.map((r) => `- ${r}/MEMORY/LESSON.md`).join("\n")}`);
1840
+ }
1841
+ /** PostToolUse: record the relevant throttle timestamp for the edited file. */
1842
+ function markWrite(payload, now) {
1843
+ const input = payload.tool_input;
1844
+ if (!input?.file_path) return;
1845
+ const abs = resolve(input.file_path);
1846
+ const root = projectRootOrNull(dirname(abs));
1847
+ if (!root) return;
1848
+ const stateFile = lessonsStateFileFor(root);
1849
+ if (abs === resolve(root, "MEMORY", "LESSON.md")) setStateField(stateFile, "lastRemindedAt", now);
1850
+ else if (isCodeFile(abs)) {
1851
+ setStateField(stateFile, "lastCodeEditAt", now);
1852
+ addRoot(root);
1853
+ }
1854
+ }
1855
+ /**
1856
+ * Route a fuse-lessons event to its handler. Returns the native stdout for
1857
+ * context-injecting events (SessionStart/SubagentStart/Stop) or "" for the
1858
+ * side-effect-only PostToolUse mark.
1859
+ * @param event - The raw hook event name.
1860
+ * @param payload - The raw hook payload.
1861
+ * @param cwd - Project root for memory injection.
1862
+ * @param now - Clock.
1863
+ * @returns The native stdout (possibly empty).
1864
+ */
1865
+ function dispatchLessons(event, payload, cwd, now) {
1866
+ switch (event) {
1867
+ case "SessionStart":
1868
+ case "SubagentStart": return injectMemory(cwd, event);
1869
+ case "Stop": return remindWrite(now);
1870
+ case "PostToolUse":
1871
+ markWrite(payload, now);
1872
+ return "";
1873
+ default: return "";
1874
+ }
1478
1875
  }
1479
1876
  //#endregion
1480
1877
  //#region src/runtime/lifecycle/aipilot/inject-apex.ts
@@ -2516,7 +2913,8 @@ async function aipilotPostToolUse(payload, cwd) {
2516
2913
  function sessionStart(input) {
2517
2914
  if (input.scope === "solid") return solidDetectStart();
2518
2915
  if (input.scope === "rules") return injectRules(process.env.CLAUDE_PLUGIN_ROOT ?? input.cwd);
2519
- if (input.scope === "carto") return cartoSessionStart(input.cwd);
2916
+ if (input.scope === "carto") return cartoSessionStart(input.cwd, input.now);
2917
+ if (input.scope === "lessons") return dispatchLessons("SessionStart", input.payload, input.cwd, input.now);
2520
2918
  return sessionStartCore(input.cwd, void 0, input.now);
2521
2919
  }
2522
2920
  /**
@@ -2530,7 +2928,11 @@ function dispatchLifecycle(input) {
2530
2928
  switch (input.event) {
2531
2929
  case "SessionStart": return sessionStart(input);
2532
2930
  case "UserPromptSubmit": return input.scope === "rules" ? injectRules(process.env.CLAUDE_PLUGIN_ROOT ?? input.cwd) : null;
2533
- case "SubagentStart": return input.scope === "aipilot" ? "" : subagentCacheContext(input.payload.session_id);
2931
+ case "SubagentStart":
2932
+ if (input.scope === "aipilot") return "";
2933
+ if (input.scope === "lessons") return dispatchLessons("SubagentStart", input.payload, input.cwd, input.now);
2934
+ return subagentCacheContext(input.payload.session_id);
2935
+ case "Stop": return input.scope === "lessons" ? dispatchLessons("Stop", input.payload, input.cwd, input.now) : null;
2534
2936
  case "SubagentStop": return input.scope === "aipilot" ? "" : trackAgentMemory(input.payload, void 0, input.now);
2535
2937
  case "TeammateIdle": return validateTeammateOutput(input.payload);
2536
2938
  case "PostToolUseFailure":
@@ -2715,13 +3117,16 @@ function trackWatchResearch(tool, input, now = Date.now(), home = homedir()) {
2715
3117
  /**
2716
3118
  * Dispatch the appropriate PostToolUse tracker for the invoking scope. Carto
2717
3119
  * persists manual enrichments; security records skill reads + MCP research;
2718
- * changelog records watch research. Side-effect only.
3120
+ * changelog records watch research; lessons arms the per-project throttle.
3121
+ * Side-effect only.
2719
3122
  * @param scope - The invoking plugin scope.
2720
3123
  * @param event - The normalized event.
2721
3124
  * @param input - The raw tool input.
2722
3125
  * @param now - Clock.
3126
+ * @param payload - The raw hook payload (for the lessons mark).
3127
+ * @param cwd - The project root (for the lessons mark).
2723
3128
  */
2724
- function postTrackingSideEffects(scope, event, input, now) {
3129
+ function postTrackingSideEffects(scope, event, input, now, payload = {}, cwd = process.cwd()) {
2725
3130
  if (scope === "carto" && (event.tool === "Edit" || event.tool === "Write") && event.filePath) {
2726
3131
  trackEnrichment(event.filePath);
2727
3132
  return;
@@ -2731,7 +3136,11 @@ function postTrackingSideEffects(scope, event, input, now) {
2731
3136
  trackMcpResearch(event.tool, input, now);
2732
3137
  return;
2733
3138
  }
2734
- if (scope === "changelog") trackWatchResearch(event.tool, input, now);
3139
+ if (scope === "changelog") {
3140
+ trackWatchResearch(event.tool, input, now);
3141
+ return;
3142
+ }
3143
+ if (scope === "lessons") dispatchLessons("PostToolUse", payload, cwd, now);
2735
3144
  }
2736
3145
  //#endregion
2737
3146
  //#region src/runtime/lifecycle/security/check-skill.ts
@@ -2765,6 +3174,42 @@ function securityAdvisory(tool, filePath, now = Date.now(), home = homedir()) {
2765
3174
  } });
2766
3175
  }
2767
3176
  //#endregion
3177
+ //#region src/runtime/lifecycle/seo/post-tool-use.ts
3178
+ /**
3179
+ * SEO PostToolUse handler (fs effects). Ports `seo/hooks/validate-seo.ts`: on an
3180
+ * edited HTML-like file under a `.fuse-seo` marker, deny when SEO elements are
3181
+ * missing. Opt-in only — silent when no marker / non-HTML / file unreadable.
3182
+ */
3183
+ /**
3184
+ * Validate the edited file's SEO completeness. Returns a deny message (for a
3185
+ * `permissionDecision: deny` response) when HTML-like, opted-in, and missing
3186
+ * elements; otherwise `null` (allow).
3187
+ * @param payload - The raw PostToolUse payload.
3188
+ * @returns The deny reason string, or `null` to allow.
3189
+ */
3190
+ function seoPostToolUse(payload) {
3191
+ const path = payload.tool_input?.file_path;
3192
+ if (!path || !isHtmlLike(path)) return null;
3193
+ if (!walkUpFor(typeof payload.cwd === "string" ? payload.cwd : dirname(path), ".fuse-seo")) return null;
3194
+ try {
3195
+ const missing = missingSeoElements(readFileSync(path, "utf-8"));
3196
+ if (missing.length === 0) return null;
3197
+ return `fuse-seo: missing SEO elements in ${path}:\n - ${missing.join("\n - ")}`;
3198
+ } catch {
3199
+ return null;
3200
+ }
3201
+ }
3202
+ /**
3203
+ * SEO PostToolUse as a ready native response: a `permissionDecision: deny`
3204
+ * string when the edited file is missing SEO elements, else `null` (allow).
3205
+ * @param payload - The raw PostToolUse payload.
3206
+ * @returns The deny response string, or `null` to allow.
3207
+ */
3208
+ function seoPostToolUseResponse(payload) {
3209
+ const deny = seoPostToolUse(payload);
3210
+ return deny ? denyResponse("PostToolUse", deny) : null;
3211
+ }
3212
+ //#endregion
2768
3213
  //#region src/runtime/lifecycle-bridge.ts
2769
3214
  /** Raw event name from a payload (Cline lacks one; lifecycle is Claude-only). */
2770
3215
  function rawEvent(payload) {
@@ -3328,7 +3773,12 @@ async function handleHook(id, payload, opts) {
3328
3773
  responseLength: extractText(response).length
3329
3774
  });
3330
3775
  if (activity) await recordActivity(file, activity);
3331
- postTrackingSideEffects(opts.scope ?? "core", event, event.input, opts.now);
3776
+ postTrackingSideEffects(opts.scope ?? "core", event, event.input, opts.now, payload, opts.cwd);
3777
+ const seoDeny = opts.scope === "seo" ? seoPostToolUseResponse(payload) : null;
3778
+ if (seoDeny) return {
3779
+ stdout: seoDeny,
3780
+ exit: 0
3781
+ };
3332
3782
  if (opts.scope === "aipilot" && (event.tool === "TaskCreate" || event.tool === "TaskUpdate")) {
3333
3783
  const out = await aipilotPostToolUse(payload, opts.cwd);
3334
3784
  if (out) return {
@@ -3353,4 +3803,4 @@ async function handleHook(id, payload, opts) {
3353
3803
  });
3354
3804
  }
3355
3805
  //#endregion
3356
- export { purgeTtlTree as $, isProject as A, cleanupSession as B, todayUtc as C, activityFor as Ct, dispatchAipilot as D, aipilotPostToolUse as E, getFileDesc as F, subagentCacheContext as G, logToolFailure as H, listChildren as I, injectRules as J, detectSolidProfile as K, postEditTypescript as L, loadEnriched as M, mergeLines as N, cartoSessionStart as O, countFiles as P, pruneEmptyDirs as Q, trackSessionChanges as R, securityStatePath as S, queryOf as St, dispatchLifecycle as T, validateTeammateOutput as U, saveApexState as V, trackAgentMemory as W, runSessionStartCleanups as X, readRules as Y, sessionStartCore as Z, trackSkillRead as _, normalizeEvent as _t, TRIVIAL_BUDGET as a, claudeHome as at, saveSecurityState as b, mcpPostStore as bt, detectDuplication as c, sanitizeSessionId as ct, lifecycleStdout as d, sessionsDir as dt, removeOldFiles as et, postEditContext as f, promptSubmitContext as ft, trackMcpResearch as g, trackFile as gt, trackWatchResearch as h, recordActivity as ht, REQUIRED_AGENTS as i, projectContext as it, writeTree as j, generateProjectMap as k, dryGate as l, saveSessionState as lt, postTrackingSideEffects as m, respond as mt, handlePre as n, devContext as nt, gate as o, fusengineCache as ot, securityAdvisory as p, taskContext as pt, solidDetectStart as q, DEFAULT_WINDOW_MS as r, gitContext as rt, preCommitGate as s, loadSessionState as st, handleHook as t, trimLogFile as tt, extractSymbols as u, sessionStatePath as ut, isoUtc as v, MCP_TTL_MS as vt, trackEnrichment as w, securityStateDir as x, mcpPreIntercept as xt, loadSecurityState as y, isMcpTool as yt, validateRulesLoaded as z };
3806
+ export { detectSolidProfile as $, dispatchLessons as A, activityFor as At, mergeLines as B, securityStateDir as C, trackFile as Ct, dispatchLifecycle as D, mcpPostStore as Dt, trackEnrichment as E, isMcpTool as Et, writePluginMap as F, trackSessionChanges as G, getFileDesc as H, generateProjectMap as I, saveApexState as J, validateRulesLoaded as K, isProject as L, lessonsStateFileFor as M, cartoSessionStart as N, aipilotPostToolUse as O, mcpPreIntercept as Ot, generateEcosystemMap as P, subagentCacheContext as Q, writeTree as R, saveSecurityState as S, recordActivity as St, todayUtc as T, MCP_TTL_MS as Tt, listChildren as U, countFiles as V, postEditTypescript as W, validateTeammateOutput as X, logToolFailure as Y, trackAgentMemory as Z, trackWatchResearch as _, sessionStatePath as _t, TRIVIAL_BUDGET as a, pruneEmptyDirs as at, isoUtc as b, taskContext as bt, detectDuplication as c, trimLogFile as ct, lifecycleStdout as d, projectContext as dt, solidDetectStart as et, postEditContext as f, claudeHome as ft, postTrackingSideEffects as g, saveSessionState as gt, securityAdvisory as h, sanitizeSessionId as ht, REQUIRED_AGENTS as i, sessionStartCore as it, lessonsFileFor as j, dispatchAipilot as k, queryOf as kt, dryGate as l, devContext as lt, seoPostToolUseResponse as m, loadSessionState as mt, handlePre as n, readRules as nt, gate as o, purgeTtlTree as ot, seoPostToolUse as p, fusengineCache as pt, cleanupSession as q, DEFAULT_WINDOW_MS as r, runSessionStartCleanups as rt, preCommitGate as s, removeOldFiles as st, handleHook as t, injectRules as tt, extractSymbols as u, gitContext as ut, trackMcpResearch as v, sessionsDir as vt, securityStatePath as w, normalizeEvent as wt, loadSecurityState as x, respond as xt, trackSkillRead as y, promptSubmitContext as yt, loadEnriched as z };
@@ -10,6 +10,13 @@ declare function compactJson(data: unknown): string;
10
10
  /** True for a source-code file outside generated/vendored directories. */
11
11
  declare function isCodeFile(p: string): boolean;
12
12
  /**
13
+ * Walk up from `dir` to the nearest ancestor directory containing `marker`.
14
+ * @param dir - Starting directory.
15
+ * @param marker - Sibling file/dir name to look for at each level.
16
+ * @returns The ancestor holding `marker`, or `null` at filesystem root.
17
+ */
18
+ declare function walkUpFor(dir: string, marker: string): string | null;
19
+ /**
13
20
  * Resolve the project root, preferring the repo boundary (`.git`) over a
14
21
  * nested `package.json` — avoids false roots in monorepos. Null if none found.
15
22
  */
@@ -17,4 +24,4 @@ declare function projectRootOrNull(dir: string): string | null;
17
24
  /** Like {@link projectRootOrNull} but falls back to `process.cwd()`. */
18
25
  declare function projectRoot(dir: string): string;
19
26
  //#endregion
20
- export { compactJson as i, projectRoot as n, projectRootOrNull as r, isCodeFile as t };
27
+ export { compactJson as a, walkUpFor as i, projectRoot as n, projectRootOrNull as r, isCodeFile as t };
@@ -435,4 +435,15 @@ declare function firstComment(text: string): string;
435
435
  */
436
436
  declare function descFromText(suffix: string, text: string, mdField: string): string;
437
437
  //#endregion
438
- export { ApexGate as $, registerGuard as A, ASK_WRITERS as B, MAX_EXA_RESULTS as C, requiredArchSkill as Ct, FAIL_CLOSED as D, detectCreationIntent as E, PHP_DECL_RE as F, protectedPathGuard as G, CODE_REDIRECT as H, PY_MODEL_RE as I, securityGuard as J, ASK_PATTERNS as K, SWIFT_PROTO_RE as L, installGuard as M, GO_DECL_RE as N, GUARDS as O, JAVA_DECL_RE as P, ApexContext as Q, TS_DECL_RE as R, frameworkSolidGate as S, isApexCommand as St, capVerbosity as T, bashWriteGuard as U, CODE_MUTATORS as V, PROTECTED_FRAGMENTS as W, GuardContext as X, Guard as Y, APEX_GATES as Z, buildClaudeMdContext as _, DEV_KEYWORDS as _t, parseEnrichment as a, PolicyContext as at, skillTriggerGate as b, detectModularArchitecture as bt, parseField as c, GIT_ASK as ct, ApexTaskState as d, SYSTEM_INSTALL as dt, brainstormGate as et, buildApexTaskContext as f, matchPatterns as ft, buildApexInstruction as g, detectFramework as gt, DEV_VERBS as h, evaluateFileSize as ht, TreeEntry as i, solidReadGate as it, runGuards as j, clearUserGuards as k, EXCLUDE_DIRS as l, GIT_BLOCKED as lt, loadApexTaskState as m, countLines as mt, firstComment as n, evaluateApex as nt, parseEntry as o, PolicyResult as ot, buildApexTaskInjection as p, FileSizeVerdict as pt, CRITICAL_PATTERNS as q, firstHeading as r, freshnessGate as rt, parseBodyDesc as s, evaluate as st, descFromText as t, docConsultedGate as tt, PROJECT_INDICATORS as u, PROJECT_INSTALL as ut, detectClaudeMdProjectType as v, ModularArchitecture as vt, MAX_TOKENS as w, SKILL_TRIGGERS as x, detectProjectType as xt, detectRequiredSkills as y, ProjectType as yt, interfaceSeparationGuard as z };
438
+ //#region src/policy/seo/validate.d.ts
439
+ /** True when `path` is an HTML-like file the SEO hook should validate. */
440
+ declare function isHtmlLike(path: string): boolean;
441
+ /**
442
+ * Report the SEO elements missing from HTML-like content (title, meta
443
+ * description, OG title/description/image, canonical, JSON-LD schema).
444
+ * @param html - The file content.
445
+ * @returns The missing element labels (empty when complete).
446
+ */
447
+ declare function missingSeoElements(html: string): string[];
448
+ //#endregion
449
+ export { APEX_GATES as $, GUARDS as A, TS_DECL_RE as B, SKILL_TRIGGERS as C, detectProjectType as Ct, capVerbosity as D, MAX_TOKENS as E, GO_DECL_RE as F, bashWriteGuard as G, ASK_WRITERS as H, JAVA_DECL_RE as I, ASK_PATTERNS as J, PROTECTED_FRAGMENTS as K, PHP_DECL_RE as L, registerGuard as M, runGuards as N, detectCreationIntent as O, installGuard as P, GuardContext as Q, PY_MODEL_RE as R, skillTriggerGate as S, detectModularArchitecture as St, MAX_EXA_RESULTS as T, requiredArchSkill as Tt, CODE_MUTATORS as U, interfaceSeparationGuard as V, CODE_REDIRECT as W, securityGuard as X, CRITICAL_PATTERNS as Y, Guard as Z, DEV_VERBS as _, evaluateFileSize as _t, firstHeading as a, freshnessGate as at, detectClaudeMdProjectType as b, ModularArchitecture as bt, parseEntry as c, PolicyResult as ct, EXCLUDE_DIRS as d, GIT_BLOCKED as dt, ApexContext as et, PROJECT_INDICATORS as f, PROJECT_INSTALL as ft, loadApexTaskState as g, countLines as gt, buildApexTaskInjection as h, FileSizeVerdict as ht, firstComment as i, evaluateApex as it, clearUserGuards as j, FAIL_CLOSED as k, parseBodyDesc as l, evaluate as lt, buildApexTaskContext as m, matchPatterns as mt, missingSeoElements as n, brainstormGate as nt, TreeEntry as o, solidReadGate as ot, ApexTaskState as p, SYSTEM_INSTALL as pt, protectedPathGuard as q, descFromText as r, docConsultedGate as rt, parseEnrichment as s, PolicyContext as st, isHtmlLike as t, ApexGate as tt, parseField as u, GIT_ASK as ut, buildApexInstruction as v, detectFramework as vt, frameworkSolidGate as w, isApexCommand as wt, detectRequiredSkills as x, ProjectType as xt, buildClaudeMdContext as y, DEV_KEYWORDS as yt, SWIFT_PROTO_RE as z };
package/dist/index.d.mts CHANGED
@@ -4,11 +4,11 @@ import { a as DEFAULT_MAX_LINES, c as splitTarget, d as resolveTtlSec, f as ttlL
4
4
  import { a as detectHarness, i as HarnessVia, n as HarnessInfo, o as detectMode, r as HarnessMode, s as modeFor, t as HarnessId } from "./harness-DwJskkz_.mjs";
5
5
  import { a as isDocConsulted, i as formatDocSatisfactionStatus, n as DocSatisfactionStatus, o as resolveSessions, r as formatDocDeny, t as AuthEntry } from "./doc-helpers-CG1nuf-c.mjs";
6
6
  import { t as incrementTrivialEditCounter } from "./index-BOBXQ91y.mjs";
7
- import { i as compactJson, n as projectRoot, r as projectRootOrNull, t as isCodeFile } from "./index-C1vLIMwN.mjs";
8
- import { $ as ApexGate, A as registerGuard, B as ASK_WRITERS, C as MAX_EXA_RESULTS, Ct as requiredArchSkill, D as FAIL_CLOSED, E as detectCreationIntent, F as PHP_DECL_RE, G as protectedPathGuard, H as CODE_REDIRECT, I as PY_MODEL_RE, J as securityGuard, K as ASK_PATTERNS, L as SWIFT_PROTO_RE, M as installGuard, N as GO_DECL_RE, O as GUARDS, P as JAVA_DECL_RE, Q as ApexContext, R as TS_DECL_RE, S as frameworkSolidGate, St as isApexCommand, T as capVerbosity, U as bashWriteGuard, V as CODE_MUTATORS, W as PROTECTED_FRAGMENTS, X as GuardContext, Y as Guard, Z as APEX_GATES, _ as buildClaudeMdContext, _t as DEV_KEYWORDS, a as parseEnrichment, at as PolicyContext, b as skillTriggerGate, bt as detectModularArchitecture, c as parseField, ct as GIT_ASK, d as ApexTaskState, dt as SYSTEM_INSTALL, et as brainstormGate, f as buildApexTaskContext, ft as matchPatterns, g as buildApexInstruction, gt as detectFramework, h as DEV_VERBS, ht as evaluateFileSize, i as TreeEntry, it as solidReadGate, j as runGuards, k as clearUserGuards, l as EXCLUDE_DIRS, lt as GIT_BLOCKED, m as loadApexTaskState, mt as countLines, n as firstComment, nt as evaluateApex, o as parseEntry, ot as PolicyResult, p as buildApexTaskInjection, pt as FileSizeVerdict, q as CRITICAL_PATTERNS, r as firstHeading, rt as freshnessGate, s as parseBodyDesc, st as evaluate, t as descFromText, tt as docConsultedGate, u as PROJECT_INDICATORS, ut as PROJECT_INSTALL, v as detectClaudeMdProjectType, vt as ModularArchitecture, w as MAX_TOKENS, x as SKILL_TRIGGERS, xt as detectProjectType, y as detectRequiredSkills, yt as ProjectType, z as interfaceSeparationGuard } from "./index-mISsk0ff.mjs";
7
+ import { a as compactJson, i as walkUpFor, n as projectRoot, r as projectRootOrNull, t as isCodeFile } from "./index-BEMumjOw.mjs";
8
+ import { $ as APEX_GATES, A as GUARDS, B as TS_DECL_RE, C as SKILL_TRIGGERS, Ct as detectProjectType, D as capVerbosity, E as MAX_TOKENS, F as GO_DECL_RE, G as bashWriteGuard, H as ASK_WRITERS, I as JAVA_DECL_RE, J as ASK_PATTERNS, K as PROTECTED_FRAGMENTS, L as PHP_DECL_RE, M as registerGuard, N as runGuards, O as detectCreationIntent, P as installGuard, Q as GuardContext, R as PY_MODEL_RE, S as skillTriggerGate, St as detectModularArchitecture, T as MAX_EXA_RESULTS, Tt as requiredArchSkill, U as CODE_MUTATORS, V as interfaceSeparationGuard, W as CODE_REDIRECT, X as securityGuard, Y as CRITICAL_PATTERNS, Z as Guard, _ as DEV_VERBS, _t as evaluateFileSize, a as firstHeading, at as freshnessGate, b as detectClaudeMdProjectType, bt as ModularArchitecture, c as parseEntry, ct as PolicyResult, d as EXCLUDE_DIRS, dt as GIT_BLOCKED, et as ApexContext, f as PROJECT_INDICATORS, ft as PROJECT_INSTALL, g as loadApexTaskState, gt as countLines, h as buildApexTaskInjection, ht as FileSizeVerdict, i as firstComment, it as evaluateApex, j as clearUserGuards, k as FAIL_CLOSED, l as parseBodyDesc, lt as evaluate, m as buildApexTaskContext, mt as matchPatterns, n as missingSeoElements, nt as brainstormGate, o as TreeEntry, ot as solidReadGate, p as ApexTaskState, pt as SYSTEM_INSTALL, q as protectedPathGuard, r as descFromText, rt as docConsultedGate, s as parseEnrichment, st as PolicyContext, t as isHtmlLike, tt as ApexGate, u as parseField, ut as GIT_ASK, v as buildApexInstruction, vt as detectFramework, w as frameworkSolidGate, wt as isApexCommand, x as detectRequiredSkills, xt as ProjectType, y as buildClaudeMdContext, yt as DEV_KEYWORDS, z as SWIFT_PROTO_RE } from "./index-DmbOUJK8.mjs";
9
9
  import { n as RouteResult, r as ScoredRef, t as RefMeta } from "./types-CY5qT2X1.mjs";
10
10
  import { a as ReminderState, c as readState, d as throttleMs, i as registryFile, l as setStateField, n as addRoot, o as lessonsFileFor, r as readRoots, s as nowStamp, t as ensureMemoryGitignore, u as stateFileFor } from "./index-DLYhervv.mjs";
11
11
  import { a as globToRe, i as scoreReferences, n as toRefMeta, o as parseFrontmatter, r as routeReferences, t as loadRefs } from "./index-DL8MxjuP.mjs";
12
12
  import { a as taskStart, c as ensureStateDir, d as stateFilePath, f as acquireLock, i as taskCreate, l as loadState, n as ApexTaskFile, o as ApexState, r as taskComplete, s as apexStateDir, t as ApexTask, u as saveState } from "./index-CPoF_hLP.mjs";
13
13
  import { _ as TIME_INTERVALS, a as formatCost, c as formatTokens, d as colors, f as progressiveColor, g as PROGRESS_CHARS, h as PROGRESS_BAR_DEFAULTS, i as formatBasename, l as ColorFn, m as GRADIENT_BLOCKS, n as generateGradientBar, o as formatPath, p as COLOR_THRESHOLDS, r as generateProgressBar, s as formatTimeLeft, t as ProgressBarOptions, u as Palette } from "./index-BWK8slRi.mjs";
14
- export { APEX_GATES, ASK_PATTERNS, ASK_WRITERS, ApexContext, ApexGate, ApexState, ApexTask, ApexTaskFile, ApexTaskState, AuthEntry, CODE_MUTATORS, CODE_REDIRECT, COLOR_THRESHOLDS, CRITICAL_PATTERNS, ColorFn, DEFAULT_MAX_LINES, DEFAULT_TTL_SEC, DEV_KEYWORDS, DEV_VERBS, DocSatisfactionStatus, EXCLUDE_DIRS, FAIL_CLOSED, FileSizeVerdict, GIT_ASK, GIT_BLOCKED, GO_DECL_RE, GRADIENT_BLOCKS, GUARDS, Guard, GuardContext, HarnessId, HarnessInfo, HarnessMode, HarnessVia, IndexSummary, JAVA_DECL_RE, MAX_EXA_RESULTS, MAX_LINES_ENV_KEY, MAX_TOKENS, ModularArchitecture, PHP_DECL_RE, PROGRESS_BAR_DEFAULTS, PROGRESS_CHARS, PROJECT_INDICATORS, PROJECT_INSTALL, PROTECTED_FRAGMENTS, PY_MODEL_RE, Palette, PolicyContext, PolicyResult, ProgressBarOptions, ProjectLayout, ProjectType, Prompt, PromptKind, RefMeta, ReminderState, RouteResult, SKILL_TRIGGERS, STATE_GITIGNORE, STATE_ROOT, SWIFT_PROTO_RE, SYSTEM_INSTALL, ScoredRef, TIME_INTERVALS, TS_DECL_RE, TTL_ENV_KEY, TreeEntry, acquireLock, addRoot, apexStateDir, bashWriteGuard, brainstormGate, buildApexInstruction, buildApexTaskContext, buildApexTaskInjection, buildClaudeMdContext, cacheLookup, cachePath, cacheStore, capVerbosity, clearUserGuards, colors, compactJson, compactMarkdown, countLines, descFromText, detectClaudeMdProjectType, detectCreationIntent, detectFramework, detectHarness, detectMode, detectModularArchitecture, detectProjectType, detectRequiredSkills, docConsultedGate, ensureMemoryGitignore, ensureStateDir, evaluate, evaluateApex, evaluateFileSize, extractText, firstComment, firstHeading, formatBasename, formatCost, formatDocDeny, formatDocSatisfactionStatus, formatPath, formatPrompt, formatTimeLeft, formatTokens, frameworkSolidGate, freshnessGate, generateGradientBar, generateProgressBar, globToRe, incrementTrivialEditCounter, installGuard, interfaceSeparationGuard, isApexCommand, isCodeFile, isDocConsulted, jaccardSimilar, lessonsFileFor, loadApexTaskState, loadIndex, loadRefs, loadState, matchPatterns, mcpCacheKey, modeFor, nowStamp, parseBodyDesc, parseEnrichment, parseEntry, parseEnvInt, parseField, parseFrontmatter, progressiveColor, projectLayout, projectRoot, projectRootOrNull, protectedPathGuard, queryHash, readRoots, readState, registerGuard, registryFile, requiredArchSkill, resolveMaxLines, resolveSessions, resolveTtlSec, routeReferences, runGuards, saveState, scoreReferences, securityGuard, setStateField, skillTriggerGate, solidReadGate, splitTarget, stateFileFor, stateFilePath, summarizeIndex, taskComplete, taskCreate, taskStart, throttleMs, toRefMeta, ttlLabel };
14
+ export { APEX_GATES, ASK_PATTERNS, ASK_WRITERS, ApexContext, ApexGate, ApexState, ApexTask, ApexTaskFile, ApexTaskState, AuthEntry, CODE_MUTATORS, CODE_REDIRECT, COLOR_THRESHOLDS, CRITICAL_PATTERNS, ColorFn, DEFAULT_MAX_LINES, DEFAULT_TTL_SEC, DEV_KEYWORDS, DEV_VERBS, DocSatisfactionStatus, EXCLUDE_DIRS, FAIL_CLOSED, FileSizeVerdict, GIT_ASK, GIT_BLOCKED, GO_DECL_RE, GRADIENT_BLOCKS, GUARDS, Guard, GuardContext, HarnessId, HarnessInfo, HarnessMode, HarnessVia, IndexSummary, JAVA_DECL_RE, MAX_EXA_RESULTS, MAX_LINES_ENV_KEY, MAX_TOKENS, ModularArchitecture, PHP_DECL_RE, PROGRESS_BAR_DEFAULTS, PROGRESS_CHARS, PROJECT_INDICATORS, PROJECT_INSTALL, PROTECTED_FRAGMENTS, PY_MODEL_RE, Palette, PolicyContext, PolicyResult, ProgressBarOptions, ProjectLayout, ProjectType, Prompt, PromptKind, RefMeta, ReminderState, RouteResult, SKILL_TRIGGERS, STATE_GITIGNORE, STATE_ROOT, SWIFT_PROTO_RE, SYSTEM_INSTALL, ScoredRef, TIME_INTERVALS, TS_DECL_RE, TTL_ENV_KEY, TreeEntry, acquireLock, addRoot, apexStateDir, bashWriteGuard, brainstormGate, buildApexInstruction, buildApexTaskContext, buildApexTaskInjection, buildClaudeMdContext, cacheLookup, cachePath, cacheStore, capVerbosity, clearUserGuards, colors, compactJson, compactMarkdown, countLines, descFromText, detectClaudeMdProjectType, detectCreationIntent, detectFramework, detectHarness, detectMode, detectModularArchitecture, detectProjectType, detectRequiredSkills, docConsultedGate, ensureMemoryGitignore, ensureStateDir, evaluate, evaluateApex, evaluateFileSize, extractText, firstComment, firstHeading, formatBasename, formatCost, formatDocDeny, formatDocSatisfactionStatus, formatPath, formatPrompt, formatTimeLeft, formatTokens, frameworkSolidGate, freshnessGate, generateGradientBar, generateProgressBar, globToRe, incrementTrivialEditCounter, installGuard, interfaceSeparationGuard, isApexCommand, isCodeFile, isDocConsulted, isHtmlLike, jaccardSimilar, lessonsFileFor, loadApexTaskState, loadIndex, loadRefs, loadState, matchPatterns, mcpCacheKey, missingSeoElements, modeFor, nowStamp, parseBodyDesc, parseEnrichment, parseEntry, parseEnvInt, parseField, parseFrontmatter, progressiveColor, projectLayout, projectRoot, projectRootOrNull, protectedPathGuard, queryHash, readRoots, readState, registerGuard, registryFile, requiredArchSkill, resolveMaxLines, resolveSessions, resolveTtlSec, routeReferences, runGuards, saveState, scoreReferences, securityGuard, setStateField, skillTriggerGate, solidReadGate, splitTarget, stateFileFor, stateFilePath, summarizeIndex, taskComplete, taskCreate, taskStart, throttleMs, toRefMeta, ttlLabel, walkUpFor };
package/dist/index.mjs CHANGED
@@ -2,18 +2,18 @@ import { a as parseEnvInt, i as splitTarget, n as MAX_LINES_ENV_KEY, r as resolv
2
2
  import { i as ttlLabel, n as TTL_ENV_KEY, r as resolveTtlSec, t as DEFAULT_TTL_SEC } from "./ttl-BG55s6HZ.mjs";
3
3
  import { n as STATE_ROOT, r as projectLayout, t as STATE_GITIGNORE } from "./layout-C0jaaCQC.mjs";
4
4
  import { t as compactJson } from "./compact-json-DK2nX-MK.mjs";
5
- import { n as projectRoot, r as projectRootOrNull, t as isCodeFile } from "./project-root-ff0_poWU.mjs";
5
+ import { i as walkUpFor, n as projectRoot, r as projectRootOrNull, t as isCodeFile } from "./project-root-3kk7gCOp.mjs";
6
6
  import { n as detectMode, r as modeFor, t as detectHarness } from "./harness-C8Nxxyn_.mjs";
7
- import { A as solidReadGate, C as capVerbosity, D as docConsultedGate, E as brainstormGate, F as requiredArchSkill, M as detectModularArchitecture, N as detectProjectType, O as evaluateApex, P as isApexCommand, S as MAX_TOKENS, T as APEX_GATES, _ as detectRequiredSkills, a as parseEntry, b as frameworkSolidGate, c as EXCLUDE_DIRS, d as buildApexTaskInjection, f as loadApexTaskState, g as detectClaudeMdProjectType, h as buildClaudeMdContext, i as parseEnrichment, j as DEV_KEYWORDS, k as freshnessGate, l as PROJECT_INDICATORS, m as buildApexInstruction, n as firstComment, o as parseBodyDesc, p as DEV_VERBS, r as firstHeading, s as parseField, t as descFromText, u as buildApexTaskContext, v as skillTriggerGate, w as detectCreationIntent, x as MAX_EXA_RESULTS, y as SKILL_TRIGGERS } from "./describe-BYqhoV4c.mjs";
8
- import { A as evaluateFileSize, C as securityGuard, D as SYSTEM_INSTALL, E as PROJECT_INSTALL, O as matchPatterns, S as CRITICAL_PATTERNS, T as GIT_BLOCKED, _ as CODE_REDIRECT, a as registerGuard, b as protectedPathGuard, c as GO_DECL_RE, d as PY_MODEL_RE, f as SWIFT_PROTO_RE, g as CODE_MUTATORS, h as ASK_WRITERS, i as clearUserGuards, j as detectFramework, k as countLines, l as JAVA_DECL_RE, m as interfaceSeparationGuard, n as FAIL_CLOSED, o as runGuards, p as TS_DECL_RE, r as GUARDS, s as installGuard, t as evaluate, u as PHP_DECL_RE, v as bashWriteGuard, w as GIT_ASK, x as ASK_PATTERNS, y as PROTECTED_FRAGMENTS } from "./evaluate-j3gRJ_ng.mjs";
7
+ import { A as evaluateApex, C as MAX_EXA_RESULTS, D as APEX_GATES, E as detectCreationIntent, F as detectProjectType, I as isApexCommand, L as requiredArchSkill, M as solidReadGate, N as DEV_KEYWORDS, O as brainstormGate, P as detectModularArchitecture, S as frameworkSolidGate, T as capVerbosity, _ as buildClaudeMdContext, a as firstHeading, b as skillTriggerGate, c as parseBodyDesc, d as PROJECT_INDICATORS, f as buildApexTaskContext, g as buildApexInstruction, h as DEV_VERBS, i as firstComment, j as freshnessGate, k as docConsultedGate, l as parseField, m as loadApexTaskState, n as missingSeoElements, o as parseEnrichment, p as buildApexTaskInjection, r as descFromText, s as parseEntry, t as isHtmlLike, u as EXCLUDE_DIRS, v as detectClaudeMdProjectType, w as MAX_TOKENS, x as SKILL_TRIGGERS, y as detectRequiredSkills } from "./validate-CccewDwk.mjs";
8
+ import { A as evaluateFileSize, C as securityGuard, D as SYSTEM_INSTALL, E as PROJECT_INSTALL, O as matchPatterns, S as CRITICAL_PATTERNS, T as GIT_BLOCKED, _ as CODE_REDIRECT, a as registerGuard, b as protectedPathGuard, c as GO_DECL_RE, d as PY_MODEL_RE, f as SWIFT_PROTO_RE, g as CODE_MUTATORS, h as ASK_WRITERS, i as clearUserGuards, j as detectFramework, k as countLines, l as JAVA_DECL_RE, m as interfaceSeparationGuard, n as FAIL_CLOSED, o as runGuards, p as TS_DECL_RE, r as GUARDS, s as installGuard, t as evaluate, u as PHP_DECL_RE, v as bashWriteGuard, w as GIT_ASK, x as ASK_PATTERNS, y as PROTECTED_FRAGMENTS } from "./evaluate-9ch1K2kt.mjs";
9
9
  import { i as resolveSessions, n as formatDocSatisfactionStatus, r as isDocConsulted, t as formatDocDeny } from "./doc-helpers-Dd_x1-tZ.mjs";
10
10
  import { i as parseFrontmatter, n as scoreReferences, r as globToRe, t as routeReferences } from "./router-D8cVrI-s.mjs";
11
11
  import { t as formatPrompt } from "./types-ernB1Dy3.mjs";
12
- import { a as nowStamp, c as stateFileFor, i as lessonsFileFor, l as throttleMs, n as readRoots, o as readState, r as registryFile, s as setStateField, t as addRoot, u as ensureMemoryGitignore } from "./memory-BkoEbdec.mjs";
12
+ import { a as nowStamp, c as stateFileFor, i as lessonsFileFor, l as throttleMs, n as readRoots, o as readState, r as registryFile, s as setStateField, t as addRoot, u as ensureMemoryGitignore } from "./registry-BkoEbdec.mjs";
13
13
  import { n as jaccardSimilar, r as queryHash, t as compactMarkdown } from "./cache-C9z9LclL.mjs";
14
14
  import { a as extractText, i as mcpCacheKey, n as cachePath, o as loadIndex, r as cacheStore, s as summarizeIndex, t as cacheLookup } from "./store-PrNPm6So.mjs";
15
15
  import { t as incrementTrivialEditCounter } from "./freshness-otdUpuvP.mjs";
16
16
  import { n as toRefMeta, t as loadRefs } from "./loader-CyAoJv2W.mjs";
17
17
  import { a as ensureStateDir, c as stateFilePath, i as apexStateDir, l as acquireLock, n as taskCreate, o as loadState, r as taskStart, s as saveState, t as taskComplete } from "./state-ByhLeKyD.mjs";
18
18
  import { a as formatPath, c as colors, d as GRADIENT_BLOCKS, f as PROGRESS_BAR_DEFAULTS, i as formatCost, l as progressiveColor, m as TIME_INTERVALS, n as generateProgressBar, o as formatTimeLeft, p as PROGRESS_CHARS, r as formatBasename, s as formatTokens, t as generateGradientBar, u as COLOR_THRESHOLDS } from "./statusline-D87eUNXl.mjs";
19
- export { APEX_GATES, ASK_PATTERNS, ASK_WRITERS, CODE_MUTATORS, CODE_REDIRECT, COLOR_THRESHOLDS, CRITICAL_PATTERNS, DEFAULT_MAX_LINES, DEFAULT_TTL_SEC, DEV_KEYWORDS, DEV_VERBS, EXCLUDE_DIRS, FAIL_CLOSED, GIT_ASK, GIT_BLOCKED, GO_DECL_RE, GRADIENT_BLOCKS, GUARDS, JAVA_DECL_RE, MAX_EXA_RESULTS, MAX_LINES_ENV_KEY, MAX_TOKENS, PHP_DECL_RE, PROGRESS_BAR_DEFAULTS, PROGRESS_CHARS, PROJECT_INDICATORS, PROJECT_INSTALL, PROTECTED_FRAGMENTS, PY_MODEL_RE, SKILL_TRIGGERS, STATE_GITIGNORE, STATE_ROOT, SWIFT_PROTO_RE, SYSTEM_INSTALL, TIME_INTERVALS, TS_DECL_RE, TTL_ENV_KEY, acquireLock, addRoot, apexStateDir, bashWriteGuard, brainstormGate, buildApexInstruction, buildApexTaskContext, buildApexTaskInjection, buildClaudeMdContext, cacheLookup, cachePath, cacheStore, capVerbosity, clearUserGuards, colors, compactJson, compactMarkdown, countLines, descFromText, detectClaudeMdProjectType, detectCreationIntent, detectFramework, detectHarness, detectMode, detectModularArchitecture, detectProjectType, detectRequiredSkills, docConsultedGate, ensureMemoryGitignore, ensureStateDir, evaluate, evaluateApex, evaluateFileSize, extractText, firstComment, firstHeading, formatBasename, formatCost, formatDocDeny, formatDocSatisfactionStatus, formatPath, formatPrompt, formatTimeLeft, formatTokens, frameworkSolidGate, freshnessGate, generateGradientBar, generateProgressBar, globToRe, incrementTrivialEditCounter, installGuard, interfaceSeparationGuard, isApexCommand, isCodeFile, isDocConsulted, jaccardSimilar, lessonsFileFor, loadApexTaskState, loadIndex, loadRefs, loadState, matchPatterns, mcpCacheKey, modeFor, nowStamp, parseBodyDesc, parseEnrichment, parseEntry, parseEnvInt, parseField, parseFrontmatter, progressiveColor, projectLayout, projectRoot, projectRootOrNull, protectedPathGuard, queryHash, readRoots, readState, registerGuard, registryFile, requiredArchSkill, resolveMaxLines, resolveSessions, resolveTtlSec, routeReferences, runGuards, saveState, scoreReferences, securityGuard, setStateField, skillTriggerGate, solidReadGate, splitTarget, stateFileFor, stateFilePath, summarizeIndex, taskComplete, taskCreate, taskStart, throttleMs, toRefMeta, ttlLabel };
19
+ export { APEX_GATES, ASK_PATTERNS, ASK_WRITERS, CODE_MUTATORS, CODE_REDIRECT, COLOR_THRESHOLDS, CRITICAL_PATTERNS, DEFAULT_MAX_LINES, DEFAULT_TTL_SEC, DEV_KEYWORDS, DEV_VERBS, EXCLUDE_DIRS, FAIL_CLOSED, GIT_ASK, GIT_BLOCKED, GO_DECL_RE, GRADIENT_BLOCKS, GUARDS, JAVA_DECL_RE, MAX_EXA_RESULTS, MAX_LINES_ENV_KEY, MAX_TOKENS, PHP_DECL_RE, PROGRESS_BAR_DEFAULTS, PROGRESS_CHARS, PROJECT_INDICATORS, PROJECT_INSTALL, PROTECTED_FRAGMENTS, PY_MODEL_RE, SKILL_TRIGGERS, STATE_GITIGNORE, STATE_ROOT, SWIFT_PROTO_RE, SYSTEM_INSTALL, TIME_INTERVALS, TS_DECL_RE, TTL_ENV_KEY, acquireLock, addRoot, apexStateDir, bashWriteGuard, brainstormGate, buildApexInstruction, buildApexTaskContext, buildApexTaskInjection, buildClaudeMdContext, cacheLookup, cachePath, cacheStore, capVerbosity, clearUserGuards, colors, compactJson, compactMarkdown, countLines, descFromText, detectClaudeMdProjectType, detectCreationIntent, detectFramework, detectHarness, detectMode, detectModularArchitecture, detectProjectType, detectRequiredSkills, docConsultedGate, ensureMemoryGitignore, ensureStateDir, evaluate, evaluateApex, evaluateFileSize, extractText, firstComment, firstHeading, formatBasename, formatCost, formatDocDeny, formatDocSatisfactionStatus, formatPath, formatPrompt, formatTimeLeft, formatTokens, frameworkSolidGate, freshnessGate, generateGradientBar, generateProgressBar, globToRe, incrementTrivialEditCounter, installGuard, interfaceSeparationGuard, isApexCommand, isCodeFile, isDocConsulted, isHtmlLike, jaccardSimilar, lessonsFileFor, loadApexTaskState, loadIndex, loadRefs, loadState, matchPatterns, mcpCacheKey, missingSeoElements, modeFor, nowStamp, parseBodyDesc, parseEnrichment, parseEntry, parseEnvInt, parseField, parseFrontmatter, progressiveColor, projectLayout, projectRoot, projectRootOrNull, protectedPathGuard, queryHash, readRoots, readState, registerGuard, registryFile, requiredArchSkill, resolveMaxLines, resolveSessions, resolveTtlSec, routeReferences, runGuards, saveState, scoreReferences, securityGuard, setStateField, skillTriggerGate, solidReadGate, splitTarget, stateFileFor, stateFilePath, summarizeIndex, taskComplete, taskCreate, taskStart, throttleMs, toRefMeta, ttlLabel, walkUpFor };
@@ -1,2 +1,3 @@
1
- import { a as nowStamp, c as stateFileFor, i as lessonsFileFor, l as throttleMs, n as readRoots, o as readState, r as registryFile, s as setStateField, t as addRoot, u as ensureMemoryGitignore } from "../memory-BkoEbdec.mjs";
1
+ import { a as nowStamp, c as stateFileFor, i as lessonsFileFor, l as throttleMs, n as readRoots, o as readState, r as registryFile, s as setStateField, t as addRoot, u as ensureMemoryGitignore } from "../registry-BkoEbdec.mjs";
2
+ import "../memory-la_KkjCS.mjs";
2
3
  export { addRoot, ensureMemoryGitignore, lessonsFileFor, nowStamp, readRoots, readState, registryFile, setStateField, stateFileFor, throttleMs };
@@ -0,0 +1 @@
1
+ export {};
@@ -1,2 +1,2 @@
1
- import { $ as ApexGate, A as registerGuard, B as ASK_WRITERS, C as MAX_EXA_RESULTS, Ct as requiredArchSkill, D as FAIL_CLOSED, E as detectCreationIntent, F as PHP_DECL_RE, G as protectedPathGuard, H as CODE_REDIRECT, I as PY_MODEL_RE, J as securityGuard, K as ASK_PATTERNS, L as SWIFT_PROTO_RE, M as installGuard, N as GO_DECL_RE, O as GUARDS, P as JAVA_DECL_RE, Q as ApexContext, R as TS_DECL_RE, S as frameworkSolidGate, St as isApexCommand, T as capVerbosity, U as bashWriteGuard, V as CODE_MUTATORS, W as PROTECTED_FRAGMENTS, X as GuardContext, Y as Guard, Z as APEX_GATES, _ as buildClaudeMdContext, _t as DEV_KEYWORDS, a as parseEnrichment, at as PolicyContext, b as skillTriggerGate, bt as detectModularArchitecture, c as parseField, ct as GIT_ASK, d as ApexTaskState, dt as SYSTEM_INSTALL, et as brainstormGate, f as buildApexTaskContext, ft as matchPatterns, g as buildApexInstruction, gt as detectFramework, h as DEV_VERBS, ht as evaluateFileSize, i as TreeEntry, it as solidReadGate, j as runGuards, k as clearUserGuards, l as EXCLUDE_DIRS, lt as GIT_BLOCKED, m as loadApexTaskState, mt as countLines, n as firstComment, nt as evaluateApex, o as parseEntry, ot as PolicyResult, p as buildApexTaskInjection, pt as FileSizeVerdict, q as CRITICAL_PATTERNS, r as firstHeading, rt as freshnessGate, s as parseBodyDesc, st as evaluate, t as descFromText, tt as docConsultedGate, u as PROJECT_INDICATORS, ut as PROJECT_INSTALL, v as detectClaudeMdProjectType, vt as ModularArchitecture, w as MAX_TOKENS, x as SKILL_TRIGGERS, xt as detectProjectType, y as detectRequiredSkills, yt as ProjectType, z as interfaceSeparationGuard } from "../index-mISsk0ff.mjs";
2
- export { APEX_GATES, ASK_PATTERNS, ASK_WRITERS, ApexContext, ApexGate, ApexTaskState, CODE_MUTATORS, CODE_REDIRECT, CRITICAL_PATTERNS, DEV_KEYWORDS, DEV_VERBS, EXCLUDE_DIRS, FAIL_CLOSED, FileSizeVerdict, GIT_ASK, GIT_BLOCKED, GO_DECL_RE, GUARDS, Guard, GuardContext, JAVA_DECL_RE, MAX_EXA_RESULTS, MAX_TOKENS, ModularArchitecture, PHP_DECL_RE, PROJECT_INDICATORS, PROJECT_INSTALL, PROTECTED_FRAGMENTS, PY_MODEL_RE, PolicyContext, PolicyResult, ProjectType, SKILL_TRIGGERS, SWIFT_PROTO_RE, SYSTEM_INSTALL, TS_DECL_RE, TreeEntry, bashWriteGuard, brainstormGate, buildApexInstruction, buildApexTaskContext, buildApexTaskInjection, buildClaudeMdContext, capVerbosity, clearUserGuards, countLines, descFromText, detectClaudeMdProjectType, detectCreationIntent, detectFramework, detectModularArchitecture, detectProjectType, detectRequiredSkills, docConsultedGate, evaluate, evaluateApex, evaluateFileSize, firstComment, firstHeading, frameworkSolidGate, freshnessGate, installGuard, interfaceSeparationGuard, isApexCommand, loadApexTaskState, matchPatterns, parseBodyDesc, parseEnrichment, parseEntry, parseField, protectedPathGuard, registerGuard, requiredArchSkill, runGuards, securityGuard, skillTriggerGate, solidReadGate };
1
+ import { $ as APEX_GATES, A as GUARDS, B as TS_DECL_RE, C as SKILL_TRIGGERS, Ct as detectProjectType, D as capVerbosity, E as MAX_TOKENS, F as GO_DECL_RE, G as bashWriteGuard, H as ASK_WRITERS, I as JAVA_DECL_RE, J as ASK_PATTERNS, K as PROTECTED_FRAGMENTS, L as PHP_DECL_RE, M as registerGuard, N as runGuards, O as detectCreationIntent, P as installGuard, Q as GuardContext, R as PY_MODEL_RE, S as skillTriggerGate, St as detectModularArchitecture, T as MAX_EXA_RESULTS, Tt as requiredArchSkill, U as CODE_MUTATORS, V as interfaceSeparationGuard, W as CODE_REDIRECT, X as securityGuard, Y as CRITICAL_PATTERNS, Z as Guard, _ as DEV_VERBS, _t as evaluateFileSize, a as firstHeading, at as freshnessGate, b as detectClaudeMdProjectType, bt as ModularArchitecture, c as parseEntry, ct as PolicyResult, d as EXCLUDE_DIRS, dt as GIT_BLOCKED, et as ApexContext, f as PROJECT_INDICATORS, ft as PROJECT_INSTALL, g as loadApexTaskState, gt as countLines, h as buildApexTaskInjection, ht as FileSizeVerdict, i as firstComment, it as evaluateApex, j as clearUserGuards, k as FAIL_CLOSED, l as parseBodyDesc, lt as evaluate, m as buildApexTaskContext, mt as matchPatterns, n as missingSeoElements, nt as brainstormGate, o as TreeEntry, ot as solidReadGate, p as ApexTaskState, pt as SYSTEM_INSTALL, q as protectedPathGuard, r as descFromText, rt as docConsultedGate, s as parseEnrichment, st as PolicyContext, t as isHtmlLike, tt as ApexGate, u as parseField, ut as GIT_ASK, v as buildApexInstruction, vt as detectFramework, w as frameworkSolidGate, wt as isApexCommand, x as detectRequiredSkills, xt as ProjectType, y as buildClaudeMdContext, yt as DEV_KEYWORDS, z as SWIFT_PROTO_RE } from "../index-DmbOUJK8.mjs";
2
+ export { APEX_GATES, ASK_PATTERNS, ASK_WRITERS, ApexContext, ApexGate, ApexTaskState, CODE_MUTATORS, CODE_REDIRECT, CRITICAL_PATTERNS, DEV_KEYWORDS, DEV_VERBS, EXCLUDE_DIRS, FAIL_CLOSED, FileSizeVerdict, GIT_ASK, GIT_BLOCKED, GO_DECL_RE, GUARDS, Guard, GuardContext, JAVA_DECL_RE, MAX_EXA_RESULTS, MAX_TOKENS, ModularArchitecture, PHP_DECL_RE, PROJECT_INDICATORS, PROJECT_INSTALL, PROTECTED_FRAGMENTS, PY_MODEL_RE, PolicyContext, PolicyResult, ProjectType, SKILL_TRIGGERS, SWIFT_PROTO_RE, SYSTEM_INSTALL, TS_DECL_RE, TreeEntry, bashWriteGuard, brainstormGate, buildApexInstruction, buildApexTaskContext, buildApexTaskInjection, buildClaudeMdContext, capVerbosity, clearUserGuards, countLines, descFromText, detectClaudeMdProjectType, detectCreationIntent, detectFramework, detectModularArchitecture, detectProjectType, detectRequiredSkills, docConsultedGate, evaluate, evaluateApex, evaluateFileSize, firstComment, firstHeading, frameworkSolidGate, freshnessGate, installGuard, interfaceSeparationGuard, isApexCommand, isHtmlLike, loadApexTaskState, matchPatterns, missingSeoElements, parseBodyDesc, parseEnrichment, parseEntry, parseField, protectedPathGuard, registerGuard, requiredArchSkill, runGuards, securityGuard, skillTriggerGate, solidReadGate };
@@ -1,4 +1,4 @@
1
- import { A as solidReadGate, C as capVerbosity, D as docConsultedGate, E as brainstormGate, F as requiredArchSkill, M as detectModularArchitecture, N as detectProjectType, O as evaluateApex, P as isApexCommand, S as MAX_TOKENS, T as APEX_GATES, _ as detectRequiredSkills, a as parseEntry, b as frameworkSolidGate, c as EXCLUDE_DIRS, d as buildApexTaskInjection, f as loadApexTaskState, g as detectClaudeMdProjectType, h as buildClaudeMdContext, i as parseEnrichment, j as DEV_KEYWORDS, k as freshnessGate, l as PROJECT_INDICATORS, m as buildApexInstruction, n as firstComment, o as parseBodyDesc, p as DEV_VERBS, r as firstHeading, s as parseField, t as descFromText, u as buildApexTaskContext, v as skillTriggerGate, w as detectCreationIntent, x as MAX_EXA_RESULTS, y as SKILL_TRIGGERS } from "../describe-BYqhoV4c.mjs";
2
- import { A as evaluateFileSize, C as securityGuard, D as SYSTEM_INSTALL, E as PROJECT_INSTALL, O as matchPatterns, S as CRITICAL_PATTERNS, T as GIT_BLOCKED, _ as CODE_REDIRECT, a as registerGuard, b as protectedPathGuard, c as GO_DECL_RE, d as PY_MODEL_RE, f as SWIFT_PROTO_RE, g as CODE_MUTATORS, h as ASK_WRITERS, i as clearUserGuards, j as detectFramework, k as countLines, l as JAVA_DECL_RE, m as interfaceSeparationGuard, n as FAIL_CLOSED, o as runGuards, p as TS_DECL_RE, r as GUARDS, s as installGuard, t as evaluate, u as PHP_DECL_RE, v as bashWriteGuard, w as GIT_ASK, x as ASK_PATTERNS, y as PROTECTED_FRAGMENTS } from "../evaluate-j3gRJ_ng.mjs";
1
+ import { A as evaluateApex, C as MAX_EXA_RESULTS, D as APEX_GATES, E as detectCreationIntent, F as detectProjectType, I as isApexCommand, L as requiredArchSkill, M as solidReadGate, N as DEV_KEYWORDS, O as brainstormGate, P as detectModularArchitecture, S as frameworkSolidGate, T as capVerbosity, _ as buildClaudeMdContext, a as firstHeading, b as skillTriggerGate, c as parseBodyDesc, d as PROJECT_INDICATORS, f as buildApexTaskContext, g as buildApexInstruction, h as DEV_VERBS, i as firstComment, j as freshnessGate, k as docConsultedGate, l as parseField, m as loadApexTaskState, n as missingSeoElements, o as parseEnrichment, p as buildApexTaskInjection, r as descFromText, s as parseEntry, t as isHtmlLike, u as EXCLUDE_DIRS, v as detectClaudeMdProjectType, w as MAX_TOKENS, x as SKILL_TRIGGERS, y as detectRequiredSkills } from "../validate-CccewDwk.mjs";
2
+ import { A as evaluateFileSize, C as securityGuard, D as SYSTEM_INSTALL, E as PROJECT_INSTALL, O as matchPatterns, S as CRITICAL_PATTERNS, T as GIT_BLOCKED, _ as CODE_REDIRECT, a as registerGuard, b as protectedPathGuard, c as GO_DECL_RE, d as PY_MODEL_RE, f as SWIFT_PROTO_RE, g as CODE_MUTATORS, h as ASK_WRITERS, i as clearUserGuards, j as detectFramework, k as countLines, l as JAVA_DECL_RE, m as interfaceSeparationGuard, n as FAIL_CLOSED, o as runGuards, p as TS_DECL_RE, r as GUARDS, s as installGuard, t as evaluate, u as PHP_DECL_RE, v as bashWriteGuard, w as GIT_ASK, x as ASK_PATTERNS, y as PROTECTED_FRAGMENTS } from "../evaluate-9ch1K2kt.mjs";
3
3
  import "../policy-la_KkjCS.mjs";
4
- export { APEX_GATES, ASK_PATTERNS, ASK_WRITERS, CODE_MUTATORS, CODE_REDIRECT, CRITICAL_PATTERNS, DEV_KEYWORDS, DEV_VERBS, EXCLUDE_DIRS, FAIL_CLOSED, GIT_ASK, GIT_BLOCKED, GO_DECL_RE, GUARDS, JAVA_DECL_RE, MAX_EXA_RESULTS, MAX_TOKENS, PHP_DECL_RE, PROJECT_INDICATORS, PROJECT_INSTALL, PROTECTED_FRAGMENTS, PY_MODEL_RE, SKILL_TRIGGERS, SWIFT_PROTO_RE, SYSTEM_INSTALL, TS_DECL_RE, bashWriteGuard, brainstormGate, buildApexInstruction, buildApexTaskContext, buildApexTaskInjection, buildClaudeMdContext, capVerbosity, clearUserGuards, countLines, descFromText, detectClaudeMdProjectType, detectCreationIntent, detectFramework, detectModularArchitecture, detectProjectType, detectRequiredSkills, docConsultedGate, evaluate, evaluateApex, evaluateFileSize, firstComment, firstHeading, frameworkSolidGate, freshnessGate, installGuard, interfaceSeparationGuard, isApexCommand, loadApexTaskState, matchPatterns, parseBodyDesc, parseEnrichment, parseEntry, parseField, protectedPathGuard, registerGuard, requiredArchSkill, runGuards, securityGuard, skillTriggerGate, solidReadGate };
4
+ export { APEX_GATES, ASK_PATTERNS, ASK_WRITERS, CODE_MUTATORS, CODE_REDIRECT, CRITICAL_PATTERNS, DEV_KEYWORDS, DEV_VERBS, EXCLUDE_DIRS, FAIL_CLOSED, GIT_ASK, GIT_BLOCKED, GO_DECL_RE, GUARDS, JAVA_DECL_RE, MAX_EXA_RESULTS, MAX_TOKENS, PHP_DECL_RE, PROJECT_INDICATORS, PROJECT_INSTALL, PROTECTED_FRAGMENTS, PY_MODEL_RE, SKILL_TRIGGERS, SWIFT_PROTO_RE, SYSTEM_INSTALL, TS_DECL_RE, bashWriteGuard, brainstormGate, buildApexInstruction, buildApexTaskContext, buildApexTaskInjection, buildClaudeMdContext, capVerbosity, clearUserGuards, countLines, descFromText, detectClaudeMdProjectType, detectCreationIntent, detectFramework, detectModularArchitecture, detectProjectType, detectRequiredSkills, docConsultedGate, evaluate, evaluateApex, evaluateFileSize, firstComment, firstHeading, frameworkSolidGate, freshnessGate, installGuard, interfaceSeparationGuard, isApexCommand, isHtmlLike, loadApexTaskState, matchPatterns, missingSeoElements, parseBodyDesc, parseEnrichment, parseEntry, parseField, protectedPathGuard, registerGuard, requiredArchSkill, runGuards, securityGuard, skillTriggerGate, solidReadGate };
@@ -9,6 +9,12 @@ const SKIP_DIRS = /(node_modules|vendor|dist|build|\.next|DerivedData|\.git)/;
9
9
  function isCodeFile(p) {
10
10
  return CODE_EXT.test(p) && !SKIP_DIRS.test(p);
11
11
  }
12
+ /**
13
+ * Walk up from `dir` to the nearest ancestor directory containing `marker`.
14
+ * @param dir - Starting directory.
15
+ * @param marker - Sibling file/dir name to look for at each level.
16
+ * @returns The ancestor holding `marker`, or `null` at filesystem root.
17
+ */
12
18
  function walkUpFor(dir, marker) {
13
19
  let current = resolve(dir);
14
20
  while (current !== "/") {
@@ -29,4 +35,4 @@ function projectRoot(dir) {
29
35
  return projectRootOrNull(dir) ?? process.cwd();
30
36
  }
31
37
  //#endregion
32
- export { projectRoot as n, projectRootOrNull as r, isCodeFile as t };
38
+ export { walkUpFor as i, projectRoot as n, projectRootOrNull as r, isCodeFile as t };
@@ -1,5 +1,5 @@
1
- import { t as isCodeFile } from "./project-root-ff0_poWU.mjs";
2
- import { t as evaluate } from "./evaluate-j3gRJ_ng.mjs";
1
+ import { t as isCodeFile } from "./project-root-3kk7gCOp.mjs";
2
+ import { t as evaluate } from "./evaluate-9ch1K2kt.mjs";
3
3
  import { t as formatPrompt } from "./types-ernB1Dy3.mjs";
4
4
  import { execSync } from "node:child_process";
5
5
  //#region src/cli/run.ts
@@ -366,7 +366,7 @@ declare function aipilotPostToolUse(payload: Record<string, unknown>, cwd: strin
366
366
  //#endregion
367
367
  //#region src/runtime/lifecycle/dispatch.d.ts
368
368
  /** Which plugin's hooks.json invoked the harness (selects SessionStart behavior). */
369
- type PluginScope = "core" | "solid" | "rules" | "carto" | "security" | "changelog" | "aipilot";
369
+ type PluginScope = "core" | "solid" | "rules" | "carto" | "security" | "changelog" | "aipilot" | "lessons" | "seo";
370
370
  /** Inputs the lifecycle dispatcher needs (clock + roots injected). */
371
371
  interface LifecycleInput {
372
372
  event: string;
@@ -388,13 +388,16 @@ declare function dispatchLifecycle(input: LifecycleInput): string | null;
388
388
  /**
389
389
  * Dispatch the appropriate PostToolUse tracker for the invoking scope. Carto
390
390
  * persists manual enrichments; security records skill reads + MCP research;
391
- * changelog records watch research. Side-effect only.
391
+ * changelog records watch research; lessons arms the per-project throttle.
392
+ * Side-effect only.
392
393
  * @param scope - The invoking plugin scope.
393
394
  * @param event - The normalized event.
394
395
  * @param input - The raw tool input.
395
396
  * @param now - Clock.
397
+ * @param payload - The raw hook payload (for the lessons mark).
398
+ * @param cwd - The project root (for the lessons mark).
396
399
  */
397
- declare function postTrackingSideEffects(scope: PluginScope, event: NormalizedEvent, input: Record<string, unknown>, now: number): void;
400
+ declare function postTrackingSideEffects(scope: PluginScope, event: NormalizedEvent, input: Record<string, unknown>, now: number, payload?: Record<string, unknown>, cwd?: string): void;
398
401
  //#endregion
399
402
  //#region src/runtime/lifecycle/changelog-research.d.ts
400
403
  /**
@@ -409,12 +412,13 @@ declare function trackWatchResearch(tool: string, input: Record<string, unknown>
409
412
  //#endregion
410
413
  //#region src/runtime/lifecycle/cartographer/session-start.d.ts
411
414
  /**
412
- * Regenerate the project map for `cwd` on SessionStart. Returns "" (side-effect
413
- * only no additionalContext).
415
+ * Regenerate the project map + plugin ecosystem map for `cwd` on SessionStart.
416
+ * Emits the ecosystem navigation context as additionalContext (or "").
414
417
  * @param cwd - The working directory.
415
- * @returns "" always.
418
+ * @param now - Clock for the ecosystem map banner timestamp.
419
+ * @returns The SessionStart additionalContext response, or "".
416
420
  */
417
- declare function cartoSessionStart(cwd: string): string;
421
+ declare function cartoSessionStart(cwd: string, now?: number): string;
418
422
  //#endregion
419
423
  //#region src/runtime/lifecycle/cartographer/project-map.d.ts
420
424
  /**
@@ -539,6 +543,71 @@ declare function loadSecurityState(now?: number, home?: string): Record<string,
539
543
  /** Persist today's security state (indent 2, no trailing newline). */
540
544
  declare function saveSecurityState(state: Record<string, unknown>, now?: number, home?: string): void;
541
545
  //#endregion
546
+ //#region src/runtime/lifecycle/lessons/dispatch.d.ts
547
+ /**
548
+ * Route a fuse-lessons event to its handler. Returns the native stdout for
549
+ * context-injecting events (SessionStart/SubagentStart/Stop) or "" for the
550
+ * side-effect-only PostToolUse mark.
551
+ * @param event - The raw hook event name.
552
+ * @param payload - The raw hook payload.
553
+ * @param cwd - Project root for memory injection.
554
+ * @param now - Clock.
555
+ * @returns The native stdout (possibly empty).
556
+ */
557
+ declare function dispatchLessons(event: string, payload: Record<string, unknown>, cwd: string, now: number): string;
558
+ //#endregion
559
+ //#region src/runtime/lifecycle/lessons/state.d.ts
560
+ /** Absolute `<root>/MEMORY/LESSON.md` — the curated, committable lessons file. */
561
+ declare function lessonsFileFor(root: string): string;
562
+ /** Absolute `<root>/MEMORY/state.json` — machine-local throttle counter. */
563
+ declare function lessonsStateFileFor(root: string): string;
564
+ //#endregion
565
+ //#region src/runtime/lifecycle/seo/post-tool-use.d.ts
566
+ /**
567
+ * Validate the edited file's SEO completeness. Returns a deny message (for a
568
+ * `permissionDecision: deny` response) when HTML-like, opted-in, and missing
569
+ * elements; otherwise `null` (allow).
570
+ * @param payload - The raw PostToolUse payload.
571
+ * @returns The deny reason string, or `null` to allow.
572
+ */
573
+ declare function seoPostToolUse(payload: Record<string, unknown>): string | null;
574
+ /**
575
+ * SEO PostToolUse as a ready native response: a `permissionDecision: deny`
576
+ * string when the edited file is missing SEO elements, else `null` (allow).
577
+ * @param payload - The raw PostToolUse payload.
578
+ * @returns The deny response string, or `null` to allow.
579
+ */
580
+ declare function seoPostToolUseResponse(payload: Record<string, unknown>): string | null;
581
+ //#endregion
582
+ //#region src/runtime/lifecycle/cartographer/ecosystem-map.d.ts
583
+ /**
584
+ * Generate the plugin ecosystem map under `<pluginsDir>/.cartographer`.
585
+ * @param now - Clock for the banner timestamp.
586
+ * @param pluginsDirOverride - Override for the marketplace plugins directory.
587
+ * @returns The map navigation context, or "".
588
+ */
589
+ declare function generateEcosystemMap(now: number, pluginsDirOverride?: string): string;
590
+ //#endregion
591
+ //#region src/policy/cartographer/build-tree.d.ts
592
+ /**
593
+ * Indented Unicode tree from scanned plugin items — pure text in, markdown out
594
+ * (no fs). Ports `build_tree.py`.
595
+ */
596
+ /** A scanned `[type, name, desc]` plugin item (agent/skill/command/hooks). */
597
+ type ScanRow = readonly [type: string, name: string, desc: string];
598
+ //#endregion
599
+ //#region src/runtime/lifecycle/cartographer/write-plugin-map.d.ts
600
+ /**
601
+ * Write `<outputDir>/<pluginName>/index.md` (indented linked tree) and recurse
602
+ * agents/skills/commands into their own index trees rooted there.
603
+ * @param outputDir - The map root directory.
604
+ * @param pluginName - Display name of the plugin (the index subfolder).
605
+ * @param version - Plugin version ("" to omit).
606
+ * @param items - The scanned `[type, name, desc]` rows.
607
+ * @param pluginPath - Absolute source plugin directory (for recursion).
608
+ */
609
+ declare function writePluginMap(outputDir: string, pluginName: string, version: string, items: ReadonlyArray<ScanRow>, pluginPath: string): void;
610
+ //#endregion
542
611
  //#region src/runtime/lifecycle-bridge.d.ts
543
612
  /**
544
613
  * Run the ported lifecycle/session/context hooks (SessionStart, SubagentStart/
@@ -609,4 +678,4 @@ interface PreContext {
609
678
  */
610
679
  declare function handlePre(ctx: PreContext): Promise<HandleOutcome>;
611
680
  //#endregion
612
- export { Activity, DEFAULT_WINDOW_MS, DuplicationVerdict, type GateInput, HandleOptions, HandleOutcome, LifecycleInput, MCP_TTL_MS, McpIntercept, NormalizedEvent, PluginScope, PreContext, REQUIRED_AGENTS, SolidProfile, TRIVIAL_BUDGET, ToolEvent, activityFor, aipilotPostToolUse, cartoSessionStart, claudeHome, cleanupSession, countFiles, detectDuplication, detectSolidProfile, devContext, dispatchAipilot, dispatchLifecycle, dryGate, extractSymbols, fusengineCache, gate, generateProjectMap, getFileDesc, gitContext, handleHook, handlePre, harnessStateDir, injectRules, isMcpTool, isProject, isoUtc, lifecycleStdout, listChildren, loadEnriched, loadSecurityState, loadSessionState, logToolFailure, mcpPostStore, mcpPreIntercept, mergeLines, normalizeEvent, postEditContext, postEditTypescript, postTrackingSideEffects, preCommitGate, projectContext, promptSubmitContext, pruneEmptyDirs, purgeTtlTree, queryOf, readRules, recordActivity, removeOldFiles, respond, runSessionStartCleanups, sanitizeSessionId, saveApexState, saveSecurityState, saveSessionState, securityAdvisory, securityStateDir, securityStatePath, sessionStartCore, sessionStatePath, sessionsDir, solidDetectStart, subagentCacheContext, taskContext, todayUtc, trackAgentMemory, trackEnrichment, trackFile, trackMcpResearch, trackSessionChanges, trackSkillRead, trackWatchResearch, trimLogFile, validateRulesLoaded, validateTeammateOutput, writeTree };
681
+ export { Activity, DEFAULT_WINDOW_MS, DuplicationVerdict, type GateInput, HandleOptions, HandleOutcome, LifecycleInput, MCP_TTL_MS, McpIntercept, NormalizedEvent, PluginScope, PreContext, REQUIRED_AGENTS, SolidProfile, TRIVIAL_BUDGET, ToolEvent, activityFor, aipilotPostToolUse, cartoSessionStart, claudeHome, cleanupSession, countFiles, detectDuplication, detectSolidProfile, devContext, dispatchAipilot, dispatchLessons, dispatchLifecycle, dryGate, extractSymbols, fusengineCache, gate, generateEcosystemMap, generateProjectMap, getFileDesc, gitContext, handleHook, handlePre, harnessStateDir, injectRules, isMcpTool, isProject, isoUtc, lessonsFileFor, lessonsStateFileFor, lifecycleStdout, listChildren, loadEnriched, loadSecurityState, loadSessionState, logToolFailure, mcpPostStore, mcpPreIntercept, mergeLines, normalizeEvent, postEditContext, postEditTypescript, postTrackingSideEffects, preCommitGate, projectContext, promptSubmitContext, pruneEmptyDirs, purgeTtlTree, queryOf, readRules, recordActivity, removeOldFiles, respond, runSessionStartCleanups, sanitizeSessionId, saveApexState, saveSecurityState, saveSessionState, securityAdvisory, securityStateDir, securityStatePath, seoPostToolUse, seoPostToolUseResponse, sessionStartCore, sessionStatePath, sessionsDir, solidDetectStart, subagentCacheContext, taskContext, todayUtc, trackAgentMemory, trackEnrichment, trackFile, trackMcpResearch, trackSessionChanges, trackSkillRead, trackWatchResearch, trimLogFile, validateRulesLoaded, validateTeammateOutput, writePluginMap, writeTree };
@@ -1,5 +1,5 @@
1
1
  import { r as projectLayout } from "../layout-C0jaaCQC.mjs";
2
- import { $ as purgeTtlTree, A as isProject, B as cleanupSession, C as todayUtc, Ct as activityFor, D as dispatchAipilot, E as aipilotPostToolUse, F as getFileDesc, G as subagentCacheContext, H as logToolFailure, I as listChildren, J as injectRules, K as detectSolidProfile, L as postEditTypescript, M as loadEnriched, N as mergeLines, O as cartoSessionStart, P as countFiles, Q as pruneEmptyDirs, R as trackSessionChanges, S as securityStatePath, St as queryOf, T as dispatchLifecycle, U as validateTeammateOutput, V as saveApexState, W as trackAgentMemory, X as runSessionStartCleanups, Y as readRules, Z as sessionStartCore, _ as trackSkillRead, _t as normalizeEvent, a as TRIVIAL_BUDGET, at as claudeHome, b as saveSecurityState, bt as mcpPostStore, c as detectDuplication, ct as sanitizeSessionId, d as lifecycleStdout, dt as sessionsDir, et as removeOldFiles, f as postEditContext, ft as promptSubmitContext, g as trackMcpResearch, gt as trackFile, h as trackWatchResearch, ht as recordActivity, i as REQUIRED_AGENTS, it as projectContext, j as writeTree, k as generateProjectMap, l as dryGate, lt as saveSessionState, m as postTrackingSideEffects, mt as respond, n as handlePre, nt as devContext, o as gate, ot as fusengineCache, p as securityAdvisory, pt as taskContext, q as solidDetectStart, r as DEFAULT_WINDOW_MS, rt as gitContext, s as preCommitGate, st as loadSessionState, t as handleHook, tt as trimLogFile, u as extractSymbols, ut as sessionStatePath, v as isoUtc, vt as MCP_TTL_MS, w as trackEnrichment, x as securityStateDir, xt as mcpPreIntercept, y as loadSecurityState, yt as isMcpTool, z as validateRulesLoaded } from "../handle-DW9cWdVt.mjs";
2
+ import { $ as detectSolidProfile, A as dispatchLessons, At as activityFor, B as mergeLines, C as securityStateDir, Ct as trackFile, D as dispatchLifecycle, Dt as mcpPostStore, E as trackEnrichment, Et as isMcpTool, F as writePluginMap, G as trackSessionChanges, H as getFileDesc, I as generateProjectMap, J as saveApexState, K as validateRulesLoaded, L as isProject, M as lessonsStateFileFor, N as cartoSessionStart, O as aipilotPostToolUse, Ot as mcpPreIntercept, P as generateEcosystemMap, Q as subagentCacheContext, R as writeTree, S as saveSecurityState, St as recordActivity, T as todayUtc, Tt as MCP_TTL_MS, U as listChildren, V as countFiles, W as postEditTypescript, X as validateTeammateOutput, Y as logToolFailure, Z as trackAgentMemory, _ as trackWatchResearch, _t as sessionStatePath, a as TRIVIAL_BUDGET, at as pruneEmptyDirs, b as isoUtc, bt as taskContext, c as detectDuplication, ct as trimLogFile, d as lifecycleStdout, dt as projectContext, et as solidDetectStart, f as postEditContext, ft as claudeHome, g as postTrackingSideEffects, gt as saveSessionState, h as securityAdvisory, ht as sanitizeSessionId, i as REQUIRED_AGENTS, it as sessionStartCore, j as lessonsFileFor, k as dispatchAipilot, kt as queryOf, l as dryGate, lt as devContext, m as seoPostToolUseResponse, mt as loadSessionState, n as handlePre, nt as readRules, o as gate, ot as purgeTtlTree, p as seoPostToolUse, pt as fusengineCache, q as cleanupSession, r as DEFAULT_WINDOW_MS, rt as runSessionStartCleanups, s as preCommitGate, st as removeOldFiles, t as handleHook, tt as injectRules, u as extractSymbols, ut as gitContext, v as trackMcpResearch, vt as sessionsDir, w as securityStatePath, wt as normalizeEvent, x as loadSecurityState, xt as respond, y as trackSkillRead, yt as promptSubmitContext, z as loadEnriched } from "../handle-DJqHZcml.mjs";
3
3
  //#region src/runtime/storage.ts
4
4
  /**
5
5
  * The project's single state dir (`<root>/.harness`) — neutral + harness-agnostic,
@@ -9,4 +9,4 @@ function harnessStateDir(root) {
9
9
  return projectLayout(root).stateDir;
10
10
  }
11
11
  //#endregion
12
- export { DEFAULT_WINDOW_MS, MCP_TTL_MS, REQUIRED_AGENTS, TRIVIAL_BUDGET, activityFor, aipilotPostToolUse, cartoSessionStart, claudeHome, cleanupSession, countFiles, detectDuplication, detectSolidProfile, devContext, dispatchAipilot, dispatchLifecycle, dryGate, extractSymbols, fusengineCache, gate, generateProjectMap, getFileDesc, gitContext, handleHook, handlePre, harnessStateDir, injectRules, isMcpTool, isProject, isoUtc, lifecycleStdout, listChildren, loadEnriched, loadSecurityState, loadSessionState, logToolFailure, mcpPostStore, mcpPreIntercept, mergeLines, normalizeEvent, postEditContext, postEditTypescript, postTrackingSideEffects, preCommitGate, projectContext, promptSubmitContext, pruneEmptyDirs, purgeTtlTree, queryOf, readRules, recordActivity, removeOldFiles, respond, runSessionStartCleanups, sanitizeSessionId, saveApexState, saveSecurityState, saveSessionState, securityAdvisory, securityStateDir, securityStatePath, sessionStartCore, sessionStatePath, sessionsDir, solidDetectStart, subagentCacheContext, taskContext, todayUtc, trackAgentMemory, trackEnrichment, trackFile, trackMcpResearch, trackSessionChanges, trackSkillRead, trackWatchResearch, trimLogFile, validateRulesLoaded, validateTeammateOutput, writeTree };
12
+ export { DEFAULT_WINDOW_MS, MCP_TTL_MS, REQUIRED_AGENTS, TRIVIAL_BUDGET, activityFor, aipilotPostToolUse, cartoSessionStart, claudeHome, cleanupSession, countFiles, detectDuplication, detectSolidProfile, devContext, dispatchAipilot, dispatchLessons, dispatchLifecycle, dryGate, extractSymbols, fusengineCache, gate, generateEcosystemMap, generateProjectMap, getFileDesc, gitContext, handleHook, handlePre, harnessStateDir, injectRules, isMcpTool, isProject, isoUtc, lessonsFileFor, lessonsStateFileFor, lifecycleStdout, listChildren, loadEnriched, loadSecurityState, loadSessionState, logToolFailure, mcpPostStore, mcpPreIntercept, mergeLines, normalizeEvent, postEditContext, postEditTypescript, postTrackingSideEffects, preCommitGate, projectContext, promptSubmitContext, pruneEmptyDirs, purgeTtlTree, queryOf, readRules, recordActivity, removeOldFiles, respond, runSessionStartCleanups, sanitizeSessionId, saveApexState, saveSecurityState, saveSessionState, securityAdvisory, securityStateDir, securityStatePath, seoPostToolUse, seoPostToolUseResponse, sessionStartCore, sessionStatePath, sessionsDir, solidDetectStart, subagentCacheContext, taskContext, todayUtc, trackAgentMemory, trackEnrichment, trackFile, trackMcpResearch, trackSessionChanges, trackSkillRead, trackWatchResearch, trimLogFile, validateRulesLoaded, validateTeammateOutput, writePluginMap, writeTree };
@@ -1,2 +1,2 @@
1
- import { i as compactJson, n as projectRoot, r as projectRootOrNull, t as isCodeFile } from "../index-C1vLIMwN.mjs";
2
- export { compactJson, isCodeFile, projectRoot, projectRootOrNull };
1
+ import { a as compactJson, i as walkUpFor, n as projectRoot, r as projectRootOrNull, t as isCodeFile } from "../index-BEMumjOw.mjs";
2
+ export { compactJson, isCodeFile, projectRoot, projectRootOrNull, walkUpFor };
@@ -1,4 +1,4 @@
1
1
  import { t as compactJson } from "../compact-json-DK2nX-MK.mjs";
2
- import { n as projectRoot, r as projectRootOrNull, t as isCodeFile } from "../project-root-ff0_poWU.mjs";
2
+ import { i as walkUpFor, n as projectRoot, r as projectRootOrNull, t as isCodeFile } from "../project-root-3kk7gCOp.mjs";
3
3
  import "../util-la_KkjCS.mjs";
4
- export { compactJson, isCodeFile, projectRoot, projectRootOrNull };
4
+ export { compactJson, isCodeFile, projectRoot, projectRootOrNull, walkUpFor };
@@ -1,5 +1,5 @@
1
1
  import { r as resolveMaxLines } from "./limits-CHn8AIL1.mjs";
2
- import { k as countLines } from "./evaluate-j3gRJ_ng.mjs";
2
+ import { k as countLines } from "./evaluate-9ch1K2kt.mjs";
3
3
  import { r as isDocConsulted, t as formatDocDeny } from "./doc-helpers-Dd_x1-tZ.mjs";
4
4
  import { t as routeReferences } from "./router-D8cVrI-s.mjs";
5
5
  import { join } from "node:path";
@@ -1034,4 +1034,49 @@ function descFromText(suffix, text, mdField) {
1034
1034
  return "";
1035
1035
  }
1036
1036
  //#endregion
1037
- export { solidReadGate as A, capVerbosity as C, docConsultedGate as D, brainstormGate as E, requiredArchSkill as F, detectModularArchitecture as M, detectProjectType as N, evaluateApex as O, isApexCommand as P, MAX_TOKENS as S, APEX_GATES as T, detectRequiredSkills as _, parseEntry as a, frameworkSolidGate as b, EXCLUDE_DIRS as c, buildApexTaskInjection as d, loadApexTaskState as f, detectClaudeMdProjectType as g, buildClaudeMdContext as h, parseEnrichment as i, DEV_KEYWORDS as j, freshnessGate as k, PROJECT_INDICATORS as l, buildApexInstruction as m, firstComment as n, parseBodyDesc as o, DEV_VERBS as p, firstHeading as r, parseField as s, descFromText as t, buildApexTaskContext as u, skillTriggerGate as v, detectCreationIntent as w, MAX_EXA_RESULTS as x, SKILL_TRIGGERS as y };
1037
+ //#region src/policy/seo/validate.ts
1038
+ /**
1039
+ * SEO completeness checks — pure text in, missing-items out (no fs). Ports the
1040
+ * `validate()` of `seo/hooks/validate-seo.ts` using regex instead of cheerio so
1041
+ * the harness keeps zero runtime HTML-parser dependency (presence-only gate).
1042
+ */
1043
+ /** Extensions the SEO hook validates (HTML-like rendered output). */
1044
+ const HTML_LIKE = /\.(html|astro|tsx|vue|blade\.php)$/;
1045
+ /** True when `path` is an HTML-like file the SEO hook should validate. */
1046
+ function isHtmlLike(path) {
1047
+ return HTML_LIKE.test(path);
1048
+ }
1049
+ /** True when a `<tag …>…</tag>` carries non-empty inner text. */
1050
+ function hasNonEmptyTag(html, tag) {
1051
+ const m = new RegExp(`<${tag}[\\s>][\\s\\S]*?</${tag}>`, "i").exec(html);
1052
+ return !!m && m[0].replace(/<[^>]*>/g, "").trim().length > 0;
1053
+ }
1054
+ /** True when a `<meta …>` whose `selAttr=selVal` has a non-empty `content`. */
1055
+ function hasMetaContent(html, selAttr, selVal) {
1056
+ const tag = new RegExp(`<meta\\b[^>]*\\b${selAttr}\\s*=\\s*["']${selVal}["'][^>]*>`, "i").exec(html)?.[0] ?? "";
1057
+ return (/\bcontent\s*=\s*["']([^"']*)["']/i.exec(tag)?.[1] ?? "").trim().length > 0;
1058
+ }
1059
+ /** True when a `<link rel="canonical">` carries a non-empty `href`. */
1060
+ function hasCanonical(html) {
1061
+ const tag = /<link\b[^>]*\brel\s*=\s*["']canonical["'][^>]*>/i.exec(html)?.[0] ?? "";
1062
+ return (/\bhref\s*=\s*["']([^"']*)["']/i.exec(tag)?.[1] ?? "").trim().length > 0;
1063
+ }
1064
+ /**
1065
+ * Report the SEO elements missing from HTML-like content (title, meta
1066
+ * description, OG title/description/image, canonical, JSON-LD schema).
1067
+ * @param html - The file content.
1068
+ * @returns The missing element labels (empty when complete).
1069
+ */
1070
+ function missingSeoElements(html) {
1071
+ const missing = [];
1072
+ if (!hasNonEmptyTag(html, "title")) missing.push("<title>");
1073
+ if (!hasMetaContent(html, "name", "description")) missing.push("<meta name='description'>");
1074
+ if (!hasMetaContent(html, "property", "og:title")) missing.push("og:title");
1075
+ if (!hasMetaContent(html, "property", "og:description")) missing.push("og:description");
1076
+ if (!hasMetaContent(html, "property", "og:image")) missing.push("og:image");
1077
+ if (!hasCanonical(html)) missing.push("canonical");
1078
+ if (!/<script\b[^>]*type\s*=\s*["']application\/ld\+json["']/i.test(html)) missing.push("JSON-LD schema");
1079
+ return missing;
1080
+ }
1081
+ //#endregion
1082
+ export { evaluateApex as A, MAX_EXA_RESULTS as C, APEX_GATES as D, detectCreationIntent as E, detectProjectType as F, isApexCommand as I, requiredArchSkill as L, solidReadGate as M, DEV_KEYWORDS as N, brainstormGate as O, detectModularArchitecture as P, frameworkSolidGate as S, capVerbosity as T, buildClaudeMdContext as _, firstHeading as a, skillTriggerGate as b, parseBodyDesc as c, PROJECT_INDICATORS as d, buildApexTaskContext as f, buildApexInstruction as g, DEV_VERBS as h, firstComment as i, freshnessGate as j, docConsultedGate as k, parseField as l, loadApexTaskState as m, missingSeoElements as n, parseEnrichment as o, buildApexTaskInjection as p, descFromText as r, parseEntry as s, isHtmlLike as t, EXCLUDE_DIRS as u, detectClaudeMdProjectType as v, MAX_TOKENS as w, SKILL_TRIGGERS as x, detectRequiredSkills as y };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fusengine/harness",
3
- "version": "0.1.31",
3
+ "version": "0.1.32",
4
4
  "description": "Harness-agnostic toolkit for AI coding agents: runtime harness detection (Claude Code, Codex, Cursor, Cline, Gemini, Aider...), pure policy core (env config, project/framework detection, SOLID/file-size limits, APEX freshness, guard patterns, portable prompts), cache, project memory, ref routing, state/locks, statusline, per-harness adapters (Claude/Cursor/Cline/Gemini) and a cli-mode harness-check binary. Bun-native, with a built dist for Node + bundlers.",
5
5
  "type": "module",
6
6
  "module": "src/index.ts",