@ouija-dev/plugin-sdk 0.1.0

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.
@@ -0,0 +1,27 @@
1
+ import type { JSONSchema } from '@ouija-dev/types';
2
+ export interface ValidationResult {
3
+ valid: boolean;
4
+ errors: string[];
5
+ }
6
+ /**
7
+ * Validate `data` against a JSON Schema.
8
+ *
9
+ * On success: `{ valid: true, errors: [] }`
10
+ * On failure: `{ valid: false, errors: ['apiToken is required', ...] }`
11
+ *
12
+ * The caller is responsible for narrowing the type after a `valid` check.
13
+ * Typical usage:
14
+ *
15
+ * const result = validateConfig(manifest.configSchema, rawConfig);
16
+ * if (!result.valid) throw new Error(result.errors.join('; '));
17
+ * const config = rawConfig as MyPluginConfig; // safe after validation
18
+ */
19
+ export declare function validateConfig(schema: JSONSchema, data: unknown): ValidationResult;
20
+ /**
21
+ * Validate config and format error messages with the plugin name prefix.
22
+ * Throws if config is invalid.
23
+ *
24
+ * Example error: "Plugin @ouija-dev/plugin-plane config error: apiToken is required"
25
+ */
26
+ export declare function validateConfigOrThrow(pluginName: string, schema: JSONSchema, data: unknown): void;
27
+ //# sourceMappingURL=config-validator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-validator.d.ts","sourceRoot":"","sources":["../src/config-validator.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAenD,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,GAAG,gBAAgB,CA6BlF;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,OAAO,GACZ,IAAI,CAMN"}
@@ -0,0 +1,61 @@
1
+ import { Ajv } from 'ajv';
2
+ import { createRequire } from 'node:module';
3
+ // ajv-formats is a CJS-only package; use createRequire to import it
4
+ // in a way that works with NodeNext module resolution.
5
+ const require = createRequire(import.meta.url);
6
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
7
+ const addFormats = require('ajv-formats');
8
+ // ---- Ajv instance (shared, compiled schemas are cached) ----
9
+ const ajv = new Ajv({ allErrors: true, strict: false });
10
+ addFormats(ajv);
11
+ /**
12
+ * Validate `data` against a JSON Schema.
13
+ *
14
+ * On success: `{ valid: true, errors: [] }`
15
+ * On failure: `{ valid: false, errors: ['apiToken is required', ...] }`
16
+ *
17
+ * The caller is responsible for narrowing the type after a `valid` check.
18
+ * Typical usage:
19
+ *
20
+ * const result = validateConfig(manifest.configSchema, rawConfig);
21
+ * if (!result.valid) throw new Error(result.errors.join('; '));
22
+ * const config = rawConfig as MyPluginConfig; // safe after validation
23
+ */
24
+ export function validateConfig(schema, data) {
25
+ const validate = ajv.compile(schema);
26
+ const valid = validate(data);
27
+ if (valid) {
28
+ return { valid: true, errors: [] };
29
+ }
30
+ const errors = (validate.errors ?? []).map((err) => {
31
+ // Build human-readable messages that include the field path.
32
+ // err.instancePath is empty for top-level missing-required errors;
33
+ // the field name comes from err.params in that case.
34
+ const path = err.instancePath
35
+ ? err.instancePath.replace(/^\//, '').replace(/\//g, '.')
36
+ : '';
37
+ if (err.keyword === 'required') {
38
+ const field = err.params.missingProperty;
39
+ return `${field} is required`;
40
+ }
41
+ if (path) {
42
+ return `${path} ${err.message ?? 'is invalid'}`;
43
+ }
44
+ return err.message ?? 'validation failed';
45
+ });
46
+ return { valid: false, errors };
47
+ }
48
+ /**
49
+ * Validate config and format error messages with the plugin name prefix.
50
+ * Throws if config is invalid.
51
+ *
52
+ * Example error: "Plugin @ouija-dev/plugin-plane config error: apiToken is required"
53
+ */
54
+ export function validateConfigOrThrow(pluginName, schema, data) {
55
+ const result = validateConfig(schema, data);
56
+ if (!result.valid) {
57
+ const messages = result.errors.join('; ');
58
+ throw new Error(`Plugin ${pluginName} config error: ${messages}`);
59
+ }
60
+ }
61
+ //# sourceMappingURL=config-validator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-validator.js","sourceRoot":"","sources":["../src/config-validator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAE1B,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAG5C,oEAAoE;AACpE,uDAAuD;AACvD,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,mEAAmE;AACnE,MAAM,UAAU,GAAkB,OAAO,CAAC,aAAa,CAAkB,CAAC;AAE1E,+DAA+D;AAE/D,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;AACxD,UAAU,CAAC,GAAG,CAAC,CAAC;AAShB;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,cAAc,CAAC,MAAkB,EAAE,IAAa;IAC9D,MAAM,QAAQ,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACrC,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAY,CAAC;IAExC,IAAI,KAAK,EAAE,CAAC;QACV,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IACrC,CAAC;IAED,MAAM,MAAM,GAAG,CAAC,QAAQ,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;QACjD,6DAA6D;QAC7D,mEAAmE;QACnE,qDAAqD;QACrD,MAAM,IAAI,GAAG,GAAG,CAAC,YAAY;YAC3B,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;YACzD,CAAC,CAAC,EAAE,CAAC;QAEP,IAAI,GAAG,CAAC,OAAO,KAAK,UAAU,EAAE,CAAC;YAC/B,MAAM,KAAK,GAAI,GAAG,CAAC,MAAsC,CAAC,eAAe,CAAC;YAC1E,OAAO,GAAG,KAAK,cAAc,CAAC;QAChC,CAAC;QAED,IAAI,IAAI,EAAE,CAAC;YACT,OAAO,GAAG,IAAI,IAAI,GAAG,CAAC,OAAO,IAAI,YAAY,EAAE,CAAC;QAClD,CAAC;QAED,OAAO,GAAG,CAAC,OAAO,IAAI,mBAAmB,CAAC;IAC5C,CAAC,CAAC,CAAC;IAEH,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;AAClC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CACnC,UAAkB,EAClB,MAAkB,EAClB,IAAa;IAEb,MAAM,MAAM,GAAG,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAC5C,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QAClB,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1C,MAAM,IAAI,KAAK,CAAC,UAAU,UAAU,kBAAkB,QAAQ,EAAE,CAAC,CAAC;IACpE,CAAC;AACH,CAAC"}
@@ -0,0 +1,6 @@
1
+ export { validateConfig, validateConfigOrThrow } from './config-validator.js';
2
+ export type { ValidationResult } from './config-validator.js';
3
+ export { PluginLoader } from './plugin-loader.js';
4
+ export type { PluginRegistration, PluginFactory } from './plugin-loader.js';
5
+ export * from './test-utils/index.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9E,YAAY,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAE9D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,YAAY,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAO5E,cAAc,uBAAuB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,10 @@
1
+ // ---- Plugin SDK public API ----
2
+ export { validateConfig, validateConfigOrThrow } from './config-validator.js';
3
+ export { PluginLoader } from './plugin-loader.js';
4
+ // Test utilities are intentionally kept under a sub-path so production code
5
+ // cannot accidentally import mocks. Re-exported here for convenience when
6
+ // tests are co-located with source (the test runner resolves from the package
7
+ // root). Plugin authors can also import directly from
8
+ // '@ouija-dev/plugin-sdk/test-utils'.
9
+ export * from './test-utils/index.js';
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,kCAAkC;AAElC,OAAO,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAG9E,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAGlD,4EAA4E;AAC5E,0EAA0E;AAC1E,8EAA8E;AAC9E,sDAAsD;AACtD,sCAAsC;AACtC,cAAc,uBAAuB,CAAC"}
@@ -0,0 +1,87 @@
1
+ import type { BasePlugin, PluginLogger, PluginHealth, JSONSchema, PluginContext } from '@ouija-dev/types';
2
+ /**
3
+ * A single plugin registration entry.
4
+ * `module` is the import specifier (file path or package name).
5
+ * `config` is the raw config object that will be validated against the manifest schema.
6
+ */
7
+ export interface PluginRegistration {
8
+ module: string;
9
+ config: Record<string, unknown>;
10
+ }
11
+ /**
12
+ * The shape of the default export (or named `PluginFactory` export) expected
13
+ * from each plugin module.
14
+ *
15
+ * Plugin modules must export a factory object whose `manifest` is read before
16
+ * `create()` is called.
17
+ */
18
+ export interface PluginFactory<TConfig = unknown> {
19
+ manifest: {
20
+ name: string;
21
+ version: string;
22
+ type: 'kanban' | 'git' | 'agent' | 'notification';
23
+ coreApiVersion: string;
24
+ configSchema: JSONSchema;
25
+ dependencies?: string[];
26
+ };
27
+ create(): BasePlugin<TConfig>;
28
+ }
29
+ /** Shape of an imported plugin module. */
30
+ type PluginModule = {
31
+ default?: PluginFactory<unknown>;
32
+ PluginFactory?: PluginFactory<unknown>;
33
+ };
34
+ /** Context factory signature. */
35
+ export type ContextFactory = (pluginName: string, config: Record<string, unknown>) => PluginContext<unknown>;
36
+ /**
37
+ * Manages the full lifecycle for a set of registered plugins:
38
+ * register → loadAll (import + validate + sort + init) → startAll → stopAll
39
+ */
40
+ export declare class PluginLoader {
41
+ private readonly logger;
42
+ private readonly registrations;
43
+ /** Ordered by dependency resolution (dependencies first). */
44
+ private loadedPlugins;
45
+ private started;
46
+ constructor(logger: PluginLogger);
47
+ /**
48
+ * Register a plugin module + config pair. The module is not imported yet.
49
+ */
50
+ register(registration: PluginRegistration): void;
51
+ /**
52
+ * Import all registered modules, validate their configs, resolve dependency
53
+ * order, and call `plugin.init(context)` for each in dependency order.
54
+ *
55
+ * @param contextFactory - builds the PluginContext for each plugin.
56
+ * @param importFn - override the import mechanism (default: dynamic import).
57
+ * Pass a custom function in tests to avoid filesystem lookups.
58
+ *
59
+ * Throws on:
60
+ * - `coreApiVersion` incompatibility
61
+ * - Config validation failure
62
+ * - Circular dependencies
63
+ * - Unknown dependency references
64
+ */
65
+ loadAll(contextFactory: ContextFactory, importFn?: (moduleSpecifier: string) => Promise<PluginModule>): Promise<void>;
66
+ /**
67
+ * Start all loaded plugins concurrently.
68
+ * A failing plugin logs the error but does not prevent others from starting.
69
+ */
70
+ startAll(): Promise<void>;
71
+ /**
72
+ * Stop all plugins in reverse dependency order.
73
+ * Each plugin gets `timeoutMs` (default 5 000 ms) to shut down.
74
+ */
75
+ stopAll(timeoutMs?: number): Promise<void>;
76
+ /**
77
+ * Get a loaded plugin by name, cast to type `T`.
78
+ * Throws if the plugin is not found.
79
+ */
80
+ getPlugin<T>(name: string): T;
81
+ /**
82
+ * Poll all loaded plugins for their health status.
83
+ */
84
+ getHealthStatuses(): Promise<Map<string, PluginHealth>>;
85
+ }
86
+ export {};
87
+ //# sourceMappingURL=plugin-loader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin-loader.d.ts","sourceRoot":"","sources":["../src/plugin-loader.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAK1G;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAED;;;;;;GAMG;AACH,MAAM,WAAW,aAAa,CAAC,OAAO,GAAG,OAAO;IAC9C,QAAQ,EAAE;QACR,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,EAAE,QAAQ,GAAG,KAAK,GAAG,OAAO,GAAG,cAAc,CAAC;QAClD,cAAc,EAAE,MAAM,CAAC;QACvB,YAAY,EAAE,UAAU,CAAC;QACzB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;KACzB,CAAC;IACF,MAAM,IAAI,UAAU,CAAC,OAAO,CAAC,CAAC;CAC/B;AAED,0CAA0C;AAC1C,KAAK,YAAY,GAAG;IAClB,OAAO,CAAC,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;IACjC,aAAa,CAAC,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;CACxC,CAAC;AAEF,iCAAiC;AACjC,MAAM,MAAM,cAAc,GAAG,CAC3B,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC5B,aAAa,CAAC,OAAO,CAAC,CAAC;AAa5B;;;GAGG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAe;IACtC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA8C;IAC5E,6DAA6D;IAC7D,OAAO,CAAC,aAAa,CAAqB;IAC1C,OAAO,CAAC,OAAO,CAAS;gBAEZ,MAAM,EAAE,YAAY;IAIhC;;OAEG;IACH,QAAQ,CAAC,YAAY,EAAE,kBAAkB,GAAG,IAAI;IAIhD;;;;;;;;;;;;;OAaG;IACG,OAAO,CACX,cAAc,EAAE,cAAc,EAC9B,QAAQ,GAAE,CAAC,eAAe,EAAE,MAAM,KAAK,OAAO,CAAC,YAAY,CACvB,GACnC,OAAO,CAAC,IAAI,CAAC;IA6DhB;;;OAGG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAkB/B;;;OAGG;IACG,OAAO,CAAC,SAAS,SAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAsB/C;;;OAGG;IACH,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,CAAC;IAQ7B;;OAEG;IACG,iBAAiB,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;CAmB9D"}
@@ -0,0 +1,202 @@
1
+ import semver from 'semver';
2
+ import { validateConfigOrThrow } from './config-validator.js';
3
+ // ---- Core API version this loader implements ----
4
+ const CORE_API_VERSION = '1.0.0';
5
+ // ---- PluginLoader ----
6
+ /**
7
+ * Manages the full lifecycle for a set of registered plugins:
8
+ * register → loadAll (import + validate + sort + init) → startAll → stopAll
9
+ */
10
+ export class PluginLoader {
11
+ logger;
12
+ registrations = new Map();
13
+ /** Ordered by dependency resolution (dependencies first). */
14
+ loadedPlugins = [];
15
+ started = false;
16
+ constructor(logger) {
17
+ this.logger = logger;
18
+ }
19
+ /**
20
+ * Register a plugin module + config pair. The module is not imported yet.
21
+ */
22
+ register(registration) {
23
+ this.registrations.set(registration.module, registration);
24
+ }
25
+ /**
26
+ * Import all registered modules, validate their configs, resolve dependency
27
+ * order, and call `plugin.init(context)` for each in dependency order.
28
+ *
29
+ * @param contextFactory - builds the PluginContext for each plugin.
30
+ * @param importFn - override the import mechanism (default: dynamic import).
31
+ * Pass a custom function in tests to avoid filesystem lookups.
32
+ *
33
+ * Throws on:
34
+ * - `coreApiVersion` incompatibility
35
+ * - Config validation failure
36
+ * - Circular dependencies
37
+ * - Unknown dependency references
38
+ */
39
+ async loadAll(contextFactory, importFn = (m) => import(m)) {
40
+ // 1. Import all modules and extract factories.
41
+ const factories = new Map();
42
+ // Map from plugin name → module specifier so we can find the registration.
43
+ const nameToModule = new Map();
44
+ for (const [moduleSpecifier, registration] of this.registrations) {
45
+ const mod = await importFn(moduleSpecifier);
46
+ const factory = mod.default ?? mod.PluginFactory;
47
+ if (!factory || typeof factory.create !== 'function') {
48
+ throw new Error(`Plugin module "${moduleSpecifier}" must export a default PluginFactory with a create() method`);
49
+ }
50
+ const { name, coreApiVersion, configSchema } = factory.manifest;
51
+ // 2. Check coreApiVersion compatibility.
52
+ if (!semver.satisfies(CORE_API_VERSION, coreApiVersion)) {
53
+ throw new Error(`Plugin ${name} requires coreApiVersion "${coreApiVersion}" but core is at ${CORE_API_VERSION}`);
54
+ }
55
+ // 3. Validate config against manifest schema.
56
+ validateConfigOrThrow(name, configSchema, registration.config);
57
+ factories.set(name, factory);
58
+ nameToModule.set(name, moduleSpecifier);
59
+ }
60
+ // 4. Topological sort by dependencies.
61
+ const sortedNames = topoSort(factories);
62
+ // 5. Create plugin instances in sorted order and init them.
63
+ for (const name of sortedNames) {
64
+ const factory = factories.get(name);
65
+ if (!factory)
66
+ continue;
67
+ const moduleSpecifier = nameToModule.get(name);
68
+ if (!moduleSpecifier) {
69
+ throw new Error(`Internal error: no module specifier found for plugin "${name}"`);
70
+ }
71
+ const registration = this.registrations.get(moduleSpecifier);
72
+ if (!registration) {
73
+ throw new Error(`Internal error: no registration found for plugin "${name}"`);
74
+ }
75
+ const plugin = factory.create();
76
+ const context = contextFactory(name, registration.config);
77
+ this.logger.info(`Initialising plugin "${name}"`);
78
+ await plugin.init(context);
79
+ this.loadedPlugins.push({ plugin, name });
80
+ }
81
+ }
82
+ /**
83
+ * Start all loaded plugins concurrently.
84
+ * A failing plugin logs the error but does not prevent others from starting.
85
+ */
86
+ async startAll() {
87
+ this.started = true;
88
+ const results = await Promise.allSettled(this.loadedPlugins.map(async ({ plugin, name }) => {
89
+ this.logger.info(`Starting plugin "${name}"`);
90
+ await plugin.start();
91
+ }));
92
+ for (const result of results) {
93
+ if (result.status === 'rejected') {
94
+ this.logger.error('Plugin failed to start', {
95
+ error: String(result.reason),
96
+ });
97
+ }
98
+ }
99
+ }
100
+ /**
101
+ * Stop all plugins in reverse dependency order.
102
+ * Each plugin gets `timeoutMs` (default 5 000 ms) to shut down.
103
+ */
104
+ async stopAll(timeoutMs = 5_000) {
105
+ const reversed = [...this.loadedPlugins].reverse();
106
+ for (const { plugin, name } of reversed) {
107
+ this.logger.info(`Stopping plugin "${name}"`);
108
+ try {
109
+ await Promise.race([
110
+ plugin.stop(),
111
+ new Promise((_, reject) => setTimeout(() => reject(new Error(`Plugin "${name}" stop timed out`)), timeoutMs)),
112
+ ]);
113
+ }
114
+ catch (err) {
115
+ this.logger.error(`Plugin "${name}" stop error`, { error: String(err) });
116
+ }
117
+ }
118
+ this.started = false;
119
+ }
120
+ /**
121
+ * Get a loaded plugin by name, cast to type `T`.
122
+ * Throws if the plugin is not found.
123
+ */
124
+ getPlugin(name) {
125
+ const entry = this.loadedPlugins.find((e) => e.name === name);
126
+ if (!entry) {
127
+ throw new Error(`Plugin "${name}" is not loaded`);
128
+ }
129
+ return entry.plugin;
130
+ }
131
+ /**
132
+ * Poll all loaded plugins for their health status.
133
+ */
134
+ async getHealthStatuses() {
135
+ const results = new Map();
136
+ await Promise.all(this.loadedPlugins.map(async ({ plugin, name }) => {
137
+ try {
138
+ const health = await plugin.healthCheck();
139
+ results.set(name, health);
140
+ }
141
+ catch (err) {
142
+ results.set(name, {
143
+ healthy: false,
144
+ message: `healthCheck threw: ${String(err)}`,
145
+ });
146
+ }
147
+ }));
148
+ return results;
149
+ }
150
+ }
151
+ // ---- Topological sort ----
152
+ /**
153
+ * Kahn's algorithm (BFS-based topological sort).
154
+ * Returns plugin names in dependency-first order.
155
+ * Throws on circular dependencies or missing dependency references.
156
+ */
157
+ function topoSort(factories) {
158
+ const inDegree = new Map();
159
+ // dependents[dep] = plugins that depend on dep
160
+ const dependents = new Map();
161
+ for (const [name] of factories) {
162
+ inDegree.set(name, 0);
163
+ dependents.set(name, []);
164
+ }
165
+ for (const [name, factory] of factories) {
166
+ for (const dep of factory.manifest.dependencies ?? []) {
167
+ if (!factories.has(dep)) {
168
+ throw new Error(`Plugin "${name}" depends on "${dep}", but "${dep}" is not registered`);
169
+ }
170
+ const existing = dependents.get(dep) ?? [];
171
+ existing.push(name);
172
+ dependents.set(dep, existing);
173
+ inDegree.set(name, (inDegree.get(name) ?? 0) + 1);
174
+ }
175
+ }
176
+ // Start with nodes that have no unmet dependencies.
177
+ const queue = [];
178
+ for (const [name, degree] of inDegree) {
179
+ if (degree === 0)
180
+ queue.push(name);
181
+ }
182
+ const sorted = [];
183
+ while (queue.length > 0) {
184
+ // Stable alphabetical sort within the queue for determinism.
185
+ queue.sort();
186
+ const current = queue.shift();
187
+ sorted.push(current);
188
+ for (const dependent of dependents.get(current) ?? []) {
189
+ const newDegree = (inDegree.get(dependent) ?? 1) - 1;
190
+ inDegree.set(dependent, newDegree);
191
+ if (newDegree === 0) {
192
+ queue.push(dependent);
193
+ }
194
+ }
195
+ }
196
+ if (sorted.length !== factories.size) {
197
+ const inCycle = [...factories.keys()].filter((n) => !sorted.includes(n));
198
+ throw new Error(`Circular dependency detected among plugins: ${inCycle.sort().join(', ')}`);
199
+ }
200
+ return sorted;
201
+ }
202
+ //# sourceMappingURL=plugin-loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin-loader.js","sourceRoot":"","sources":["../src/plugin-loader.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAE5B,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAmD9D,oDAAoD;AACpD,MAAM,gBAAgB,GAAG,OAAO,CAAC;AAEjC,yBAAyB;AAEzB;;;GAGG;AACH,MAAM,OAAO,YAAY;IACN,MAAM,CAAe;IACrB,aAAa,GAAoC,IAAI,GAAG,EAAE,CAAC;IAC5E,6DAA6D;IACrD,aAAa,GAAkB,EAAE,CAAC;IAClC,OAAO,GAAG,KAAK,CAAC;IAExB,YAAY,MAAoB;QAC9B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED;;OAEG;IACH,QAAQ,CAAC,YAAgC;QACvC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,YAAY,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAC5D,CAAC;IAED;;;;;;;;;;;;;OAaG;IACH,KAAK,CAAC,OAAO,CACX,cAA8B,EAC9B,WAA+D,CAAC,CAAC,EAAE,EAAE,CACnE,MAAM,CAAC,CAAC,CAA0B;QAEpC,+CAA+C;QAC/C,MAAM,SAAS,GAAG,IAAI,GAAG,EAAkC,CAAC;QAC5D,2EAA2E;QAC3E,MAAM,YAAY,GAAG,IAAI,GAAG,EAAkB,CAAC;QAE/C,KAAK,MAAM,CAAC,eAAe,EAAE,YAAY,CAAC,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;YACjE,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,eAAe,CAAC,CAAC;YAC5C,MAAM,OAAO,GACX,GAAG,CAAC,OAAO,IAAI,GAAG,CAAC,aAAa,CAAC;YAEnC,IAAI,CAAC,OAAO,IAAI,OAAO,OAAO,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;gBACrD,MAAM,IAAI,KAAK,CACb,kBAAkB,eAAe,8DAA8D,CAChG,CAAC;YACJ,CAAC;YAED,MAAM,EAAE,IAAI,EAAE,cAAc,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,QAAQ,CAAC;YAEhE,yCAAyC;YACzC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,gBAAgB,EAAE,cAAc,CAAC,EAAE,CAAC;gBACxD,MAAM,IAAI,KAAK,CACb,UAAU,IAAI,6BAA6B,cAAc,oBAAoB,gBAAgB,EAAE,CAChG,CAAC;YACJ,CAAC;YAED,8CAA8C;YAC9C,qBAAqB,CAAC,IAAI,EAAE,YAAY,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC;YAE/D,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YAC7B,YAAY,CAAC,GAAG,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC;QAC1C,CAAC;QAED,uCAAuC;QACvC,MAAM,WAAW,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC;QAExC,4DAA4D;QAC5D,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;YAC/B,MAAM,OAAO,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACpC,IAAI,CAAC,OAAO;gBAAE,SAAS;YAEvB,MAAM,eAAe,GAAG,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAC/C,IAAI,CAAC,eAAe,EAAE,CAAC;gBACrB,MAAM,IAAI,KAAK,CAAC,yDAAyD,IAAI,GAAG,CAAC,CAAC;YACpF,CAAC;YAED,MAAM,YAAY,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;YAC7D,IAAI,CAAC,YAAY,EAAE,CAAC;gBAClB,MAAM,IAAI,KAAK,CAAC,qDAAqD,IAAI,GAAG,CAAC,CAAC;YAChF,CAAC;YAED,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;YAChC,MAAM,OAAO,GAAG,cAAc,CAAC,IAAI,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC;YAE1D,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,wBAAwB,IAAI,GAAG,CAAC,CAAC;YAClD,MAAM,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAE3B,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5C,CAAC;IACH,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,QAAQ;QACZ,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,UAAU,CACtC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE;YAChD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,oBAAoB,IAAI,GAAG,CAAC,CAAC;YAC9C,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;QACvB,CAAC,CAAC,CACH,CAAC;QAEF,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC7B,IAAI,MAAM,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;gBACjC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,wBAAwB,EAAE;oBAC1C,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC;iBAC7B,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,OAAO,CAAC,SAAS,GAAG,KAAK;QAC7B,MAAM,QAAQ,GAAG,CAAC,GAAG,IAAI,CAAC,aAAa,CAAC,CAAC,OAAO,EAAE,CAAC;QAEnD,KAAK,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,QAAQ,EAAE,CAAC;YACxC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,oBAAoB,IAAI,GAAG,CAAC,CAAC;YAC9C,IAAI,CAAC;gBACH,MAAM,OAAO,CAAC,IAAI,CAAC;oBACjB,MAAM,CAAC,IAAI,EAAE;oBACb,IAAI,OAAO,CAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAC/B,UAAU,CACR,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,WAAW,IAAI,kBAAkB,CAAC,CAAC,EAC1D,SAAS,CACV,CACF;iBACF,CAAC,CAAC;YACL,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,IAAI,cAAc,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAC3E,CAAC;QACH,CAAC;QACD,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;IACvB,CAAC;IAED;;;OAGG;IACH,SAAS,CAAI,IAAY;QACvB,MAAM,KAAK,GAAG,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;QAC9D,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,IAAI,KAAK,CAAC,WAAW,IAAI,iBAAiB,CAAC,CAAC;QACpD,CAAC;QACD,OAAO,KAAK,CAAC,MAAsB,CAAC;IACtC,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,iBAAiB;QACrB,MAAM,OAAO,GAAG,IAAI,GAAG,EAAwB,CAAC;QAEhD,MAAM,OAAO,CAAC,GAAG,CACf,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE;YAChD,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,WAAW,EAAE,CAAC;gBAC1C,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YAC5B,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE;oBAChB,OAAO,EAAE,KAAK;oBACd,OAAO,EAAE,sBAAsB,MAAM,CAAC,GAAG,CAAC,EAAE;iBAC7C,CAAC,CAAC;YACL,CAAC;QACH,CAAC,CAAC,CACH,CAAC;QAEF,OAAO,OAAO,CAAC;IACjB,CAAC;CACF;AAED,6BAA6B;AAE7B;;;;GAIG;AACH,SAAS,QAAQ,CAAC,SAA8C;IAC9D,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC3C,+CAA+C;IAC/C,MAAM,UAAU,GAAG,IAAI,GAAG,EAAoB,CAAC;IAE/C,KAAK,MAAM,CAAC,IAAI,CAAC,IAAI,SAAS,EAAE,CAAC;QAC/B,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QACtB,UAAU,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IAC3B,CAAC;IAED,KAAK,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,SAAS,EAAE,CAAC;QACxC,KAAK,MAAM,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC,YAAY,IAAI,EAAE,EAAE,CAAC;YACtD,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;gBACxB,MAAM,IAAI,KAAK,CACb,WAAW,IAAI,iBAAiB,GAAG,WAAW,GAAG,qBAAqB,CACvE,CAAC;YACJ,CAAC;YACD,MAAM,QAAQ,GAAG,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;YAC3C,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACpB,UAAU,CAAC,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;YAC9B,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QACpD,CAAC;IACH,CAAC;IAED,oDAAoD;IACpD,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACtC,IAAI,MAAM,KAAK,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACrC,CAAC;IAED,MAAM,MAAM,GAAa,EAAE,CAAC;IAE5B,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,6DAA6D;QAC7D,KAAK,CAAC,IAAI,EAAE,CAAC;QACb,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,EAAG,CAAC;QAC/B,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAErB,KAAK,MAAM,SAAS,IAAI,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC;YACtD,MAAM,SAAS,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;YACrD,QAAQ,CAAC,GAAG,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;YACnC,IAAI,SAAS,KAAK,CAAC,EAAE,CAAC;gBACpB,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACxB,CAAC;QACH,CAAC;IACH,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,CAAC,IAAI,EAAE,CAAC;QACrC,MAAM,OAAO,GAAG,CAAC,GAAG,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;QACzE,MAAM,IAAI,KAAK,CACb,+CAA+C,OAAO,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC3E,CAAC;IACJ,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,7 @@
1
+ export { createMockLogger, createMockContext } from './mock-context.js';
2
+ export type { RecordedLogEntry, MockLogger, MockContext } from './mock-context.js';
3
+ export { MockKanbanPlugin } from './mock-kanban.js';
4
+ export { MockGitPlugin } from './mock-git.js';
5
+ export { MockAgentPlugin } from './mock-agent.js';
6
+ export type { DispatchRecord, CancelRecord } from './mock-agent.js';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/test-utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACxE,YAAY,EAAE,gBAAgB,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEnF,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,YAAY,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,5 @@
1
+ export { createMockLogger, createMockContext } from './mock-context.js';
2
+ export { MockKanbanPlugin } from './mock-kanban.js';
3
+ export { MockGitPlugin } from './mock-git.js';
4
+ export { MockAgentPlugin } from './mock-agent.js';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/test-utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAGxE,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,54 @@
1
+ import type { AgentPlugin, WorkOrder, AgentStatus, AgentStatusState, PluginManifest, PluginContext, PluginHealth } from '@ouija-dev/types';
2
+ import type { DispatchId } from '@ouija-dev/types';
3
+ /** A dispatched work order with the ID assigned to it. */
4
+ export interface DispatchRecord {
5
+ dispatchId: DispatchId;
6
+ workOrder: WorkOrder;
7
+ }
8
+ /** A recorded cancellation. */
9
+ export interface CancelRecord {
10
+ dispatchId: DispatchId;
11
+ }
12
+ /**
13
+ * In-memory AgentPlugin for engine integration tests.
14
+ *
15
+ * - `dispatch()` records the work order and returns a deterministic fake ID.
16
+ * - `cancel()` records the cancellation request.
17
+ * - `getStatus()` returns a configurable default state (`idle` by default).
18
+ * Override per-dispatch via `setStatus()`.
19
+ *
20
+ * Inspect `dispatchedWorkOrders` and `cancelledIds` in test assertions.
21
+ */
22
+ export declare class MockAgentPlugin implements AgentPlugin<Record<string, never>> {
23
+ readonly manifest: PluginManifest;
24
+ /** All work orders passed to `dispatch()`, in insertion order. */
25
+ readonly dispatchedWorkOrders: DispatchRecord[];
26
+ /** All dispatch IDs passed to `cancel()`, in insertion order. */
27
+ readonly cancelledIds: CancelRecord[];
28
+ /** Override per-dispatch status here for getStatus() to return. */
29
+ private readonly statusOverrides;
30
+ /** Default state returned when no override exists. */
31
+ private defaultState;
32
+ private dispatchCounter;
33
+ private initialised;
34
+ private running;
35
+ init(_context: PluginContext<Record<string, never>>): Promise<void>;
36
+ start(): Promise<void>;
37
+ stop(): Promise<void>;
38
+ healthCheck(): Promise<PluginHealth>;
39
+ dispatch(workOrder: WorkOrder): Promise<DispatchId>;
40
+ cancel(id: DispatchId): Promise<void>;
41
+ getStatus(id: DispatchId): Promise<AgentStatus>;
42
+ /**
43
+ * Set a specific status that `getStatus()` will return for the given dispatch ID.
44
+ * Useful for simulating state transitions in tests.
45
+ */
46
+ setStatus(id: DispatchId, status: Omit<AgentStatus, 'dispatchId'>): void;
47
+ /**
48
+ * Change the default state returned by `getStatus()` when no override is set.
49
+ */
50
+ setDefaultState(state: AgentStatusState): void;
51
+ /** Reset all recorded data and overrides. Useful between tests. */
52
+ reset(): void;
53
+ }
54
+ //# sourceMappingURL=mock-agent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mock-agent.d.ts","sourceRoot":"","sources":["../../src/test-utils/mock-agent.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EACX,SAAS,EACT,WAAW,EACX,gBAAgB,EAChB,cAAc,EACd,aAAa,EACb,YAAY,EACb,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,UAAU,EAAc,MAAM,kBAAkB,CAAC;AAK/D,0DAA0D;AAC1D,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,UAAU,CAAC;IACvB,SAAS,EAAE,SAAS,CAAC;CACtB;AAED,+BAA+B;AAC/B,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,UAAU,CAAC;CACxB;AAED;;;;;;;;;GASG;AACH,qBAAa,eAAgB,YAAW,WAAW,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IACxE,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAO/B;IAEF,kEAAkE;IAClE,QAAQ,CAAC,oBAAoB,EAAE,cAAc,EAAE,CAAM;IACrD,iEAAiE;IACjE,QAAQ,CAAC,YAAY,EAAE,YAAY,EAAE,CAAM;IAE3C,mEAAmE;IACnE,OAAO,CAAC,QAAQ,CAAC,eAAe,CAA2C;IAC3E,sDAAsD;IACtD,OAAO,CAAC,YAAY,CAA4B;IAEhD,OAAO,CAAC,eAAe,CAAK;IAC5B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,OAAO,CAAS;IAIlB,IAAI,CAAC,QAAQ,EAAE,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAInE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAItB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAIrB,WAAW,IAAI,OAAO,CAAC,YAAY,CAAC;IAcpC,QAAQ,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC;IAOnD,MAAM,CAAC,EAAE,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAIrC,SAAS,CAAC,EAAE,EAAE,UAAU,GAAG,OAAO,CAAC,WAAW,CAAC;IAcrD;;;OAGG;IACH,SAAS,CAAC,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,CAAC,WAAW,EAAE,YAAY,CAAC,GAAG,IAAI;IAIxE;;OAEG;IACH,eAAe,CAAC,KAAK,EAAE,gBAAgB,GAAG,IAAI;IAI9C,mEAAmE;IACnE,KAAK,IAAI,IAAI;CAOd"}
@@ -0,0 +1,97 @@
1
+ import { dispatchId, instanceId } from '@ouija-dev/types';
2
+ /**
3
+ * In-memory AgentPlugin for engine integration tests.
4
+ *
5
+ * - `dispatch()` records the work order and returns a deterministic fake ID.
6
+ * - `cancel()` records the cancellation request.
7
+ * - `getStatus()` returns a configurable default state (`idle` by default).
8
+ * Override per-dispatch via `setStatus()`.
9
+ *
10
+ * Inspect `dispatchedWorkOrders` and `cancelledIds` in test assertions.
11
+ */
12
+ export class MockAgentPlugin {
13
+ manifest = {
14
+ name: '@ouija-dev/mock-agent',
15
+ version: '0.1.0',
16
+ type: 'agent',
17
+ coreApiVersion: '>=1.0.0 <2.0.0',
18
+ configSchema: { type: 'object', properties: {}, additionalProperties: false },
19
+ dependencies: [],
20
+ };
21
+ /** All work orders passed to `dispatch()`, in insertion order. */
22
+ dispatchedWorkOrders = [];
23
+ /** All dispatch IDs passed to `cancel()`, in insertion order. */
24
+ cancelledIds = [];
25
+ /** Override per-dispatch status here for getStatus() to return. */
26
+ statusOverrides = new Map();
27
+ /** Default state returned when no override exists. */
28
+ defaultState = 'idle';
29
+ dispatchCounter = 0;
30
+ initialised = false;
31
+ running = false;
32
+ // ---- Lifecycle ----
33
+ async init(_context) {
34
+ this.initialised = true;
35
+ }
36
+ async start() {
37
+ this.running = true;
38
+ }
39
+ async stop() {
40
+ this.running = false;
41
+ }
42
+ async healthCheck() {
43
+ return {
44
+ healthy: true,
45
+ message: 'Mock agent plugin is always healthy',
46
+ details: {
47
+ initialised: this.initialised,
48
+ running: this.running,
49
+ dispatched: this.dispatchedWorkOrders.length,
50
+ },
51
+ };
52
+ }
53
+ // ---- AgentPlugin methods ----
54
+ async dispatch(workOrder) {
55
+ this.dispatchCounter += 1;
56
+ const id = dispatchId(`mock-dispatch-${this.dispatchCounter}`);
57
+ this.dispatchedWorkOrders.push({ dispatchId: id, workOrder });
58
+ return id;
59
+ }
60
+ async cancel(id) {
61
+ this.cancelledIds.push({ dispatchId: id });
62
+ }
63
+ async getStatus(id) {
64
+ const override = this.statusOverrides.get(id);
65
+ if (override)
66
+ return { ...override };
67
+ return {
68
+ dispatchId: id,
69
+ instanceId: instanceId('mock-instance'),
70
+ state: this.defaultState,
71
+ updatedAt: new Date().toISOString(),
72
+ };
73
+ }
74
+ // ---- Test helpers ----
75
+ /**
76
+ * Set a specific status that `getStatus()` will return for the given dispatch ID.
77
+ * Useful for simulating state transitions in tests.
78
+ */
79
+ setStatus(id, status) {
80
+ this.statusOverrides.set(id, { ...status, dispatchId: id });
81
+ }
82
+ /**
83
+ * Change the default state returned by `getStatus()` when no override is set.
84
+ */
85
+ setDefaultState(state) {
86
+ this.defaultState = state;
87
+ }
88
+ /** Reset all recorded data and overrides. Useful between tests. */
89
+ reset() {
90
+ this.dispatchedWorkOrders.length = 0;
91
+ this.cancelledIds.length = 0;
92
+ this.statusOverrides.clear();
93
+ this.dispatchCounter = 0;
94
+ this.defaultState = 'idle';
95
+ }
96
+ }
97
+ //# sourceMappingURL=mock-agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mock-agent.js","sourceRoot":"","sources":["../../src/test-utils/mock-agent.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import type { PluginContext, PluginLogger } from '@ouija-dev/types';
2
+ export interface RecordedLogEntry {
3
+ level: 'debug' | 'info' | 'warn' | 'error';
4
+ msg: string;
5
+ meta?: Record<string, unknown>;
6
+ }
7
+ export interface MockLogger extends PluginLogger {
8
+ /** All recorded log calls in insertion order. */
9
+ entries: RecordedLogEntry[];
10
+ /** Convenience: only entries at a given level. */
11
+ entriesAt(level: RecordedLogEntry['level']): RecordedLogEntry[];
12
+ }
13
+ export declare function createMockLogger(): MockLogger;
14
+ export interface MockContext<TConfig> extends PluginContext<TConfig> {
15
+ logger: MockLogger;
16
+ /** All events published via publishEvent(), in insertion order. */
17
+ publishedEvents: Array<{
18
+ topic: string;
19
+ payload: unknown;
20
+ }>;
21
+ /** All jobs enqueued via enqueueJob(), in insertion order. */
22
+ enqueuedJobs: Array<{
23
+ queue: string;
24
+ job: unknown;
25
+ options?: {
26
+ delay?: number;
27
+ attempts?: number;
28
+ };
29
+ }>;
30
+ }
31
+ export declare function createMockContext<TConfig>(config: TConfig): MockContext<TConfig>;
32
+ //# sourceMappingURL=mock-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mock-context.d.ts","sourceRoot":"","sources":["../../src/test-utils/mock-context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAIpE,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;IAC3C,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAED,MAAM,WAAW,UAAW,SAAQ,YAAY;IAC9C,iDAAiD;IACjD,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,kDAAkD;IAClD,SAAS,CAAC,KAAK,EAAE,gBAAgB,CAAC,OAAO,CAAC,GAAG,gBAAgB,EAAE,CAAC;CACjE;AAED,wBAAgB,gBAAgB,IAAI,UAAU,CAmB7C;AAID,MAAM,WAAW,WAAW,CAAC,OAAO,CAAE,SAAQ,aAAa,CAAC,OAAO,CAAC;IAClE,MAAM,EAAE,UAAU,CAAC;IACnB,mEAAmE;IACnE,eAAe,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAC5D,8DAA8D;IAC9D,YAAY,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE;YAAE,KAAK,CAAC,EAAE,MAAM,CAAC;YAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAC,CAAC;CACvG;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC,CAqBhF"}
@@ -0,0 +1,35 @@
1
+ export function createMockLogger() {
2
+ const entries = [];
3
+ function log(level, msg, meta) {
4
+ entries.push({ level, msg, ...(meta !== undefined ? { meta } : {}) });
5
+ }
6
+ const logger = {
7
+ entries,
8
+ entriesAt(level) {
9
+ return entries.filter((e) => e.level === level);
10
+ },
11
+ debug: (msg, meta) => log('debug', msg, meta),
12
+ info: (msg, meta) => log('info', msg, meta),
13
+ warn: (msg, meta) => log('warn', msg, meta),
14
+ error: (msg, meta) => log('error', msg, meta),
15
+ };
16
+ return logger;
17
+ }
18
+ export function createMockContext(config) {
19
+ const logger = createMockLogger();
20
+ const publishedEvents = [];
21
+ const enqueuedJobs = [];
22
+ return {
23
+ config,
24
+ logger,
25
+ publishedEvents,
26
+ enqueuedJobs,
27
+ publishEvent: async (topic, payload) => {
28
+ publishedEvents.push({ topic, payload });
29
+ },
30
+ enqueueJob: async (queue, job, options) => {
31
+ enqueuedJobs.push({ queue, job, ...(options !== undefined ? { options } : {}) });
32
+ },
33
+ };
34
+ }
35
+ //# sourceMappingURL=mock-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mock-context.js","sourceRoot":"","sources":["../../src/test-utils/mock-context.ts"],"names":[],"mappings":"AAiBA,MAAM,UAAU,gBAAgB;IAC9B,MAAM,OAAO,GAAuB,EAAE,CAAC;IAEvC,SAAS,GAAG,CAAC,KAAgC,EAAE,GAAW,EAAE,IAA8B;QACxF,OAAO,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IACxE,CAAC;IAED,MAAM,MAAM,GAAe;QACzB,OAAO;QACP,SAAS,CAAC,KAAK;YACb,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,KAAK,CAAC,CAAC;QAClD,CAAC;QACD,KAAK,EAAE,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC;QAC7C,IAAI,EAAE,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,CAAC;QAC3C,IAAI,EAAE,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,CAAC;QAC3C,KAAK,EAAE,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC;KAC9C,CAAC;IAEF,OAAO,MAAM,CAAC;AAChB,CAAC;AAYD,MAAM,UAAU,iBAAiB,CAAU,MAAe;IACxD,MAAM,MAAM,GAAG,gBAAgB,EAAE,CAAC;IAClC,MAAM,eAAe,GAA+C,EAAE,CAAC;IACvE,MAAM,YAAY,GAA4F,EAAE,CAAC;IAEjH,OAAO;QACL,MAAM;QACN,MAAM;QACN,eAAe;QACf,YAAY;QACZ,YAAY,EAAE,KAAK,EAAE,KAAa,EAAE,OAAgB,EAAiB,EAAE;YACrE,eAAe,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;QAC3C,CAAC;QACD,UAAU,EAAE,KAAK,EACf,KAAa,EACb,GAAY,EACZ,OAA+C,EAChC,EAAE;YACjB,YAAY,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QACnF,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,31 @@
1
+ import type { GitPlugin, StandardPR, OpenPRParams, PluginManifest, PluginContext, PluginHealth } from '@ouija-dev/types';
2
+ import type { PrId } from '@ouija-dev/types';
3
+ /**
4
+ * In-memory GitPlugin for use in engine integration tests and plugin development.
5
+ * No network calls. Branches and PRs are tracked in Maps.
6
+ *
7
+ * `openPR()` generates deterministic fake IDs and URLs.
8
+ * `mergePR()` marks the PR as merged in-place.
9
+ */
10
+ export declare class MockGitPlugin implements GitPlugin<Record<string, never>> {
11
+ readonly manifest: PluginManifest;
12
+ /** repoUrl → Set of branch names */
13
+ readonly branches: Map<string, Set<string>>;
14
+ /** PR id → StandardPR */
15
+ readonly prs: Map<PrId, StandardPR>;
16
+ /** PR id → list of comment bodies */
17
+ readonly prComments: Map<PrId, string[]>;
18
+ private prCounter;
19
+ private initialised;
20
+ private running;
21
+ init(_context: PluginContext<Record<string, never>>): Promise<void>;
22
+ start(): Promise<void>;
23
+ stop(): Promise<void>;
24
+ healthCheck(): Promise<PluginHealth>;
25
+ createBranch(repoUrl: string, branchName: string, _fromBranch: string): Promise<void>;
26
+ openPR(repoUrl: string, params: OpenPRParams): Promise<StandardPR>;
27
+ mergePR(id: PrId): Promise<void>;
28
+ addPRComment(id: PrId, body: string): Promise<void>;
29
+ getPR(id: PrId): Promise<StandardPR>;
30
+ }
31
+ //# sourceMappingURL=mock-git.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mock-git.d.ts","sourceRoot":"","sources":["../../src/test-utils/mock-git.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,SAAS,EACT,UAAU,EACV,YAAY,EACZ,cAAc,EACd,aAAa,EACb,YAAY,EACb,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAK7C;;;;;;GAMG;AACH,qBAAa,aAAc,YAAW,SAAS,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IACpE,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAO/B;IAEF,oCAAoC;IACpC,QAAQ,CAAC,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAa;IACxD,yBAAyB;IACzB,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,EAAE,UAAU,CAAC,CAAa;IAChD,qCAAqC;IACrC,QAAQ,CAAC,UAAU,EAAE,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,CAAa;IAErD,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,OAAO,CAAS;IAIlB,IAAI,CAAC,QAAQ,EAAE,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAInE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAItB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAIrB,WAAW,IAAI,OAAO,CAAC,YAAY,CAAC;IAUpC,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMrF,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,UAAU,CAAC;IAsBlE,OAAO,CAAC,EAAE,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAShC,YAAY,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKnD,KAAK,CAAC,EAAE,EAAE,IAAI,GAAG,OAAO,CAAC,UAAU,CAAC;CAO3C"}
@@ -0,0 +1,90 @@
1
+ import { prId } from '@ouija-dev/types';
2
+ // ---- Mock Git Plugin ----
3
+ /**
4
+ * In-memory GitPlugin for use in engine integration tests and plugin development.
5
+ * No network calls. Branches and PRs are tracked in Maps.
6
+ *
7
+ * `openPR()` generates deterministic fake IDs and URLs.
8
+ * `mergePR()` marks the PR as merged in-place.
9
+ */
10
+ export class MockGitPlugin {
11
+ manifest = {
12
+ name: '@ouija-dev/mock-git',
13
+ version: '0.1.0',
14
+ type: 'git',
15
+ coreApiVersion: '>=1.0.0 <2.0.0',
16
+ configSchema: { type: 'object', properties: {}, additionalProperties: false },
17
+ dependencies: [],
18
+ };
19
+ /** repoUrl → Set of branch names */
20
+ branches = new Map();
21
+ /** PR id → StandardPR */
22
+ prs = new Map();
23
+ /** PR id → list of comment bodies */
24
+ prComments = new Map();
25
+ prCounter = 0;
26
+ initialised = false;
27
+ running = false;
28
+ // ---- Lifecycle ----
29
+ async init(_context) {
30
+ this.initialised = true;
31
+ }
32
+ async start() {
33
+ this.running = true;
34
+ }
35
+ async stop() {
36
+ this.running = false;
37
+ }
38
+ async healthCheck() {
39
+ return {
40
+ healthy: true,
41
+ message: 'Mock git plugin is always healthy',
42
+ details: { initialised: this.initialised, running: this.running },
43
+ };
44
+ }
45
+ // ---- GitPlugin methods ----
46
+ async createBranch(repoUrl, branchName, _fromBranch) {
47
+ const repo = this.branches.get(repoUrl) ?? new Set();
48
+ repo.add(branchName);
49
+ this.branches.set(repoUrl, repo);
50
+ }
51
+ async openPR(repoUrl, params) {
52
+ this.prCounter += 1;
53
+ const id = prId(`mock-pr-${this.prCounter}`);
54
+ const now = new Date().toISOString();
55
+ const pr = {
56
+ id,
57
+ url: `https://mock.git/${repoUrl}/pull/${this.prCounter}`,
58
+ title: params.title,
59
+ body: params.body,
60
+ branch: params.branch,
61
+ baseBranch: params.baseBranch,
62
+ state: 'open',
63
+ draft: params.draft ?? false,
64
+ createdAt: now,
65
+ updatedAt: now,
66
+ };
67
+ this.prs.set(id, pr);
68
+ return { ...pr };
69
+ }
70
+ async mergePR(id) {
71
+ const pr = this.prs.get(id);
72
+ if (!pr) {
73
+ throw new Error(`MockGitPlugin: PR "${id}" not found`);
74
+ }
75
+ const now = new Date().toISOString();
76
+ this.prs.set(id, { ...pr, state: 'merged', mergedAt: now, updatedAt: now });
77
+ }
78
+ async addPRComment(id, body) {
79
+ const existing = this.prComments.get(id) ?? [];
80
+ this.prComments.set(id, [...existing, body]);
81
+ }
82
+ async getPR(id) {
83
+ const pr = this.prs.get(id);
84
+ if (!pr) {
85
+ throw new Error(`MockGitPlugin: PR "${id}" not found`);
86
+ }
87
+ return { ...pr };
88
+ }
89
+ }
90
+ //# sourceMappingURL=mock-git.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mock-git.js","sourceRoot":"","sources":["../../src/test-utils/mock-git.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAExC,4BAA4B;AAE5B;;;;;;GAMG;AACH,MAAM,OAAO,aAAa;IACf,QAAQ,GAAmB;QAClC,IAAI,EAAE,qBAAqB;QAC3B,OAAO,EAAE,OAAO;QAChB,IAAI,EAAE,KAAK;QACX,cAAc,EAAE,gBAAgB;QAChC,YAAY,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,EAAE,oBAAoB,EAAE,KAAK,EAAE;QAC7E,YAAY,EAAE,EAAE;KACjB,CAAC;IAEF,oCAAoC;IAC3B,QAAQ,GAA6B,IAAI,GAAG,EAAE,CAAC;IACxD,yBAAyB;IAChB,GAAG,GAA0B,IAAI,GAAG,EAAE,CAAC;IAChD,qCAAqC;IAC5B,UAAU,GAAwB,IAAI,GAAG,EAAE,CAAC;IAE7C,SAAS,GAAG,CAAC,CAAC;IACd,WAAW,GAAG,KAAK,CAAC;IACpB,OAAO,GAAG,KAAK,CAAC;IAExB,sBAAsB;IAEtB,KAAK,CAAC,IAAI,CAAC,QAA8C;QACvD,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;IAC1B,CAAC;IAED,KAAK,CAAC,KAAK;QACT,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;IACtB,CAAC;IAED,KAAK,CAAC,IAAI;QACR,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;IACvB,CAAC;IAED,KAAK,CAAC,WAAW;QACf,OAAO;YACL,OAAO,EAAE,IAAI;YACb,OAAO,EAAE,mCAAmC;YAC5C,OAAO,EAAE,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE;SAClE,CAAC;IACJ,CAAC;IAED,8BAA8B;IAE9B,KAAK,CAAC,YAAY,CAAC,OAAe,EAAE,UAAkB,EAAE,WAAmB;QACzE,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,IAAI,GAAG,EAAU,CAAC;QAC7D,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QACrB,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IACnC,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,OAAe,EAAE,MAAoB;QAChD,IAAI,CAAC,SAAS,IAAI,CAAC,CAAC;QACpB,MAAM,EAAE,GAAG,IAAI,CAAC,WAAW,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;QAC7C,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAErC,MAAM,EAAE,GAAe;YACrB,EAAE;YACF,GAAG,EAAE,oBAAoB,OAAO,SAAS,IAAI,CAAC,SAAS,EAAE;YACzD,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,UAAU,EAAE,MAAM,CAAC,UAAU;YAC7B,KAAK,EAAE,MAAM;YACb,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,KAAK;YAC5B,SAAS,EAAE,GAAG;YACd,SAAS,EAAE,GAAG;SACf,CAAC;QAEF,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QACrB,OAAO,EAAE,GAAG,EAAE,EAAE,CAAC;IACnB,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,EAAQ;QACpB,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC5B,IAAI,CAAC,EAAE,EAAE,CAAC;YACR,MAAM,IAAI,KAAK,CAAC,sBAAsB,EAAE,aAAa,CAAC,CAAC;QACzD,CAAC;QACD,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACrC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC;IAC9E,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,EAAQ,EAAE,IAAY;QACvC,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC;QAC/C,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,GAAG,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC;IAC/C,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,EAAQ;QAClB,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC5B,IAAI,CAAC,EAAE,EAAE,CAAC;YACR,MAAM,IAAI,KAAK,CAAC,sBAAsB,EAAE,aAAa,CAAC,CAAC;QACzD,CAAC;QACD,OAAO,EAAE,GAAG,EAAE,EAAE,CAAC;IACnB,CAAC;CACF"}
@@ -0,0 +1,54 @@
1
+ import type { KanbanPlugin, KanbanCard, KanbanColumn, PluginManifest, PluginContext, PluginHealth } from '@ouija-dev/types';
2
+ import type { CardId, ColumnId, BoardId } from '@ouija-dev/types';
3
+ /**
4
+ * In-memory KanbanPlugin for use in engine integration tests and plugin
5
+ * development. No network calls. All methods operate on internal Maps.
6
+ *
7
+ * Seed data via the `cards`, `columns`, and `assignments` properties before
8
+ * calling the plugin's methods.
9
+ */
10
+ export declare class MockKanbanPlugin implements KanbanPlugin<Record<string, never>> {
11
+ readonly manifest: PluginManifest;
12
+ /** Mutable store: card ID → card */
13
+ readonly cards: Map<CardId, KanbanCard>;
14
+ /** Mutable store: board ID → columns */
15
+ readonly columns: Map<BoardId, KanbanColumn[]>;
16
+ /** Recorded comments: card ID → list of comment bodies */
17
+ readonly comments: Map<CardId, string[]>;
18
+ /** Recorded assignments: card ID → list of user IDs */
19
+ readonly assignments: Map<CardId, string[]>;
20
+ private initialised;
21
+ private running;
22
+ init(_context: PluginContext<Record<string, never>>): Promise<void>;
23
+ start(): Promise<void>;
24
+ stop(): Promise<void>;
25
+ healthCheck(): Promise<PluginHealth>;
26
+ getCard(id: CardId): Promise<KanbanCard>;
27
+ moveCard(id: CardId, toColumnId: ColumnId): Promise<void>;
28
+ addComment(id: CardId, body: string): Promise<void>;
29
+ assignUser(id: CardId, userId: string): Promise<void>;
30
+ getColumns(board: BoardId): Promise<KanbanColumn[]>;
31
+ /**
32
+ * Add a card to the in-memory store.
33
+ * All fields have sensible defaults — only `id`, `title`, and `columnId` are required.
34
+ */
35
+ seedCard(partial: {
36
+ id: string;
37
+ title: string;
38
+ columnId: string;
39
+ boardId?: string;
40
+ description?: string;
41
+ labels?: string[];
42
+ assignees?: string[];
43
+ url?: string;
44
+ createdAt?: string;
45
+ updatedAt?: string;
46
+ }): KanbanCard;
47
+ /** Add columns for a board. */
48
+ seedColumns(board: string, cols: Array<{
49
+ id: string;
50
+ name: string;
51
+ position: number;
52
+ }>): void;
53
+ }
54
+ //# sourceMappingURL=mock-kanban.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mock-kanban.d.ts","sourceRoot":"","sources":["../../src/test-utils/mock-kanban.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,cAAc,EACd,aAAa,EACb,YAAY,EACb,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAKlE;;;;;;GAMG;AACH,qBAAa,gBAAiB,YAAW,YAAY,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAC1E,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAO/B;IAEF,oCAAoC;IACpC,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAa;IACpD,wCAAwC;IACxC,QAAQ,CAAC,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,YAAY,EAAE,CAAC,CAAa;IAC3D,0DAA0D;IAC1D,QAAQ,CAAC,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAa;IACrD,uDAAuD;IACvD,QAAQ,CAAC,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAa;IAExD,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,OAAO,CAAS;IAIlB,IAAI,CAAC,QAAQ,EAAE,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAInE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAItB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAIrB,WAAW,IAAI,OAAO,CAAC,YAAY,CAAC;IAUpC,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAQxC,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAQzD,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKnD,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAerD,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAMzD;;;OAGG;IACH,QAAQ,CAAC,OAAO,EAAE;QAChB,EAAE,EAAE,MAAM,CAAC;QACX,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,MAAM,CAAC;QACjB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;QAClB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;QACrB,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,GAAG,UAAU;IAkBd,+BAA+B;IAC/B,WAAW,CACT,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,GAC1D,IAAI;CAMR"}
@@ -0,0 +1,108 @@
1
+ import { cardId, columnId, boardId } from '@ouija-dev/types';
2
+ // ---- Mock Kanban Plugin ----
3
+ /**
4
+ * In-memory KanbanPlugin for use in engine integration tests and plugin
5
+ * development. No network calls. All methods operate on internal Maps.
6
+ *
7
+ * Seed data via the `cards`, `columns`, and `assignments` properties before
8
+ * calling the plugin's methods.
9
+ */
10
+ export class MockKanbanPlugin {
11
+ manifest = {
12
+ name: '@ouija-dev/mock-kanban',
13
+ version: '0.1.0',
14
+ type: 'kanban',
15
+ coreApiVersion: '>=1.0.0 <2.0.0',
16
+ configSchema: { type: 'object', properties: {}, additionalProperties: false },
17
+ dependencies: [],
18
+ };
19
+ /** Mutable store: card ID → card */
20
+ cards = new Map();
21
+ /** Mutable store: board ID → columns */
22
+ columns = new Map();
23
+ /** Recorded comments: card ID → list of comment bodies */
24
+ comments = new Map();
25
+ /** Recorded assignments: card ID → list of user IDs */
26
+ assignments = new Map();
27
+ initialised = false;
28
+ running = false;
29
+ // ---- Lifecycle ----
30
+ async init(_context) {
31
+ this.initialised = true;
32
+ }
33
+ async start() {
34
+ this.running = true;
35
+ }
36
+ async stop() {
37
+ this.running = false;
38
+ }
39
+ async healthCheck() {
40
+ return {
41
+ healthy: true,
42
+ message: 'Mock kanban plugin is always healthy',
43
+ details: { initialised: this.initialised, running: this.running },
44
+ };
45
+ }
46
+ // ---- KanbanPlugin methods ----
47
+ async getCard(id) {
48
+ const card = this.cards.get(id);
49
+ if (!card) {
50
+ throw new Error(`MockKanbanPlugin: card "${id}" not found`);
51
+ }
52
+ return { ...card };
53
+ }
54
+ async moveCard(id, toColumnId) {
55
+ const card = this.cards.get(id);
56
+ if (!card) {
57
+ throw new Error(`MockKanbanPlugin: card "${id}" not found`);
58
+ }
59
+ this.cards.set(id, { ...card, columnId: toColumnId, updatedAt: new Date().toISOString() });
60
+ }
61
+ async addComment(id, body) {
62
+ const existing = this.comments.get(id) ?? [];
63
+ this.comments.set(id, [...existing, body]);
64
+ }
65
+ async assignUser(id, userId) {
66
+ const existing = this.assignments.get(id) ?? [];
67
+ this.assignments.set(id, [...existing, userId]);
68
+ // Mirror the assignee onto the card.
69
+ const card = this.cards.get(id);
70
+ if (card) {
71
+ this.cards.set(id, {
72
+ ...card,
73
+ assignees: [...card.assignees, userId],
74
+ updatedAt: new Date().toISOString(),
75
+ });
76
+ }
77
+ }
78
+ async getColumns(board) {
79
+ return this.columns.get(board) ?? [];
80
+ }
81
+ // ---- Seeding helpers ----
82
+ /**
83
+ * Add a card to the in-memory store.
84
+ * All fields have sensible defaults — only `id`, `title`, and `columnId` are required.
85
+ */
86
+ seedCard(partial) {
87
+ const now = new Date().toISOString();
88
+ const card = {
89
+ id: cardId(partial.id),
90
+ title: partial.title,
91
+ description: partial.description ?? '',
92
+ columnId: columnId(partial.columnId),
93
+ boardId: boardId(partial.boardId ?? 'board-1'),
94
+ labels: partial.labels ?? [],
95
+ assignees: partial.assignees ?? [],
96
+ url: partial.url ?? `https://mock.kanban/cards/${partial.id}`,
97
+ createdAt: partial.createdAt ?? now,
98
+ updatedAt: partial.updatedAt ?? now,
99
+ };
100
+ this.cards.set(card.id, card);
101
+ return card;
102
+ }
103
+ /** Add columns for a board. */
104
+ seedColumns(board, cols) {
105
+ this.columns.set(boardId(board), cols.map((c) => ({ id: columnId(c.id), name: c.name, position: c.position })));
106
+ }
107
+ }
108
+ //# sourceMappingURL=mock-kanban.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mock-kanban.js","sourceRoot":"","sources":["../../src/test-utils/mock-kanban.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAE7D,+BAA+B;AAE/B;;;;;;GAMG;AACH,MAAM,OAAO,gBAAgB;IAClB,QAAQ,GAAmB;QAClC,IAAI,EAAE,wBAAwB;QAC9B,OAAO,EAAE,OAAO;QAChB,IAAI,EAAE,QAAQ;QACd,cAAc,EAAE,gBAAgB;QAChC,YAAY,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,EAAE,oBAAoB,EAAE,KAAK,EAAE;QAC7E,YAAY,EAAE,EAAE;KACjB,CAAC;IAEF,oCAAoC;IAC3B,KAAK,GAA4B,IAAI,GAAG,EAAE,CAAC;IACpD,wCAAwC;IAC/B,OAAO,GAAiC,IAAI,GAAG,EAAE,CAAC;IAC3D,0DAA0D;IACjD,QAAQ,GAA0B,IAAI,GAAG,EAAE,CAAC;IACrD,uDAAuD;IAC9C,WAAW,GAA0B,IAAI,GAAG,EAAE,CAAC;IAEhD,WAAW,GAAG,KAAK,CAAC;IACpB,OAAO,GAAG,KAAK,CAAC;IAExB,sBAAsB;IAEtB,KAAK,CAAC,IAAI,CAAC,QAA8C;QACvD,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;IAC1B,CAAC;IAED,KAAK,CAAC,KAAK;QACT,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;IACtB,CAAC;IAED,KAAK,CAAC,IAAI;QACR,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;IACvB,CAAC;IAED,KAAK,CAAC,WAAW;QACf,OAAO;YACL,OAAO,EAAE,IAAI;YACb,OAAO,EAAE,sCAAsC;YAC/C,OAAO,EAAE,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE;SAClE,CAAC;IACJ,CAAC;IAED,iCAAiC;IAEjC,KAAK,CAAC,OAAO,CAAC,EAAU;QACtB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChC,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,IAAI,KAAK,CAAC,2BAA2B,EAAE,aAAa,CAAC,CAAC;QAC9D,CAAC;QACD,OAAO,EAAE,GAAG,IAAI,EAAE,CAAC;IACrB,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,EAAU,EAAE,UAAoB;QAC7C,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChC,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,IAAI,KAAK,CAAC,2BAA2B,EAAE,aAAa,CAAC,CAAC;QAC9D,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,GAAG,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;IAC7F,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,EAAU,EAAE,IAAY;QACvC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC;QAC7C,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,GAAG,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC;IAC7C,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,EAAU,EAAE,MAAc;QACzC,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC;QAChD,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,GAAG,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC;QAEhD,qCAAqC;QACrC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChC,IAAI,IAAI,EAAE,CAAC;YACT,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE;gBACjB,GAAG,IAAI;gBACP,SAAS,EAAE,CAAC,GAAG,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC;gBACtC,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aACpC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,KAAc;QAC7B,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;IACvC,CAAC;IAED,4BAA4B;IAE5B;;;OAGG;IACH,QAAQ,CAAC,OAWR;QACC,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACrC,MAAM,IAAI,GAAe;YACvB,EAAE,EAAE,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;YACtB,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,WAAW,EAAE,OAAO,CAAC,WAAW,IAAI,EAAE;YACtC,QAAQ,EAAE,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC;YACpC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,OAAO,IAAI,SAAS,CAAC;YAC9C,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,EAAE;YAC5B,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,EAAE;YAClC,GAAG,EAAE,OAAO,CAAC,GAAG,IAAI,6BAA6B,OAAO,CAAC,EAAE,EAAE;YAC7D,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,GAAG;YACnC,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,GAAG;SACpC,CAAC;QACF,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;QAC9B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,+BAA+B;IAC/B,WAAW,CACT,KAAa,EACb,IAA2D;QAE3D,IAAI,CAAC,OAAO,CAAC,GAAG,CACd,OAAO,CAAC,KAAK,CAAC,EACd,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAC9E,CAAC;IACJ,CAAC;CACF"}
package/package.json ADDED
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "@ouija-dev/plugin-sdk",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": ["dist/", "README.md"],
8
+ "publishConfig": { "access": "public" },
9
+ "repository": { "type": "git", "url": "https://github.com/muhammadkh4n/ouija.git" },
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "typecheck": "tsc --noEmit"
13
+ },
14
+ "dependencies": {
15
+ "@ouija-dev/types": "*",
16
+ "@types/semver": "^7.7.1",
17
+ "ajv": "^8.18.0",
18
+ "ajv-formats": "^3.0.1",
19
+ "semver": "^7.7.4"
20
+ },
21
+ "devDependencies": {
22
+ "typescript": "^5.5.0"
23
+ }
24
+ }