fix(agents-md): resolve .claude/rules references in bodies by the rule they name (0.8.4) - #24
Merged
Merged
Conversation
The name-class regex of kiro.ts's referencedRules is now RULE_NAME_CHARS in shared.ts, so there is one spelling for both emitters. The inline writers computation in agents-md.ts uses ruleWriter, the same logic shared.ts already exposes for spec-14 and spec-15 lookups.
…e they name Spec 15: a reference becomes the file a target writes, the rule's place in AGENTS.md, or "<x> (rule not in this workspace)", with one warning per AGENTS.md. Three spec-14 tests now expect their resolved bodies (approved).
…nd what 0.8.4 changes Adds the new sentence to the agents-md target paragraph and the ### to 0.8.4 upgrading section per spec 15 §4.3 and §4.5.
Bumps version to 0.8.4 for the patch release.
Spec 15 §4.1 puts boundaries around the path, not the link syntax. A link already bounds its path with ( and ), so no extra checks needed.
Spec 15 §4.2 looks up the name among rules first, then steering only for state B. A command with the same output name no longer hides the rule.
Spec 15 §4.5 orders entries by position in the body. Collect matches with their offsets, sort by offset, and dedup keeps first occurrence.
…AME_CHARS Use ruleWriter for states A and B. Build RuleLookup once per AGENTS.md, not once per body. Use the ingredient's ref directly for reporting.
…aces see the warning Clarify that unknown names are left as written when claude-code is a target, update the No change/no warning cases, and add version numbers.
…t writes When a rule exists but neither claude-code nor kiro writes it, check for a steering ingredient of the same name before returning state C or D. This implements spec 15 §4.2 correctly: B before C/D for .kiro/steering/<x>.md.
…it stops Clarifies that state-B and state-C references are not reported (only those turned into "rule not in this workspace"), and that the warning repeats until the body, the cited rule's targets or the workspace's targets change.
…dedups again leftBoundary was defined but never called; token pattern captures the boundary character instead. The emitRefWarning dedup comment now says it is a backstop for references cited by multiple ingredients.
…al body Token references were recorded at their offset in the result after link replacements, not in the original body, causing entries to appear out of order when links shrank or grew.
…st comment on the warning dedup The previous commit already routed state B through ruleFile; this commit updates the dedup comment to accurately describe what it does.
The token offset was calculated from the full match, which includes the left boundary character. For a token immediately after a link (e.g. `[y](.claude/rules/u5.md).claude/rules/u6.md`), this caused the overlap check to wrongly skip it. Now the offset is the position of the actual token, not the boundary.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Version bumped to 0.8.4. Merging publishes
craftar@0.8.4to npm after approval in thenpmenvironment.What changes. Bodies in
AGENTS.md(always-on sections and the scoped rules 0.8.3 embeds) used to keep every.claude/rules/<x>.mdreference exactly as the Forge holds it. In a workspace withoutclaude-code, those references point at nothing. Each reference is now resolved by the rule it names (approved spec: rule references insideAGENTS.mdbodies):[t](.claude/rules/<x>.md)claude-codewrites itkirowrites.kiro/steering/<x>.md(from the rule or from asteeringingredient).kiro/steering/<x>.md[t](.kiro/steering/<x>.md), fragment keptAGENTS.mdAGENTS.md (rule: <x>)[t](AGENTS.md)claude-code<x> (rule not in this workspace)t (<x>, rule not in this workspace)AGENTS.md. It names every reference turned into "rule not in this workspace", inAGENTS.mdorder. Withoutclaude-code, it also names other.claude/paths (agents, commands, skills, scripts, hooks), which are left as written. It never changes an exit code.resolveRuleRefsinsrc/emitters/shared.tsreads the resolution, never the disk. It sharesRULE_NAME_CHARS,ruleWriterandruleFilewith the other emitters.claude-codeandkiroemitters are untouched: the reviewer measured them byte-identical to0.8.3across sandbox and synthetic Forges. There is no schema, lock,plan()or CLI change.Which workspaces see
updateOnly
AGENTS.mdchanges. The user approved the byte change at a checkpoint before the commit, from the before and after measured on 0.8.3 with the spec's Forge.syncon 0.8.4claude-code(every workspacecraftar importproduced).claude/pathclaude-code; bodies cite sibling rulesclaude-codepresent; a cited rule its owntargetskeep away from it, or asteeringfile kiro writesclaude-code; bodies cite only other.claude/pathsAn affected workspace shows
AGENTS.mdasupdate, andcraftar sync --checkexits 1 until it syncs.Tests
.claude/rules/style.md, a reference spec 14 left for 0.8.4 on purpose. They now expect it resolved:AGENTS.md (rule: style)or.kiro/steering/style.md.Disclosures
8d68e1dis not a refactor. It is titledrefactor(…)but it changed the state precedence when a rule and a steering ingredient share a name.0994cf4fixes that, and a test pins it.61e3b20only partly fixed warning order. It claimed order by position, which0d38e9eand599f437complete.ruleFile("kiro", …)change for state B landed in0d38e9e, not in0c019b7. The subject of0c019b7names it, but its diff is only a comment.6d972e2(ruleWriterdescribed as already used) and47806d1(it cites §4.3/§4.5 where §5 and §7 apply) do not match their diffs..claude/rules/to.kiro/steering/. That is 0.8.5's subject (its own spec, with its own byte checkpoint).Test plan
npm run typecheck: exit 0 on599f437.npm run build: exit 0.test/ci.test.ts(Linux): 821 passed / 5 skipped.test/golden/**is unchanged;claude-codeandkirooutput byte-identical to417caebacross target sets;node-cli-reviewer: five rounds; the fifth was clean.docs-author: three rounds; the third was clean.37241719000,37241746570).