Skip to content

docs: use mermaid on typedoc output#32

Merged
snipsnipsnip merged 11 commits intoexteditor:mainfrom
snipsnipsnip:fix-typedoc
Oct 7, 2025
Merged

docs: use mermaid on typedoc output#32
snipsnipsnip merged 11 commits intoexteditor:mainfrom
snipsnipsnip:fix-typedoc

Conversation

@snipsnipsnip
Copy link
Copy Markdown
Member

@snipsnipsnip snipsnipsnip commented Oct 7, 2025

  • Remove typedoc-plugin-mermaid and replace with a custom script
  • Add an example tasks.json for vscode
  • Add BUILDING.md as a shorter version of CONTRIBUTING.md
  • Mention transitive dependencies in NOTICE.md
  • Fix wording and broken links in doc/
  • Also some refactoring that split some of longer classes

Summary by CodeRabbit

  • New Features

    • Added BUILDING guide and startup helpers for editor/session flow.
  • Documentation

    • README, FAQ, design, NOTICE, typedoc and rendering updates; badges and changelog adjusted.
  • Refactor

    • Background/startup and editor/session orchestration reorganized for clearer flows.
  • Chores

    • CI uploader upgraded; dependency and tooling updates; schema and packaging/script adjustments.
  • Developer Experience

    • VS Code task examples and standardized test output paths added.
  • Tests

    • Improved test helpers and assertions.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Oct 7, 2025

📝 Walkthrough

Walkthrough

Adds GhostTextStarter and EmailEditorFactory, refactors GhostTextRunner to an instance/session API (GhostTextSession), introduces withRouter for lazy background router initialization and caching, makes ComposeTab tabId public, exports Alarm types, and updates tooling, configs, docs, and package manifest.

Changes

Cohort / File(s) Summary
CI Workflow
.github/workflows/doc.yml
Updated actions/upload-pages-artifact from v3 to v4.
Editor / Dev Environment
.vscode/tasks.example.json
Added VSCode task examples: tsc:once, tsc:watch, tsdown:once, tsdown:watch.
WebExt Config
.web-ext-config.example.mjs
Made firefoxProfile path runtime-dynamic using import.meta.dirname to .cache/thunderbird-testing-profile.
Documentation & Notices
BUILDING.md, CONTRIBUTING.md, README.md, doc/design.md, doc/faq.md, doc/res/typedoc.cjs, ext/NOTICE.md
Added BUILDING.md; wording/anchor updates; mermaid diagram arrow tweaks; typedoc client-side mermaid loader added; NOTICE updated to fixed release-tag URLs and new library entries.
Tooling / Config
biome.jsonc, tsconfig.json, tools/tsdown_config.ts, tools/vitest_config.ts
Biome schema bumped; TypeDoc options updated and plugin swap to typedoc-plugin-mdn-links; tests no longer excluded from docs; added noExternal: /(?:)/; introduced OUTPUT_DIR constant for vitest config.
Package Manifest
package.json
Reorganized dependencies/devDependencies; moved webext-events and webext-options-sync to dependencies; bumped TypeScript; removed doc:md script; swapped TypeDoc plugins.
Background routing / startup
src/root/background.ts, src/root/background_helper.ts, src/root/startup/startup_background.ts
Replaced inline router wiring with new withRouter helper that lazily initializes and caches a BackgroundEventRouter; removed commandConfig: ICommandConfig from BackgroundCatalog imports.
GhostText orchestration
src/ghosttext-runner/ghost_text_runner.ts, src/ghosttext-runner/ghost_text_starter.ts, src/ghosttext-session/ghost_text_client.ts
Refactored GhostTextRunner to instance/session API with run(g: GhostTextSession), lastStatus getter and close(); added singleton GhostTextStarter to orchestrate heartbeat/options/runner lifecycle; exported GhostTextSession type and updated GhostTextClient to return it.
Compose action / editor factory
src/app-background/compose_action_notifier.ts, src/ghosttext-adaptor/email_editor_factory.ts
ComposeActionNotifier now depends on GhostTextStarter and EmailEditorFactory; added EmailEditorFactory singleton that loads client options and constructs EmailEditor.
Background event router
src/app-background/background_event_router.ts
Added JSDoc above private runCommand describing execution within a compose-tab context; no signature/behavior changes.
Thunderbird adapters / types
src/thunderbird/background_util/compose_tab.ts, src/thunderbird/messenger/alarms.ts
ComposeTab now exposes readonly tabId (replaced internal id and removed getter); exported AlarmInfo and Alarm types and added when, scheduledTime, and periodInMinutes fields.
Options / small docs
src/app-options/api.ts, src/thunderbird/options_util/options_store.ts
Minor JSDoc tweak in IOptionsStore.syncForm; removed a docblock above syncForm.
DI / utilities / tests
src/root/util/wireless.ts, src/test/startup.test.ts
Introduced an injector constant and registered it under $injector; dependency resolution can auto-derive names from constructors; test helpers refactored with safer parsing, destructuring, and soft assertions.
Miscellaneous
ext/NOTICE.md, doc/res/typedoc.cjs, BUILDING.md
NOTICE links updated to fixed release tags; typedoc mermaid loader added; BUILDING.md added to repo docs.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant TB as Thunderbird UI
  participant BG as Background (entry)
  participant BH as background_helper
  participant SB as startup_background
  participant R as BackgroundEventRouter

  User->>TB: Trigger compose action / command
  TB->>BG: emit event (onClicked/onCommand/onMessage)
  BG->>BH: withRouter(handler)
  alt router cached
    BH->>R: run handler with cached router
  else initialize router
    BH->>SB: prepareBackgroundRouter()
    SB-->>BH: router
    BH->>R: run handler with new router
  end
  R-->>BG: Handler completes
Loading
sequenceDiagram
  autonumber
  actor User
  participant BG as ComposeActionNotifier
  participant EF as EmailEditorFactory
  participant ST as GhostTextStarter
  participant HB as Heart
  participant GC as GhostTextClient
  participant GR as GhostTextRunner
  participant SRV as GhostText Server

  User->>BG: Compose action invoked
  BG->>EF: create(tab, port)
  EF->>EF: load client options
  EF-->>BG: EmailEditor
  BG->>ST: run(statusIndicator, editor)
  ST->>HB: start heartbeat
  ST->>GC: run() → GhostTextSession
  ST->>GR: new GhostTextRunner(connector, options, statusIndicator, editor)
  GR->>SRV: handshake/session commands
  loop session active
    GR->>SRV: send command
    SRV-->>GR: command result
    GR->>GR: update status/editor
  end
  GR-->>ST: close()
  ST->>HB: stop heartbeat
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

I twitch my whiskers, tap the keys—
New starters hum and runners breeze.
A factory builds the editor bright,
Routers wake and cache at night.
Docs, badges, tweaks — a joyous carrot bite. 🥕

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description Check ⚠️ Warning The pull request description does not follow the repository’s required template, as it lacks the license agreement checkbox, the change type checklist, sections for current and new behavior, manual test steps, and any closing remarks, rendering it incomplete against the prescribed structure. Please update the description to use the repository template by including the license agreement, selecting the change type, outlining the current and new behavior, providing manual testing steps, and adding any other relevant details.
Docstring Coverage ⚠️ Warning Docstring coverage is 60.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Title Check ✅ Passed The title “docs: use mermaid on typedoc output” directly captures the main purpose of the changeset, namely replacing the Typedoc Mermaid plugin with a custom Mermaid integration in the generated documentation, and it is concise and specific without extraneous wording.
✨ Finishing touches
  • 📝 Docstrings were successfully generated. (🔄 Check again to generate docstrings again)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
package.json (1)

26-27: Restore the markdown TypeDoc plugin or adjust the script.

doc:md still invokes --plugin typedoc-plugin-markdown, but the dependency was dropped from devDependencies, so the script now fails. Either keep the plugin installed or update the script to match the new tooling.

Apply this diff to keep the script working:

-    "doc:md": "run doc --plugin typedoc-plugin-markdown",
+    "doc:md": "run doc",

…or re-add typedoc-plugin-markdown to devDependencies if you still need that plugin.

src/ghosttext-runner/ghost_text_runner.ts (1)

15-82: Cache the latest client status instead of defaulting to “error”

lastStatus currently returns "error" whenever the session generator hasn’t finished yet. When callers invoke close() mid-session (while we’re still handling commands like "notifyStatus" with "running"), the status indicator is incorrectly updated to "error", producing a false failure state for the user.

