agentsmesh 0.24.0 → 0.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -457,7 +457,7 @@ declare function toRelPath(projectRoot: string, absolute: string): string;
457
457
  * survives generate → import → generate round-trip; only the wording inside each
458
458
  * block is tightened for maximum agent compliance.
459
459
  */
460
- declare const LESSONS_PROCEDURAL_RULE = "## Lessons (BLOCKING REQUIREMENT \u2014 MUST run both, no exceptions; the user will check)\n\nGraph `.agentsmesh/lessons/lessons.json` is canonical \u2014 never hand-edit. Manual: the `lessons` skill.\n\n**Recall \u2014 MUST run before every file edit and every state-changing command** (build/test/install/migrate/git-write): `agentsmesh lessons query --file <path> --cmd <command>`, then apply every rule. Pure-read commands (cat/ls/grep/git-log) and the recall query itself are exempt.\n\n**Capture \u2014 MUST run immediately after any failure** (a failing test/CI/lint/typecheck, a code review, a user correction, a regression, or a wrong assumption \u2014 yours or anyone's): `agentsmesh lessons add \"<rule>\" --topic <id> --trigger-file <glob> --evidence <sha|lesson-id>`.\n\nNo shell? Use the `lessons_query` / `lessons_add` MCP tools. Skip either and the system does not exist.";
460
+ declare const LESSONS_PROCEDURAL_RULE = "## Lessons (BLOCKING)\n\nGraph `.agentsmesh/lessons/lessons.json` is canonical; never hand-edit it. Manual: `lessons` skill.\n\n**Recall:** before every file edit or state-changing command, MUST run `agentsmesh lessons query --file <path> --cmd <command>` and obey matches. Pure-read commands and recall itself are exempt.\n\n**Capture:** after any failure, user correction, regression, wrong assumption, useful surprise, repeated friction, or non-obvious fix, MUST self-critique and run `agentsmesh lessons add \"<imperative rule>\" --topic <id> --trigger-file <glob> --evidence <sha|lesson-id>`.\n\n**Before final:** report `Lesson: captured <id>` or `Lesson: none`. No recall/capture gate = task incomplete. No shell: use `lessons_query` / `lessons_add`.";
461
461
 
