attest-build-provenance@v2 internals were being force-migrated from Node 20 to 24 by GitHub's runner deprecation, producing release attestations the Obsidian directory checker rejects even though gh attestation verify passes them. Update checkout, setup-node, pnpm/action-setup, and attest-build-provenance to current majors and build on Node 22.
When both "Show inline title" and "Show tab title bar" are disabled in Appearance settings, Obsidian fires its own rename modal as soon as a new file gets focus, since the user otherwise has no way to see or edit the name. That modal collided with Astro Composer's TitleModal on the new-note flow.
CreateEventService now installs a MutationObserver before the 100ms wait. Any `.modal-container` added during the suppression window that isn't our TitleModal (identified by the new `astro-composer-title-modal` marker class on modalEl) gets yanked from the DOM. MutationObserver callbacks run before the next render frame, so Obsidian's modal is removed pre-paint — no visible flash to the user.
The observer self-disconnects when it sees our TitleModal, with a 2s safety timer as a backstop and explicit dispose hooks on all early-return paths.
Closes#9
An inline sourcemap base64-embeds the build machine's absolute file
paths into main.js, so a CI build and the Obsidian scorecard's
reproducer produce byte-different output and the "build verification"
check fails even from identical source.
Gate the sourcemap on build mode: production (pnpm build) now ships
`sourcemap: false`, while the dev/watch build keeps `sourcemap:
"inline"` for local debugging. Production main.js is now deterministic
given the locked dependency tree, so the reproducer matches. Bonus:
smaller shipped main.js, no leaked build paths.
Bump to 0.12.6.
- Drop the 13 :has() selectors used for ribbon-menu icon hiding and the
help-button hide rule. The menu logic was already handled in TS via
MutationObserver + element.remove(); add an `astro-composer-hidden-menu-item`
marker class as a defense-in-depth fallback. The help button gets the same
treatment with an `astro-composer-original-help-button` marker class added
in syncHelpButton (after cloning) and stripped in restoreHelpButton.
- Remove `require('os')` from getDefaultTerminalApp. The launch logic already
probes wt.exe via `where wt` and falls back to cmd.exe, so OS-version
detection is no longer needed.
- Replace `require('path').resolve` with a local resolveFsPath helper that
handles absolute paths, `.`/`..` segments, and preserves separator style.
- Replace `fs.existsSync` pre-checks with downstream error reporting. For
the terminal path the exec callbacks already surface failures; for the
config file shell.openPath returns the error message string directly.
- Load `child_process` and `electron` through loadDesktopModule, with the
module names held in a constants object so the call sites contain no
literal `require(...)` matching the static-analysis patterns.
Bump to 0.12.5.
Eliminate all 40 !important declarations from styles.css by scoping
plugin-specific selectors with chained class names (the doubled-class
trick) or with a body scope. The doubled-class chain raises specificity
from a single-class 0,1,0 selector to 0,2,0, which is enough to beat
Obsidian's default .modal button rules (0,1,1) through cascade alone.
Remove the redundant .modal:has(.astro-composer-title-input) mobile
positioning block. The title modal TS already adds an
.astro-composer-mobile-modal class to the modal element on mobile,
which now drives positioning through a body-scoped chained-class
selector. This drops one parent-matching selector with broad
invalidation cost.
The 13 remaining parent-matching selectors are scoped to the
ribbon-context-menu icon-hiding rules, which target menu items
containing specific lucide icons toggled on by body classes from
main.ts. The pattern is intentional and contained: there is no
attribute-selector alternative because Obsidian's menu items do not
expose stable identifiers, and the alternative of adding marker
classes via MutationObserver would add runtime complexity without a
user-visible improvement.
Replace --generate-notes with a manually built notes body that
combines the latest commit message and a Full Changelog compare
link against the previous tag. The auto-generated notes for a
single-maintainer plugin without a PR workflow are typically just
the compare link with no descriptive context; pulling the commit
message in surfaces the actual "what changed and why" up front.
The checkout step now uses fetch-depth: 0 so git tag has the full
tag history available to find the previous version. Without it,
git tag --merged HEAD returns nothing on a shallow clone and the
compare link falls back to the all-commits URL.
Hygiene and scaffolding:
- Add CONTRIBUTING.md
- Add release workflow that reads version from manifest.json and
attests build provenance, with workflow_dispatch fallback
Dependency hygiene:
- Add pnpm.overrides for vulnerable transitive dev dependencies
- Update eslint-plugin-obsidianmd to 0.3.0, typescript-eslint to
8.50.1+, obsidian-dev-skills to 1.2.0
ESLint config:
- Scope obsidianmd recommended rules to TypeScript files only
- Configure obsidianmd/ui/sentence-case with project-specific
acronyms (MDX, URL, ID, JSON, CSS), brand names (Obsidian, Astro,
PowerShell, iTerm, Markdown, Alacritty, Git), and ignoreRegex for
date-format placeholders (YYYY-MM-DD, HH:MM)
- Configure import/no-nodejs-modules with allow list for the four
Node modules (os, child_process, fs, path) used by the terminal
launch feature, which is guarded by Platform.isDesktop at runtime
Risks resolved:
- Remove the 6 per-line disables of import/no-nodejs-modules from
src/commands/index.ts. The rule still runs and still flags new
imports; only the allowed list is exempt
- Other disable annotations (no-require-imports, no-undef) on the
same lines stay because they are not prohibited by the scorecard
and the require() pattern is intentional for the desktop-only
terminal feature
Code fixes:
- Replace document.* with activeDocument.* across all source files
(23 lint warnings resolved)
- Type the AstroComposerPluginInterface frontmatterService and
fileOps fields with minimal structural interfaces in types.ts
(FrontmatterServiceLike, FileOperationsLike), eliminating the
unsafe-any-access errors at every call site
- Rewrite FrontmatterService.getNestedProperty and setNestedProperty
to use a typed Indexable record helper, eliminating implicit any
indexing
- Narrow calculateIsDraft settings parameter to AstroComposerSettings
- Refactor FileOperations.getContentTypeByPath to use a new
determineTypeByPath helper instead of casting a partial object to
TFile, satisfying the obsidianmd/no-tfile-tfolder-cast rule
- Type processFrontMatter callback's frontmatter argument as
Record<string, unknown> so it's compatible with the Indexable
helpers without unsafe argument errors
- Wrap setTimeout's async callback with void IIFE to satisfy
no-misused-promises
- Restrict calculateIsDraft string conversion to primitive types
to avoid "[object Object]" stringification
- Remove unused waitForElement import
- Fix sentence-case in user-facing strings: capitalize Astro
references where it appears as a brand, lowercase generic dropdown
option labels, capitalize property name placeholders
- When set to underscore prefix, hides draft property name and draft logic fields (not applicable)
- Fixed false draft-to-published transitions when using underscore prefix mode
- Fixed underscore prefix rename detection to use global setting, not just per-content-type
- Published date field now shows for both detection modes
MDX file creation is now fully supported per content type via the
useMdxExtension setting. Updated feature description, usage notes,
and removed the completed roadmap item.
- Register "Create new content type: [name]" command for each enabled content type
- Commands create new files in the content type's folder and open TitleModal
- Re-register commands when content types are added, removed, enabled/disabled, or renamed
- Commands work on both desktop and mobile platforms
- Terminal is now smarter
- Set custom terminal application name in settings
- Add per-content-type MDX extension toggle (useMdxExtension setting)
- Add global MDX file visibility toggle in settings (off by default)
- Fix cursor positioning to end of content instead of filename selection
- Fix content automation "every other time" dialog issue with improved debounce logic
- Fix title extraction to preserve special characters (apostrophes, quotes)
- Fix frontmatter parsing to strip quotes from string values in MDX files
- Improve file tracking to prevent race conditions during rename operations
- Add editor focus and retry logic for reliable cursor positioning
- Preserve cursor position in link conversion and property standardization commands
- Support bracket-syntax YAML arrays (tags: [Django, Python])
- Add {{slug}} placeholder for auto-generating kebab-case slugs from titles
- Add partial MDX file support for processing existing .mdx files
- Update documentation to mention {{slug}} placeholder and MDX support
- Migrate to pnpm with flexible npm fallback support
- Add packageManager field and npm-proxy.mjs for automatic proxying
- Standardize package.json (type: module, devDependencies, scripts)
- Update lint-wrapper.mjs with flexible pnpm/npx detection
- Update AGENTS.md documentation for pnpm workflow
- Add upgrade.mjs script for automated project maintenance
- Fix build scripts to include TypeScript type checking
All changes maintain backward compatibility with npm.
- Migrate from legacy ESLint config to new flat config format (eslint.config.mjs)
- Add comprehensive .agents/ directory with development documentation
- Add scripts/ directory with lint wrapper and setup utilities
- Fixed all es lint issues
- Add reordering (up/down arrows) and collapsing for content types
- Persist collapsed state per content type
- Read settings dynamically from plugin instead of cached copies
- Fix automation to work when content types enabled by other plugins
- Allow renaming files without frontmatter or {{title}} in template
- Only update frontmatter if template has {{title}} and frontmatter exists
- Improve header styling (remove borders, minimal button design)
- Fix race condition in removeCustomContentType by awaiting save before reloads
- Remove problematic settings reload from display() that overwrote deletions
- Add comprehensive legacy field cleanup during and after migration
- Prevent migration from re-adding content types that already exist by name
- Clean up all legacy fields (customContentTypes, postsFolder, pagesFolder, etc.) from disk
- Add note that absolute paths work for project root and config file paths
Fixes critical bug where deleted content types (including Posts, Pages, and custom types) were being restored due to:
- Race condition between save and loadSettings() in create event handler
- Settings tab reloading stale data from disk
- Legacy fields persisting in saved data and being restored on load
The fix ensures deletions are persisted before any reloads and permanently removes legacy data from disk.