diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7afe14b..dcf0f42 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,9 +8,38 @@ This file summarizes notable repository changes in a compact, release-oriented f
### Unreleased Git Log
+Used git range: `v1.0.1..HEAD`
+
+```txt
+```
+
+## v1.0.1 Changes (2026-05-30)
+
+### v1.0.1 Overview
+
+* Generated ToC links now reuse explicit managed anchor IDs when `anchor=true`:
+ * `numbering=true` still affects ToC labels and heading display text
+ * link targets stay tied to the generated unnumbered `` values
+ * duplicate headings keep matching ToC and anchor suffixes such as `summary` and `summary-1`
+* VS Code Marketplace publishing is more robust:
+ * VSIX publishing now retries transient `vsce publish` failures
+ * already-published package responses are treated as non-fatal after the VSIX assets have been validated
+* Extension development dependency lockfile updates:
+ * `qs` was updated from `6.15.1` to `6.15.2`
+ * `tmp` was updated from `0.2.5` to `0.2.7`
+
+### v1.0.1 Git Log
+
Used git range: `v1.0.0..HEAD`
```txt
+* 838007c Issue #109 fixed
+* 7a37122 Merge pull request #108 from rokath/dependabot/npm_and_yarn/extension/tmp-0.2.7
+* afcaafb Merge pull request #107 from rokath/dependabot/npm_and_yarn/extension/qs-6.15.2
+* 57f2cc9 build(deps-dev): bump tmp from 0.2.5 to 0.2.7 in /extension
+* c4aae24 build(deps-dev): bump qs from 6.15.1 to 6.15.2 in /extension
+* e173126 Merge pull request #106 from rokath/dev
+* b9c11fa retry logic added for poblishing
```
## v1.0.0 Changes (2026-05-20)
diff --git a/extension/package-lock.json b/extension/package-lock.json
index 97f552d..37fc6d9 100644
--- a/extension/package-lock.json
+++ b/extension/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "mdtoc-vscode",
- "version": "1.0.0",
+ "version": "1.0.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "mdtoc-vscode",
- "version": "1.0.0",
+ "version": "1.0.1",
"license": "MIT",
"devDependencies": {
"@types/node": "^22.15.17",
diff --git a/extension/package.json b/extension/package.json
index 04b6987..34f4384 100644
--- a/extension/package.json
+++ b/extension/package.json
@@ -2,7 +2,7 @@
"name": "mdtoc",
"displayName": "mdtoc - Markdown ToC with section numbering and stable links",
"description": "Generate, strip and configure a Markdown table of contents. Toggle ToC, numbering and links; choose heading levels, bullet style and slug method.",
- "version": "1.0.0",
+ "version": "1.0.1",
"publisher": "rokath",
"license": "MIT",
"icon": "mdtoc_icon_128.png",
diff --git a/internal/mdtoc/process.go b/internal/mdtoc/process.go
index eb7c878..26a6397 100644
--- a/internal/mdtoc/process.go
+++ b/internal/mdtoc/process.go
@@ -226,6 +226,13 @@ func assignDerivedArtifacts(headings []Heading, cfg Config) {
h.ManagedNumber = ""
}
+ // Explicit managed anchors own the document target identity. Reusing
+ // anchorID keeps ToC hrefs tied to the exact ID rendered into headings
+ // instead of independently deriving a renderer-style slug.
+ if cfg.Anchor {
+ h.ManagedTOCTarget = anchorID
+ continue
+ }
h.ManagedTOCTarget = tocSlugger.Next(tocSlugSource(*h, cfg))
}
}
@@ -243,9 +250,6 @@ func anchorSlugSource(h Heading, cfg Config) string {
}
func tocSlugSource(h Heading, cfg Config) string {
- if cfg.Anchor {
- return anchorSlugSource(h, cfg)
- }
source := h.TitleText
switch cfg.Slug {
case SlugCrossnote:
diff --git a/internal/mdtoc/process_test.go b/internal/mdtoc/process_test.go
index 6dcd14c..28f102d 100644
--- a/internal/mdtoc/process_test.go
+++ b/internal/mdtoc/process_test.go
@@ -304,6 +304,143 @@ func TestGenerateLinkFalseRendersPlainTOC(t *testing.T) {
}
}
+// TestGenerateTOCTargetsFollowAnchorOwnershipMatrix verifies the issue #109
+// invariant across the persisted config flags that decide whether mdtoc owns
+// heading IDs or delegates them to the selected renderer slug profile.
+func TestGenerateTOCTargetsFollowAnchorOwnershipMatrix(t *testing.T) {
+ input := "# Title\n\n## Foo Bar\n## Foo Bar\n"
+ slugCases := []struct {
+ slug SlugMode
+ anchorTargets [2]string
+ plainTargets [2]string
+ numberedTargets [2]string
+ }{
+ {
+ slug: SlugGitHub,
+ anchorTargets: [2]string{"foo--bar", "foo--bar-1"},
+ plainTargets: [2]string{"foo--bar", "foo--bar-1"},
+ numberedTargets: [2]string{"1-foo--bar", "2-foo--bar"},
+ },
+ {
+ slug: SlugGitLab,
+ anchorTargets: [2]string{"foo-bar", "foo-bar-1"},
+ plainTargets: [2]string{"foo-bar", "foo-bar-1"},
+ numberedTargets: [2]string{"1-foo-bar", "2-foo-bar"},
+ },
+ {
+ slug: SlugCrossnote,
+ anchorTargets: [2]string{"foo--bar", "foo--bar-1"},
+ plainTargets: [2]string{"foo--bar", "foo--bar-1"},
+ numberedTargets: [2]string{"1-foo--bar", "2-foo--bar"},
+ },
+ }
+
+ for _, sc := range slugCases {
+ for _, numbering := range []bool{false, true} {
+ for _, anchor := range []bool{false, true} {
+ for _, link := range []bool{false, true} {
+ for _, toc := range []bool{false, true} {
+ name := fmt.Sprintf("slug=%s/numbering=%t/anchor=%t/link=%t/toc=%t", sc.slug, numbering, anchor, link, toc)
+ t.Run(name, func(t *testing.T) {
+ got, _, err := Generate(input, Options{
+ Numbering: numbering,
+ MinLevel: 2,
+ MaxLevel: 2,
+ Slug: sc.slug,
+ Anchor: anchor,
+ AnchorSet: true,
+ Link: link,
+ LinkSet: true,
+ TOC: toc,
+ Bullets: BulletStar,
+ })
+ if err != nil {
+ t.Fatalf("Generate error: %v", err)
+ }
+
+ firstLabel := "Foo Bar"
+ secondLabel := "Foo Bar"
+ if numbering {
+ firstLabel = "1. " + firstLabel
+ secondLabel = "2. " + secondLabel
+ }
+
+ firstHeading := "## "
+ secondHeading := "## "
+ if numbering {
+ firstHeading += "1. "
+ secondHeading += "2. "
+ }
+ if anchor {
+ firstHeading += fmt.Sprintf(``, sc.anchorTargets[0])
+ secondHeading += fmt.Sprintf(``, sc.anchorTargets[1])
+ }
+ firstHeading += "Foo Bar"
+ secondHeading += "Foo Bar"
+
+ for _, want := range []string{firstHeading, secondHeading} {
+ if !strings.Contains(got, want) {
+ t.Fatalf("generated output missing heading %q:\n%s", want, got)
+ }
+ }
+ if !anchor && strings.Contains(got, "