Skip to content

feat: plugin template + create-plugin scaffold#34

Closed
kayodebristol wants to merge 1 commit into
mainfrom
feature/plugin-template
Closed

feat: plugin template + create-plugin scaffold#34
kayodebristol wants to merge 1 commit into
mainfrom
feature/plugin-template

Conversation

@kayodebristol

Copy link
Copy Markdown
Contributor

Adds a complete plugin template and scaffolding script. Usage: ./scripts/create-plugin.sh my-plugin 'My Plugin' author. Encodes the .px-first development pattern. Equivalent to svelte-tauri-template for plugin-scoped development.

Adds a complete plugin template at template/ and a create-plugin.sh
script that scaffolds new plugins with all placeholders replaced.

The template encodes the .px-first development pattern:
- px/ directory for declarative logic (auto-compiled by radix)
- src/handlers/ for ActionHandler implementations (IO boundary)
- tests/ for executable .px test scenarios
- manifest.json with full schema-compliant metadata

Usage:
  ./scripts/create-plugin.sh my-plugin "My Plugin" author

This gives pares-radix plugin development the same 'batteries included'
experience that svelte-tauri-template provides for general app development.
Copilot AI review requested due to automatic review settings May 20, 2026 15:46
@kayodebristol kayodebristol added the enhancement New feature or request label May 20, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds a new template/ directory intended to serve as the starting point for pares-radix plugins, plus a scripts/create-plugin.sh scaffolder that copies the template into plugins/<id> and substitutes placeholders.

Changes:

  • Introduces a plugin template containing a manifest, TypeScript entry/handlers, .px examples, and .px-based tests.
  • Adds scripts/create-plugin.sh to scaffold a new plugin from the template and replace placeholders.
  • Adds template documentation describing the plugin architecture and publishing flow.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
template/tests/plugin.px Adds an example executable .px test procedure.
template/src/index.ts Adds a template plugin entrypoint and lifecycle hooks.
template/src/handlers/index.ts Adds an example action handler and handler map.
template/README.md Documents the template structure, workflow, and publishing steps.
template/px/main.px Adds example .px procedures and trigger documentation.
template/px/constraints.px Adds example constraint documentation for .px.
template/manifest.json Adds a template plugin manifest with placeholders.
scripts/create-plugin.sh Adds a scaffold script to copy the template and substitute placeholders.
Comments suppressed due to low confidence (3)

template/src/index.ts:32

  • console.log in the plugin lifecycle entrypoint conflicts with the repo’s platform guidance to avoid manual console logging for business events (see plures/no-manual-logging). Since this file is intended to be copied into plugins/, it will introduce lint warnings in new plugins; prefer removing it or routing through the platform’s structured/contract-based observability mechanism.
    // .px files in the px/ directory are automatically compiled and
    // registered by pares-radix. You don't need to do anything here
    // for .px procedures to work — just drop .px files in px/.

    console.log(`[{{plugin-id}}] loaded`);
  },

template/src/index.ts:40

  • onActivate and onDeactivate declare a ctx parameter that isn't used. In this repo ESLint enforces @typescript-eslint/no-unused-vars as an error for plugin sources, so scaffolded plugins will fail lint unless the param is used or renamed (e.g. _ctx) / removed.
  async onActivate(ctx: PluginContext) {
    // Plugin activated — start any background work, subscriptions, etc.
  },

  async onDeactivate(ctx: PluginContext) {
    // Plugin deactivated — clean up subscriptions, timers, etc.
  },

template/src/handlers/index.ts:23

  • The example handler destructures params via a type assertion without runtime validation. If a procedure calls hello with a non-object/null payload, this will throw at runtime. Since this is the scaffolded starting point, it’s better to demonstrate safe parsing/validation (or at least guard typeof params === 'object' && params !== null).
const hello: ActionHandler = async (params: unknown) => {
  const { name } = params as { name: string };
  return { greeting: `Hello, ${name}!` };
};

Comment thread template/manifest.json
"dependencies": [],
"peerDependencies": {},
"entry": "src/index.ts",
"px": "px/",
Comment thread template/manifest.json
"keywords": [],
"homepage": "https://github.com/plures/pares-modulus/tree/main/plugins/{{plugin-id}}",
"repository": "https://github.com/plures/pares-modulus",
"radix": ">=1.44.0",
Comment thread template/src/index.ts
* and register your action handlers here.
*/

import type { PluginContext, PluginLifecycle } from '@pares/radix-plugin';
* and returns whatever $result should be.
*/

import type { ActionHandler } from '@pares/radix-plugin';
Comment thread template/tests/plugin.px
@@ -0,0 +1,17 @@
# Plugin tests — executable .px test scenarios.
#
# These run via `px run tests.px` or the pares-radix test harness.
Comment thread template/README.md

## Publishing

1. Validate your manifest: `scripts/validate-manifest.sh plugins/my-plugin`
Comment thread template/px/main.px
Comment on lines +10 to +11
# timer("name") — fires on a scheduled timer
# state_change("key") — fires when a PluresDB key is written
Comment thread scripts/create-plugin.sh
Comment on lines +8 to +32
PLUGIN_ID="${1:-}"
PLUGIN_NAME="${2:-}"
AUTHOR="${3:-plures}"

if [[ -z "$PLUGIN_ID" ]]; then
echo "Usage: $0 <plugin-id> [\"Plugin Name\"] [author]"
echo ""
echo "Example: $0 weather-advisor \"Weather Advisor\" kayodebristol"
exit 1
fi

if [[ -z "$PLUGIN_NAME" ]]; then
# Convert kebab-case to Title Case
PLUGIN_NAME=$(echo "$PLUGIN_ID" | sed 's/-/ /g' | awk '{for(i=1;i<=NF;i++) $i=toupper(substr($i,1,1))substr($i,2)}1')
fi

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
REPO_ROOT="$(dirname "$SCRIPT_DIR")"
TEMPLATE_DIR="$REPO_ROOT/template"
DEST_DIR="$REPO_ROOT/plugins/$PLUGIN_ID"

if [[ -d "$DEST_DIR" ]]; then
echo "Error: plugins/$PLUGIN_ID already exists"
exit 1
fi
Comment thread scripts/create-plugin.sh
Comment on lines +44 to +49
find "$DEST_DIR" -type f \( -name "*.json" -o -name "*.ts" -o -name "*.px" -o -name "*.md" \) -exec sed -i \
-e "s/{{plugin-id}}/$PLUGIN_ID/g" \
-e "s/{{Plugin Name}}/$PLUGIN_NAME/g" \
-e "s/{{your-name}}/$AUTHOR/g" \
-e "s/{{Brief description of your plugin}}/A pares-radix plugin/g" \
{} \;
@kayodebristol

Copy link
Copy Markdown
Contributor Author

Closing: CI uses npm but package.json has workspace:* deps (requires pnpm). Stale since May 20. Will recreate with corrected CI config when plugin template work resumes.

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

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants