fix(02): revise plans based on checker feedback

- 02-01 Task 3: Add concrete REPL verification command for PluginManifest.parse
- 02-02 Task 1: Add FieldDef case class to placeholder types in PluginRegistration.scala
- 02-02 Task 1: Document PluginEnv as placeholder to be expanded in 02-03
- 02-03 Task 3: Remove duplicate Main.scala code, keep only corrected version
- 02-03: Add SummerPlugin.scala to files_modified for PluginEnv update
This commit is contained in:
Jakub Zych
2026-02-05 13:29:45 +01:00
parent 336acf5572
commit 5f2e7b87c9
3 changed files with 68 additions and 79 deletions

View File

@@ -9,6 +9,7 @@ files_modified:
- summercms/src/plugin/ExtensionRegistry.scala
- summercms/src/plugin/SummerEvent.scala
- summercms/src/plugin/package.scala
- summercms/src/plugin/SummerPlugin.scala
- summercms/src/Main.scala
autonomous: true
@@ -311,7 +312,7 @@ trait BlogExtension:
/** Validate post data */
def validate(data: Map[String, Any]): Either[String, Unit] = Right(())
// FieldDef is already defined in PluginRegistration.scala, reuse it
// FieldDef is defined in PluginRegistration.scala
```
</action>
<verify>Run `./mill summercms.compile` - ExtensionRegistry compiles. It provides type-safe extension registration keyed by ClassTag.</verify>
@@ -319,9 +320,10 @@ trait BlogExtension:
</task>
<task type="auto">
<name>Task 3: Create plugin package exports and integrate with Main</name>
<name>Task 3: Create plugin package exports, update PluginEnv, and integrate with Main</name>
<files>
summercms/src/plugin/package.scala
summercms/src/plugin/SummerPlugin.scala
summercms/src/Main.scala
</files>
<action>
@@ -340,87 +342,47 @@ package object plugin:
type PluginBootEnv = PluginContext & EventService & ExtensionRegistry
```
**Update Main.scala** to integrate the plugin system:
**Update SummerPlugin.scala** to use the expanded PluginEnv:
Read the existing file from 02-02 and update ONLY the PluginEnv type alias at the bottom:
```scala
package plugin
import zio.*
import zio.http.*
import zio.config.typesafe.TypesafeConfigProvider
import api.Routes
import _root_.config.{AppConfig as SummerConfig}
import db.QuillContext
import plugin.{PluginManager, PluginDiscovery, pluginLayer}
/** Base trait for all SummerCMS plugins */
trait SummerPlugin:
/** Plugin identifier - must match manifest */
def id: PluginId
object Main extends ZIOAppDefault {
/**
* Synchronous registration phase - pure data, no effects.
* Called during discovery to collect plugin declarations.
*/
def register(ctx: PluginContext): PluginRegistration = PluginRegistration.empty
private val banner: String =
"""
|
| | .
| `. * | .'
| `. ._|_* .' .
| . * .' `. *
| -------| |-------
| . *`.___.' * .
| .' |* `. *
| .' * | . `.
| . |
|
| S U M M E R C M S
|""".stripMargin
/**
* Async boot phase - can perform effects.
* Called after all dependencies have booted.
* Use for: database setup, event subscriptions, service initialization.
*/
def boot: ZIO[PluginEnv, PluginError, Unit] = ZIO.unit
override val bootstrap: ZLayer[ZIOAppArgs, Any, Any] =
Runtime.setConfigProvider(TypesafeConfigProvider.fromResourcePath())
/**
* Async shutdown phase - cleanup resources.
* Called in reverse dependency order during application shutdown.
*/
def shutdown: ZIO[Any, Nothing, Unit] = ZIO.unit
override def run: ZIO[Any, Any, Any] =
for {
cfg <- ZIO.config[SummerConfig](SummerConfig.config)
_ <- Console.printLine(banner)
_ <- Console.printLine(s"Starting on port ${cfg.server.port}...")
_ <- Console.printLine("")
// Initialize plugin system
_ <- Console.printLine("Loading plugins...")
_ <- PluginManager.loadPlugins(PluginDiscovery.defaultPluginsDir)
.catchAll(e => Console.printLine(s"Plugin loading warning: ${e.message}").as(()))
_ <- PluginManager.bootAll
.catchAll(e => Console.printLine(s"Plugin boot warning: ${e.message}").as(()))
plugins <- PluginManager.listPlugins
_ <- Console.printLine(s"Loaded ${plugins.count(_._2.isActive)} plugin(s)")
_ <- Console.printLine("")
// Note: Migrations are NOT auto-run. Use CLI to run migrations (Phase 5).
_ <- Server.serve(Routes.routes).provide(
Server.defaultWithPort(cfg.server.port),
QuillContext.dataSourceLayer
)
} yield ()
// Provide plugin layers
override def run: ZIO[Any, Any, Any] =
(for {
cfg <- ZIO.config[SummerConfig](SummerConfig.config)
_ <- Console.printLine(banner)
_ <- Console.printLine(s"Starting on port ${cfg.server.port}...")
_ <- Console.printLine("")
// Initialize plugin system
_ <- Console.printLine("Loading plugins...")
_ <- PluginManager.loadPlugins(PluginDiscovery.defaultPluginsDir)
.catchAll(e => Console.printLine(s"Plugin loading warning: ${e.message}").as(()))
_ <- PluginManager.bootAll
.catchAll(e => Console.printLine(s"Plugin boot warning: ${e.message}").as(()))
plugins <- PluginManager.listPlugins
_ <- Console.printLine(s"Loaded ${plugins.count(_._2.isActive)} plugin(s)")
_ <- Console.printLine("")
// Note: Migrations are NOT auto-run. Use CLI to run migrations (Phase 5).
_ <- Server.serve(Routes.routes).provide(
Server.defaultWithPort(cfg.server.port),
QuillContext.dataSourceLayer
)
} yield ()).provide(pluginLayer)
/**
* Environment available to plugins during boot.
* Includes context, events, and extension registry for full plugin capabilities.
*/
type PluginEnv = PluginContext & EventService & ExtensionRegistry
```
Wait - the above has a duplicate `def run`. Let me provide the correct version:
**Main.scala (corrected full file):**
**Main.scala** (complete replacement):
```scala
import zio.*
import zio.http.*
@@ -483,7 +445,7 @@ object Main extends ZIOAppDefault {
Run `./mill summercms.compile` - Main.scala compiles with plugin integration.
Run `./mill summercms.run` - Server starts, logs "Loading plugins..." and "Loaded 0 plugin(s)" (since no plugins exist yet).
</verify>
<done>Plugin package exports combined layer, Main.scala loads and boots plugins on startup</done>
<done>Plugin package exports combined layer, PluginEnv updated to include EventService and ExtensionRegistry, Main.scala loads and boots plugins on startup</done>
</task>
</tasks>