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:
@@ -282,7 +282,25 @@ dependencies:
|
|||||||
golem15.user: "^1.0.0"
|
golem15.user: "^1.0.0"
|
||||||
```
|
```
|
||||||
|
|
||||||
Then verify parsing works by checking the code compiles and the types are correct.
|
Then test discovery works by running this command in the Mill REPL:
|
||||||
|
```bash
|
||||||
|
./mill -i summercms.console
|
||||||
|
```
|
||||||
|
|
||||||
|
Once in the REPL, verify parsing:
|
||||||
|
```scala
|
||||||
|
import plugin._
|
||||||
|
val yaml = """
|
||||||
|
vendor: test
|
||||||
|
name: sample
|
||||||
|
version: 1.0.0
|
||||||
|
description: Test plugin
|
||||||
|
"""
|
||||||
|
val result = PluginManifest.parse(yaml)
|
||||||
|
println(result) // Should print Right(PluginManifest(test,sample,1.0.0,...))
|
||||||
|
```
|
||||||
|
|
||||||
|
Exit REPL with `:quit` after verification.
|
||||||
</verify>
|
</verify>
|
||||||
<done>PluginManifest parses YAML manifests, PluginDiscovery scans plugins/ directory, plugins/ directory exists</done>
|
<done>PluginManifest parses YAML manifests, PluginDiscovery scans plugins/ directory, plugins/ directory exists</done>
|
||||||
</task>
|
</task>
|
||||||
|
|||||||
@@ -136,7 +136,9 @@ case class PluginRegistration(
|
|||||||
// Event subscriptions (Phase 2 extension API)
|
// Event subscriptions (Phase 2 extension API)
|
||||||
events: List[EventSubscription] = List.empty,
|
events: List[EventSubscription] = List.empty,
|
||||||
// Extensions to other plugins (Phase 2 extension API)
|
// Extensions to other plugins (Phase 2 extension API)
|
||||||
extensions: List[ExtensionDef] = List.empty
|
extensions: List[ExtensionDef] = List.empty,
|
||||||
|
// Form field definitions (for YAML-driven forms)
|
||||||
|
fields: List[FieldDef] = List.empty
|
||||||
)
|
)
|
||||||
|
|
||||||
object PluginRegistration:
|
object PluginRegistration:
|
||||||
@@ -149,6 +151,7 @@ case class NavigationDef(id: String, label: String, url: String, icon: String =
|
|||||||
case class SettingDef(key: String, label: String, icon: String = "")
|
case class SettingDef(key: String, label: String, icon: String = "")
|
||||||
case class EventSubscription(eventType: String, handler: String)
|
case class EventSubscription(eventType: String, handler: String)
|
||||||
case class ExtensionDef(target: String, extensionClass: String)
|
case class ExtensionDef(target: String, extensionClass: String)
|
||||||
|
case class FieldDef(name: String, fieldType: String)
|
||||||
```
|
```
|
||||||
|
|
||||||
**SummerPlugin.scala:**
|
**SummerPlugin.scala:**
|
||||||
@@ -172,6 +175,9 @@ trait SummerPlugin:
|
|||||||
* Async boot phase - can perform effects.
|
* Async boot phase - can perform effects.
|
||||||
* Called after all dependencies have booted.
|
* Called after all dependencies have booted.
|
||||||
* Use for: database setup, event subscriptions, service initialization.
|
* Use for: database setup, event subscriptions, service initialization.
|
||||||
|
*
|
||||||
|
* PluginEnv is a placeholder that will be expanded in 02-03 to include
|
||||||
|
* EventService and ExtensionRegistry when the extension API is implemented.
|
||||||
*/
|
*/
|
||||||
def boot: ZIO[PluginEnv, PluginError, Unit] = ZIO.unit
|
def boot: ZIO[PluginEnv, PluginError, Unit] = ZIO.unit
|
||||||
|
|
||||||
@@ -181,12 +187,15 @@ trait SummerPlugin:
|
|||||||
*/
|
*/
|
||||||
def shutdown: ZIO[Any, Nothing, Unit] = ZIO.unit
|
def shutdown: ZIO[Any, Nothing, Unit] = ZIO.unit
|
||||||
|
|
||||||
/** Environment available to plugins during boot */
|
/**
|
||||||
|
* Environment available to plugins during boot.
|
||||||
|
* Initially just PluginContext; extended in 02-03 to include EventService & ExtensionRegistry.
|
||||||
|
*/
|
||||||
type PluginEnv = PluginContext
|
type PluginEnv = PluginContext
|
||||||
```
|
```
|
||||||
</action>
|
</action>
|
||||||
<verify>Run `./mill summercms.compile` - all types compile without errors</verify>
|
<verify>Run `./mill summercms.compile` - all types compile without errors</verify>
|
||||||
<done>PluginState enum with all lifecycle states, PluginContext, PluginRegistration with placeholder defs, SummerPlugin trait</done>
|
<done>PluginState enum with all lifecycle states, PluginContext, PluginRegistration with placeholder defs including FieldDef, SummerPlugin trait</done>
|
||||||
</task>
|
</task>
|
||||||
|
|
||||||
<task type="auto">
|
<task type="auto">
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ files_modified:
|
|||||||
- summercms/src/plugin/ExtensionRegistry.scala
|
- summercms/src/plugin/ExtensionRegistry.scala
|
||||||
- summercms/src/plugin/SummerEvent.scala
|
- summercms/src/plugin/SummerEvent.scala
|
||||||
- summercms/src/plugin/package.scala
|
- summercms/src/plugin/package.scala
|
||||||
|
- summercms/src/plugin/SummerPlugin.scala
|
||||||
- summercms/src/Main.scala
|
- summercms/src/Main.scala
|
||||||
autonomous: true
|
autonomous: true
|
||||||
|
|
||||||
@@ -311,7 +312,7 @@ trait BlogExtension:
|
|||||||
/** Validate post data */
|
/** Validate post data */
|
||||||
def validate(data: Map[String, Any]): Either[String, Unit] = Right(())
|
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>
|
</action>
|
||||||
<verify>Run `./mill summercms.compile` - ExtensionRegistry compiles. It provides type-safe extension registration keyed by ClassTag.</verify>
|
<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>
|
||||||
|
|
||||||
<task type="auto">
|
<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>
|
<files>
|
||||||
summercms/src/plugin/package.scala
|
summercms/src/plugin/package.scala
|
||||||
|
summercms/src/plugin/SummerPlugin.scala
|
||||||
summercms/src/Main.scala
|
summercms/src/Main.scala
|
||||||
</files>
|
</files>
|
||||||
<action>
|
<action>
|
||||||
@@ -340,87 +342,47 @@ package object plugin:
|
|||||||
type PluginBootEnv = PluginContext & EventService & ExtensionRegistry
|
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
|
```scala
|
||||||
|
package plugin
|
||||||
|
|
||||||
import zio.*
|
import zio.*
|
||||||
import zio.http.*
|
|
||||||
import zio.config.typesafe.TypesafeConfigProvider
|
|
||||||
|
|
||||||
import api.Routes
|
/** Base trait for all SummerCMS plugins */
|
||||||
import _root_.config.{AppConfig as SummerConfig}
|
trait SummerPlugin:
|
||||||
import db.QuillContext
|
/** Plugin identifier - must match manifest */
|
||||||
import plugin.{PluginManager, PluginDiscovery, pluginLayer}
|
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 =
|
/**
|
||||||
"""
|
* 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
|
||||||
| . * .' `. *
|
|
||||||
| -------| |-------
|
|
||||||
| . *`.___.' * .
|
|
||||||
| .' |* `. *
|
|
||||||
| .' * | . `.
|
|
||||||
| . |
|
|
||||||
|
|
|
||||||
| S U M M E R C M S
|
|
||||||
|""".stripMargin
|
|
||||||
|
|
||||||
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 {
|
* Environment available to plugins during boot.
|
||||||
cfg <- ZIO.config[SummerConfig](SummerConfig.config)
|
* Includes context, events, and extension registry for full plugin capabilities.
|
||||||
_ <- Console.printLine(banner)
|
*/
|
||||||
_ <- Console.printLine(s"Starting on port ${cfg.server.port}...")
|
type PluginEnv = PluginContext & EventService & ExtensionRegistry
|
||||||
_ <- 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)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Wait - the above has a duplicate `def run`. Let me provide the correct version:
|
**Main.scala** (complete replacement):
|
||||||
|
|
||||||
**Main.scala (corrected full file):**
|
|
||||||
```scala
|
```scala
|
||||||
import zio.*
|
import zio.*
|
||||||
import zio.http.*
|
import zio.http.*
|
||||||
@@ -483,7 +445,7 @@ object Main extends ZIOAppDefault {
|
|||||||
Run `./mill summercms.compile` - Main.scala compiles with plugin integration.
|
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).
|
Run `./mill summercms.run` - Server starts, logs "Loading plugins..." and "Loaded 0 plugin(s)" (since no plugins exist yet).
|
||||||
</verify>
|
</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>
|
</task>
|
||||||
|
|
||||||
</tasks>
|
</tasks>
|
||||||
|
|||||||
Reference in New Issue
Block a user