Skip to content

Plugin support#62

Open
darrenpicard25 wants to merge 7 commits intomasterfrom
plugin-support
Open

Plugin support#62
darrenpicard25 wants to merge 7 commits intomasterfrom
plugin-support

Conversation

@darrenpicard25
Copy link
Collaborator

@darrenpicard25 darrenpicard25 commented Feb 14, 2026

Introducing new Plugin support for Chrono

Plugin contract is extremely flexible allowing plugins almost complete access to defined contracts of chrono internals

Summary by CodeRabbit

  • New Features

    • Plugin system for extending Chrono
    • Configurable uninitialized datastore behavior (queue or throw) and deferred MongoDB initialization
  • Documentation

    • Updated README content and package READMEs with simplified quick-starts and examples
  • Tests

    • Added integration and unit tests for plugin lifecycle and datastore uninitialized behavior
  • Chores

    • Updated dev dependencies, bumped package versions to 0.6.0, and added .DS_Store to .gitignore

@darrenpicard25 darrenpicard25 marked this pull request as ready for review February 14, 2026 00:08
maiahneo
maiahneo previously approved these changes Feb 24, 2026
Copy link
Collaborator

@tjamescouch tjamescouch left a comment

Choose a reason for hiding this comment

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

Just the one comment - looks good otherwise.

@coderabbitai
Copy link

coderabbitai bot commented Mar 14, 2026

📝 Walkthrough

Walkthrough

Introduces a plugin system with lifecycle hooks to Chrono, adds plugin context and types, updates MongoDB datastore to support uninitialized behavior, updates tooling/dependencies and test config, rewrites documentation, and adds comprehensive tests for plugin and datastore behaviors.

Changes

Cohort / File(s) Summary
Root config & docs
/.gitignore, biome.json, package.json, README.md
Adds .DS_Store ignore; updates Biome schema to 2.4.7 and bumps devDependency versions; replaces README with a streamlined quick-start and maintenance content.
Core package — API & implementation
packages/chrono-core/src/chrono.ts, packages/chrono-core/src/index.ts
Adds Chrono.use() plugin registration API and started/pluginContexts fields; exports new plugin types in public index.
Core package — plugin types & context
packages/chrono-core/src/plugins/...
packages/chrono-core/src/plugins/index.ts, .../chrono-plugin-context.ts, .../lifecycle-context.ts, .../registration-context.ts
Adds ChronoPlugin interface, PluginLifecycleContext and PluginRegistrationContext interfaces, and ChronoPluginContext class handling hook registration and lifecycle execution (FIFO start, LIFO stop).
Core package — tests & config
packages/chrono-core/vitest.config.ts, packages/chrono-core/test/...
test/integration/plugins.test.ts, test/unit/...
Restricts vitest include patterns; adds integration and unit tests covering plugin registration, nested plugins, lifecycle hook ordering, Chrono.use behavior, and ChronoPluginContext delegation.
Core package — docs & version
packages/chrono-core/README.md, packages/chrono-core/package.json
README expanded with plugin details and examples; package version bumped 0.5.3 → 0.6.0.
MongoDB datastore — API & behavior
packages/chrono-mongo-datastore/src/chrono-mongo-datastore.ts, packages/chrono-mongo-datastore/README.md
Introduces UninitializedDatastoreBehaviorConfig and maxQueueSize; updates ChronoMongoDatastore to construct/initialize lifecycle and enforce queue/throw semantics for uninitialized access; docs updated to reflect constructor+initialize pattern and enum/type changes.
MongoDB datastore — tests & version
packages/chrono-mongo-datastore/test/unit/chrono-mongo-datastore.test.ts, packages/chrono-mongo-datastore/package.json
Adds tests for uninitializedDatastoreBehavior (default queue, throw option, maxQueueSize enforcement); package version bumped 0.5.3 → 0.6.0.

Sequence Diagram(s)