462
462
  interface ScaffoldLessonsResult {
463
463
  readonly created: string[];
package/dist/lessons.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { o as RankedLesson, A as AddLessonInput, a as AddLessonOptions, b as AddLessonResult, j as LessonsQuery } from './init-YKxF2zpQ.js';
2
- export { c as AddLessonTriggers, D as DEFAULT_RECALL_LIMIT, X as DEFAULT_RECALL_MAX_TOKENS, I as ImportLegacyOptions, d as ImportLegacyReport, Y as LESSONS_LOCK_FILENAME, L as LESSONS_PROCEDURAL_RULE, e as Lesson, f as LessonStatus, g as LessonsGraph, Z as LessonsGraphExistsError, h as LessonsGraphSchema, i as LessonsPaths, M as MatchedLesson, k as MergeLessonsOptions, l as MergeLessonsResult, m as MutateOptions, R as RankOptions, n as RankReason, S as ScaffoldLessonsResult, p as StripMarkersOptions, q as StripMarkersReport, T as Topic, r as Trigger, s as TriggerKind, U as UnknownTopicError, V as ValidationFinding, t as ValidationLevel, u as ValidationReport, v as acquireLessonsLock, w as addLesson, x as graphFilePath, y as importLegacyLessons, _ as lessonsLockPath, z as lessonsPaths, B as loadLessonsGraph, C as mergeLessons, E as mutateLessonsGraph, F as parseGraph, G as queryLessons, H as rankLessons, J as scaffoldLessons, K as serializeGraph, N as stripLegacyMarkers, O as stripMarkersInGraph, P as toRelPath, Q as tryLoadLessonsGraph, W as validateLessonsGraph } from './init-YKxF2zpQ.js';
1
+ import { o as RankedLesson, A as AddLessonInput, a as AddLessonOptions, b as AddLessonResult, j as LessonsQuery } from './init-B0aI-g8W.js';
2
+ export { c as AddLessonTriggers, D as DEFAULT_RECALL_LIMIT, X as DEFAULT_RECALL_MAX_TOKENS, I as ImportLegacyOptions, d as ImportLegacyReport, Y as LESSONS_LOCK_FILENAME, L as LESSONS_PROCEDURAL_RULE, e as Lesson, f as LessonStatus, g as LessonsGraph, Z as LessonsGraphExistsError, h as LessonsGraphSchema, i as LessonsPaths, M as MatchedLesson, k as MergeLessonsOptions, l as MergeLessonsResult, m as MutateOptions, R as RankOptions, n as RankReason, S as ScaffoldLessonsResult, p as StripMarkersOptions, q as StripMarkersReport, T as Topic, r as Trigger, s as TriggerKind, U as UnknownTopicError, V as ValidationFinding, t as ValidationLevel, u as ValidationReport, v as acquireLessonsLock, w as addLesson, x as graphFilePath, y as importLegacyLessons, _ as lessonsLockPath, z as lessonsPaths, B as loadLessonsGraph, C as mergeLessons, E as mutateLessonsGraph, F as parseGraph, G as queryLessons, H as rankLessons, J as scaffoldLessons, K as serializeGraph, N as stripLegacyMarkers, O as stripMarkersInGraph, P as toRelPath, Q as tryLoadLessonsGraph, W as validateLessonsGraph } from './init-B0aI-g8W.js';
3
3
  import 'zod';
4
4
 
5
5
  /**
package/dist/lessons.js CHANGED
@@ -571,15 +571,15 @@ function lessonsPaths(projectRoot) {
571
571
  function toRelPath(projectRoot, absolute) {
572
572
  return relative(projectRoot, absolute).split(sep).join("/");
573
573
  }
574
- var LESSONS_PROCEDURAL_RULE = `## Lessons (BLOCKING REQUIREMENT \u2014 MUST run both, no exceptions; the user will check)
574
+ var LESSONS_PROCEDURAL_RULE = `## Lessons (BLOCKING)
575
575
 
576
- Graph \`.agentsmesh/lessons/lessons.json\` is canonical \u2014 never hand-edit. Manual: the \`lessons\` skill.
576
+ Graph \`.agentsmesh/lessons/lessons.json\` is canonical; never hand-edit it. Manual: \`lessons\` skill.
577
577
 
578
- **Recall \u2014 MUST run before every file edit and every state-changing command** (build/test/install/migrate/git-write): \`agentsmesh lessons query --file <path> --cmd <command>\`, then apply every rule. Pure-read commands (cat/ls/grep/git-log) and the recall query itself are exempt.
578
+ **Recall:** before every file edit or state-changing command, MUST run \`agentsmesh lessons query --file <path> --cmd <command>\` and obey matches. Pure-read commands and recall itself are exempt.
579
579
 
580
- **Capture \u2014 MUST run immediately after any failure** (a failing test/CI/lint/typecheck, a code review, a user correction, a regression, or a wrong assumption \u2014 yours or anyone's): \`agentsmesh lessons add "<rule>" --topic <id> --trigger-file <glob> --evidence <sha|lesson-id>\`.
580
+ **Capture:** after any failure, user correction, regression, wrong assumption, useful surprise, repeated friction, or non-obvious fix, MUST self-critique and run \`agentsmesh lessons add "<imperative rule>" --topic <id> --trigger-file <glob> --evidence <sha|lesson-id>\`.
581
581
 
582
- No shell? Use the \`lessons_query\` / \`lessons_add\` MCP tools. Skip either and the system does not exist.`;
582
+ **Before final:** report \`Lesson: captured <id>\` or \`Lesson: none\`. No recall/capture gate = task incomplete. No shell: use \`lessons_query\` / \`lessons_add\`.`;
583
583
 
584
584
  // src/lessons/import-legacy.ts
585
585
  var LessonsGraphExistsError = class extends Error {
@@ -1618,15 +1618,27 @@ function validateLessonsGraph(graph, options = {}) {
1618
1618
  function emptyGraph() {
1619
1619
  return { version: 1, lessons: {}, topics: {}, triggers: {} };
1620
1620
  }
1621
+ function findingKey(f) {
1622
+ return `${f.code}|${f.triggerId ?? ""}|${f.lessonId ?? ""}`;
1623
+ }
1624
+ function errorSignatures(report) {
1625
+ return new Set(report.findings.filter((f) => f.level === "error").map(findingKey));
1626
+ }
1621
1627
  async function mutateLessonsGraphLocked(projectRoot, mutator, options = {}) {
1622
1628
  const release = await acquireLessonsLock(projectRoot, { retries: options.retries });
1623
1629
  try {
1624
1630
  const graph = tryLoadLessonsGraph(projectRoot) ?? emptyGraph();
1631
+ const baseline = errorSignatures(validateLessonsGraph(graph));
1625
1632
  const result = await mutator(graph);
1626
1633
  const report = validateLessonsGraph(graph);
1627
- if (!report.ok) {
1628
- const errors = report.findings.filter((f) => f.level === "error").map((f) => `${f.code}: ${f.message}`).join("; ");
1629
- throw new Error(`mutateLessonsGraph: refusing to write an invalid graph \u2014 ${errors}`);
1634
+ const introduced = report.findings.filter(
1635
+ (f) => f.level === "error" && !baseline.has(findingKey(f))
1636
+ );
1637
+ if (introduced.length > 0) {
1638
+ const errors = introduced.map((f) => `${f.code}: ${f.message}`).join("; ");
1639
+ throw new Error(
1640
+ `mutateLessonsGraph: refusing to write \u2014 this change introduces ${errors}. (Pre-existing graph issues are not blocking; run \`agentsmesh lessons validate\` to review and \`lessons untrigger\`/\`prune\` to repair them.)`
1641
+ );
1630
1642
  }
1631
1643
  saveLessonsGraph(projectRoot, graph);
1632
1644
  return result;
@@ -2586,6 +2598,17 @@ ${placed}` : placed;
2586
2598
  }
2587
2599
 
2588
2600
  // src/targets/projection/lessons-paragraph.ts
2601
+ var LEGACY_RAW_FORMS = [
2602
+ `## Lessons (BLOCKING REQUIREMENT \u2014 MUST run both, no exceptions; the user will check)
2603
+
2604
+ Graph \`.agentsmesh/lessons/lessons.json\` is canonical \u2014 never hand-edit. Manual: the \`lessons\` skill.
2605
+
2606
+ **Recall \u2014 MUST run before every file edit and every state-changing command** (build/test/install/migrate/git-write): \`agentsmesh lessons query --file <path> --cmd <command>\`, then apply every rule. Pure-read commands (cat/ls/grep/git-log) and the recall query itself are exempt.
2607
+
2608
+ **Capture \u2014 MUST run immediately after any failure** (a failing test/CI/lint/typecheck, a code review, a user correction, a regression, or a wrong assumption \u2014 yours or anyone's): \`agentsmesh lessons add "<rule>" --topic <id> --trigger-file <glob> --evidence <sha|lesson-id>\`.
2609
+
2610
+ No shell? Use the \`lessons_query\` / \`lessons_add\` MCP tools. Skip either and the system does not exist.`
2611
+ ];
2589
2612
  var LESSONS_PARAGRAPH_BLOCK = `${LESSONS_CONTRACT_START}
2590
2613
  ${LESSONS_PROCEDURAL_RULE}
2591
2614
  ${LESSONS_CONTRACT_END}`;
@@ -2598,9 +2621,12 @@ function stripLessonsParagraph(content) {
2598
2621
  return stripRawProceduralRule(withoutBlock).trim();
2599
2622
  }
2600
2623
  function stripRawProceduralRule(content) {
2601
- return content.replace(`
2624
+ return [LESSONS_PROCEDURAL_RULE, ...LEGACY_RAW_FORMS].reduce(
2625
+ (next, rule) => next.replace(`
2602
2626
 
2603
- ${LESSONS_PROCEDURAL_RULE}`, "").replace(LESSONS_PROCEDURAL_RULE, "");
2627
+ ${rule}`, "").replace(rule, ""),
2628
+ content
2629
+ );
2604
2630
  }
2605
2631
  function serializeFrontmatter(frontmatter, body) {
2606
2632
  const keys = Object.keys(frontmatter);
@@ -2615,68 +2641,55 @@ ${body}`;
2615
2641
 
2616
2642
  // src/lessons/skill.ts
2617
2643
  var LESSONS_SKILL_NAME = "lessons";
2618
- var LESSONS_SKILL_DESCRIPTION = "Full operating manual for the agentsmesh lessons system (recall + capture). Consult when running any `agentsmesh lessons` subcommand (query, add, topics, show, deprecate, merge, untrigger, strip-markers, journal, validate, stats, prune, import-md), choosing a topic or trigger flags, using the lessons MCP tools, or when unsure how to phrase or capture a lesson.";
2619
- var LESSONS_SKILL_BODY = `# Lessons \u2014 operating manual
2620
-
2621
- Two commands: **Recall** before you act, **Capture** after any failure. The graph
2622
- \`.agentsmesh/lessons/lessons.json\` is canonical \u2014 never hand-edit.
2623
-
2624
- ## Recall \u2014 before each file edit and each state-changing command
2644
+ var LESSONS_SKILL_DESCRIPTION = "Use when about to edit a file or run a state-changing command, or after any failure, correction, or surprising result.";
2645
+ var LESSONS_SKILL_BODY = `# Lessons \u2014 operating manual (Iron Law)
2625
2646
 
2626
- \`agentsmesh lessons query --file <path> --cmd <command>\` (add \`--keyword <text>\` to
2627
- match by task), then apply every rule returned. Scope is MUTATING actions: file edits
2628
- and state-changing commands (build/test/install/migrate/git-write). Pure-read commands
2629
- (cat/ls/grep/git-log; read-only) and the recall query itself are **exempt** \u2014 no
2630
- infinite regress. A predicate-less query is rejected; **keyword-only recall is the
2631
- anti-pattern** \u2014 most lessons are keyed to a \`file_glob\`/\`command_pattern\` and won't
2632
- surface (the CLI warns). Excuses ("small edit", "I already know this", "later") all
2633
- mean: query first \u2014 skipping recall on a mutating action is a process violation, and
2634
- the user will check.
2647
+ ## The Iron Law
2635
2648
 
2636
- ## Capture \u2014 immediately after any failure
2649
+ **NO MUTATION WITHOUT RECALL. NO COMPLETION WITHOUT A CAPTURE DECISION.**
2637
2650
 
2638
- Any failure counts, not just red tests: a failing test/CI/lint/typecheck, a code
2639
- review, a user correction, a regression, or a wrong assumption \u2014 yours or anyone's.
2640
-
2641
- \`agentsmesh lessons add "<imperative rule>" --topic <id> --trigger-file <glob> --evidence <sha|lesson-id>\`
2651
+ Violating the letter is violating the spirit. Edited a file or ran a state-changing
2652
+ command without recall? Process violation. Did the turn hit a failure / correction /
2653
+ regression / wrong assumption / surprise and you have not captured (nor stated
2654
+ \`Lesson: none\`)? The task is INCOMPLETE \u2014 and the user will check. The graph
2655
+ \`.agentsmesh/lessons/lessons.json\` is canonical \u2014 never hand-edit.
2642
2656
 
2643
- - **At least one _effective_ trigger is required.** A capture is rejected
2644
- (\`UNRECALLABLE_LESSON\`) when EVERY trigger is dead on the mandatory \`--file\`/\`--cmd\`
2645
- recall path \u2014 a stopword-only keyword ("state of the art"), or an invalid/ReDoS
2646
- command regex \u2014 because the lesson could never be recalled there. Prefer
2647
- \`--trigger-file\`: the most reliable trigger, it fires on \`--file\` recall. A keyword
2648
- alone is discouraged (\`KEYWORD_ONLY_LESSON\`); paraphrasing an existing rule warns
2649
- (\`NEAR_DUPLICATE_LESSON\` \u2014 update that lesson instead).
2650
- - **One imperative sentence.** A rule over 2000 chars is rejected (\`OVERSIZED_RULE\`) \u2014
2651
- trim it or split into separate lessons; don't paste a log/diff.
2652
- - Widen with \`--trigger-cmd <regex>\` / \`--trigger-kw <text>\`. New area:
2653
- \`--new-topic --topic-summary "<line>"\` (list ids with \`agentsmesh lessons topics\`).
2657
+ ## Recall \u2014 before each file edit and each state-changing command
2654
2658
 
2655
- ## No shell? \u2014 MCP tools
2659
+ \`agentsmesh lessons query --file <path> --cmd <command>\`, then apply every rule.
2660
+ Pure-read commands (read-only) and the query itself are exempt. **keyword-only recall
2661
+ is the anti-pattern** \u2014 lessons are keyed to a \`file_glob\`/\`command_pattern\`.
2656
2662
 
2657
- \`lessons_query\`, \`lessons_add\`, \`lessons_topics\`, \`lessons_show\` (inspect a topic),
2658
- \`lessons_deprecate\` (retire). validate / prune / merge / import-md are CLI-only.
2663
+ ## Capture \u2014 Gate Function (before any completion claim)
2659
2664
 
2660
- ## Other subcommands
2665
+ 1. **SELF-CRITIQUE**: any failure, correction, regression, wrong assumption,
2666
+ useful surprise, repeated friction, or non-obvious fix? Failing
2667
+ tests/lint/typecheck and user/review corrections \u2014 yours or anyone's \u2014 all count.
2668
+ 2. **CAPTURE** a reusable imperative rule with an effective trigger (else say so):
2669
+ \`agentsmesh lessons add "<rule>" --topic <id> --trigger-file <glob>\`
2670
+ 3. **RECEIPT**: emit \`Lesson: captured <id>\` or \`Lesson: none\`.
2661
2671
 
2662
- \`agentsmesh lessons <cmd>\`: \`show\` \xB7 \`deprecate\` (\`--superseded-by\`) \xB7 \`merge\` \xB7
2663
- \`untrigger\` \xB7 \`strip-markers\` \xB7 \`prune\` (\`--apply\`; trims over-cap triggers, GCs
2664
- orphan triggers/topics) \xB7 \`journal\` \xB7 \`validate\` \xB7 \`stats\` \xB7 \`import-md\`. Full
2665
- help: \`agentsmesh lessons --help\`.
2672
+ At least one _effective_ trigger is required or the capture is rejected
2673
+ (\`UNRECALLABLE_LESSON\`); prefer \`--trigger-file\`. No shell \u2192 MCP \`lessons_query\`,
2674
+ \`lessons_add\`, \`lessons_topics\`, \`lessons_show\`, \`lessons_deprecate\`. Run
2675
+ \`agentsmesh lessons --help\` for every subcommand and flag: query, add, topics, show,
2676
+ deprecate, merge, untrigger, strip-markers, prune, journal, validate, stats, import-md.
2666
2677
 
2667
- ## Config (\`.agentsmesh/lessons/config.json\`)
2678
+ ### Rationalization Prevention \u2014 these excuses mean STOP
2668
2679
 
2669
- \`recallLimit\` / \`recallMaxTokens\` (canonical recall caps; per-call overrides
2670
- \`--top\` / \`--max-tokens\`). \`recallMaxTokens\` is approximate \u2014 \`rule.length / 4\`,
2671
- not a real tokenizer. \`autoPrune: true\` (default off) auto-GCs structural cruft
2672
- after each capture \u2014 orphan triggers/topics + non-stranding dead globs, the safe
2673
- half of \`prune\`; never trims/strands an active lesson, git-reversible.
2680
+ | Excuse | Reality |
2681
+ | --- | --- |
2682
+ | "Small edit / I already know this / later" | Query first \u2014 skipping recall is a process violation |
2683
+ | "Nothing reusable here" | You hit a failure/surprise \u2014 name it or capture it |
2684
+ | "My own TDD red, not a real failure" | A red you did not predict IS a lesson |
2685
+ | "I fixed one site; the twin is obvious" | Capture it \u2014 the unfixed twin is what gets missed |
2686
+ | "Different words, so the rule doesn't apply" | Spirit over letter |
2674
2687
 
2675
- ## Dedup (opt-in)
2688
+ ## Lesson gate \u2014 before final response
2676
2689
 
2677
- Set \`--session <id>\` (or \`AGENTSMESH_SESSION_ID\`) and lessons already delivered this
2678
- session are suppressed, so each recall carries only what is new (\`--no-dedup\` opts
2679
- out). With no session id, recall is fully stateless \u2014 unchanged.`;
2690
+ The final response MUST carry the receipt: \`Lesson: captured <id>\` or \`Lesson: none\`.
2691
+ No receipt = task incomplete. Do not capture one-off facts, task summaries, or project
2692
+ context \u2014 only reusable imperative rules with an effective trigger.`;
2680
2693
  var LESSONS_SKILL_FILE = serializeFrontmatter(
2681
2694
  { name: LESSONS_SKILL_NAME, description: LESSONS_SKILL_DESCRIPTION },
2682
2695
  LESSONS_SKILL_BODY