Commit graph

88 commits

Author SHA1 Message Date
mpstaton
d3d7a6a626 chore(release): 0.2.3 — workflow-driven releases + artifact attestations + log.json gitignored
Three things bundled:

1. Release workflow at .github/workflows/release.yml fires on every 3-digit-semver tag push. Builds main.js + styles.css in a clean Ubuntu runner, signs all three release assets via actions/attest-build-provenance@v1 (sigstore-backed via OIDC), creates the GitHub Release with notes pulled from release-notes/<tag>.md. Identical to the workflow landing across cite-wide, perplexed, metafetch as a family-wide pattern.

2. release-notes/0.2.3.md authored in marketing-shape per content-farm/context-v/skills/changelog-conventions/SKILL.md "These are marketing artifacts" section. Convention going forward: every release's body lives in the repo at this path before the tag is pushed.

3. log.json now in .gitignore — runtime plugin telemetry that captures at first-run per-vault, never source-of-truth. Was tracked accidentally in earlier commits; this stops the dirty-tree noise on every git status.

Version bumped 0.2.2 → 0.2.3 across manifest.json / package.json / versions.json. No source-code changes — Drop Gate, Recraft generation, Ideogram v3, Magnific search, ImageKit upload all behave identically to 0.2.2.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 03:09:02 -05:00
mpstaton
673e0334dd chore(gitignore): stop tracking styles.css (build artifact, ships via release assets)
styles.css is regenerated on every pnpm build / pnpm dev and minification differs run-to-run, so the tracked version was perpetually dirty in git status — same chronic noise pattern across cite-wide / image-gin / perplexed / metafetch. main.js was already gitignored for the same reason; this just brings styles.css onto the same footing.

Local devs still build styles.css for symlinked-vault testing. The GitHub Release attaches the freshly-built styles.css from the developer's filesystem at release time (gh release upload doesn't care about gitignore), so end users installing from the Community Plugins directory still receive it normally.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 02:40:25 -05:00
mpstaton
7b4667c384 fix(manifest): fundingUrl points to Buy Me a Coffee, not the group homepage
The fundingUrl is meant to be a tip-jar / sponsorship destination per the
Obsidian manifest spec — was previously set to https://lossless.group (the
group homepage, no way to send money). Corrected to
https://buymeacoffee.com/losslessgroup, which is the actual destination
across all Lossless-authored plugins.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 23:10:49 -05:00
mpstaton
ffaaa1b1ca docs(release): retrofit 0.1.1 release narrative to magazine-subtitle frontmatter pattern
Adds proper frontmatter (title, lede, dates, category: Release, release_tag, release_url, etc.) to match the convention established by 0.2.2's narrative and the sibling cite-wide/perplexed releases. Body H1 dropped — the title now lives in frontmatter and gets rendered by the splash's release-card layout. Replaces the previous standalone product-README format with the family-wide release-narrative shape so the splash's /releases index can render it consistently (was previously displaying as `image-gin/releases/0.1.1` because the frontmatter title was missing).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 22:58:19 -05:00
mpstaton
563cc5eef6 docs(release): repoint context-v/changelogs reference in 0.1.1 narrative
Stray reference missed when the file was renamed from context-v/releases/0.1.1.md to changelog/releases/0.1.1.md in the prior commit. Repoints to changelog/ to match where the per-day changelogs actually live now.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 22:18:40 -05:00
mpstaton
76d9789d7f docs(changelog): relocate to repo-root + add 0.2.2 release narrative + ChromaDB-RAG note
Two changes bundled:

1. Changelog layout aligned with the repo-wide convention. Per-day entries from context-v/changelogs/ moved to changelog/; prior 0.1.1 release narrative moved from context-v/releases/ to changelog/releases/. Cross-references between the two release narratives repointed. context-v/ no longer holds changelogs/ or releases/ subdirs.

2. New 0.2.2 release narrative at changelog/releases/0.2.2.md — user-facing roll-up covering the Drop Gate feature shipped through the new community.obsidian.md portal. Magazine-subtitle lede + Why Care? / What's New? / Under the Hood / What's Next sections per the family-wide release-narrative pattern established alongside cite-wide and perplexed.