sequenceDiagram
    participant App as Application
    participant Chrono
    participant Plugin
    participant PluginCtx as PluginContext
    participant DataStore

    App->>Chrono: use(plugin)
    Chrono->>Plugin: register(PluginRegistrationContext)
    Plugin->>PluginCtx: hooks.onStart(handler)
    Plugin->>PluginCtx: hooks.onStop(handler)
    Plugin-->>Chrono: return PluginAPI
    Chrono-->>App: return PluginAPI

    App->>Chrono: start()
    Chrono->>PluginCtx: executeStartHooks()
    PluginCtx->>PluginCtx: create LifecycleContext
    PluginCtx->>Plugin: onStart(LifecycleContext) [FIFO order]
    Plugin->>DataStore: getDatastore()
    Plugin-->>PluginCtx: hook complete
    PluginCtx-->>Chrono: hooks executed
    Chrono->>Chrono: start processors

    App->>Chrono: stop()
    Chrono->>PluginCtx: executeStopHooks()
    PluginCtx->>PluginCtx: create LifecycleContext
    PluginCtx->>Plugin: onStop(LifecycleContext) [LIFO order]
    Plugin->>DataStore: getDatastore()
    Plugin-->>PluginCtx: hook complete
    PluginCtx-->>Chrono: hooks executed
    Chrono->>Chrono: stop processors
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

🐰 I hopped in with a tiny ring,
Added hooks and made them sing,
Start goes first, then stop says bye,
Datastores queue while I sniff the sky,
Plugins bloom — a carrot-shaped high! 🥕

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Plugin support' directly and clearly summarizes the main change: introducing a new plugin system to Chrono with flexible contract access.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch plugin-support
📝 Coding Plan
  • Generate coding plan for human review comments

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

Copy link

@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)
packages/chrono-core/src/chrono.ts (1)

99-110: ⚠️ Potential issue | 🔴 Critical

Ensure processor shutdown still runs when a stop hook fails.

If any plugin stop hook throws at Line 100, stop() exits before stopping processors, which can leave workers running.

