From e08cf2af3459add59aac798cd3940e149788bc3f Mon Sep 17 00:00:00 2001 From: Noel Saw <56978803+noelsaw1@users.noreply.github.com> Date: Tue, 26 Aug 2025 08:26:24 -0700 Subject: [PATCH] Add FSM-based NHK PoC plugin starter --- assets/dist/fsm.js | 41 ++++++++++++++++++++ assets/ts/fsm.ts | 49 +++++++++++++++++++++++ changelog.md | 4 ++ composer.json | 12 ++++++ nhk-poc.php | 37 ++++++++++++++++++ package.json | 10 +++++ src/Admin/Menu.php | 73 +++++++++++++++++++++++++++++++++++ src/Api/AjaxHandler.php | 33 ++++++++++++++++ src/Core/FSM/StateMachine.php | 61 +++++++++++++++++++++++++++++ src/Core/Plugin.php | 70 +++++++++++++++++++++++++++++++++ 10 files changed, 390 insertions(+) create mode 100644 assets/dist/fsm.js create mode 100644 assets/ts/fsm.ts create mode 100644 changelog.md create mode 100644 composer.json create mode 100644 nhk-poc.php create mode 100644 package.json create mode 100644 src/Admin/Menu.php create mode 100644 src/Api/AjaxHandler.php create mode 100644 src/Core/FSM/StateMachine.php create mode 100644 src/Core/Plugin.php diff --git a/assets/dist/fsm.js b/assets/dist/fsm.js new file mode 100644 index 0000000..cc9c2bc --- /dev/null +++ b/assets/dist/fsm.js @@ -0,0 +1,41 @@ +"use strict"; +/** + * Shared FSM implementation in TypeScript. + * Mirrors PHP backend to maintain SSoT across contexts. + */ +Object.defineProperty(exports, "__esModule", { value: true }); +exports.StateMachine = void 0; +class StateMachine { + constructor(transitions, initial) { + this.transitions = transitions; + this.history = []; + this.state = initial; + this.history.push(initial); + } + transition(to) { + const allowed = this.transitions[this.state] || []; + if (allowed.includes(to)) { + this.state = to; + this.history.push(to); + return true; + } + return false; + } + getState() { + return this.state; + } + getHistory() { + return this.history; + } +} +exports.StateMachine = StateMachine; +// Example FSM instance for dashboard visualiser. +const definition = { + init: ['ready'], + ready: ['running', 'error'], + running: ['ready', 'error'], + error: ['ready'], +}; +const machine = new StateMachine(definition, 'init'); +// Expose machine for debugging in admin screens. +window.nhkPocMachine = machine; diff --git a/assets/ts/fsm.ts b/assets/ts/fsm.ts new file mode 100644 index 0000000..38b486a --- /dev/null +++ b/assets/ts/fsm.ts @@ -0,0 +1,49 @@ +/** + * Shared FSM implementation in TypeScript. + * Mirrors PHP backend to maintain SSoT across contexts. + */ + +export interface MachineDefinition { + [state: string]: string[]; +} + +export class StateMachine { + private state: string; + private history: string[] = []; + + constructor(private transitions: MachineDefinition, initial: string) { + this.state = initial; + this.history.push(initial); + } + + public transition(to: string): boolean { + const allowed = this.transitions[this.state] || []; + if (allowed.includes(to)) { + this.state = to; + this.history.push(to); + return true; + } + return false; + } + + public getState(): string { + return this.state; + } + + public getHistory(): string[] { + return this.history; + } +} + +// Example FSM instance for dashboard visualiser. +const definition: MachineDefinition = { + init: ['ready'], + ready: ['running', 'error'], + running: ['ready', 'error'], + error: ['ready'], +}; + +const machine = new StateMachine(definition, 'init'); + +// Expose machine for debugging in admin screens. +(window as any).nhkPocMachine = machine; diff --git a/changelog.md b/changelog.md new file mode 100644 index 0000000..e2b96db --- /dev/null +++ b/changelog.md @@ -0,0 +1,4 @@ +# Changelog + +## 1.0.0 +- Initial proof-of-concept release with FSM-based architecture. diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..48d3ed0 --- /dev/null +++ b/composer.json @@ -0,0 +1,12 @@ +{ + "name": "nhk/poc", + "description": "NHK Proof of Concept WordPress plugin framework", + "type": "wordpress-plugin", + "license": "GPL-2.0-or-later", + "autoload": { + "psr-4": { + "NHK\\Poc\\": "src/" + } + }, + "require": {} +} diff --git a/nhk-poc.php b/nhk-poc.php new file mode 100644 index 0000000..429f267 --- /dev/null +++ b/nhk-poc.php @@ -0,0 +1,37 @@ +boot(); +} ); + +// Add settings link on Plugins listing page. +add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ), function ( $links ) { + $url = admin_url( 'admin.php?page=nhk-poc-settings' ); + $links[] = '' . esc_html__( 'Settings', 'nhk-poc' ) . ''; + return $links; +} ); diff --git a/package.json b/package.json new file mode 100644 index 0000000..46243bd --- /dev/null +++ b/package.json @@ -0,0 +1,10 @@ +{ + "name": "nhk-poc", + "version": "1.0.0", + "devDependencies": { + "typescript": "^5.0.0" + }, + "scripts": { + "build": "tsc assets/ts/fsm.ts --target ES2017 --module commonjs --outDir assets/dist" + } +} diff --git a/src/Admin/Menu.php b/src/Admin/Menu.php new file mode 100644 index 0000000..5ddc45a --- /dev/null +++ b/src/Admin/Menu.php @@ -0,0 +1,73 @@ +serialize() ); + } ); + } + + public static function render_dashboard(): void { + echo '
FSM-driven settings page.
FSM History: ' . esc_html( implode( ' → ', $this->sm->history() ) ) . '