Also includes the ChromaDB-RAG backstop block added to the local CLAUDE.md (mirrors the same block added at parent and root tiers).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 22:17:57 -05:00
mpstaton
18f7c64b0e chore(release): bump to 0.2.2 for marketplace submission
Supersedes 0.2.1 with a fresh build of main.js/styles.css against the latest ObsidianReviewBot lint fixes so the community-directory scan sees the corrected code.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 18:05:45 -05:00
mpstaton
b839d1670e doc(plan): final ObsidianReviewBot cleanup round for v0.2.x
Captures the journey for PR obsidianmd/obsidian-releases#12524:
where we are after four bot scans, why local eslint diverges from
the server-side scanner (brand allowlist + require-await override),
the per-file fix audit, the three-commit implementation plan, and
the draft `/skip` comment for the brand-name false positives the
bot will continue to flag.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 22:32:22 -05:00
mpstaton
5f71f5159e fix(lint): sentence-case audit on user-facing strings
ObsidianReviewBot flagged 49 sentence-case findings on commit
cfbceba2; an audit of every cited line classified ~47 of them as
brand-name false positives (Recraft, Magnific, Freepik, Ideogram,
ImageKit, Imgur, WebP — all product names that our local
eslint.config.mjs allowlists for `obsidianmd/ui/sentence-case`, but
the server-side bot runs the rule with the default DEFAULT_BRANDS
list which doesn't know our integrations).

Two strings were genuine violations of sentence case and are fixed
here:

- main.ts:153 — command name `'Drop gate: Reset session-remembered
  destination'` → lowercase `reset` after the colon, since "Reset"
  is not a proper noun and after-colon capitalization isn't standard
  sentence case in Obsidian's UI conventions.
- settings/settings.ts:915 — heading
  `"Drag-Drop / paste confirmation gate"` → lowercase `drop` after
  the hyphen; "Drag-drop" is one compound word, not two proper nouns.

The remaining brand-name flags are addressed via a `/skip` comment
on PR #12524 once the bot rescans this push. Plan and `/skip` draft
text live at:
context-v/plans/2026-05-10_Final-ObsidianReviewBot-Cleanup-Round.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 22:32:11 -05:00
mpstaton
d4f50dbbef fix(lint): switch Vault.delete() to FileManager.trashFile()
ObsidianReviewBot's `prefer-file-manager-trash-file` is the optional
finding it surfaces against image-gin: `Vault.delete()` ignores the
user's "Files & links → Move to system trash / Obsidian trash / delete
permanently" preference, while `FileManager.trashFile()` respects it.

Three sites, all behind explicit user actions (settings toggle or
the Clear Cache button), so the deletion-preference is exactly the
contract we want to honor.

- BatchDirectoryConvertLocalToRemote.ts:449 — local file removal
  after a successful ImageKit upload, gated by
  `imageKit.removeLocalFiles` setting.
- imageCacheService.ts:156, 164 — `clearCache()` removing the
  configured cache folder (either as a single TFile or as the
  contents of a folder).

After this commit `pnpm exec eslint .` reports 0 errors and 0
warnings against the obsidianmd recommended config.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 22:31:06 -05:00
mpstaton
aa3ddf42e3 fix(lint): drop async on methods with no await expression
ObsidianReviewBot flagged three `require-await` violations at commit
cfbceba2 (PR obsidianmd/obsidian-releases#12524). None of the three
methods awaited anything; promoting them to sync is the correct fix
and removes the false-positive shape for the marketplace scanner.

- VaultDestination#uniqueFileName: sync helper, drop `async` and
  Promise<string> wrapper; drop the unnecessary `await` at the lone
  caller in VaultDestination#deposit.
- BatchDirectoryConvertLocalToRemote#onOpen: drop `async`; Obsidian's
  Modal.onOpen signature already permits a sync return.
- MagnificModal#onSelect default callback: drop `async`; narrow the
  field type to `(image) => void`; drop the now-pointless `await`
  at the two internal call sites.

Build is green (`pnpm build` — eslint clean + tsc + esbuild).
Local lint surface unchanged from before this commit (still 3
optional trashFile warnings, addressed in the next commit).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 22:30:36 -05:00
mpstaton
cfbceba299 chore(marketplace): pass ObsidianReviewBot lint cleanly — v0.2.1
Applies all required fixes from the bot's review of PR #12524
(obsidianmd/obsidian-releases). ESLint now passes 0 errors with the
Obsidian community ruleset; tsc passes; production build is clean.
3 warnings remain (FileManager.trashFile preference — non-blocking).

Lint setup:
- Adopted eslint-plugin-obsidianmd@^0.2.9 in eslint.config.mjs
- Mirrored the bot's rule surface locally so violations surface in
  `pnpm lint` instead of the marketplace PR thread
- Configured the ui/sentence-case rule with a brand allowlist
  (Recraft, Magnific, Freepik, Ideogram, ImageKit, Imgur, Anthropic,
  Claude, OpenAI, Obsidian, WebP, JSON, YAML, URL, API, CDN)

Code fixes (263 → 0):
- console.log/info → console.debug across all sources
- UI strings normalized to sentence case (~150 sites)
- Command IDs / names: dropped "image-gin-" plugin-id prefix on the
  drop-gate reset command; renamed problematic settings heading
  ("Image cache settings" → "Image cache")
- Settings tab section headers via setHeading() instead of <h2>/<h3>
- Inline element.style.* migrated to a new CSS class set in
  src/styles/marketplace-compliance.css (~60 sites collapsed to
  ~10 reusable classes: image-gin-row, image-gin-row-tight,
  image-gin-text-area + variants, image-gin-cache-stats,
  image-gin-error-text, image-gin-error-banner, image-gin-preview,
  image-gin-thumb, image-gin-hidden)
- TFile cast → instanceof check (BatchDirectoryConvertLocalToRemote)
- require('fs')/require('path') → ES imports (allowed since
  isDesktopOnly: true)
- Hardcoded ".obsidian/plugins/image-gin/..." paths replaced with
  ${vault.configDir}/plugins/image-gin/... (logger, imageCacheService)
- Async input handlers wrapped: addEventListener('input', () => void
  (async () => { ... })()) so the listener type matches
- forEach((opt) => dd.addOption(...)) blocks made void-returning
- JSON.parse results typed as unknown then narrowed
- Logger console-method dispatch rewritten as a switch instead of
  dynamic console[level] indexing
- Replaced builtin-modules dev-dependency with node:module's
  builtinModules — same data, no extra package
- DragEventCopy/PasteEventCopy classes (which used 'instanceof' on
  user classes) replaced with sentinel-tagged factory functions
  (makeSyntheticDragEvent / isSyntheticDropEvent) so we don't trip
  the obsidianmd/prefer-instanceof rule for non-Obsidian classes

Bumps version to 0.2.1.

Plan + design rationale:
context-v/issues/Obsidian-Review-Bot-Feedback-on-Perplexed-Submission.md
context-v/reminders/Obsidian-Marketplace-Compliance.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 03:47:52 -05:00
mpstaton
b6e7d7f6ed feat(drop-gate): confirm modal for every dragged or pasted image — v0.2.0
Image Gin now intercepts every image dropped or pasted into a markdown
note and asks where it should go: vault attachments, ImageKit, or
Imgur. Built for writers who handle private client imagery and don't
want a default-on third-party uploader silently shipping screenshots
to a public CDN. Default is the vault. ImageKit is the recommended
destination for less-public information that still wants a CDN. Imgur
is there when something is genuinely shareable.

Off by default. Enable in Settings → Image Gin → "Drag-Drop / Paste
Confirmation Gate". Two policy modes:

- always-confirm — modal on every image drop or paste
- external-only — vault drops fall through silently; modal only
  appears when at least one external destination is enabled

Per-session "remember choice" checkbox in the modal skips the gate for
subsequent drops in the same note, resets on active-leaf-change, and
never persists across Obsidian restarts. A reset command is registered
under "Drop Gate: Reset session-remembered destination."

Three destinations behind a small DropGateDestination interface:

- VaultDestination — re-dispatches a synthetic event copy into
  Obsidian's internal view.currentMode.clipboardManager so the default
  attachment-handling code runs cleanly. Falls back to
  Vault.createBinary + FileManager.generateMarkdownLink if the
  internal surface ever disappears.
- ImageKitDestination — thin adapter over the existing
  ImageKitService.uploadFile pipeline image-gin already uses for
  "Convert Local Images to Remote." Honors a drop-gate-specific folder
  setting (settings.dropGate.imageKitFolder) that overrides the main
  upload folder when set, so ad-hoc dropped images can be routed
  somewhere different from generated images. Inherits the main folder
  when blank.
- ImgurDestination — anonymous client-ID upload to
  api.imgur.com/3/image. Hand-rolled multipart body because Obsidian's
  requestUrl doesn't accept FormData.

The modal is widened correctly (modalEl, not contentEl, per the
perplexed widening reminder), shows all three destinations every time
— configured ones selectable, un-configured ones greyed-out with a
hint pointing at the right setting — and captures cursor position
synchronously at drop-time, threading it through DropGateContext as
insertPos so editor.replaceRange lands the markdown link where the
user dropped, not wherever the cursor drifted while the modal was
open.

Conflict detection: if the third-party obsidian-imgur-plugin is also
enabled, both plugins handle every drop and the user gets two modals
back-to-back — preventDefault() blocks the browser default, not other
plugins. We surface a persistent Notice on plugin load telling the
user to disable the other one and configure Imgur from inside Image
Gin.

Bumps version to 0.2.0 (manifest.json, package.json, versions.json).

Plan + design rationale:
content-farm/context-v/plans/Image-Drop-Confirmation-Gate.md
Ship note:
plugin-modules/image-gin/changelog/2026-05-09_01.md
Interception pattern adapted from gavvvr/obsidian-imgur-plugin (MIT).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 02:03:00 -05:00
mpstaton
91922ccf80 fill(prompt): flesh out the Add-New-Model-Provider agent prompt
Replaces a stub (just a Gemini Imagen URL) with a complete agent-facing
instruction that references the canonical blueprint at
context-v/blueprints/Add-New-Image-API-to-Providers.md, lists the three
existing reference implementations (Recraft, Ideogram, Magnific), and
includes provider-specific notes for Gemini Imagen, Stability AI, and
Flux.

The intent: when adding a new provider, paste this prompt at the agent
and the agent has the canonical pattern, the reference files, the
required scope, and the validation steps in one place.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 01:29:07 -05:00
mpstaton
946db7aadc add(changelog), fix(manifest): pull forward 2025-07-20 release entry; add fundingUrl
Repatriates the original Image Gin plugin-release announcement from
content/changelog--code into this repo's changelog/. Same cross-tree
re-arch as the other plugins.

Also: adds 'fundingUrl' to manifest.json for parity with the rest of the
content-farm plugins (cite-wide, plunk-it, lmstud-yo, filestarter,
file-transporter all carry it; image-gin and perplexed were the holdouts).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 00:48:15 -05:00
mpstaton
6d9f77c9e3 revise(changelog): de-emphasize starter-fork lineage in retrospective
Tighten the retrospective to lead with this repo's own substance.
Lineage from the official Obsidian sample plugin is what every plugin
forks from on day one — not interesting and now relegated to a footnote
or removed entirely.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 21:57:50 -05:00
mpstaton
504822dcfd add(changelog): retrospective entry for 2025-07-21 substance commit
Seeds the changelog/ directory with a retrospective entry dated to the
first commit of substance in this repo, written in May 2026 from the
content-farm pseudomonorepo cleanup. The convention didn't exist when
the original work shipped; this entry exists so the upcoming GitHub
Content API roll-up loader has something from this plugin to surface
on the content-farm splash.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 21:50:08 -05:00
mpstaton
fd0ae6768c add(reminder): seed Obsidian-API-docs reminder for context-v
Adds a context-v/reminders/ note that points future humans and AI agents
to the canonical Obsidian API source of truth and lists the most common
community plugin review-bot rejection reasons. Same canonical reminder is
being seeded across every plugin in the content-farm ecosystem so the
content-farm splash's rolled-up context-v feed has reminders surfacing
from every plugin once the GitHub Content API loader lands.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 21:35:30 -05:00
mpstaton
94dead1946 chore(wip): snapshot before relocating into content-farm/plugin-modules
Pre-relocation snapshot captured on development. Bundles in-flight changes
to the modal UX, logger, and plugin-config docs alongside the new
context-v/prompts/Add-New-Model-Provider.md so the move into the
content-farm pseudomonorepo doesn't leave the work behind.

Master remains untouched; merge this development branch back into master
once the relocation settles.

Also included: fast-forward of development to match master prior to the
WIP commit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 19:53:00 -05:00
mpstaton
351e1a2400 improve(modals): bring Recraft + Ideogram modals to UX parity; bump to 0.1.1
Follow-up to the initial Ideogram integration. Addresses friction the
user hit while actually using the plugin: opaque brand-template fields,
no "select all" affordance on size toggles, modal state forgotten
between opens, and an invisible image_prompt frontmatter convention.

Both modals now share:
- Master "All" toggle in the Image Sizes header with two-way sync to
  individual size toggles
- last-session persistence via plugin.saveData() (selected sizes,
  writeToFrontmatter; plus per-call overrides for Ideogram)
- Auto-creation of empty image_prompt frontmatter key on modal open
  so the convention is visible to first-time users
- Diagnostic [Recraft] / [Ideogram] logging in the size-toggle path

Ideogram-specific copy rewrite:
- Brand Template settings intro + per-field labels rewritten to make
  the bookend vs. slot-insertion modes explicit, with example placeholders
- Modal Resolved Prompt Preview now shows mode-aware guidance text
  (no template / slot insertion / bookend) above the preview
- Image Prompt section hint clarifies "subject matter only — style
  comes from settings"

Asymmetries that remain (custom style_id / imageStylesJSON for Recraft,
brand-template wrapping / per-call style overrides / layerize / per-file
frontmatter overrides for Ideogram) are genuine API-capability differences
documented in the changelog parity matrix.

Version bumped 0.1.0 → 0.1.1 across manifest.json, package.json, and
versions.json (kept prior version entries).

See context-v/changelogs/2026-05-03_02.md for full details.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 20:50:43 -05:00
mpstaton
8ccf7898dc fix(api-call): fix Ideogram api call that was causing an issue
On branch main
 Your branch is ahead of 'origin/main' by 1 commit.
   (use "git push" to publish your local commits)
 Changes to be committed:
	new file:   log.json
	modified:   main.ts
	new file:   src/modals/IdeogramModal.ts
	new file:   src/services/ideogramService.ts
	modified:   src/settings/settings.ts
	modified:   styles.css
2026-05-03 13:58:10 -05:00
mpstaton
e17159c834 new(context): new spec from context-v on implementing Ideogram API 2026-05-03 04:26:45 -05:00
mpstaton
c70885d6a4 align(api): align frontmatter parsing with Obsidian recent API changes
Replace the in-tree hand-rolled YAML parser with Obsidian's first-party
frontmatter APIs (`app.metadataCache.getFileCache(file)?.frontmatter`
for reads, `app.fileManager.processFrontMatter(file, fn)` for writes).
Closes Phase 4.3-B of the Obsidian community-plugin publishing-prep plan
at context-v/plans/2026-05-03_Assuring-Obsidian-Community-Plugin-Requirements.md.

Why
---
The earlier publishing-prep pass typed away the parser's `any` to
satisfy ObsidianReviewBot, which kept lint green but left the underlying
parser intact. The hand-rolled parser had real edge-case correctness
bugs the type system could not catch: URL values containing colons
were mis-split, multi-line strings were truncated, YAML anchors and
list-of-maps were not understood, and the in-tree YAML emitter would
produce `[object Object]` output for plain-object values. Obsidian's
own implementation handles all of those correctly and is the path the
Obsidian community-plugin guidelines explicitly point at. Carrying our
own parser meant carrying the bug surface forever; deleting it
externalizes that work.

Files
-----
Deleted:
- src/utils/yamlFrontmatter.ts (176 lines: parser + emitter +
  updateFileFrontmatter helper). No replacement file in our codebase
  — the responsibility moves to Obsidian's APIs.

Modified:
- src/modals/CurrentFileModal.ts — three usages refactored
- src/modals/ConvertLocalImagesForCurrentFile.ts — three usages
  refactored, including the largest restructure (see below)
- context-v/changelogs/2026-05-03_01.md — appended a §6 covering this
  phase, updated the front-matter title and summary intro to claim
  completion of every blocking publishing-prep phase, added the parser
  to the deleted-files inventory at the bottom

Call-site categorization (5 sites total)
----------------------------------------
Pure reads → `metadataCache.getFileCache(file)?.frontmatter`:
- CurrentFileModal.loadExistingPrompt — was reading `image_prompt`
  to seed the modal textarea. Bonus: removes a `vault.read` (the cache
  is in-memory and synchronous) so the modal opens marginally faster
  on files without an existing prompt.
- ConvertLocalImagesForCurrentFile.analyzeCurrentFile — discovers
  image properties on file open.
- ConvertLocalImagesForCurrentFile.handleConvert — snapshots
  frontmatter once at the top of the loop for tag extraction. Tags
  are only used as upload metadata, not as a source of truth, so a
  one-time snapshot is fine and avoids re-fetching from cache on
  every iteration.

Single-key writes → `app.fileManager.processFrontMatter(file, fn)`:
- CurrentFileModal.updateFrontmatter — writes `image_prompt`.
- CurrentFileModal.updateImagePathInFrontmatter — writes
  `<size>_image` keys with the URL of a generated image.

Both single-key writes now follow the uniform pattern:

    await this.app.fileManager.processFrontMatter(file, (fm) => {
        fm[key] = value;
    });

processFrontMatter reads, mutates, and writes atomically via
Obsidian's own YAML emitter — no hand-rolled vault.read /
formatFrontmatter / vault.modify cycle, no race window between read
and re-write.

The harder case: handleConvert's mixed-mutation loop
----------------------------------------------------
The original handleConvert read the file once, parsed frontmatter into
an object, peeled off the body, then ran two long async loops:

  1. For each frontmatter image: upload to ImageKit, then
     `frontmatter[key] = uploadResult.url` in the in-memory object.
  2. For each markdown body image: upload, then
     `markdownContent = markdownContent.replace(...)` in the in-memory
     string.

After both loops, it reassembled the file as
`---\n${formatFrontmatter(frontmatter)}---\n\n${markdownContent}` and
wrote the whole thing with vault.modify. The formatFrontmatter step
was where the hand-rolled YAML emitter was doing its damage.

Restructured so frontmatter and body live on independent code paths:

- Frontmatter mutations: each upload's frontmatter assignment now
  calls processFrontMatter directly — atomic per upload, written by
  Obsidian's emitter.
- Body mutations: accumulated into a `bodyMutations: Array<{from, to}>`
  list during the markdown-image loop. After both loops complete, a
  single vault.read(file) + N string replacements + one
  vault.modify(file, updated) flushes them. The body re-read happens
  *after* all processFrontMatter calls so it picks up the latest
  version (including the frontmatter changes those calls just made);
  no stale-content / lost-update race.

Also pulled `const file = this.currentFile;` to a local once at the
top of handleConvert so TypeScript's narrowing survives across
awaits — without the alias, the `if (!this.currentFile) return;`
guard is invalidated at every await boundary because modal lifecycle
could in principle null out currentFile.

Verification
------------
- pnpm build green: ESLint (the bot-mirror flat config from the
  prior commit) + tsc strict + esbuild production.
- git grep -nE ": any\\b|as any\\b|<any>|any\\[\\]" -- "*.ts" empty.
- git grep -n "innerHTML" -- "*.ts" empty.
- main.js bundle 54 KB → 52 KB (the deleted parser was being bundled
  in; net -2 KB shipped to users).
- All four version markers still in sync at 0.1.0
  (manifest.json, package.json, versions.json key + value).

Risk worth knowing about
------------------------
processFrontMatter's callback signature is `(frontmatter: any) => void`
per Obsidian's type definitions. We mutate `fm[key] = value` directly
without a cast — that's the path of least friction, and the bot's
no-explicit-any rule does not fire because we are not *writing* `any`
in our source (we are receiving it from a third-party API). If a
future Obsidian update tightens the type to `Record<string, unknown>`,
our callsites will keep compiling. If it tightens to a stricter shape,
narrowing at the callsite is a small change.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 02:03:06 -05:00
mpstaton
e117ceaf54 update(logs): update console log hygiene across many files
Changes to be committed:
	deleted:    .eslintignore
	deleted:    .eslintrc
	modified:   README.md
	new file:   context-v/changelogs/2026-05-03_01.md
	new file:   context-v/plans/2026-05-03_Assuring-Obsidian-Community-Plugin-Requirements.md
	new file:   eslint.config.mjs
	modified:   main.ts
	modified:   manifest.json
	modified:   package.json
	modified:   src/modals/BatchDirectoryConvertLocalToRemote.ts
	modified:   src/modals/ConvertLocalImagesForCurrentFile.ts
	modified:   src/modals/CurrentFileModal.ts
	modified:   src/modals/MagnificModal.ts
	modified:   src/services/imageCacheService.ts
	modified:   src/services/imagekitService.ts
	modified:   src/services/magnificService.ts
	modified:   src/services/recraftImageService.ts
	modified:   src/settings/settings.ts
	modified:   src/types/index.ts
	modified:   src/types/obsidian.d.ts
	new file:   src/utils/coerce.ts
	modified:   src/utils/logger.ts
	modified:   src/utils/yamlFrontmatter.ts
	modified:   versions.json
2026-05-03 01:35:13 -05:00
mpstaton
0cb935d55b improve(modals): improve modal for Magnific image selection, improve
image response rate, embedding image in document
2026-05-03 00:52:34 -05:00
mpstaton
bd6055f0de update(dependencies, providers): update all dependencies, support
Magnific after rebranding from Freepik

 On branch master
 Your branch is up to date with 'origin/master'.
 Changes to be committed:
	new file:   CLAUDE.md
	new file:   context-v/Chore-to-Update-All-Dependencies.md
	new file:   context-v/changelogs/2026-05-02_01.md
	modified:   main.ts
	modified:   package.json
	modified:   pnpm-lock.yaml
	new file:   pnpm-workspace.yaml
	renamed:    src/modals/FreepikModal.ts -> src/modals/MagnificModal.ts
	deleted:    src/services/freepikService.ts
	modified:   src/services/imageCacheService.ts
	new file:   src/services/magnificService.ts
	modified:   src/services/recraftImageService.ts
	modified:   src/settings/settings.ts
	modified:   src/styles/current-file-modal.css
	renamed:    src/styles/freepik.css -> src/styles/magnific.css
	modified:   src/utils/logger.ts
	modified:   styles.css
	modified:   tsconfig.json
2026-05-02 23:41:43 -05:00
mpstaton
42fab025e1 feature(Freepik): select stock images from Freepik
Changes to be committed:
	modified:   README.md
	modified:   main.ts
	new file:   src/modals/FreepikModal.ts
	new file:   src/services/freepikService.ts
	new file:   src/services/imageCacheService.ts
	modified:   src/settings/settings.ts
	new file:   src/styles/freepik.css
2025-09-15 16:43:22 +02:00
mpstaton
8a0efcf797 Merge branch 'development' 2025-09-14 20:27:59 +02:00
mpstaton
7f67d94c5e feature(modal): add new modal that enables batch image uploads
On branch development
 Your branch is up to date with 'origin/development'.
 Changes to be committed:
	modified:   README.md
	modified:   main.ts
	modified:   manifest.json
	modified:   package.json
	new file:   src/modals/BatchDirectoryConvertLocalToRemote.ts
2025-09-14 20:24:34 +02:00
mpstaton
ba0ade35fe clean(file): remove unnecessary file
On branch development
 Your branch is up to date with 'origin/development'.
 Changes to be committed:
	deleted:    add
2025-08-11 11:33:11 +02:00
mpstaton
769b3b5c61 feat(uploads): uploads local files found in markdown text and replaces
with unique url from image service, for now ImageKit

 On branch development
 Your branch is up to date with 'origin/development'.
 Changes to be committed:
	modified:   README.md
	new file:   add
	new file:   git
	modified:   src/modals/ConvertLocalImagesForCurrentFile.ts
	modified:   styles.css
2025-07-30 02:32:14 +03:00
mpstaton
1fd68e7406 Merge branch 'development'
merge(development): merge development into master
2025-07-30 02:28:21 +03:00
mpstaton
09868ddd1f feat(uploads): uploads local files found in markdown text and replaces
with unique url from image service, for now ImageKit

 On branch development
 Your branch is up to date with 'origin/development'.
 Changes to be committed:
	modified:   README.md
	new file:   add
	new file:   git
	modified:   src/modals/ConvertLocalImagesForCurrentFile.ts
	modified:   styles.css
2025-07-30 02:27:28 +03:00
mpstaton
324437effa fix(yaml): fix unwanted wrapping of tags with quotes
On branch master
 Your branch is up to date with 'origin/master'.
 Changes to be committed:
	modified:   src/utils/yamlFrontmatter.ts
2025-07-22 18:54:36 +03:00
mpstaton
8c1f3aef4a fix(yaml): fix unwanted wrapping of tags with quotes
On branch master
 Your branch is up to date with 'origin/master'.
 Changes to be committed:
	modified:   src/utils/yamlFrontmatter.ts
2025-07-22 18:52:30 +03:00
TanujKS
0fa52493e3 chore(files) Removed extra files that were ported over from starter project 2025-07-21 14:00:47 -07:00
mpstaton
9b3d2e8e9c update(version): update version now that basic functionality on single
file is working

 On branch development
 Your branch is up to date with 'origin/development'.
 Changes to be committed:
	modified:   manifest.json
	modified:   package.json
	modified:   versions.json
2025-07-21 03:10:59 +03:00
mpstaton
e83c790411 fix(settings), improve(readme): improve readme and fix settings
On branch development
 Your branch is up to date with 'origin/development'.
 Changes to be committed:
	modified:   README.md
	modified:   src/settings/settings.ts
	modified:   src/utils/yamlFrontmatter.ts
2025-07-21 02:15:04 +03:00
mpstaton
45396f8924 milestone(modal): command launching local to remote images now works
with user set image parameters

 On branch development
 Your branch is up to date with 'origin/development'.
 Changes to be committed:
	modified:   main.ts
	new file:   src/modals/ConvertLocalImagesForCurrentFile.ts
	modified:   src/services/imagekitService.ts
	modified:   src/settings/settings.ts
2025-07-21 01:39:47 +03:00
mpstaton
7a150b94d6 add(service): add imagekit service
On branch development
 Your branch is up to date with 'origin/development'.
 Changes to be committed:
	deleted:    src/services/citationService.ts.backup
	new file:   src/services/imagekitService.ts
2025-07-21 01:20:09 +03:00
mpstaton
e64af90c16 milestone(settings): absolute paths now work
On branch development
 Your branch is ahead of 'origin/development' by 1 commit.
   (use "git push" to publish your local commits)
 Changes to be committed:
	modified:   src/modals/CurrentFileModal.ts
2025-07-21 00:53:53 +03:00
mpstaton
2f8f8dd79c milestone(api): ImageKit API call now storing files in the right place
On branch development
 Your branch is up to date with 'origin/development'.
 Changes to be committed:
	modified:   src/services/recraftImageService.ts
	modified:   src/settings/settings.ts
2025-07-21 00:44:21 +03:00
mpstaton
caf05dfac0 progress(image-styles): branded image styles now go with the request.
On branch development
 Your branch is up to date with 'origin/development'.
 Changes to be committed:
	modified:   src/modals/CurrentFileModal.ts
2025-07-21 00:08:43 +03:00
mpstaton
c54fe5a502 progress(modal): modal now appearing and API call is now working
On branch development
 Your branch is up to date with 'origin/development'.
 Changes to be committed:
	modified:   esbuild.config.mjs
	modified:   main.ts
	deleted:    src/modals/CitationModal.ts.backup
	modified:   src/modals/CurrentFileModal.ts
	new file:   src/services/recraftImageService.ts
	modified:   src/settings/settings.ts
	deleted:    src/styles/citations.css.backup
	renamed:    src/styles/plugin-basics.css -> src/styles/current-file-modal.css
2025-07-21 00:01:50 +03:00
mpstaton
559a76abc2 remove(script): remove script that required another library, opted for
JS script

 On branch development
 Your branch is up to date with 'origin/development'.
 Changes to be committed:
	deleted:    scripts/test-recraft-api.ts
2025-07-20 20:43:59 +03:00
mpstaton
0a33233236 inspect(api-response): add scripts to inspect API response
On branch feature/settings
 Changes to be committed:
	modified:   .gitignore
	new file:   reference/model-recraft-response.md
	new file:   scripts/test-api.js
	modified:   scripts/test-recraft-api.ts
	modified:   src/settings/settings.ts
2025-07-20 20:42:04 +03:00
mpstaton
5099e99d71 progress(settings): progress on settings ui and accuracy
On branch feature/settings
 Changes to be committed:
	new file:   .env.example
	new file:   scripts/test-recraft-api.ts
	modified:   src/settings/settings.ts
	modified:   src/types/index.ts
	modified:   styles.css
2025-07-20 19:59:24 +03:00
mpstaton
f059096a5a progress(settings): progress on settings for ImageGin
On branch feature/settings
 Changes to be committed:
	modified:   main.ts
	deleted:    src/services/cleanReferencesSectionService.ts.backup
	modified:   src/settings/settings.ts
2025-07-20 19:24:18 +03:00
mpstaton
0dce9409a7 update(settings, types): updated settings and types as initial setup
On branch feature/settings
 Changes to be committed:
	new file:   src/settings/settings.ts
	modified:   src/types/index.ts
2025-07-20 18:35:16 +03:00
mpstaton
d3245b8115 update(readme, license): udpates to readme and license
On branch master
 Your branch is up to date with 'origin/master'.
 Changes to be committed:
	new file:   LICENSE
	modified:   README.md
2025-07-20 17:17:34 +03:00