💡 Proposed fix
 public async stop(): Promise<void> {
-  // Execute plugin stop hooks first (in reverse order - LIFO)
-  for (const context of [...this.pluginContexts].reverse()) {
-    await context.executeStopHooks();
-  }
-
-  const stopPromises = Array.from(this.processors.values()).map((processor) => processor.stop());
-
-  try {
-    await promiseWithTimeout(Promise.all(stopPromises), this.exitTimeoutMs);
-  } catch (error) {
-    this.emit(ChronoEvents.STOP_ABORTED, { error, timestamp: new Date() });
+  try {
+    // Execute plugin stop hooks first (in reverse order - LIFO)
+    for (const context of [...this.pluginContexts].reverse()) {
+      await context.executeStopHooks();
+    }
+  } finally {
+    const stopPromises = Array.from(this.processors.values()).map((processor) => processor.stop());
+
+    try {
+      await promiseWithTimeout(Promise.all(stopPromises), this.exitTimeoutMs);
+    } catch (error) {
+      this.emit(ChronoEvents.STOP_ABORTED, { error, timestamp: new Date() });
+    }
   }
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/chrono-core/src/chrono.ts` around lines 99 - 110, A plugin stop hook
thrown inside the loop over this.pluginContexts (calling
context.executeStopHooks()) aborts the whole stop sequence and prevents
processors from being stopped; surround each context.executeStopHooks() call (or
the whole plugin stop hook phase) with try/catch so failures are caught and
logged/emitted (e.g., emit ChronoEvents.STOP_ABORTED with the hook error and
timestamp) but do not return/throw, then proceed to collect and await the
processors' stop() promises via promiseWithTimeout with this.exitTimeoutMs;
ensure processor.stop() is always invoked even if plugin stop hooks fail and
surface both hook and processor errors appropriately.
🧹 Nitpick comments (2)
packages/chrono-core/src/plugins/lifecycle-context.ts (1)

8-8: Match the “read-only” contract in the type signature.

Line 8 describes read-only access, but Line 15 exposes a mutable array type. Prefer a readonly array return type to enforce the contract.

♻️ Suggested API tweak
-  getRegisteredTaskKinds(): (keyof TaskMapping)[];
+  getRegisteredTaskKinds(): readonly (keyof TaskMapping)[];

Also applies to: 15-15

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/chrono-core/src/plugins/lifecycle-context.ts` at line 8, The API
claims "read-only" access but the LifecycleContext interface exposes a mutable
array type; update the array-returning member on LifecycleContext (e.g., the
getPlugins / plugins method) to return a readonly array type (use
ReadonlyArray<Plugin> or readonly Plugin[]) and adjust the implementation to
return an immutable view (return a copy or Object.freeze/as const) so callers
cannot mutate internal state.
packages/chrono-core/test/unit/chrono.test.ts (1)

165-200: Add a regression test for failed plugin startup hooks.

A case where onStart throws would lock in expected state-recovery behavior and guard against lifecycle regressions.

💡 Suggested test case
 describe('use', () => {
+  test('allows retry after start() fails in a plugin onStart hook', async () => {
+    const failingPlugin: ChronoPlugin<TaskMapping, DatastoreOptions> = {
+      name: 'failing-plugin',
+      register(context) {
+        context.hooks.onStart(() => {
+          throw new Error('boom');
+        });
+      },
+    };
+
+    chrono.use(failingPlugin);
+    await expect(chrono.start()).rejects.toThrow('boom');
+
+    const plugin: ChronoPlugin<TaskMapping, DatastoreOptions> = {
+      name: 'late-plugin',
+      register: vitest.fn(),
+    };
+
+    expect(() => chrono.use(plugin)).not.toThrow();
+  });
+
   test('throws when called after start()', async () => {
     await chrono.start();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/chrono-core/test/unit/chrono.test.ts` around lines 165 - 200, Add a
regression test that registers a plugin whose onStart hook throws, then assert
that calling chrono.start() rejects with that error (or propagates it) and that
Chrono recovers to a pre-start state by allowing subsequent plugin
registrations; specifically, in chrono.test.ts create a plugin object with name
like 'failing-start-plugin' and an onStart that throws, call chrono.use(plugin),
await expect(chrono.start()).rejects.toThrow(/* error */), and then verify you
can call chrono.use(anotherPlugin) successfully (or check any available
pre-start flag/state) to ensure the failed onStart doesn't leave Chrono
permanently started/locked.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/chrono-core/README.md`:
- Line 58: The README's quick-start uses an undeclared type DatastoreOptions (in
the sample instantiation of Chrono<TaskMapping, DatastoreOptions> and nearby
examples); fix by either declaring and showing the DatastoreOptions
interface/type in the snippet or replacing DatastoreOptions with the actual
options type exported by the library (or a clear inline example like
Record<string, unknown>), and ensure any referenced types (TaskMapping, Chrono)
include import or declaration notes so the examples type-check.

In `@packages/chrono-core/src/chrono.ts`:
- Around line 85-89: In Chrono.start, currently this.started is set to true
before awaiting startup work (looping pluginContexts and
executingExecuteStartHooks), so if any hook throws the method leaves
started=true; change the start flow in the start method (the block that sets
this.started and iterates this.pluginContexts executing executeStartHooks) to
set this.started only after all startup work completes successfully, or wrap the
startup sequence in try/catch and reset this.started = false in the catch before
rethrowing; ensure any startup steps that include executeStartHooks() and
processor startup are covered so subsequent start()/use() behavior is correct.

In `@packages/chrono-mongo-datastore/src/chrono-mongo-datastore.ts`:
- Around line 76-84: The constructor currently uses
rest.uninitializedDatastoreBehavior to decide whether to include maxQueueSize,
which is undefined when the caller omits uninitializedDatastoreBehavior even
though the code sets the default to 'queue'; update the logic to compute the
effective behavior first (e.g., const behavior =
rest.uninitializedDatastoreBehavior || 'queue') and then set
uninitializedDatastoreBehavior: behavior and include maxQueueSize when behavior
=== 'queue' (e.g., ...(behavior === 'queue' ? { maxQueueSize: rest.maxQueueSize
} : undefined)); reference the constructor, ChronoMongoDatastoreConfig, config,
uninitializedDatastoreBehavior, and maxQueueSize when making this change.

In `@README.md`:
- Line 62: The README's Node prerequisite ("Node.js >= 22.14.0") conflicts with
package.json's engines.node (">= 20.18.3"); pick the intended minimum Node
version and make both sources consistent by updating either README.md to match
the package.json engines.node value or updating package.json.engines.node to the
README value—ensure you edit the exact string "Node.js >= 22.14.0" in README.md
or the "engines.node" entry in package.json so they match exactly.

---

Outside diff comments:
In `@packages/chrono-core/src/chrono.ts`:
- Around line 99-110: A plugin stop hook thrown inside the loop over
this.pluginContexts (calling context.executeStopHooks()) aborts the whole stop
sequence and prevents processors from being stopped; surround each
context.executeStopHooks() call (or the whole plugin stop hook phase) with
try/catch so failures are caught and logged/emitted (e.g., emit
ChronoEvents.STOP_ABORTED with the hook error and timestamp) but do not
return/throw, then proceed to collect and await the processors' stop() promises
via promiseWithTimeout with this.exitTimeoutMs; ensure processor.stop() is
always invoked even if plugin stop hooks fail and surface both hook and
processor errors appropriately.

---

Nitpick comments:
In `@packages/chrono-core/src/plugins/lifecycle-context.ts`:
- Line 8: The API claims "read-only" access but the LifecycleContext interface
exposes a mutable array type; update the array-returning member on
LifecycleContext (e.g., the getPlugins / plugins method) to return a readonly
array type (use ReadonlyArray<Plugin> or readonly Plugin[]) and adjust the
implementation to return an immutable view (return a copy or Object.freeze/as
const) so callers cannot mutate internal state.

In `@packages/chrono-core/test/unit/chrono.test.ts`:
- Around line 165-200: Add a regression test that registers a plugin whose
onStart hook throws, then assert that calling chrono.start() rejects with that
error (or propagates it) and that Chrono recovers to a pre-start state by
allowing subsequent plugin registrations; specifically, in chrono.test.ts create
a plugin object with name like 'failing-start-plugin' and an onStart that
throws, call chrono.use(plugin), await expect(chrono.start()).rejects.toThrow(/*
error */), and then verify you can call chrono.use(anotherPlugin) successfully
(or check any available pre-start flag/state) to ensure the failed onStart
doesn't leave Chrono permanently started/locked.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: cae4f299-c0ac-403b-9bcb-e5290b3efa0c

📥 Commits

Reviewing files that changed from the base of the PR and between dfb3c5c and eb1c2bf.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (20)
  • .gitignore
  • README.md
  • biome.json
  • package.json
  • packages/chrono-core/README.md
  • packages/chrono-core/package.json
  • packages/chrono-core/src/chrono.ts
  • packages/chrono-core/src/index.ts
  • packages/chrono-core/src/plugins/chrono-plugin-context.ts
  • packages/chrono-core/src/plugins/index.ts
  • packages/chrono-core/src/plugins/lifecycle-context.ts
  • packages/chrono-core/src/plugins/registration-context.ts
  • packages/chrono-core/test/integration/plugins.test.ts
  • packages/chrono-core/test/unit/chrono.test.ts
  • packages/chrono-core/test/unit/plugins/chrono-plugin-context.test.ts
  • packages/chrono-core/vitest.config.ts
  • packages/chrono-mongo-datastore/README.md
  • packages/chrono-mongo-datastore/package.json
  • packages/chrono-mongo-datastore/src/chrono-mongo-datastore.ts
  • packages/chrono-mongo-datastore/test/unit/chrono-mongo-datastore.test.ts

Comment on lines 76 to 84
constructor(config?: Partial<ChronoMongoDatastoreConfig>) {
const { completedDocumentTTLSeconds, collectionName, ...rest } = config || {};

this.config = {
completedDocumentTTLSeconds: config?.completedDocumentTTLSeconds,
collectionName: config?.collectionName || DEFAULT_COLLECTION_NAME,
uninitializedDatastoreBehavior: rest.uninitializedDatastoreBehavior || 'queue',
...(rest.uninitializedDatastoreBehavior === 'queue' ? { maxQueueSize: rest.maxQueueSize } : undefined),
};
Copy link

@coderabbitai coderabbitai bot Mar 14, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

maxQueueSize is silently ignored when uninitializedDatastoreBehavior is not explicitly provided.

When a user provides { maxQueueSize: 100 } without explicitly setting uninitializedDatastoreBehavior, the default behavior correctly becomes 'queue' (line 82). However, line 83 checks rest.uninitializedDatastoreBehavior === 'queue', which is false when the property is undefined. This causes maxQueueSize to be dropped from the config.

Proposed fix
   constructor(config?: Partial<ChronoMongoDatastoreConfig>) {
     const { completedDocumentTTLSeconds, collectionName, ...rest } = config || {};
+    const behavior = rest.uninitializedDatastoreBehavior || 'queue';

     this.config = {
       completedDocumentTTLSeconds: config?.completedDocumentTTLSeconds,
       collectionName: config?.collectionName || DEFAULT_COLLECTION_NAME,
-      uninitializedDatastoreBehavior: rest.uninitializedDatastoreBehavior || 'queue',
-      ...(rest.uninitializedDatastoreBehavior === 'queue' ? { maxQueueSize: rest.maxQueueSize } : undefined),
+      uninitializedDatastoreBehavior: behavior,
+      ...(behavior === 'queue' ? { maxQueueSize: rest.maxQueueSize } : undefined),
     };
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
constructor(config?: Partial<ChronoMongoDatastoreConfig>) {
const { completedDocumentTTLSeconds, collectionName, ...rest } = config || {};
this.config = {
completedDocumentTTLSeconds: config?.completedDocumentTTLSeconds,
collectionName: config?.collectionName || DEFAULT_COLLECTION_NAME,
uninitializedDatastoreBehavior: rest.uninitializedDatastoreBehavior || 'queue',
...(rest.uninitializedDatastoreBehavior === 'queue' ? { maxQueueSize: rest.maxQueueSize } : undefined),
};
constructor(config?: Partial<ChronoMongoDatastoreConfig>) {
const { completedDocumentTTLSeconds, collectionName, ...rest } = config || {};
const behavior = rest.uninitializedDatastoreBehavior || 'queue';
this.config = {
completedDocumentTTLSeconds: config?.completedDocumentTTLSeconds,
collectionName: config?.collectionName || DEFAULT_COLLECTION_NAME,
uninitializedDatastoreBehavior: behavior,
...(behavior === 'queue' ? { maxQueueSize: rest.maxQueueSize } : undefined),
};
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/chrono-mongo-datastore/src/chrono-mongo-datastore.ts` around lines
76 - 84, The constructor currently uses rest.uninitializedDatastoreBehavior to
decide whether to include maxQueueSize, which is undefined when the caller omits
uninitializedDatastoreBehavior even though the code sets the default to 'queue';
update the logic to compute the effective behavior first (e.g., const behavior =
rest.uninitializedDatastoreBehavior || 'queue') and then set
uninitializedDatastoreBehavior: behavior and include maxQueueSize when behavior
=== 'queue' (e.g., ...(behavior === 'queue' ? { maxQueueSize: rest.maxQueueSize
} : undefined)); reference the constructor, ChronoMongoDatastoreConfig, config,
uninitializedDatastoreBehavior, and maxQueueSize when making this change.

Copy link
Collaborator

Choose a reason for hiding this comment

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

@darrenpicard25 this seems valid - since uninitializedDatastoreBehavior defaults to queue, shouldn't the maxQueueSize take effect in this case?

Copy link

Choose a reason for hiding this comment

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

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

possible code wise. But not possible typescript wise as you can only pass in a maxQueueSize if uninitializedDatastoreBehavior = 'queue'

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

input is a union

Copy link
Collaborator

@tjamescouch tjamescouch left a comment

Choose a reason for hiding this comment

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

I think this code rabbit comment should be addressed.

Comment on lines 76 to 84
constructor(config?: Partial<ChronoMongoDatastoreConfig>) {
const { completedDocumentTTLSeconds, collectionName, ...rest } = config || {};

this.config = {
completedDocumentTTLSeconds: config?.completedDocumentTTLSeconds,
collectionName: config?.collectionName || DEFAULT_COLLECTION_NAME,
uninitializedDatastoreBehavior: rest.uninitializedDatastoreBehavior || 'queue',
...(rest.uninitializedDatastoreBehavior === 'queue' ? { maxQueueSize: rest.maxQueueSize } : undefined),
};
Copy link
Collaborator

Choose a reason for hiding this comment

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

@darrenpicard25 this seems valid - since uninitializedDatastoreBehavior defaults to queue, shouldn't the maxQueueSize take effect in this case?

@wiz-a38520980d
Copy link

Wiz Scan Summary

Scanner Findings
Vulnerability Finding Vulnerabilities 1 Medium
Data Finding Sensitive Data -
Secret Finding Secrets -
IaC Misconfiguration IaC Misconfigurations -
SAST Finding SAST Findings -
Total 1 Medium

View scan details in Wiz

To detect these findings earlier in the dev lifecycle, try using Wiz Code VS Code Extension.

Copy link

@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.

🧹 Nitpick comments (1)
README.md (1)

25-52: Consider adding shutdown to the quick example.

After await chrono.start(), the sample never demonstrates teardown. Adding await chrono.stop() (or equivalent) makes copy-paste usage safer for scripts/tests.

Suggested README snippet tweak
 await chrono.scheduleTask({
   kind: "send-email",
   when: new Date(),
   data: { to: "user@example.com", subject: "Hello!", body: "Welcome!" },
 });
+
+await chrono.stop();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@README.md` around lines 25 - 52, The quick example starts the scheduler with
await chrono.start() but never shows teardown; update the snippet to demonstrate
clean shutdown by calling await chrono.stop() after scheduling/processing tasks
(or at the end of the example), ensuring you reference the same Chrono instance
(chrono) created from ChronoMemoryDatastore and keep the
registerTaskHandler/scheduleTask usage intact so users can copy-paste safe
scripts/tests.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@README.md`:
- Around line 25-52: The quick example starts the scheduler with await
chrono.start() but never shows teardown; update the snippet to demonstrate clean
shutdown by calling await chrono.stop() after scheduling/processing tasks (or at
the end of the example), ensuring you reference the same Chrono instance
(chrono) created from ChronoMemoryDatastore and keep the
registerTaskHandler/scheduleTask usage intact so users can copy-paste safe
scripts/tests.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9111d6eb-36d5-4e59-a5e0-733fd20a56c7

📥 Commits

Reviewing files that changed from the base of the PR and between eb1c2bf and 51e0b2d.

📒 Files selected for processing (1)
  • README.md

Copy link
Collaborator

@maiahneo maiahneo left a comment

Choose a reason for hiding this comment

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

🚀

) {
this.chrono = {
registerTaskHandler: chrono.registerTaskHandler.bind(chrono),
use: chrono.use.bind(chrono),
Copy link
Collaborator

Choose a reason for hiding this comment

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

A plugin can compose other plugins as well, nice!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants