@crossdelta/platform-sdk 0.19.0 → 0.19.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/README.md +27 -5
  2. package/bin/chunk-634PL24Z.mjs +20 -0
  3. package/bin/cli.mjs +604 -0
  4. package/bin/config-CKQHYOF4.mjs +2 -0
  5. package/bin/docs/generators/code-style.md +79 -0
  6. package/bin/docs/generators/natural-language.md +117 -0
  7. package/bin/docs/generators/service.md +129 -60
  8. package/bin/templates/hono-microservice/Dockerfile.hbs +3 -1
  9. package/bin/templates/hono-microservice/src/config/env.ts.hbs +3 -0
  10. package/bin/templates/nest-microservice/Dockerfile.hbs +6 -2
  11. package/bin/templates/nest-microservice/src/config/env.ts.hbs +17 -0
  12. package/bin/templates/nest-microservice/src/main.ts.hbs +2 -1
  13. package/bin/templates/workspace/.github/actions/prepare-build-context/action.yml +58 -6
  14. package/bin/templates/workspace/.github/workflows/build-and-deploy.yml.hbs +25 -3
  15. package/bin/templates/workspace/.github/workflows/publish-packages.yml +6 -8
  16. package/bin/templates/workspace/biome.json.hbs +4 -1
  17. package/bin/templates/workspace/infra/package.json.hbs +2 -2
  18. package/bin/templates/workspace/package.json.hbs +1 -0
  19. package/bin/templates/workspace/packages/contracts/README.md.hbs +5 -5
  20. package/bin/templates/workspace/packages/contracts/package.json.hbs +15 -6
  21. package/bin/templates/workspace/packages/contracts/src/index.ts +1 -1
  22. package/bin/templates/workspace/packages/contracts/tsconfig.json.hbs +6 -1
  23. package/bin/templates/workspace/turbo.json +8 -11
  24. package/bin/templates/workspace/turbo.json.hbs +6 -5
  25. package/dist/facade.d.mts +840 -0
  26. package/dist/facade.d.ts +840 -0
  27. package/dist/facade.js +2294 -0
  28. package/dist/facade.js.map +1 -0
  29. package/dist/facade.mjs +2221 -0
  30. package/dist/facade.mjs.map +1 -0
  31. package/dist/plugin-types-DQOv97Zh.d.mts +180 -0
  32. package/dist/plugin-types-DQOv97Zh.d.ts +180 -0
  33. package/dist/plugin-types.d.mts +1 -0
  34. package/dist/plugin-types.d.ts +1 -0
  35. package/dist/plugin-types.js +19 -0
  36. package/dist/plugin-types.js.map +1 -0
  37. package/dist/plugin-types.mjs +1 -0
  38. package/dist/plugin-types.mjs.map +1 -0
  39. package/dist/plugin.d.mts +31 -0
  40. package/dist/plugin.d.ts +31 -0
  41. package/dist/plugin.js +105 -0
  42. package/dist/plugin.js.map +1 -0
  43. package/dist/plugin.mjs +75 -0
  44. package/dist/plugin.mjs.map +1 -0
  45. package/package.json +118 -99
  46. package/bin/cli.js +0 -540