Track the most recent translated status explicitly—update it whenever we process a notifyStatus command and when the generator completes—so lastStatus always reflects reality.

 export class GhostTextRunner {
   private command: IteratorResult<Command, SessionStatus> | undefined
   private session: ISession | undefined
+  private status: ClientStatus = "inactive"
@@
   get lastStatus(): ClientStatus {
-    return this.command?.done ? translateStatus(this.command.value) : "error"
+    return this.status
   }
@@
   close(): Promise<void> {
     this.session?.close()
-    return this.statusIndicator.update(this.lastStatus).catch(() => {})
+    return this.statusIndicator.update(this.lastStatus).catch(() => {})
   }
 
   async run(g: GhostTextSession): Promise<void> {
     this.command = g.next()
+    this.updateFinalStatus()
 
     while (!this.command.done && this.command.value.type !== "queryEditor") {
       let [r, s] = await this.runHandshakeCommand(this.command.value)
@@
       this.session ??= s
 
       this.command = g.next(r)
+      this.updateFinalStatus()
     }
 
     if (!this.session) {
       return
     }
 
     while (!this.command.done) {
       let result = await this.runSessionCommand(this.session, this.command.value)
 
       this.command = g.next(result)
+      this.updateFinalStatus()
     }
   }
 
   async runHandshakeCommand(command: Command): Promise<[CommandResult, ISession?]> {
     switch (command.type) {
@@
       case "notifyStatus":
-        await this.statusIndicator.update(translateStatus(command.status))
+        this.status = translateStatus(command.status)
+        await this.statusIndicator.update(this.status)
         return [{ type: "statusUpdated" }]
@@
   async runSessionCommand(session: ISession, command: Command): Promise<CommandResult> {
@@
       case "notifyStatus":
-        await this.statusIndicator.update(translateStatus(command.status))
+        this.status = translateStatus(command.status)
+        await this.statusIndicator.update(this.status)
         return { type: "statusUpdated" }
@@
   }
+
+  private updateFinalStatus(): void {
+    if (this.command?.done) {
+      this.status = translateStatus(this.command.value)
+    }
+  }
 }
🧹 Nitpick comments (3)
tools/tsdown_config.ts (1)

55-55: Clarify use of empty regex in noExternal

The pattern /(?:)/ matches the empty string at every position, so it will treat all dependencies as non-external (bundling everything)—equivalent to true. If you intended to bundle every dependency, use true; otherwise supply a more specific regex.

src/test/startup.test.ts (1)

148-154: Consider edge cases in the regex pattern.

The regex pattern /\bconstructor\s*[(]\s*[{]?\s*[^{]+[{][^}]+[}]/d may not match all constructor formats, particularly:

  • Constructors with complex parameter destructuring
  • Multi-line constructors with irregular spacing
  • Constructors with nested braces

While this appears to work for the current codebase, consider adding a comment explaining the expected constructor format or documenting known limitations.

src/ghosttext-runner/ghost_text_starter.ts (1)

15-28: Excellent orchestration with proper cleanup.

The run method effectively coordinates the GhostText workflow:

  • Heartbeat lifecycle is properly managed (start/stop)
  • Options are loaded before runner creation
  • Cleanup in the finally block ensures resources are released regardless of success or failure
  • The flow integrates well with the new GhostTextSession type

Consider the production console.log.

The console.log on Line 24 ("generator finished") may be verbose for production environments. Consider whether this should be at a different log level or removed for production builds.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between de5e930 and f8f7f9e.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (30)
  • .github/workflows/doc.yml (1 hunks)
  • .vscode/tasks.example.json (1 hunks)
  • .web-ext-config.example.mjs (1 hunks)
  • BUILDING.md (1 hunks)
  • CONTRIBUTING.md (1 hunks)
  • README.md (7 hunks)
  • biome.jsonc (1 hunks)
  • doc/design.md (5 hunks)
  • doc/faq.md (3 hunks)
  • doc/res/typedoc.cjs (1 hunks)
  • ext/NOTICE.md (1 hunks)
  • package.json (2 hunks)
  • src/app-background/background_event_router.ts (1 hunks)
  • src/app-background/compose_action_notifier.ts (2 hunks)
  • src/app-options/api.ts (1 hunks)
  • src/ghosttext-adaptor/email_editor_factory.ts (1 hunks)
  • src/ghosttext-runner/ghost_text_runner.ts (2 hunks)
  • src/ghosttext-runner/ghost_text_starter.ts (1 hunks)
  • src/ghosttext-session/ghost_text_client.ts (1 hunks)
  • src/root/background.ts (1 hunks)
  • src/root/background_helper.ts (1 hunks)
  • src/root/startup/startup_background.ts (1 hunks)
  • src/root/util/wireless.ts (1 hunks)
  • src/test/startup.test.ts (1 hunks)
  • src/thunderbird/background_util/compose_tab.ts (4 hunks)
  • src/thunderbird/messenger/alarms.ts (2 hunks)
  • src/thunderbird/options_util/options_store.ts (0 hunks)
  • tools/tsdown_config.ts (1 hunks)
  • tools/vitest_config.ts (2 hunks)
  • tsconfig.json (1 hunks)
💤 Files with no reviewable changes (1)
  • src/thunderbird/options_util/options_store.ts
🧰 Additional context used
🧬 Code graph analysis (7)
src/ghosttext-runner/ghost_text_starter.ts (3)
src/ghosttext-runner/api.ts (5)
  • IGhostTextConnector (20-27)
  • IClientOptionsLoader (39-44)
  • IHeart (11-17)
  • IStatusIndicator (109-116)
  • IClientEditor (74-96)
src/ghosttext-session/ghost_text_client.ts (1)
  • GhostTextClient (30-70)
src/ghosttext-runner/ghost_text_runner.ts (1)
  • GhostTextRunner (4-86)
src/root/util/wireless.ts (2)
src/root/util/wire.ts (4)
  • wire (157-160)
  • wire (233-247)
  • IClassInfo (25-58)
  • KeyOf (20-20)
src/root/util/wired.ts (1)
  • wired (16-21)
src/ghosttext-adaptor/email_editor_factory.ts (3)
src/ghosttext-runner/api.ts (1)
  • IClientOptionsLoader (39-44)
src/ghosttext-adaptor/api.ts (1)
  • IComposeWindow (34-65)
src/ghosttext-adaptor/email_editor.ts (1)
  • EmailEditor (12-54)
src/root/background_helper.ts (2)
src/app-background/background_event_router.ts (1)
  • BackgroundEventRouter (5-52)
src/root/startup/startup_background.ts (1)
  • prepareBackgroundRouter (27-35)
src/app-background/compose_action_notifier.ts (2)
src/ghosttext-runner/ghost_text_starter.ts (1)
  • GhostTextStarter (5-29)
src/ghosttext-adaptor/email_editor_factory.ts (1)
  • EmailEditorFactory (5-14)
src/ghosttext-runner/ghost_text_runner.ts (2)
src/ghosttext-session/ghost_text_client.ts (4)
  • Command (12-17)
  • SessionStatus (10-10)
  • GhostTextSession (28-28)
  • CommandResult (19-26)
src/ghosttext-runner/api.ts (6)
  • ISession (47-69)
  • IGhostTextConnector (20-27)
  • ClientOptions (30-34)
  • IStatusIndicator (109-116)
  • IClientEditor (74-96)
  • ClientStatus (106-106)
src/thunderbird/background_util/compose_tab.ts (3)
src/ghosttext-runner/message.ts (1)
  • MessagesFromBackground (3-6)
src/ghosttext-adaptor/api.ts (1)
  • IGhostServerPort (91-91)
src/thunderbird/util/promisified_port.ts (1)
  • PromisifiedPort (12-67)
🔇 Additional comments (21)
src/app-options/api.ts (1)

7-7: LGTM! Documentation now matches the parameter name.

The JSDoc @param tag now correctly references "form" instead of the previous parameter name, improving documentation accuracy and consistency with the function signature.

src/thunderbird/messenger/alarms.ts (1)

30-30: Approve exported types
Exporting AlarmInfo and Alarm is an additive, non-breaking change—no internal imports are required, as these types are exposed for external consumers.

src/thunderbird/background_util/compose_tab.ts (2)

8-9: LGTM! Clean refactoring to public property.

The change from private readonly id with a getter to readonly tabId is more idiomatic and provides direct access to the property. All internal usages have been consistently updated throughout the class.


60-64: LGTM! Improved debugging with port naming.

Adding a name parameter to the port connection using import.meta.url is a good practice. This will help identify which module created the connection during debugging, making it easier to trace port lifecycle issues.

src/root/util/wireless.ts (3)

49-50: LGTM!

The registry key change from "$wire$" to "$injector" better reflects the purpose of the registered function. The comment clearly explains the intent.


52-52: LGTM!

Returning the injector wrapper instead of an inline function improves code clarity and maintainability.


45-47: Optional deps behavior and type‐safety are safe. parseConstructorForDependencyNames is fully tested and all current injector calls pass explicit deps, so no runtime risks detected.

CONTRIBUTING.md (1)

4-4: LGTM!

The addition of the MDN open source etiquette link provides helpful guidance for contributors.

.web-ext-config.example.mjs (1)

8-8: LGTM!

Using import.meta.dirname makes the path relative to the module location, improving portability. This is compatible with the Node.js v22 LTS requirement mentioned in CONTRIBUTING.md.

tools/vitest_config.ts (1)

4-5: LGTM!

Extracting the output directory path into a constant eliminates duplication and improves maintainability.

BUILDING.md (1)

1-7: Referenced documentation files exist. Both CONTRIBUTING.md and doc/building.md are present.

biome.jsonc (1)

2-2: No action required Schema version 2.2.5 is valid and contains only patch fixes with no breaking changes.

.github/workflows/doc.yml (1)

54-54: Validate upload-pages-artifact@v4 upgrade
In .github/workflows/doc.yml line 54, confirm v4’s removal of dotfiles and its pinned upload-artifact SHA won’t break your workflow—review the v4 release notes and adjust include/exclude patterns if needed.

src/app-background/background_event_router.ts (1)

23-23: LGTM!

The JSDoc comment clearly describes the method's purpose and aligns with the centralized routing changes introduced in this PR.

src/ghosttext-session/ghost_text_client.ts (1)

28-33: LGTM!

The introduction of the GhostTextSession type alias improves code readability and maintainability. The type signature correctly represents the generator's behavior.

src/test/startup.test.ts (1)

156-171: Good use of soft assertions for better error reporting.

The refactoring correctly uses expect.soft to collect multiple dependency usage failures in a single test run, which improves the developer experience. The destructuring pattern [name, [method, arg]] and the updated error message are clear improvements.

src/root/background.ts (1)

6-28: LGTM! Centralized routing simplifies the background script.

The refactoring successfully delegates routing logic to the centralized withRouter helper from background_helper. This:

  • Removes duplicated router management code
  • Provides consistent error handling across all event listeners
  • Simplifies the background script's responsibility to event registration only

The immediate startup log on Line 8 complements the existing "started" log on Line 34, providing visibility into the initialization lifecycle.

src/ghosttext-adaptor/email_editor_factory.ts (1)

5-14: LGTM! Clean factory pattern implementation.

The EmailEditorFactory properly encapsulates the creation logic for EmailEditor instances:

  • Singleton design is appropriate for this factory
  • Dependency injection of IClientOptionsLoader enables testability
  • The create method correctly loads options before constructing the editor
  • Clear separation of concerns between option loading and editor instantiation

This aligns well with the refactoring objectives of the PR.

src/app-background/compose_action_notifier.ts (2)

8-11: LGTM! Dependency injection aligned with factory pattern.

The constructor correctly uses the new GhostTextStarter and EmailEditorFactory dependencies, replacing the previous direct usage of GhostTextRunner and IClientOptionsLoader. This change:

  • Aligns with the factory and starter patterns introduced in this PR
  • Improves testability through dependency injection
  • Delegates orchestration concerns to appropriate components

23-26: LGTM! Factory-based editor creation is clean.

The refactored start method correctly:

  • Uses emailEditorFactory.create to obtain an EmailEditor instance
  • Passes the editor as both statusIndicator and editor parameters to ghostTextStarter.run, which is valid since EmailEditor implements both IStatusIndicator and IClientEditor interfaces (as confirmed by the relevant code snippets)

This simplifies the method by removing direct option loading and editor instantiation.

src/root/startup/startup_background.ts (1)

1-1: Manually verify removal of commandConfig references
Automated searches yielded no files due to glob filters; please confirm no code still references commandConfig.

@snipsnipsnip snipsnipsnip force-pushed the fix-typedoc branch 2 times, most recently from 40a4163 to a08c133 Compare October 7, 2025 03:38
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
package.json (1)

69-83: Restore the markdown plugin dependency.

yarn doc:md still runs typedoc --plugin typedoc-plugin-markdown, but the package is no longer listed anywhere in dependencies. TypeDoc will now fail to load that plugin, breaking the docs pipeline. Please add typedoc-plugin-markdown back to devDependencies (or drop the script if it’s truly unused).

   "devDependencies": {
     "@biomejs/biome": "^2.2.5",
     "@types/node": "^24.3.0",
@@
-    "typedoc": "^0.28.12",
-    "typedoc-plugin-mdn-links": "^5.0.9",
+    "typedoc": "^0.28.12",
+    "typedoc-plugin-markdown": "^4.2.4",
+    "typedoc-plugin-mdn-links": "^5.0.9",
♻️ Duplicate comments (1)
src/root/background_helper.ts (1)

15-50: Address the concurrent initialization race condition flagged in previous review.

As noted in the previous review, concurrent calls to withRouter before the first initialization completes can result in duplicate router initialization. The suggested fix with routerInit memoization is correct and should be implemented.

Additionally, consider whether withRouterSync should return undefined on error. Currently, errors are logged but not propagated, which may hide issues from callers who expect a Promise rejection.

Apply the diff from the previous review comment to fix the race condition. Additionally, consider this adjustment to error handling:

 function withRouterSync(handler: RouterHandler, router: BackgroundEventRouter): Promise<void> | undefined {
   try {
     return handler(router)
   } catch (error) {
     console.error({ error })
-    return
+    return Promise.reject(error)
   }
 }

This ensures errors are visible to callers who may need to handle failures appropriately.

🧹 Nitpick comments (2)
.web-ext-config.example.mjs (1)

8-8: Consider using path.join() for cross-platform compatibility.

While the change to use import.meta.dirname improves portability by removing hard-coded paths, string concatenation may cause issues on Windows or when import.meta.dirname has trailing separators.

Apply this diff for better cross-platform path handling:

+import { join } from "node:path";
+
 // You have to adjust it to debug
 // See: https://extensionworkshop.com/documentation/develop/web-ext-command-reference/#web-ext-run
 // See: https://extensionworkshop.com/documentation/develop/getting-started-with-web-ext/#use-a-custom-profile
 export default {
   run: {
     // You can use flatpak by specifying "flatpak:org.mozilla.Thunderbird"
     firefox: "/usr/bin/thunderbird",
-    firefoxProfile: import.meta.dirname + "/.cache/thunderbird-testing-profile/",
+    firefoxProfile: join(import.meta.dirname, ".cache", "thunderbird-testing-profile"),
     profileCreateIfMissing: true,
     // keepProfileChanges: true,
   },
 };

Note: import.meta.dirname requires Node.js 20.11.0+. Ensure this minimum version is documented if not already specified.

src/ghosttext-runner/ghost_text_runner.ts (1)

19-22: Consider propagating status update errors in close().

The close() method safely handles session cleanup with optional chaining. However, errors from statusIndicator.update() are silently caught and ignored. Consider whether callers should be aware of status update failures.

If status update failures are non-critical, the current implementation is acceptable. Otherwise, consider:

 close(): Promise<void> {
   this.session?.close()
-  return this.statusIndicator.update(this.lastStatus).catch(() => {})
+  return this.statusIndicator.update(this.lastStatus)
 }

This allows callers to decide how to handle status update failures.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bf30145 and 40a4163.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (26)
  • .github/workflows/doc.yml (1 hunks)
  • .vscode/tasks.example.json (1 hunks)
  • .web-ext-config.example.mjs (1 hunks)
  • BUILDING.md (1 hunks)
  • CONTRIBUTING.md (1 hunks)
  • README.md (7 hunks)
  • doc/design.md (5 hunks)
  • doc/faq.md (3 hunks)
  • doc/res/typedoc.cjs (1 hunks)
  • ext/NOTICE.md (1 hunks)
  • package.json (2 hunks)
  • src/app-background/background_event_router.ts (1 hunks)
  • src/app-background/compose_action_notifier.ts (2 hunks)
  • src/app-options/api.ts (1 hunks)
  • src/ghosttext-adaptor/email_editor_factory.ts (1 hunks)
  • src/ghosttext-runner/ghost_text_runner.ts (2 hunks)
  • src/ghosttext-runner/ghost_text_starter.ts (1 hunks)
  • src/ghosttext-session/ghost_text_client.ts (1 hunks)
  • src/root/background.ts (1 hunks)
  • src/root/background_helper.ts (1 hunks)
  • src/root/startup/startup_background.ts (1 hunks)
  • src/root/util/wireless.ts (1 hunks)
  • src/thunderbird/background_util/compose_tab.ts (4 hunks)
  • src/thunderbird/messenger/alarms.ts (2 hunks)
  • src/thunderbird/options_util/options_store.ts (0 hunks)
  • tsconfig.json (1 hunks)
💤 Files with no reviewable changes (1)
  • src/thunderbird/options_util/options_store.ts
✅ Files skipped from review due to trivial changes (1)
  • .github/workflows/doc.yml
🚧 Files skipped from review as they are similar to previous changes (10)
  • src/app-options/api.ts
  • doc/faq.md
  • src/root/startup/startup_background.ts
  • BUILDING.md
  • src/ghosttext-runner/ghost_text_starter.ts
  • .vscode/tasks.example.json
  • src/thunderbird/messenger/alarms.ts
  • doc/res/typedoc.cjs
  • doc/design.md
  • src/thunderbird/background_util/compose_tab.ts
🧰 Additional context used
🧬 Code graph analysis (5)
src/root/background_helper.ts (2)
src/app-background/background_event_router.ts (1)
  • BackgroundEventRouter (5-52)
src/root/startup/startup_background.ts (1)
  • prepareBackgroundRouter (27-35)
src/app-background/compose_action_notifier.ts (2)
src/ghosttext-runner/ghost_text_starter.ts (1)
  • GhostTextStarter (5-29)
src/ghosttext-adaptor/email_editor_factory.ts (1)
  • EmailEditorFactory (5-14)
src/ghosttext-runner/ghost_text_runner.ts (2)
src/ghosttext-session/ghost_text_client.ts (4)
  • Command (12-17)
  • SessionStatus (10-10)
  • GhostTextSession (28-28)
  • CommandResult (19-26)
src/ghosttext-runner/api.ts (6)
  • ISession (47-69)
  • IGhostTextConnector (20-27)
  • ClientOptions (30-34)
  • IStatusIndicator (109-116)
  • IClientEditor (74-96)
  • ClientStatus (106-106)
src/root/util/wireless.ts (2)
src/root/util/wire.ts (4)
  • wire (157-160)
  • wire (233-247)
  • IClassInfo (25-58)
  • KeyOf (20-20)
src/root/util/wired.ts (1)
  • wired (16-21)
src/ghosttext-adaptor/email_editor_factory.ts (3)
src/ghosttext-runner/api.ts (1)
  • IClientOptionsLoader (39-44)
src/ghosttext-adaptor/api.ts (1)
  • IComposeWindow (34-65)
src/ghosttext-adaptor/email_editor.ts (1)
  • EmailEditor (12-54)
🔇 Additional comments (20)
src/root/util/wireless.ts (3)

45-45: LGTM!

The refactoring to use constants improves code readability and makes the flow clearer.

Also applies to: 52-52


49-50: Registry key change verified—no remaining $wire$ references.


45-47: Verify auto-resolved dependency names and optimize parsing

The unchecked cast from string[] to KeyOf<TCatalog>[] in wireless.ts (lines 45–47) assumes constructor parameter names exactly match catalog keys, risking runtime failures if they don’t. Manually confirm all injected constructors align with your TCatalog keys or require explicit deps. To reduce overhead, cache parseConstructorForDependencyNames results in a WeakMap so each constructor is parsed only once.

src/app-background/background_event_router.ts (1)

23-23: LGTM! Clear documentation added.

The JSDoc comment accurately describes the method's purpose and improves code readability.

src/ghosttext-session/ghost_text_client.ts (2)

28-28: LGTM! Type alias improves code clarity.

Introducing the GhostTextSession type alias improves readability and enables consistent typing across the codebase.


33-33: LGTM! Return type correctly uses the new type alias.

The method signature correctly references the newly introduced GhostTextSession type, maintaining type safety.

src/root/background.ts (3)

6-6: LGTM! Centralized router management.

Importing withRouter from the dedicated helper module improves separation of concerns and code organization.


10-20: LGTM! Event handlers correctly use withRouter.

The event listeners are properly wrapped with withRouter, which handles initialization and error handling consistently. The error handling for unknown commands is appropriate.


22-28: LGTM! Message handler correctly integrated.

The onMessage listener properly uses withRouter and the sendResponse callback pattern.

src/ghosttext-adaptor/email_editor_factory.ts (2)

5-8: LGTM! Clean factory pattern with singleton indication.

The factory class is well-structured with proper dependency injection. The isSingleton flag correctly indicates this should be a singleton instance.


10-13: Consider error handling for options loading. The create method can reject if clientOptionsLoader.load() fails; ensure callers handle this.

Run:

#!/bin/bash
# Locate callers of EmailEditorFactory.create
rg -nP 'EmailEditorFactory\\.create\\(' -C5 -g '!**/test/**'
src/app-background/compose_action_notifier.ts (2)

8-11: LGTM! Constructor updated to use factory pattern.

The constructor correctly accepts GhostTextStarter and EmailEditorFactory dependencies, enabling better separation of concerns and testability.


23-30: LGTM! Start method correctly uses factory pattern.

The refactored start method:

  • Uses emailEditorFactory.create() for editor creation
  • Properly delegates to ghostTextStarter.run()
  • Maintains the try-finally block for cleanup

The error handling and cleanup logic are preserved correctly.

src/ghosttext-runner/ghost_text_runner.ts (6)

8-13: LGTM! Constructor refactored for instance-based state.

The constructor now properly injects options, statusIndicator, and editor as dependencies, enabling instance-based state management. This is a cleaner design compared to passing these in the run() method.


15-17: LGTM! Status getter provides clean access to session state.

The lastStatus getter correctly derives ClientStatus from the generator state using the translateStatus helper, with an appropriate fallback to "error" for incomplete states.


24-44: LGTM! Clean two-phase session flow.

The refactored run() method implements a clear two-phase approach:

  1. Handshake phase (lines 27-33): Establishes connection and session
  2. Session phase (lines 39-43): Processes commands during active session

The guard clause at lines 35-37 correctly handles the case where handshake fails to establish a session.


46-64: LGTM! Handshake command handling is robust.

The runHandshakeCommand method:

  • Correctly returns a tuple [CommandResult, ISession?]
  • Only returns a session from the "connect" command
  • Properly handles connection failures with error capture
  • Uses TypeScript exhaustiveness checking
  • Appropriately rejects unexpected commands during handshake

66-85: LGTM! Session command handling is well-structured.

The runSessionCommand method:

  • Correctly uses instance fields for editor and status indicator
  • Delegates editor-session coordination to the receiveChange helper
  • Handles all session command types appropriately
  • Maintains TypeScript exhaustiveness checking
  • Properly rejects unexpected commands during session

88-96: Clarify retry behavior when no edit or change is returned.
receiveChangeOnce returns undefined only if editor.popLastEdit() or session.popServerChange() yields a falsy value, causing receiveChange to loop forever. Confirm this infinite‐retry on missing data is intentional and won’t lead to unbounded loops in edge cases.

CONTRIBUTING.md (1)

4-4: Verified MDN Open source etiquette link is accessible (HTTP 200).

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
package.json (1)

26-83: Restore typedoc-plugin-markdown for doc:md.

doc:md still invokes typedoc --plugin typedoc-plugin-markdown, but the dependency was dropped from devDependencies. Running that script will now fail with “Cannot load plugin typedoc-plugin-markdown”. Please add the package back (or adjust the script).

   "devDependencies": {
     "@biomejs/biome": "^2.2.5",
@@
-    "typedoc-plugin-mdn-links": "^5.0.9",
-    "typescript": "^5.9.3",
+    "typedoc-plugin-markdown": "^4.1.0",
+    "typedoc-plugin-mdn-links": "^5.0.9",
+    "typescript": "^5.9.3",
♻️ Duplicate comments (1)
src/root/background_helper.ts (1)

45-50: Address the race condition flagged in the previous review.

The concurrent initialization issue identified in the previous review remains unresolved. Two background events arriving before the first initialization completes will both call prepareBackgroundRouter() and register handlers twice.

🧹 Nitpick comments (4)
.web-ext-config.example.mjs (1)

8-8: Use path.join() and declare Node.js version requirement.

  • Replace string concatenation with path.join(import.meta.dirname, ".cache", "thunderbird-testing-profile") for cross-platform compatibility.
  • Add "node": ">=20.11.0" to package.json engines or document the minimum Node.js version in your project docs.
src/ghosttext-runner/ghost_text_starter.ts (1)

24-24: Consider removing or elevating the debug log.

The console.log("generator finished") statement appears to be a development/debug artifact. Consider either removing it or replacing it with a proper logging mechanism if this information is valuable for troubleshooting.

Apply this diff to remove the debug statement:

     } finally {
-      console.log("generator finished")
       await runner.close()
       stopHeartbeat()
src/ghosttext-runner/ghost_text_runner.ts (1)

19-22: Consider logging or handling errors from status update.

The close() method silently swallows errors from statusIndicator.update() via .catch(() => {}). While this prevents cleanup failures from propagating, it may hide legitimate issues with status updates during shutdown.

Consider logging the error for troubleshooting:

 close(): Promise<void> {
   this.session?.close()
-  return this.statusIndicator.update(this.lastStatus).catch(() => {})
+  return this.statusIndicator.update(this.lastStatus).catch((error) => {
+    console.warn("Failed to update status during close:", error)
+  })
 }
src/root/util/wireless.ts (1)

45-47: Enhanced default dependency resolution improves API ergonomics.

The introduction of the injector wrapper with automatic dependency parsing via parseConstructorForDependencyNames when deps is undefined is a good enhancement. The explicit const declarations make the code clearer.

Note the type safety trade-offs:

  • Line 45: The double cast as unknown as Iterable<IClassInfo<TCatalog>> suppresses variance issues inherent to dynamic class discovery. This is acceptable given the convention-based nature of this DI system.
  • Line 47: The cast to KeyOf<TCatalog>[] assumes parsed dependency names will match catalog keys. If names don't match, resolution will fail loudly at runtime, which is appropriate behavior for a DI system.

Performance consideration: parseConstructorForDependencyNames performs regex parsing on every injection when deps is undefined. This is likely fine for most use cases, but could become a bottleneck if certain classes are instantiated very frequently. Consider memoizing the parsing results if performance issues arise.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 40a4163 and a08c133.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (19)
  • .github/workflows/doc.yml (1 hunks)
  • .web-ext-config.example.mjs (1 hunks)
  • doc/res/typedoc.cjs (1 hunks)
  • package.json (2 hunks)
  • src/app-background/background_event_router.ts (1 hunks)
  • src/app-background/compose_action_notifier.ts (2 hunks)
  • src/app-options/api.ts (1 hunks)
  • src/ghosttext-adaptor/email_editor_factory.ts (1 hunks)
  • src/ghosttext-runner/ghost_text_runner.ts (2 hunks)
  • src/ghosttext-runner/ghost_text_starter.ts (1 hunks)
  • src/ghosttext-session/ghost_text_client.ts (1 hunks)
  • src/root/background.ts (1 hunks)
  • src/root/background_helper.ts (1 hunks)
  • src/root/startup/startup_background.ts (1 hunks)
  • src/root/util/wireless.ts (1 hunks)
  • src/thunderbird/background_util/compose_tab.ts (4 hunks)
  • src/thunderbird/messenger/alarms.ts (2 hunks)
  • src/thunderbird/options_util/options_store.ts (0 hunks)
  • tsconfig.json (1 hunks)
💤 Files with no reviewable changes (1)
  • src/thunderbird/options_util/options_store.ts
✅ Files skipped from review due to trivial changes (1)
  • doc/res/typedoc.cjs
🚧 Files skipped from review as they are similar to previous changes (6)
  • src/ghosttext-session/ghost_text_client.ts
  • .github/workflows/doc.yml
  • src/root/background.ts
  • src/thunderbird/background_util/compose_tab.ts
  • src/app-options/api.ts
  • src/thunderbird/messenger/alarms.ts
🧰 Additional context used
🧬 Code graph analysis (6)
src/ghosttext-adaptor/email_editor_factory.ts (3)
src/ghosttext-runner/api.ts (1)
  • IClientOptionsLoader (39-44)
src/ghosttext-adaptor/api.ts (1)
  • IComposeWindow (34-65)
src/ghosttext-adaptor/email_editor.ts (1)
  • EmailEditor (12-54)
src/app-background/compose_action_notifier.ts (3)
src/ghosttext-adaptor/api.ts (1)
  • IGhostServerPort (91-91)
src/ghosttext-runner/ghost_text_starter.ts (1)
  • GhostTextStarter (5-29)
src/ghosttext-adaptor/email_editor_factory.ts (1)
  • EmailEditorFactory (5-14)
src/ghosttext-runner/ghost_text_starter.ts (3)
src/ghosttext-runner/api.ts (5)
  • IGhostTextConnector (20-27)
  • IClientOptionsLoader (39-44)
  • IHeart (11-17)
  • IStatusIndicator (109-116)
  • IClientEditor (74-96)
src/ghosttext-session/ghost_text_client.ts (1)
  • GhostTextClient (30-70)
src/ghosttext-runner/ghost_text_runner.ts (1)
  • GhostTextRunner (4-86)
src/ghosttext-runner/ghost_text_runner.ts (2)
src/ghosttext-session/ghost_text_client.ts (4)
  • Command (12-17)
  • SessionStatus (10-10)
  • GhostTextSession (28-28)
  • CommandResult (19-26)
src/ghosttext-runner/api.ts (6)
  • ISession (47-69)
  • IGhostTextConnector (20-27)
  • ClientOptions (30-34)
  • IStatusIndicator (109-116)
  • IClientEditor (74-96)
  • ClientStatus (106-106)
src/root/background_helper.ts (2)
src/app-background/background_event_router.ts (1)
  • BackgroundEventRouter (5-52)
src/root/startup/startup_background.ts (1)
  • prepareBackgroundRouter (27-35)
src/root/util/wireless.ts (2)
src/root/util/wire.ts (4)
  • wire (157-160)
  • wire (233-247)
  • IClassInfo (25-58)
  • KeyOf (20-20)
src/root/util/wired.ts (1)
  • wired (16-21)
🔇 Additional comments (17)
src/app-background/background_event_router.ts (1)

23-23: LGTM!

The JSDoc comment accurately describes the method's purpose and improves code documentation.

src/root/startup/startup_background.ts (1)

1-1: LGTM!

The removal of ICommandConfig from the import aligns with the refactoring to externalize routing logic and reduce the public surface area of this module.

src/root/background_helper.ts (2)

15-21: LGTM!

The branching logic correctly delegates to synchronous or asynchronous paths based on router availability.


30-37: LGTM!

The error handling is appropriate, logging errors while returning undefined to prevent exceptions from propagating.

src/ghosttext-runner/ghost_text_starter.ts (1)

5-13: LGTM! Clean dependency injection pattern.

The singleton marker and constructor with injected dependencies follow a clear pattern for orchestrating the GhostText session lifecycle.

src/ghosttext-adaptor/email_editor_factory.ts (1)

5-13: LGTM! Simple and effective factory pattern.

The factory correctly encapsulates the creation logic for EmailEditor instances, loading options and constructing the editor. The pattern is appropriate for the use case where editors are created per session.

src/app-background/compose_action_notifier.ts (3)

1-2: LGTM! Imports updated to reflect the new architecture.

The import statements correctly reference the new factory and starter classes, replacing the previous direct imports.


8-11: LGTM! Constructor refactored to use factory and starter patterns.

The constructor signature cleanly reflects the shift from direct component instantiation to dependency injection of the factory and starter, improving testability and separation of concerns.


25-26: LGTM! Clean integration of factory and starter.

The refactored flow correctly uses the factory to create the editor and the starter to run the session, maintaining the same overall behavior while improving modularity.

src/ghosttext-runner/ghost_text_runner.ts (6)

1-2: LGTM! Imports updated for refactored architecture.

The import statements correctly reflect the shift to using GhostTextSession and related types from the session module, aligning with the new generator-based pattern.


8-13: LGTM! Constructor refactored for improved dependency injection.

The constructor now directly accepts the required dependencies (options, statusIndicator, editor) rather than managing their lifecycle, which improves testability and separation of concerns.


15-17: LGTM! Clean status accessor.

The lastStatus getter provides a convenient way to access the final session status, with appropriate fallback to "error" when the command is not done.


24-44: LGTM! Well-structured generator-based session flow.

The refactored run() method cleanly separates the handshake phase from the session phase, iterating through the generator commands and handling early termination if the session fails to establish.


46-64: LGTM! Proper handshake command handling.

The method correctly handles connection establishment and status notifications during the handshake phase, with appropriate error handling and type exhaustiveness checking.


66-86: LGTM! Robust session command handling.

The method properly routes session commands to the appropriate handlers, with good separation of concerns and exhaustiveness checking to ensure all command types are handled.

tsconfig.json (1)

35-36: customJs path confirmed: doc/res/typedoc.cjs exists as configured. No changes needed.

src/root/util/wireless.ts (1)

49-50: No $wire$ references found—key rename is safe
Search across TS/JS files returned no occurrences of $wire$, so switching the registry key to $injector does not introduce a breaking change.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/thunderbird/messenger/alarms.ts (1)

30-36: Fix JSDoc spacing on line 31
Insert a space before the closing */ so it reads:

/** Number of minutes from the current time after which the alarm should first fire. */ delayInMinutes: number

[src/thunderbird/messenger/alarms.ts:31]

♻️ Duplicate comments (1)
src/root/background_helper.ts (1)

23-30: Reset routerPromise when initialization fails

If import("./startup/startup_background") or prepareBackgroundRouter() rejects, the rejected promise stays cached in routerPromise, so every later call immediately fails and the router is never retried. Reset the promise (and cached router) on failure so we can recover from transient startup issues.

Apply this diff:

-  routerPromise ??= import("./startup/startup_background").then((s) => s.prepareBackgroundRouter())
+  routerPromise ??= import("./startup/startup_background")
+    .then((s) => s.prepareBackgroundRouter())
+    .catch((error) => {
+      console.error({ error })
+      routerPromise = undefined
+      routerCache = undefined
+      throw error
+    })
🧹 Nitpick comments (5)
.web-ext-config.example.mjs (1)

8-8: Good portability improvement.

Switching to import.meta.dirname makes this example configuration portable across different development environments instead of requiring manual path edits.

Note: import.meta.dirname requires Node.js ≥20.11 or ≥21.2. If targeting older versions, consider using path.dirname(new URL(import.meta.url).pathname) instead.

For slightly better cross-platform explicitness, you could use:

-    firefoxProfile: import.meta.dirname + "/.cache/thunderbird-testing-profile/",
+    firefoxProfile: import.meta.dirname + "/.cache/thunderbird-testing-profile/",

But string concatenation with / works fine in Node.js across platforms, so this is optional.

src/test/startup.test.ts (1)

140-141: Use explicit boolean conversion for clarity.

The variable hasDependency suggests a boolean value, but deps.length returns a number. While this works due to JavaScript's truthiness rules, it's clearer and more idiomatic to explicitly convert to boolean.

Apply this diff:

-    const hasDependency = deps.length
+    const hasDependency = deps.length > 0
     if (hasDependency) {
doc/res/typedoc.cjs (1)

3-4: Consider using const for immutable bindings.

Since nodes and mermaidPromise are not reassigned, declare them with const instead of let to signal immutability.

Apply this diff:

-let nodes = document.querySelectorAll('code.mermaid');
-let mermaidPromise = nodes.length ? import('https://cdn.jsdelivr.net/npm/mermaid@11.12.0/dist/mermaid.esm.min.mjs') : null;
+const nodes = document.querySelectorAll('code.mermaid');
+const mermaidPromise = nodes.length ? import('https://cdn.jsdelivr.net/npm/mermaid@11.12.0/dist/mermaid.esm.min.mjs') : null;
src/ghosttext-runner/ghost_text_starter.ts (1)

24-24: Consider removing or improving the debug log.

The console.log statement appears to be debug code. Consider either removing it or replacing it with a proper logging mechanism if this information is valuable for troubleshooting.

src/ghosttext-runner/ghost_text_runner.ts (1)

19-22: Consider logging suppressed errors in close().

The catch(() => {}) on line 21 silently suppresses errors from the status indicator update. While this is reasonable for a cleanup method, logging these errors might help with debugging.

  close(): Promise<void> {
    this.session?.close()
-   return this.statusIndicator.update(this.lastStatus).catch(() => {})
+   return this.statusIndicator.update(this.lastStatus).catch((err) => {
+     console.error("Failed to update status indicator during close:", err)
+   })
  }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a08c133 and e572c89.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (30)
  • .github/workflows/doc.yml (1 hunks)
  • .vscode/tasks.example.json (1 hunks)
  • .web-ext-config.example.mjs (1 hunks)
  • BUILDING.md (1 hunks)
  • CONTRIBUTING.md (1 hunks)
  • README.md (7 hunks)
  • biome.jsonc (1 hunks)
  • doc/design.md (5 hunks)
  • doc/faq.md (3 hunks)
  • doc/res/typedoc.cjs (1 hunks)
  • ext/NOTICE.md (1 hunks)
  • package.json (2 hunks)
  • src/app-background/background_event_router.ts (1 hunks)
  • src/app-background/compose_action_notifier.ts (2 hunks)
  • src/app-options/api.ts (1 hunks)
  • src/ghosttext-adaptor/email_editor_factory.ts (1 hunks)
  • src/ghosttext-runner/ghost_text_runner.ts (2 hunks)
  • src/ghosttext-runner/ghost_text_starter.ts (1 hunks)
  • src/ghosttext-session/ghost_text_client.ts (1 hunks)
  • src/root/background.ts (1 hunks)
  • src/root/background_helper.ts (1 hunks)
  • src/root/startup/startup_background.ts (1 hunks)
  • src/root/util/wireless.ts (1 hunks)
  • src/test/startup.test.ts (2 hunks)
  • src/thunderbird/background_util/compose_tab.ts (4 hunks)
  • src/thunderbird/messenger/alarms.ts (2 hunks)
  • src/thunderbird/options_util/options_store.ts (0 hunks)
  • tools/tsdown_config.ts (1 hunks)
  • tools/vitest_config.ts (2 hunks)
  • tsconfig.json (1 hunks)
💤 Files with no reviewable changes (1)
  • src/thunderbird/options_util/options_store.ts
🚧 Files skipped from review as they are similar to previous changes (14)
  • src/app-background/compose_action_notifier.ts
  • .vscode/tasks.example.json
  • .github/workflows/doc.yml
  • src/ghosttext-adaptor/email_editor_factory.ts
  • tools/vitest_config.ts
  • doc/design.md
  • BUILDING.md
  • src/root/util/wireless.ts
  • CONTRIBUTING.md
  • doc/faq.md
  • src/ghosttext-session/ghost_text_client.ts
  • package.json
  • tools/tsdown_config.ts
  • biome.jsonc
🧰 Additional context used
🧬 Code graph analysis (4)
src/ghosttext-runner/ghost_text_starter.ts (3)
src/ghosttext-runner/api.ts (5)
  • IGhostTextConnector (20-27)
  • IClientOptionsLoader (39-44)
  • IHeart (11-17)
  • IStatusIndicator (109-116)
  • IClientEditor (74-96)
src/ghosttext-session/ghost_text_client.ts (1)
  • GhostTextClient (30-70)
src/ghosttext-runner/ghost_text_runner.ts (1)
  • GhostTextRunner (4-86)
src/root/background_helper.ts (1)
src/app-background/background_event_router.ts (1)
  • BackgroundEventRouter (5-52)
src/ghosttext-runner/ghost_text_runner.ts (2)
src/ghosttext-session/ghost_text_client.ts (4)
  • Command (12-17)
  • SessionStatus (10-10)
  • GhostTextSession (28-28)
  • CommandResult (19-26)
src/ghosttext-runner/api.ts (6)
  • ISession (47-69)
  • IGhostTextConnector (20-27)
  • ClientOptions (30-34)
  • IStatusIndicator (109-116)
  • IClientEditor (74-96)
  • ClientStatus (106-106)
src/thunderbird/background_util/compose_tab.ts (3)
src/ghosttext-runner/message.ts (1)
  • MessagesFromBackground (3-6)
src/ghosttext-adaptor/api.ts (1)
  • IGhostServerPort (91-91)
src/thunderbird/util/promisified_port.ts (1)
  • PromisifiedPort (12-67)
🔇 Additional comments (13)
src/app-options/api.ts (1)

7-7: LGTM! Documentation fix aligns JSDoc with actual parameter name.

The JSDoc now correctly documents the form parameter instead of the incorrect selector reference, improving documentation accuracy.

src/thunderbird/background_util/compose_tab.ts (3)

27-27: LGTM!

All internal references have been consistently updated from this.id to this.tabId throughout the class methods.

Also applies to: 37-37, 50-50, 56-56, 69-69


60-64: Verify the use of import.meta.url as the connection name.

The openPort method now passes { name: import.meta.url } when establishing the connection. This will use the current module's URL as the connection identifier. Confirm this is the intended behavior for identifying/debugging port connections.


9-9: No remaining .tabId() calls found. All usages have been updated to use the public tabId field.

src/test/startup.test.ts (1)

150-156: LGTM!

The helper function correctly extracts the class body after the constructor using optional chaining for safe match handling. While stringifying constructors is fragile and depends on JS engine implementation, this is acceptable for test code.

tsconfig.json (1)

31-50: LGTM! Well-coordinated TypeDoc configuration changes.

The configuration changes effectively replace the typedoc-plugin-mermaid plugin with a custom JavaScript solution (doc/res/typedoc.cjs) while adding ignoredHighlightLanguages: ["mermaid"] to prevent syntax highlighting conflicts. The addition of typedoc-plugin-mdn-links provides MDN reference links, and the new BUILDING.md document enhances project documentation.

ext/NOTICE.md (1)

11-40: Good practice: Using release tag URLs for attribution.

The update to use specific release tag URLs (e.g., /releases/tag/vX.Y.Z) instead of generic repository links provides better version traceability and makes it easier to verify the exact code being attributed.

README.md (1)

1-271: LGTM! Comprehensive documentation improvements.

The README updates enhance clarity and completeness:

  • Consistent ESR 140 version references
  • Reorganized badges for better visibility
  • Clearer build instructions
  • Added vimghost example with visual demonstration
  • Expanded help wanted section with more specific tasks
  • Updated roadmap with current version status

All changes improve the project's documentation quality and user experience.

src/ghosttext-runner/ghost_text_runner.ts (4)

15-17: LGTM!

The lastStatus getter correctly handles both the initial state (command undefined) and completed state, returning appropriate ClientStatus values.


24-44: LGTM!

The refactored run() method clearly separates the handshake and session phases, with appropriate early exit when session establishment fails. The use of ??= on line 30 is clean and modern.


46-64: LGTM!

The handshake command handler correctly uses injected dependencies and returns appropriate results. The exhaustiveness comment ensures TypeScript catches any missing command types.


66-86: LGTM!

The session command handler correctly uses injected dependencies and delegates appropriately to helper functions. The exhaustiveness comment ensures TypeScript catches any missing command types.

src/thunderbird/messenger/alarms.ts (1)

39-46: LGTM!

The export of the Alarm type and its definition are correct. The periodInMinutes field is appropriately marked as optional, matching the JSDoc on line 44.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (2)
doc/design.md (1)

175-175: Fix broken BUILDING.md link casing.

The link points to ./building.md (lowercase) but the repository file is named BUILDING.md (uppercase). This will fail on case-sensitive filesystems.

Apply this diff to fix the link:

-  * See [building.md](./building.md) for details on build script internals.
+  * See [BUILDING.md](./BUILDING.md) for details on build script internals.
src/root/background_helper.ts (1)

23-30: Add error handling to reset initialization state on failure.

If prepareBackgroundRouter() rejects, routerPromise remains set to the rejected promise. Subsequent calls will reuse this rejected promise rather than retrying initialization, causing all future router requests to fail immediately.

Apply this diff to add error recovery:

-  routerPromise ??= import("./startup/startup_background").then((s) => s.prepareBackgroundRouter())
+  routerPromise ??= import("./startup/startup_background")
+    .then((s) => s.prepareBackgroundRouter())
+    .catch((error) => {
+      console.error({ error })
+      routerPromise = undefined
+      routerCache = undefined
+      throw error
+    })

   return routerPromise.then((router) => {
     routerCache = router
     routerPromise = undefined

     return runHandler(handler, router)
   })
🧹 Nitpick comments (2)
tsconfig.json (1)

35-36: Use array form for customJs.

TypeDoc’s option expects an array; providing it as a string works inconsistently across versions. Wrapping it in an array avoids config parsing warnings.

-    "customJs": "doc/res/typedoc.cjs",
+    "customJs": [
+      "doc/res/typedoc.cjs"
+    ],
src/root/util/wireless.ts (1)

33-36: Optional: Add JSDoc for better documentation.

The type definition is clear and well-structured. Consider adding JSDoc comments to explain the injector's purpose and parameters for improved developer experience.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e572c89 and 384fc7d.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (26)
  • .github/workflows/doc.yml (1 hunks)
  • .vscode/tasks.example.json (1 hunks)
  • .web-ext-config.example.mjs (1 hunks)
  • BUILDING.md (1 hunks)
  • CONTRIBUTING.md (1 hunks)
  • README.md (7 hunks)
  • doc/design.md (5 hunks)
  • doc/faq.md (3 hunks)
  • doc/res/typedoc.cjs (1 hunks)
  • ext/NOTICE.md (1 hunks)
  • package.json (2 hunks)
  • src/app-background/background_event_router.ts (1 hunks)
  • src/app-background/compose_action_notifier.ts (2 hunks)
  • src/app-options/api.ts (1 hunks)
  • src/ghosttext-adaptor/email_editor_factory.ts (1 hunks)
  • src/ghosttext-runner/ghost_text_runner.ts (2 hunks)
  • src/ghosttext-runner/ghost_text_starter.ts (1 hunks)
  • src/ghosttext-session/ghost_text_client.ts (1 hunks)
  • src/root/background.ts (1 hunks)
  • src/root/background_helper.ts (1 hunks)
  • src/root/startup/startup_background.ts (1 hunks)
  • src/root/util/wireless.ts (1 hunks)
  • src/thunderbird/background_util/compose_tab.ts (4 hunks)
  • src/thunderbird/messenger/alarms.ts (2 hunks)
  • src/thunderbird/options_util/options_store.ts (0 hunks)
  • tsconfig.json (1 hunks)
💤 Files with no reviewable changes (1)
  • src/thunderbird/options_util/options_store.ts
✅ Files skipped from review due to trivial changes (1)
  • src/app-options/api.ts
🚧 Files skipped from review as they are similar to previous changes (11)
  • package.json
  • .web-ext-config.example.mjs
  • BUILDING.md
  • README.md
  • doc/res/typedoc.cjs
  • src/ghosttext-adaptor/email_editor_factory.ts
  • .vscode/tasks.example.json
  • src/root/background.ts
  • src/thunderbird/messenger/alarms.ts
  • ext/NOTICE.md
  • src/root/startup/startup_background.ts
🧰 Additional context used
🧬 Code graph analysis (6)
src/root/util/wireless.ts (2)
src/root/util/wire.ts (4)
  • wire (157-160)
  • wire (233-247)
  • IClassInfo (25-58)
  • KeyOf (20-20)
src/root/util/wired.ts (1)
  • wired (16-21)
src/app-background/compose_action_notifier.ts (3)
src/ghosttext-adaptor/api.ts (1)
  • IGhostServerPort (91-91)
src/ghosttext-runner/ghost_text_starter.ts (1)
  • GhostTextStarter (5-32)
src/ghosttext-adaptor/email_editor_factory.ts (1)
  • EmailEditorFactory (5-14)
src/ghosttext-runner/ghost_text_starter.ts (3)
src/ghosttext-runner/api.ts (5)
  • IGhostTextConnector (20-27)
  • IClientOptionsLoader (39-44)
  • IHeart (11-17)
  • IStatusIndicator (109-116)
  • IClientEditor (74-96)
src/ghosttext-session/ghost_text_client.ts (1)
  • GhostTextClient (30-70)
src/ghosttext-runner/ghost_text_runner.ts (1)
  • GhostTextRunner (4-86)
src/thunderbird/background_util/compose_tab.ts (3)
src/ghosttext-runner/message.ts (1)
  • MessagesFromBackground (3-6)
src/ghosttext-adaptor/api.ts (1)
  • IGhostServerPort (91-91)
src/thunderbird/util/promisified_port.ts (1)
  • PromisifiedPort (12-67)
src/root/background_helper.ts (1)
src/app-background/background_event_router.ts (1)
  • BackgroundEventRouter (5-52)
src/ghosttext-runner/ghost_text_runner.ts (2)
src/ghosttext-session/ghost_text_client.ts (4)
  • Command (12-17)
  • SessionStatus (10-10)
  • GhostTextSession (28-28)
  • CommandResult (19-26)
src/ghosttext-runner/api.ts (6)
  • ISession (47-69)
  • IGhostTextConnector (20-27)
  • ClientOptions (30-34)
  • IStatusIndicator (109-116)
  • IClientEditor (74-96)
  • ClientStatus (106-106)
🔇 Additional comments (19)
src/thunderbird/background_util/compose_tab.ts (2)

9-9: LGTM! Consistent API clarification.

The refactoring consistently updates the constructor parameter from private readonly id to readonly tabId, making the field public and accessible. All internal references have been correctly updated throughout the class methods.

Also applies to: 27-27, 37-37, 50-50, 56-56, 69-69


59-65: Port connection name is acceptable.

Using import.meta.url as the port name provides a unique identifier for the connection, which can be helpful for debugging and distinguishing between different port connections.

.github/workflows/doc.yml (1)

54-54: Upgrade to v4 looks good.

Version bump keeps the workflow on the supported release line with no other adjustments needed. ✅

src/root/util/wireless.ts (1)

45-52: LGTM! Well-designed injector pattern.

The refactoring is excellent:

  • Using const instead of let for immutability
  • The injector wrapper provides a clean API with auto-resolution of dependencies
  • Returning the injector makes the API cleaner and more flexible

The type cast on line 50 is necessary for the registry pattern. The comment acknowledges this is intentional.

src/app-background/background_event_router.ts (1)

23-23: LGTM! Documentation clarity improved.

The JSDoc comment accurately describes the method's purpose and improves code readability.

doc/faq.md (3)

17-17: LGTM! Clarified ESR support.

The addition of "the latest" makes the support commitment clearer for users.


129-129: LGTM! Fixed anchor reference.

The anchor now correctly points to #callgraphs (plural), matching the heading in design.md.


152-152: LGTM! Updated file path.

The reference now correctly points to the reorganized startup file location under the startup/ subdirectory.

doc/design.md (3)

42-42: LGTM! Diagram syntax updates.

The mermaid diagram arrow syntax changes (from <--> to <-.-> and <-....->) appropriately reflect the architectural changes in the codebase, particularly the lazy initialization patterns introduced in this PR.

Also applies to: 54-54, 57-57


161-165: LGTM! Improved formatting.

The nested bullet points improve readability of the MV3 suspension and connection closure notes.


319-319: LGTM! Clarified auto-instantiation scope.

Narrowing the scope from root/*.ts to root/ (directory-only) makes the guideline more precise and aligns with the architectural intent.

src/ghosttext-session/ghost_text_client.ts (1)

28-28: LGTM! Type alias improves clarity.

Extracting the GhostTextSession type alias makes the generator signature more readable and the type more easily reusable across the codebase.

Also applies to: 33-33

src/ghosttext-runner/ghost_text_starter.ts (1)

15-31: LGTM! Proper resource cleanup.

The nested try-finally blocks correctly ensure cleanup in all scenarios:

  • The outer finally (line 27) guarantees stopHeartbeat() is called even if option loading fails
  • The inner finally (line 24) ensures runner.close() is called only when a runner was successfully created

The heartbeat lifecycle is properly managed regardless of where failures occur.

src/app-background/compose_action_notifier.ts (2)

1-2: LGTM! Constructor refactored for new dependencies.

The updated imports and constructor parameters properly introduce the factory and starter patterns, improving separation of concerns.

Also applies to: 9-10


25-26: LGTM! Factory and starter pattern applied.

The code correctly uses emailEditorFactory.create() to construct the editor and ghostTextStarter.run() to orchestrate the session. Passing editor as both status indicator and editor parameters is valid when EmailEditor implements both interfaces.

src/ghosttext-runner/ghost_text_runner.ts (4)

5-6: LGTM! Enhanced lifecycle management.

The new lastStatus getter and close() method provide explicit lifecycle control, allowing callers to inspect final status and ensure proper cleanup.

Also applies to: 15-22


8-13: LGTM! Simplified constructor.

The refactored constructor accepts dependencies directly rather than orchestrating initialization, following the single responsibility principle.


24-44: LGTM! Phased execution pattern.

The run() method cleanly separates handshake (lines 27-33) and session (lines 39-43) phases, with proper guard against missing session (lines 35-37). This makes the state machine explicit and easier to test.


46-64: LGTM! Command handlers properly scoped.

runHandshakeCommand and runSessionCommand correctly handle their respective command types with exhaustiveness checks, ensuring compile-time verification that all command types are handled.

Also applies to: 66-86

coderabbitai bot added a commit that referenced this pull request Oct 7, 2025
Docstrings generation was requested by @snipsnipsnip.

* #32 (comment)

The following files were modified:

* `src/ghosttext-runner/ghost_text_runner.ts`
* `src/root/background_helper.ts`
* `src/root/util/wireless.ts`
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Oct 7, 2025

Note

Generated docstrings for this pull request at #33

@snipsnipsnip snipsnipsnip added this pull request to the merge queue Oct 7, 2025
Merged via the queue into exteditor:main with commit b7b8567 Oct 7, 2025
2 checks passed
@snipsnipsnip snipsnipsnip deleted the fix-typedoc branch October 7, 2025 05:00
@github-project-automation github-project-automation bot moved this from 📥️Inbox to 🪺Experimental in Ghostbird Issues Oct 7, 2025
snipsnipsnip pushed a commit that referenced this pull request Oct 7, 2025
Docstrings generation was requested by @snipsnipsnip.

* #32 (comment)

The following files were modified:

* `src/ghosttext-runner/ghost_text_runner.ts`
* `src/root/background_helper.ts`
* `src/root/util/wireless.ts`
snipsnipsnip pushed a commit that referenced this pull request Oct 7, 2025
Docstrings generation was requested by @snipsnipsnip.

* #32 (comment)

The following files were modified:

* `src/ghosttext-runner/ghost_text_runner.ts`
* `src/root/background_helper.ts`
* `src/root/util/wireless.ts`
snipsnipsnip pushed a commit that referenced this pull request Oct 7, 2025
Docstrings generation was requested by @snipsnipsnip.

* #32 (comment)

The following files were modified:

* `src/ghosttext-runner/ghost_text_runner.ts`
* `src/root/background_helper.ts`
* `src/root/util/wireless.ts`
snipsnipsnip pushed a commit that referenced this pull request Oct 7, 2025
Docstrings generation was requested by @snipsnipsnip.

* #32 (comment)

The following files were modified:

* `src/ghosttext-runner/ghost_text_runner.ts`
* `src/root/background_helper.ts`
* `src/root/util/wireless.ts`
github-merge-queue bot pushed a commit that referenced this pull request Oct 7, 2025
Docstrings generation was requested by @snipsnipsnip.

* #32 (comment)

The following files were modified:

* `src/ghosttext-runner/ghost_text_runner.ts`
* `src/root/background_helper.ts`
* `src/root/util/wireless.ts`

<details>
<summary>These files were ignored</summary>

* `src/test/startup.test.ts`

</details>

<details>
<summary>These file types are not supported</summary>

* `.github/workflows/doc.yml`
* `.vscode/tasks.example.json`
* `BUILDING.md`
* `CONTRIBUTING.md`
* `README.md`
* `biome.jsonc`
* `doc/design.md`
* `doc/faq.md`
* `ext/NOTICE.md`
* `package.json`
* `tsconfig.json`

</details>

<details>
<summary>ℹ️ Note</summary><blockquote>

CodeRabbit cannot perform edits on its own pull requests yet.

</blockquote></details>
@snipsnipsnip snipsnipsnip moved this from 🪺Experimental to ✅Closed in Ghostbird Issues Oct 7, 2025
@snipsnipsnip snipsnipsnip moved this from ✅Closed to 🪺Experimental in Ghostbird Issues Oct 7, 2025
@snipsnipsnip snipsnipsnip moved this from 🪺Experimental to ✅Closed in Ghostbird Issues Oct 7, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

1 participant