@@ -0,0 +1,180 @@
1
+ /**
2
+ * Plugin System Types
3
+ *
4
+ * pf owns and defines these interfaces.
5
+ * Plugins MUST adapt to these interfaces.
6
+ * pf is strict and predictable - no duck-typing, no fallbacks.
7
+ */
8
+ /**
9
+ * Base effect type - all domain effects must have a kind
10
+ * pf handles effects generically via kind-based handler registry
11
+ */
12
+ interface PfEffect {
13
+ readonly kind: string;
14
+ }
15
+ /**
16
+ * File write effect - write content to a file
17
+ */
18
+ interface FileWriteEffect extends PfEffect {
19
+ readonly kind: 'file:write';
20
+ readonly path: string;
21
+ readonly content: string;
22
+ }
23
+ /**
24
+ * Infrastructure service configuration effect
25
+ */
26
+ interface InfraAddEffect extends PfEffect {
27
+ readonly kind: 'infra:add';
28
+ readonly serviceName: string;
29
+ readonly port: number;
30
+ readonly framework: string;
31
+ readonly runtime: string;
32
+ }
33
+ /**
34
+ * Environment variable effect
35
+ */
36
+ interface EnvAddEffect extends PfEffect {
37
+ readonly kind: 'env:add';
38
+ readonly key: string;
39
+ readonly value: string;
40
+ }
41
+ /**
42
+ * Field definition for input elicitation
43
+ *
44
+ * Describes a single field that needs user input.
45
+ * Host-agnostic - CLI and MCP interpret this differently.
46
+ */
47
+ interface ElicitInputField {
48
+ /** Field name (used as key in response) */
49
+ readonly name: string;
50
+ /** Human-readable prompt/question */
51
+ readonly prompt: string;
52
+ /** Whether the field is required */
53
+ readonly required?: boolean;
54
+ /** Detailed description (shown as help text) */
55
+ readonly description?: string;
56
+ /** Default value if user provides nothing */
57
+ readonly defaultValue?: unknown;
58
+ /** Allowed values (enum constraint) */
59
+ readonly enum?: readonly string[];
60
+ /** Field type hint */
61
+ readonly type?: 'string' | 'number' | 'boolean';
62
+ }
63
+ /**
64
+ * Input elicitation effect
65
+ *
66
+ * Returned by tools when required inputs are missing.
67
+ * Pure data - no MCP SDK imports, no host-specific logic.
68
+ *
69
+ * Hosts interpret this effect differently:
70
+ * - CLI: Interactive prompt
71
+ * - MCP: server.elicitInput() or structured error
72
+ */
73
+ interface ElicitInputEffect extends PfEffect {
74
+ readonly kind: 'elicit:input';
75
+ /** Message explaining what's needed */
76
+ readonly message: string;
77
+ /** Fields to collect from user */
78
+ readonly fields: readonly ElicitInputField[];
79
+ }
80
+ /**
81
+ * Type guard for ElicitInputEffect
82
+ */
83
+ declare const isElicitInputEffect: (effect: PfEffect) => effect is ElicitInputEffect;
84
+ /**
85
+ * Result of running a command
86
+ */
87
+ interface PfCommandResult {
88
+ /** Domain effects to be applied by the runtime */
89
+ effects: PfEffect[];
90
+ /** Optional output to display (for read-only commands) */
91
+ output?: string | string[];
92
+ }
93
+ /**
94
+ * Command argument definition
95
+ */
96
+ interface PfCommandArg {
97
+ name: string;
98
+ description: string;
99
+ required: boolean;
100
+ }
101
+ /**
102
+ * Command option definition
103
+ */
104
+ interface PfCommandOption {
105
+ flags: string;
106
+ description: string;
107
+ default?: unknown;
108
+ }
109
+ /**
110
+ * A CLI command provided by a plugin
111
+ *
112
+ * Plugins MUST implement this exact interface.
113
+ */
114
+ interface PfCommand {
115
+ name: string;
116
+ description: string;
117
+ args: PfCommandArg[];
118
+ options: PfCommandOption[];
119
+ run(args: Record<string, unknown>, options: Record<string, unknown>): Promise<PfCommandResult>;
120
+ }
121
+ /**
122
+ * An interactive flow provided by a plugin
123
+ */
124
+ interface PfFlow {
125
+ name: string;
126
+ description: string;
127
+ getSteps(initialContext?: Record<string, unknown>): Promise<unknown[]>;
128
+ }
129
+ /**
130
+ * Workspace context with all discovered information
131
+ * pf owns this - plugins receive it during setup
132
+ */
133
+ interface PfWorkspaceContext {
134
+ /** Absolute path to workspace root */
135
+ workspaceRoot: string;
136
+ /** Discovered services (relative paths like 'services/api-gateway') */
137
+ availableServices: string[];
138
+ /** Contracts package configuration */
139
+ contracts: {
140
+ /** Relative path to contracts source (e.g., 'packages/contracts/src') */
141
+ path: string;
142
+ /** Package name (e.g., '@my-platform/contracts') */
143
+ packageName?: string;
144
+ };
145
+ }
146
+ /**
147
+ * Plugin context provided by pf during setup
148
+ */
149
+ interface PfPluginContext {
150
+ workspace: PfWorkspaceContext;
151
+ logger: {
152
+ debug: (message: string) => void;
153
+ info: (message: string) => void;
154
+ warn: (message: string) => void;
155
+ error: (message: string) => void;
156
+ };
157
+ }
158
+ /**
159
+ * A plugin that can be loaded by pf
160
+ *
161
+ * Plugins MUST implement this exact interface.
162
+ * If a plugin has a different internal API, it must provide an adapter.
163
+ */
164
+ interface PfPlugin {
165
+ name: string;
166
+ version: string;
167
+ description?: string;
168
+ commands: PfCommand[];
169
+ flows: PfFlow[];
170
+ setup: (context: PfPluginContext) => Promise<void> | void;
171
+ }
172
+ /**
173
+ * Result of loading a plugin
174
+ */
175
+ interface LoadedPlugin {
176
+ plugin: PfPlugin;
177
+ source: string;
178
+ }
179
+
180
+ export { type ElicitInputEffect as E, type FileWriteEffect as F, type InfraAddEffect as I, type LoadedPlugin as L, type PfWorkspaceContext as P, type PfPluginContext as a, type PfPlugin as b, type PfCommand as c, type PfCommandArg as d, type PfCommandOption as e, type PfFlow as f, type PfEffect as g, type ElicitInputField as h, type EnvAddEffect as i, type PfCommandResult as j, isElicitInputEffect as k };
@@ -0,0 +1,180 @@
1
+ /**
2
+ * Plugin System Types
3
+ *
4
+ * pf owns and defines these interfaces.
5
+ * Plugins MUST adapt to these interfaces.
6
+ * pf is strict and predictable - no duck-typing, no fallbacks.
7
+ */
8
+ /**
9
+ * Base effect type - all domain effects must have a kind
10
+ * pf handles effects generically via kind-based handler registry
11
+ */
12
+ interface PfEffect {
13
+ readonly kind: string;
14
+ }
15
+ /**
16
+ * File write effect - write content to a file
17
+ */
18
+ interface FileWriteEffect extends PfEffect {
19
+ readonly kind: 'file:write';
20
+ readonly path: string;
21
+ readonly content: string;
22
+ }
23
+ /**
24
+ * Infrastructure service configuration effect
25
+ */
26
+ interface InfraAddEffect extends PfEffect {
27
+ readonly kind: 'infra:add';
28
+ readonly serviceName: string;
29
+ readonly port: number;
30
+ readonly framework: string;
31
+ readonly runtime: string;
32
+ }
33
+ /**
34
+ * Environment variable effect
35
+ */
36
+ interface EnvAddEffect extends PfEffect {
37
+ readonly kind: 'env:add';
38
+ readonly key: string;
39
+ readonly value: string;
40
+ }
41
+ /**
42
+ * Field definition for input elicitation
43
+ *
44
+ * Describes a single field that needs user input.
45
+ * Host-agnostic - CLI and MCP interpret this differently.
46
+ */
47
+ interface ElicitInputField {
48
+ /** Field name (used as key in response) */
49
+ readonly name: string;
50
+ /** Human-readable prompt/question */
51
+ readonly prompt: string;
52
+ /** Whether the field is required */
53
+ readonly required?: boolean;
54
+ /** Detailed description (shown as help text) */
55
+ readonly description?: string;
56
+ /** Default value if user provides nothing */
57
+ readonly defaultValue?: unknown;
58
+ /** Allowed values (enum constraint) */
59
+ readonly enum?: readonly string[];
60
+ /** Field type hint */
61
+ readonly type?: 'string' | 'number' | 'boolean';
62
+ }
63
+ /**
64
+ * Input elicitation effect
65
+ *
66
+ * Returned by tools when required inputs are missing.
67
+ * Pure data - no MCP SDK imports, no host-specific logic.
68
+ *
69
+ * Hosts interpret this effect differently:
70
+ * - CLI: Interactive prompt
71
+ * - MCP: server.elicitInput() or structured error
72
+ */
73
+ interface ElicitInputEffect extends PfEffect {
74
+ readonly kind: 'elicit:input';
75
+ /** Message explaining what's needed */
76
+ readonly message: string;
77
+ /** Fields to collect from user */
78
+ readonly fields: readonly ElicitInputField[];
79
+ }
80
+ /**
81
+ * Type guard for ElicitInputEffect
82
+ */
83
+ declare const isElicitInputEffect: (effect: PfEffect) => effect is ElicitInputEffect;
84
+ /**
85
+ * Result of running a command
86
+ */
87
+ interface PfCommandResult {
88
+ /** Domain effects to be applied by the runtime */
89
+ effects: PfEffect[];
90
+ /** Optional output to display (for read-only commands) */
91
+ output?: string | string[];
92
+ }
93
+ /**
94
+ * Command argument definition
95
+ */
96
+ interface PfCommandArg {
97
+ name: string;
98
+ description: string;
99
+ required: boolean;
100
+ }
101
+ /**
102
+ * Command option definition
103
+ */
104
+ interface PfCommandOption {
105
+ flags: string;
106
+ description: string;
107
+ default?: unknown;
108
+ }
109
+ /**
110
+ * A CLI command provided by a plugin
111
+ *
112
+ * Plugins MUST implement this exact interface.
113
+ */
114
+ interface PfCommand {
115
+ name: string;
116
+ description: string;
117
+ args: PfCommandArg[];
118
+ options: PfCommandOption[];
119
+ run(args: Record<string, unknown>, options: Record<string, unknown>): Promise<PfCommandResult>;
120
+ }
121
+ /**
122
+ * An interactive flow provided by a plugin
123
+ */
124
+ interface PfFlow {
125
+ name: string;
126
+ description: string;
127
+ getSteps(initialContext?: Record<string, unknown>): Promise<unknown[]>;
128
+ }
129
+ /**
130
+ * Workspace context with all discovered information
131
+ * pf owns this - plugins receive it during setup
132
+ */
133
+ interface PfWorkspaceContext {
134
+ /** Absolute path to workspace root */
135
+ workspaceRoot: string;
136
+ /** Discovered services (relative paths like 'services/api-gateway') */
137
+ availableServices: string[];
138
+ /** Contracts package configuration */
139
+ contracts: {
140
+ /** Relative path to contracts source (e.g., 'packages/contracts/src') */
141
+ path: string;
142
+ /** Package name (e.g., '@my-platform/contracts') */
143
+ packageName?: string;
144
+ };
145
+ }
146
+ /**
147
+ * Plugin context provided by pf during setup
148
+ */
149
+ interface PfPluginContext {
150
+ workspace: PfWorkspaceContext;
151
+ logger: {
152
+ debug: (message: string) => void;
153
+ info: (message: string) => void;
154
+ warn: (message: string) => void;
155
+ error: (message: string) => void;
156
+ };
157
+ }
158
+ /**
159
+ * A plugin that can be loaded by pf
160
+ *
161
+ * Plugins MUST implement this exact interface.
162
+ * If a plugin has a different internal API, it must provide an adapter.
163
+ */
164
+ interface PfPlugin {
165
+ name: string;
166
+ version: string;
167
+ description?: string;
168
+ commands: PfCommand[];
169
+ flows: PfFlow[];
170
+ setup: (context: PfPluginContext) => Promise<void> | void;
171
+ }
172
+ /**
173
+ * Result of loading a plugin
174
+ */
175
+ interface LoadedPlugin {
176
+ plugin: PfPlugin;
177
+ source: string;
178
+ }
179
+
180
+ export { type ElicitInputEffect as E, type FileWriteEffect as F, type InfraAddEffect as I, type LoadedPlugin as L, type PfWorkspaceContext as P, type PfPluginContext as a, type PfPlugin as b, type PfCommand as c, type PfCommandArg as d, type PfCommandOption as e, type PfFlow as f, type PfEffect as g, type ElicitInputField as h, type EnvAddEffect as i, type PfCommandResult as j, isElicitInputEffect as k };
@@ -0,0 +1 @@
1
+ export { L as LoadedPlugin, c as PfCommand, d as PfCommandArg, e as PfCommandOption, f as PfFlow, b as PfPlugin, a as PfPluginContext } from './plugin-types-DQOv97Zh.mjs';
@@ -0,0 +1 @@
1
+ export { L as LoadedPlugin, c as PfCommand, d as PfCommandArg, e as PfCommandOption, f as PfFlow, b as PfPlugin, a as PfPluginContext } from './plugin-types-DQOv97Zh.js';
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __copyProps = (to, from, except, desc) => {
7
+ if (from && typeof from === "object" || typeof from === "function") {
8
+ for (let key of __getOwnPropNames(from))
9
+ if (!__hasOwnProp.call(to, key) && key !== except)
10
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
11
+ }
12
+ return to;
13
+ };
14
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
15
+
16
+ // cli/src/plugin-types.ts
17
+ var plugin_types_exports = {};
18
+ module.exports = __toCommonJS(plugin_types_exports);
19
+ //# sourceMappingURL=plugin-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../cli/src/plugin-types.ts"],"sourcesContent":["/**\n * Plugin System Types - Public API\n *\n * pf owns and defines these interfaces.\n * Plugins MUST import these and implement them.\n *\n * This is the ONLY public export for plugin development.\n */\n\nexport type {\n LoadedPlugin,\n PfCommand,\n PfCommandArg,\n PfCommandOption,\n PfFlow,\n PfPlugin,\n PfPluginContext,\n} from './core/plugins'\n"],"mappings":";;;;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=plugin-types.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,31 @@
1
+ import { P as PfWorkspaceContext, a as PfPluginContext, L as LoadedPlugin, b as PfPlugin } from './plugin-types-DQOv97Zh.mjs';
2
+ export { c as PfCommand, d as PfCommandArg, e as PfCommandOption, f as PfFlow } from './plugin-types-DQOv97Zh.mjs';
3
+
4
+ /**
5
+ * Plugin Loader
6
+ *
7
+ * pf owns the plugin interface. Plugins MUST conform exactly.
8
+ * Strict validation - no duck-typing, no fallbacks.
9
+ */
10
+
11
+ /**
12
+ * Validates that an object conforms to the PfPlugin interface
13
+ */
14
+ declare const validatePlugin: (obj: unknown) => obj is PfPlugin;
15
+ /**
16
+ * Detailed validation with error messages
17
+ */
18
+ declare const validatePluginStrict: (obj: unknown) => string[];
19
+ /**
20
+ * Create a plugin context from workspace discovery
21
+ */
22
+ declare const createPluginContext: (workspace: PfWorkspaceContext, logger?: PfPluginContext["logger"]) => PfPluginContext;
23
+ /**
24
+ * Load and initialize a plugin from a module
25
+ *
26
+ * @param moduleName - The module to import (e.g., '@crossdelta/cloudevents')
27
+ * @param context - Full plugin context with workspace info
28
+ */
29
+ declare const loadPluginFromModule: (moduleName: string, context: PfPluginContext) => Promise<LoadedPlugin>;
30
+
31
+ export { LoadedPlugin, PfPlugin, PfPluginContext, PfWorkspaceContext, createPluginContext, loadPluginFromModule, validatePlugin, validatePluginStrict };
@@ -0,0 +1,31 @@
1
+ import { P as PfWorkspaceContext, a as PfPluginContext, L as LoadedPlugin, b as PfPlugin } from './plugin-types-DQOv97Zh.js';
2
+ export { c as PfCommand, d as PfCommandArg, e as PfCommandOption, f as PfFlow } from './plugin-types-DQOv97Zh.js';
3
+
4
+ /**
5
+ * Plugin Loader
6
+ *
7
+ * pf owns the plugin interface. Plugins MUST conform exactly.
8
+ * Strict validation - no duck-typing, no fallbacks.
9
+ */
10
+
11
+ /**
12
+ * Validates that an object conforms to the PfPlugin interface
13
+ */
14
+ declare const validatePlugin: (obj: unknown) => obj is PfPlugin;
15
+ /**
16
+ * Detailed validation with error messages
17
+ */
18
+ declare const validatePluginStrict: (obj: unknown) => string[];
19
+ /**
20
+ * Create a plugin context from workspace discovery
21
+ */
22
+ declare const createPluginContext: (workspace: PfWorkspaceContext, logger?: PfPluginContext["logger"]) => PfPluginContext;
23
+ /**
24
+ * Load and initialize a plugin from a module
25
+ *
26
+ * @param moduleName - The module to import (e.g., '@crossdelta/cloudevents')
27
+ * @param context - Full plugin context with workspace info
28
+ */
29
+ declare const loadPluginFromModule: (moduleName: string, context: PfPluginContext) => Promise<LoadedPlugin>;
30
+
31
+ export { LoadedPlugin, PfPlugin, PfPluginContext, PfWorkspaceContext, createPluginContext, loadPluginFromModule, validatePlugin, validatePluginStrict };
package/dist/plugin.js ADDED
@@ -0,0 +1,105 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // cli/src/core/plugins/index.ts
21
+ var plugins_exports = {};
22
+ __export(plugins_exports, {
23
+ createPluginContext: () => createPluginContext,
24
+ loadPluginFromModule: () => loadPluginFromModule,
25
+ validatePlugin: () => validatePlugin,
26
+ validatePluginStrict: () => validatePluginStrict
27
+ });
28
+ module.exports = __toCommonJS(plugins_exports);
29
+
30
+ // cli/src/core/plugins/loader.ts
31
+ var defaultLogger = {
32
+ debug: () => {
33
+ },
34
+ info: console.log,
35
+ warn: console.warn,
36
+ error: console.error
37
+ };
38
+ var isObject = (val) => val !== null && typeof val === "object";
39
+ var isNonEmptyString = (val) => typeof val === "string" && val.length > 0;
40
+ var isString = (val) => typeof val === "string";
41
+ var isFunction = (val) => typeof val === "function";
42
+ var validateCommand = (cmd, index) => {
43
+ if (!isObject(cmd)) return [`commands[${index}]: must be an object`];
44
+ return [
45
+ !isNonEmptyString(cmd.name) && `commands[${index}]: missing or invalid 'name'`,
46
+ !isString(cmd.description) && `commands[${index}]: missing or invalid 'description'`,
47
+ !Array.isArray(cmd.args) && `commands[${index}]: missing 'args' array`,
48
+ !Array.isArray(cmd.options) && `commands[${index}]: missing 'options' array`,
49
+ !isFunction(cmd.run) && `commands[${index}]: missing 'run' function`
50
+ ].filter((e) => e !== false);
51
+ };
52
+ var validatePlugin = (obj) => {
53
+ if (!isObject(obj)) return false;
54
+ return isNonEmptyString(obj.name) && isString(obj.version) && Array.isArray(obj.commands) && Array.isArray(obj.flows) && isFunction(obj.setup);
55
+ };
56
+ var validatePluginStrict = (obj) => {
57
+ if (!isObject(obj)) return ["Plugin must be an object"];
58
+ const baseErrors = [
59
+ !isNonEmptyString(obj.name) && "Missing or invalid 'name'",
60
+ !isString(obj.version) && "Missing or invalid 'version'",
61
+ !Array.isArray(obj.commands) && "Missing 'commands' array",
62
+ !Array.isArray(obj.flows) && "Missing 'flows' array",
63
+ !isFunction(obj.setup) && "Missing 'setup' function"
64
+ ].filter((e) => e !== false);
65
+ const commandErrors = Array.isArray(obj.commands) ? obj.commands.flatMap((cmd, i) => validateCommand(cmd, i)) : [];
66
+ return [...baseErrors, ...commandErrors];
67
+ };
68
+ var createPluginContext = (workspace, logger = defaultLogger) => ({
69
+ workspace,
70
+ logger
71
+ });
72
+ var loadPluginFromModule = async (moduleName, context) => {
73
+ const { logger } = context;
74
+ logger.debug(`Loading plugin from module: ${moduleName}`);
75
+ const mod = await import(moduleName);
76
+ const createPlugin = mod.createPfPlugin || mod.default?.createPfPlugin;
77
+ if (!isFunction(createPlugin)) {
78
+ throw new Error(`Module ${moduleName} does not export createPfPlugin`);
79
+ }
80
+ const plugin = createPlugin({
81
+ contractsPath: context.workspace.contracts.path,
82
+ contractsPackage: context.workspace.contracts.packageName,
83
+ availableServices: context.workspace.availableServices
84
+ });
85
+ const errors = validatePluginStrict(plugin);
86
+ if (errors.length > 0) {
87
+ throw new Error(`Plugin from ${moduleName} does not conform to PfPlugin interface:
88
+ - ${errors.join("\n - ")}`);
89
+ }
90
+ const validatedPlugin = plugin;
91
+ logger.debug(`Loaded plugin: ${validatedPlugin.name} v${validatedPlugin.version}`);
92
+ await validatedPlugin.setup(context);
93
+ return {
94
+ plugin: validatedPlugin,
95
+ source: moduleName
96
+ };
97
+ };
98
+ // Annotate the CommonJS export names for ESM import in node:
99
+ 0 && (module.exports = {
100
+ createPluginContext,
101
+ loadPluginFromModule,
102
+ validatePlugin,
103
+ validatePluginStrict
104
+ });
105
+ //# sourceMappingURL=plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../cli/src/core/plugins/index.ts","../cli/src/core/plugins/loader.ts"],"sourcesContent":["/**\n * Plugin System\n *\n * pf owns and defines the plugin interfaces.\n * Plugins MUST adapt to these interfaces.\n */\n\nexport {\n createPluginContext,\n loadPluginFromModule,\n validatePlugin,\n validatePluginStrict,\n} from './loader'\nexport type {\n LoadedPlugin,\n PfCommand,\n PfCommandArg,\n PfCommandOption,\n PfFlow,\n PfPlugin,\n PfPluginContext,\n PfWorkspaceContext,\n} from './types'\n","/**\n * Plugin Loader\n *\n * pf owns the plugin interface. Plugins MUST conform exactly.\n * Strict validation - no duck-typing, no fallbacks.\n */\nimport type { LoadedPlugin, PfPlugin, PfPluginContext, PfWorkspaceContext } from './types'\n\nconst defaultLogger: PfPluginContext['logger'] = {\n debug: () => {},\n info: console.log,\n warn: console.warn,\n error: console.error,\n}\n\nconst isObject = (val: unknown): val is Record<string, unknown> =>\n val !== null && typeof val === 'object'\n\nconst isNonEmptyString = (val: unknown): val is string =>\n typeof val === 'string' && val.length > 0\n\nconst isString = (val: unknown): val is string =>\n typeof val === 'string'\n\nconst isFunction = (val: unknown): val is (...args: unknown[]) => unknown =>\n typeof val === 'function'\n\n/**\n * Validates a single command conforms to PfCommand interface\n */\nconst validateCommand = (cmd: unknown, index: number): string[] => {\n if (!isObject(cmd)) return [`commands[${index}]: must be an object`]\n\n return [\n !isNonEmptyString(cmd.name) && `commands[${index}]: missing or invalid 'name'`,\n !isString(cmd.description) && `commands[${index}]: missing or invalid 'description'`,\n !Array.isArray(cmd.args) && `commands[${index}]: missing 'args' array`,\n !Array.isArray(cmd.options) && `commands[${index}]: missing 'options' array`,\n !isFunction(cmd.run) && `commands[${index}]: missing 'run' function`,\n ].filter((e): e is string => e !== false)\n}\n\n/**\n * Validates that an object conforms to the PfPlugin interface\n */\nexport const validatePlugin = (obj: unknown): obj is PfPlugin => {\n if (!isObject(obj)) return false\n\n return (\n isNonEmptyString(obj.name) &&\n isString(obj.version) &&\n Array.isArray(obj.commands) &&\n Array.isArray(obj.flows) &&\n isFunction(obj.setup)\n )\n}\n\n/**\n * Detailed validation with error messages\n */\nexport const validatePluginStrict = (obj: unknown): string[] => {\n if (!isObject(obj)) return ['Plugin must be an object']\n\n const baseErrors = [\n !isNonEmptyString(obj.name) && \"Missing or invalid 'name'\",\n !isString(obj.version) && \"Missing or invalid 'version'\",\n !Array.isArray(obj.commands) && \"Missing 'commands' array\",\n !Array.isArray(obj.flows) && \"Missing 'flows' array\",\n !isFunction(obj.setup) && \"Missing 'setup' function\",\n ].filter((e): e is string => e !== false)\n\n const commandErrors = Array.isArray(obj.commands)\n ? obj.commands.flatMap((cmd, i) => validateCommand(cmd, i))\n : []\n\n return [...baseErrors, ...commandErrors]\n}\n\n/**\n * Create a plugin context from workspace discovery\n */\nexport const createPluginContext = (\n workspace: PfWorkspaceContext,\n logger: PfPluginContext['logger'] = defaultLogger,\n): PfPluginContext => ({\n workspace,\n logger,\n})\n\n/**\n * Load and initialize a plugin from a module\n *\n * @param moduleName - The module to import (e.g., '@crossdelta/cloudevents')\n * @param context - Full plugin context with workspace info\n */\nexport const loadPluginFromModule = async (\n moduleName: string,\n context: PfPluginContext,\n): Promise<LoadedPlugin> => {\n const { logger } = context\n\n logger.debug(`Loading plugin from module: ${moduleName}`)\n\n const mod = await import(moduleName)\n\n const createPlugin = mod.createPfPlugin || mod.default?.createPfPlugin\n if (!isFunction(createPlugin)) {\n throw new Error(`Module ${moduleName} does not export createPfPlugin`)\n }\n\n const plugin = createPlugin({\n contractsPath: context.workspace.contracts.path,\n contractsPackage: context.workspace.contracts.packageName,\n availableServices: context.workspace.availableServices,\n })\n\n const errors = validatePluginStrict(plugin)\n if (errors.length > 0) {\n throw new Error(`Plugin from ${moduleName} does not conform to PfPlugin interface:\\n - ${errors.join('\\n - ')}`)\n }\n\n const validatedPlugin = plugin as PfPlugin\n\n logger.debug(`Loaded plugin: ${validatedPlugin.name} v${validatedPlugin.version}`)\n\n await validatedPlugin.setup(context)\n\n return {\n plugin: validatedPlugin,\n source: moduleName,\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,75 @@
1
+ // cli/src/core/plugins/loader.ts
2
+ var defaultLogger = {
3
+ debug: () => {
4
+ },
5
+ info: console.log,
6
+ warn: console.warn,
7
+ error: console.error
8
+ };
9
+ var isObject = (val) => val !== null && typeof val === "object";
10
+ var isNonEmptyString = (val) => typeof val === "string" && val.length > 0;
11
+ var isString = (val) => typeof val === "string";
12
+ var isFunction = (val) => typeof val === "function";
13
+ var validateCommand = (cmd, index) => {
14
+ if (!isObject(cmd)) return [`commands[${index}]: must be an object`];
15
+ return [
16
+ !isNonEmptyString(cmd.name) && `commands[${index}]: missing or invalid 'name'`,
17
+ !isString(cmd.description) && `commands[${index}]: missing or invalid 'description'`,
18
+ !Array.isArray(cmd.args) && `commands[${index}]: missing 'args' array`,
19
+ !Array.isArray(cmd.options) && `commands[${index}]: missing 'options' array`,
20
+ !isFunction(cmd.run) && `commands[${index}]: missing 'run' function`
21
+ ].filter((e) => e !== false);
22
+ };
23
+ var validatePlugin = (obj) => {
24
+ if (!isObject(obj)) return false;
25
+ return isNonEmptyString(obj.name) && isString(obj.version) && Array.isArray(obj.commands) && Array.isArray(obj.flows) && isFunction(obj.setup);
26
+ };
27
+ var validatePluginStrict = (obj) => {
28
+ if (!isObject(obj)) return ["Plugin must be an object"];
29
+ const baseErrors = [
30
+ !isNonEmptyString(obj.name) && "Missing or invalid 'name'",
31
+ !isString(obj.version) && "Missing or invalid 'version'",
32
+ !Array.isArray(obj.commands) && "Missing 'commands' array",
33
+ !Array.isArray(obj.flows) && "Missing 'flows' array",
34
+ !isFunction(obj.setup) && "Missing 'setup' function"
35
+ ].filter((e) => e !== false);
36
+ const commandErrors = Array.isArray(obj.commands) ? obj.commands.flatMap((cmd, i) => validateCommand(cmd, i)) : [];
37
+ return [...baseErrors, ...commandErrors];
38
+ };
39
+ var createPluginContext = (workspace, logger = defaultLogger) => ({
40
+ workspace,
41
+ logger
42
+ });
43
+ var loadPluginFromModule = async (moduleName, context) => {
44
+ const { logger } = context;
45
+ logger.debug(`Loading plugin from module: ${moduleName}`);
46
+ const mod = await import(moduleName);
47
+ const createPlugin = mod.createPfPlugin || mod.default?.createPfPlugin;
48
+ if (!isFunction(createPlugin)) {
49
+ throw new Error(`Module ${moduleName} does not export createPfPlugin`);
50
+ }
51
+ const plugin = createPlugin({
52
+ contractsPath: context.workspace.contracts.path,
53
+ contractsPackage: context.workspace.contracts.packageName,
54
+ availableServices: context.workspace.availableServices
55
+ });
56
+ const errors = validatePluginStrict(plugin);
57
+ if (errors.length > 0) {
58
+ throw new Error(`Plugin from ${moduleName} does not conform to PfPlugin interface:
59
+ - ${errors.join("\n - ")}`);
60
+ }
61
+ const validatedPlugin = plugin;
62
+ logger.debug(`Loaded plugin: ${validatedPlugin.name} v${validatedPlugin.version}`);
63
+ await validatedPlugin.setup(context);
64
+ return {
65
+ plugin: validatedPlugin,
66
+ source: moduleName
67
+ };
68
+ };
69
+ export {
70
+ createPluginContext,
71
+ loadPluginFromModule,
72
+ validatePlugin,
73
+ validatePluginStrict
74
+ };
75
+ //# sourceMappingURL=plugin.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../cli/src/core/plugins/loader.ts"],"sourcesContent":["/**\n * Plugin Loader\n *\n * pf owns the plugin interface. Plugins MUST conform exactly.\n * Strict validation - no duck-typing, no fallbacks.\n */\nimport type { LoadedPlugin, PfPlugin, PfPluginContext, PfWorkspaceContext } from './types'\n\nconst defaultLogger: PfPluginContext['logger'] = {\n debug: () => {},\n info: console.log,\n warn: console.warn,\n error: console.error,\n}\n\nconst isObject = (val: unknown): val is Record<string, unknown> =>\n val !== null && typeof val === 'object'\n\nconst isNonEmptyString = (val: unknown): val is string =>\n typeof val === 'string' && val.length > 0\n\nconst isString = (val: unknown): val is string =>\n typeof val === 'string'\n\nconst isFunction = (val: unknown): val is (...args: unknown[]) => unknown =>\n typeof val === 'function'\n\n/**\n * Validates a single command conforms to PfCommand interface\n */\nconst validateCommand = (cmd: unknown, index: number): string[] => {\n if (!isObject(cmd)) return [`commands[${index}]: must be an object`]\n\n return [\n !isNonEmptyString(cmd.name) && `commands[${index}]: missing or invalid 'name'`,\n !isString(cmd.description) && `commands[${index}]: missing or invalid 'description'`,\n !Array.isArray(cmd.args) && `commands[${index}]: missing 'args' array`,\n !Array.isArray(cmd.options) && `commands[${index}]: missing 'options' array`,\n !isFunction(cmd.run) && `commands[${index}]: missing 'run' function`,\n ].filter((e): e is string => e !== false)\n}\n\n/**\n * Validates that an object conforms to the PfPlugin interface\n */\nexport const validatePlugin = (obj: unknown): obj is PfPlugin => {\n if (!isObject(obj)) return false\n\n return (\n isNonEmptyString(obj.name) &&\n isString(obj.version) &&\n Array.isArray(obj.commands) &&\n Array.isArray(obj.flows) &&\n isFunction(obj.setup)\n )\n}\n\n/**\n * Detailed validation with error messages\n */\nexport const validatePluginStrict = (obj: unknown): string[] => {\n if (!isObject(obj)) return ['Plugin must be an object']\n\n const baseErrors = [\n !isNonEmptyString(obj.name) && \"Missing or invalid 'name'\",\n !isString(obj.version) && \"Missing or invalid 'version'\",\n !Array.isArray(obj.commands) && \"Missing 'commands' array\",\n !Array.isArray(obj.flows) && \"Missing 'flows' array\",\n !isFunction(obj.setup) && \"Missing 'setup' function\",\n ].filter((e): e is string => e !== false)\n\n const commandErrors = Array.isArray(obj.commands)\n ? obj.commands.flatMap((cmd, i) => validateCommand(cmd, i))\n : []\n\n return [...baseErrors, ...commandErrors]\n}\n\n/**\n * Create a plugin context from workspace discovery\n */\nexport const createPluginContext = (\n workspace: PfWorkspaceContext,\n logger: PfPluginContext['logger'] = defaultLogger,\n): PfPluginContext => ({\n workspace,\n logger,\n})\n\n/**\n * Load and initialize a plugin from a module\n *\n * @param moduleName - The module to import (e.g., '@crossdelta/cloudevents')\n * @param context - Full plugin context with workspace info\n */\nexport const loadPluginFromModule = async (\n moduleName: string,\n context: PfPluginContext,\n): Promise<LoadedPlugin> => {\n const { logger } = context\n\n logger.debug(`Loading plugin from module: ${moduleName}`)\n\n const mod = await import(moduleName)\n\n const createPlugin = mod.createPfPlugin || mod.default?.createPfPlugin\n if (!isFunction(createPlugin)) {\n throw new Error(`Module ${moduleName} does not export createPfPlugin`)\n }\n\n const plugin = createPlugin({\n contractsPath: context.workspace.contracts.path,\n contractsPackage: context.workspace.contracts.packageName,\n availableServices: context.workspace.availableServices,\n })\n\n const errors = validatePluginStrict(plugin)\n if (errors.length > 0) {\n throw new Error(`Plugin from ${moduleName} does not conform to PfPlugin interface:\\n - ${errors.join('\\n - ')}`)\n }\n\n const validatedPlugin = plugin as PfPlugin\n\n logger.debug(`Loaded plugin: ${validatedPlugin.name} v${validatedPlugin.version}`)\n\n await validatedPlugin.setup(context)\n\n return {\n plugin: validatedPlugin,\n source: moduleName,\n }\n}\n"],"mappings":"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","names":[]}