@a16njs/engine 0.5.0 → 0.6.1

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 @@
1
+ {"version":3,"file":"plugin-discovery.js","sourceRoot":"","sources":["../src/plugin-discovery.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,aAAa,CAAC;AAClC,OAAO,EAAE,QAAQ,EAAE,MAAM,IAAI,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AA+BnD,4DAA4D;AAC5D,MAAM,aAAa,GAAG,cAAc,CAAC;AAErC;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,OAAgC;IAEhC,MAAM,WAAW,GAAG,OAAO,EAAE,WAAW,IAAI,qBAAqB,EAAE,CAAC;IACpE,MAAM,OAAO,GAAiB,EAAE,CAAC;IACjC,MAAM,MAAM,GAAsB,EAAE,CAAC;IACrC,MAAM,aAAa,GAAG,IAAI,GAAG,EAAU,CAAC;IAExC,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE,CAAC;QACrC,qDAAqD;QACrD,IAAI,OAAiB,CAAC;QACtB,IAAI,CAAC;YACH,OAAO,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QACzC,CAAC;QAAC,MAAM,CAAC;YACP,kDAAkD;YAClD,SAAS;QACX,CAAC;QAED,+DAA+D;QAC/D,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC,CAAC;QAE5E,KAAK,MAAM,OAAO,IAAI,UAAU,EAAE,CAAC;YACjC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;YAE/C,IAAI,CAAC;gBACH,6EAA6E;gBAC7E,MAAM,SAAS,GAAG,MAAM,kBAAkB,CAAC,OAAO,CAAC,CAAC;gBACpD,MAAM,SAAS,GAAG,aAAa,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC;gBAChD,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,CAAC;gBAEpC,yEAAyE;gBACzE,MAAM,SAAS,GAAG,GAAG,CAAC,OAAO,IAAI,GAAG,CAAC;gBAErC,IAAI,aAAa,CAAC,SAAS,CAAC,EAAE,CAAC;oBAC7B,IAAI,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE,CAAC;wBACpC,MAAM,CAAC,IAAI,CAAC;4BACV,WAAW,EAAE,OAAO;4BACpB,KAAK,EAAE,wBAAwB,SAAS,CAAC,EAAE,uBAAuB;yBACnE,CAAC,CAAC;oBACL,CAAC;yBAAM,CAAC;wBACN,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;wBAChC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;oBAC1B,CAAC;gBACH,CAAC;qBAAM,CAAC;oBACN,MAAM,CAAC,IAAI,CAAC;wBACV,WAAW,EAAE,OAAO;wBACpB,KAAK,EAAE,kGAAkG;qBAC1G,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,MAAM,CAAC,IAAI,CAAC;oBACV,WAAW,EAAE,OAAO;oBACpB,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;iBACxD,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;AAC7B,CAAC;AAED;;;;;;;;GAQG;AACH,KAAK,UAAU,kBAAkB,CAAC,OAAe;IAC/C,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,cAAc,CAAC,EAAE,OAAO,CAAC,CAAC;QAC3E,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAA4B,CAAC;QACvD,IAAI,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ,IAAI,GAAG,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACxD,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;QACzC,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,0DAA0D;IAC5D,CAAC;IACD,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;AACxC,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,aAAa,CAAC,GAAY;IACxC,IAAI,GAAG,IAAI,IAAI,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QAC3C,OAAO,KAAK,CAAC;IACf,CAAC;IACD,MAAM,SAAS,GAAG,GAA8B,CAAC;IACjD,OAAO,CACL,OAAO,SAAS,CAAC,EAAE,KAAK,QAAQ;QAChC,OAAO,SAAS,CAAC,IAAI,KAAK,QAAQ;QAClC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,QAAQ,CAAC;QACjC,OAAO,SAAS,CAAC,QAAQ,KAAK,UAAU;QACxC,OAAO,SAAS,CAAC,IAAI,KAAK,UAAU,CACrC,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,qBAAqB;IACnC,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,MAAM,QAAQ,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAChD,IAAI,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACjC,OAAO,GAAG,KAAK,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACjC,0DAA0D;QAC1D,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,cAAc,EAAE,CAAC;YAC1C,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAChB,MAAM;QACR,CAAC;QACD,oEAAoE;QACpE,iEAAiE;QACjE,6DAA6D;QAC7D,MAAM,kBAAkB,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;QAC1D,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,QAAQ,CAAC,kBAAkB,CAAC,CAAC;YAC1C,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;gBACvB,KAAK,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;YACjC,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,wCAAwC;QAC1C,CAAC;QACD,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC1B,CAAC;IAED,yFAAyF;IACzF,MAAM,WAAW,GAAG,6BAA6B,EAAE,CAAC;IACpD,IAAI,WAAW,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;QAChD,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAC1B,CAAC;IAED,4BAA4B;IAC5B,MAAM,gBAAgB,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,cAAc,CAAC,CAAC;IAClE,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,CAAC;QACtC,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;IAC/B,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,6BAA6B;IAC3C,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC9B,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IAExB,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACnC,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,KAAK;QAAE,OAAO,IAAI,CAAC;IAEjD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAEvC,gCAAgC;IAChC,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,EAAE,cAAc,CAAC,CAAC;IAC1D,IAAI,CAAC;QACH,IAAI,QAAQ,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE;YAAE,OAAO,KAAK,CAAC;IAClD,CAAC;IAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC;IAE3B,kDAAkD;IAClD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;IACtD,IAAI,CAAC;QACH,IAAI,QAAQ,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE;YAAE,OAAO,QAAQ,CAAC;IACxD,CAAC;IAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC;IAE3B,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,96 @@
1
+ import type { A16nPlugin } from '@a16njs/models';
2
+ import type { PluginRegistrationInput } from './plugin-registry.js';
3
+ import { PluginRegistry } from './plugin-registry.js';
4
+ import { type PluginDiscoveryOptions } from './plugin-discovery.js';
5
+ /**
6
+ * Strategy for resolving conflicts when a discovered plugin has the
7
+ * same ID as an already-registered plugin.
8
+ */
9
+ export declare enum PluginConflictStrategy {
10
+ /** Keep the existing (bundled) plugin, skip the discovered one. This is the default and matches current behavior. */
11
+ PREFER_BUNDLED = "prefer-bundled",
12
+ /** Replace the existing plugin with the discovered (installed) one. */
13
+ PREFER_INSTALLED = "prefer-installed",
14
+ /** Throw an error when a conflict is detected. */
15
+ FAIL = "fail"
16
+ }
17
+ /**
18
+ * Information about a plugin that was skipped during conflict resolution.
19
+ */
20
+ export interface SkippedPlugin {
21
+ /** The plugin that was skipped */
22
+ plugin: A16nPlugin;
23
+ /** Human-readable reason for skipping */
24
+ reason: string;
25
+ /** ID of the plugin it conflicted with */
26
+ conflictsWith: string;
27
+ }
28
+ /**
29
+ * Result of loading and resolving plugins.
30
+ */
31
+ export interface PluginLoadResult {
32
+ /** Plugins that passed conflict resolution and are ready for registration */
33
+ loaded: PluginRegistrationInput[];
34
+ /** Plugins that were skipped due to conflicts */
35
+ skipped: SkippedPlugin[];
36
+ /** Errors encountered during discovery */
37
+ errors: Array<{
38
+ packageName: string;
39
+ error: string;
40
+ }>;
41
+ }
42
+ /**
43
+ * Orchestrates plugin loading by coordinating discovery and conflict
44
+ * resolution as separate, testable phases.
45
+ *
46
+ * Separates three distinct concerns:
47
+ * 1. **Discovery** - Finding plugins in node_modules (delegated to discoverInstalledPlugins)
48
+ * 2. **Conflict Resolution** - Deciding what to do when discovered plugins conflict with existing ones
49
+ * 3. **Registration** - Adding resolved plugins to the registry (done by the caller)
50
+ *
51
+ * @example
52
+ * ```typescript
53
+ * const loader = new PluginLoader(PluginConflictStrategy.PREFER_BUNDLED);
54
+ * const candidates = await loader.loadInstalled({ searchPaths: ['/path/to/node_modules'] });
55
+ * const resolved = loader.resolveConflicts(registry, candidates);
56
+ * for (const reg of resolved.loaded) {
57
+ * registry.register(reg);
58
+ * }
59
+ * ```
60
+ */
61
+ export declare class PluginLoader {
62
+ private readonly _conflictStrategy;
63
+ /**
64
+ * Create a new PluginLoader with the given conflict resolution strategy.
65
+ *
66
+ * @param conflictStrategy - How to handle plugin ID conflicts (default: PREFER_BUNDLED)
67
+ */
68
+ constructor(_conflictStrategy?: PluginConflictStrategy);
69
+ /**
70
+ * The conflict resolution strategy in use.
71
+ */
72
+ get conflictStrategy(): PluginConflictStrategy;
73
+ /**
74
+ * Discover installed plugins from node_modules and wrap them
75
+ * as PluginRegistrationInput candidates with source='installed'.
76
+ *
77
+ * This is Phase 1 (Discovery) of the loading pipeline.
78
+ *
79
+ * @param options - Plugin discovery options (search paths, etc.)
80
+ * @returns Load result with candidates ready for conflict resolution
81
+ */
82
+ loadInstalled(options?: PluginDiscoveryOptions): Promise<PluginLoadResult>;
83
+ /**
84
+ * Resolve conflicts between discovered plugin candidates and
85
+ * already-registered plugins using the configured strategy.
86
+ *
87
+ * This is Phase 2 (Conflict Resolution) of the loading pipeline.
88
+ * Pure function: does not modify the registry.
89
+ *
90
+ * @param existing - The current plugin registry to check for conflicts
91
+ * @param candidates - The load result from loadInstalled()
92
+ * @returns Resolved load result with loaded (ready to register) and skipped plugins
93
+ */
94
+ resolveConflicts(existing: PluginRegistry, candidates: PluginLoadResult): PluginLoadResult;
95
+ }
96
+ //# 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":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,KAAK,EAAsB,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AACxF,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAEL,KAAK,sBAAsB,EAC5B,MAAM,uBAAuB,CAAC;AAE/B;;;GAGG;AACH,oBAAY,sBAAsB;IAChC,qHAAqH;IACrH,cAAc,mBAAmB;IACjC,uEAAuE;IACvE,gBAAgB,qBAAqB;IACrC,kDAAkD;IAClD,IAAI,SAAS;CACd;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,kCAAkC;IAClC,MAAM,EAAE,UAAU,CAAC;IACnB,yCAAyC;IACzC,MAAM,EAAE,MAAM,CAAC;IACf,0CAA0C;IAC1C,aAAa,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,6EAA6E;IAC7E,MAAM,EAAE,uBAAuB,EAAE,CAAC;IAClC,iDAAiD;IACjD,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,0CAA0C;IAC1C,MAAM,EAAE,KAAK,CAAC;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACvD;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,YAAY;IAOrB,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IANpC;;;;OAIG;gBAEgB,iBAAiB,GAAE,sBAA8D;IAGpG;;OAEG;IACH,IAAI,gBAAgB,IAAI,sBAAsB,CAE7C;IAED;;;;;;;;OAQG;IACG,aAAa,CAAC,OAAO,CAAC,EAAE,sBAAsB,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAahF;;;;;;;;;;OAUG;IACH,gBAAgB,CAAC,QAAQ,EAAE,cAAc,EAAE,UAAU,EAAE,gBAAgB,GAAG,gBAAgB;CAoC3F"}
@@ -0,0 +1,112 @@
1
+ import { discoverInstalledPlugins, } from './plugin-discovery.js';
2
+ /**
3
+ * Strategy for resolving conflicts when a discovered plugin has the
4
+ * same ID as an already-registered plugin.
5
+ */
6
+ export var PluginConflictStrategy;
7
+ (function (PluginConflictStrategy) {
8
+ /** Keep the existing (bundled) plugin, skip the discovered one. This is the default and matches current behavior. */
9
+ PluginConflictStrategy["PREFER_BUNDLED"] = "prefer-bundled";
10
+ /** Replace the existing plugin with the discovered (installed) one. */
11
+ PluginConflictStrategy["PREFER_INSTALLED"] = "prefer-installed";
12
+ /** Throw an error when a conflict is detected. */
13
+ PluginConflictStrategy["FAIL"] = "fail";
14
+ })(PluginConflictStrategy || (PluginConflictStrategy = {}));
15
+ /**
16
+ * Orchestrates plugin loading by coordinating discovery and conflict
17
+ * resolution as separate, testable phases.
18
+ *
19
+ * Separates three distinct concerns:
20
+ * 1. **Discovery** - Finding plugins in node_modules (delegated to discoverInstalledPlugins)
21
+ * 2. **Conflict Resolution** - Deciding what to do when discovered plugins conflict with existing ones
22
+ * 3. **Registration** - Adding resolved plugins to the registry (done by the caller)
23
+ *
24
+ * @example
25
+ * ```typescript
26
+ * const loader = new PluginLoader(PluginConflictStrategy.PREFER_BUNDLED);
27
+ * const candidates = await loader.loadInstalled({ searchPaths: ['/path/to/node_modules'] });
28
+ * const resolved = loader.resolveConflicts(registry, candidates);
29
+ * for (const reg of resolved.loaded) {
30
+ * registry.register(reg);
31
+ * }
32
+ * ```
33
+ */
34
+ export class PluginLoader {
35
+ _conflictStrategy;
36
+ /**
37
+ * Create a new PluginLoader with the given conflict resolution strategy.
38
+ *
39
+ * @param conflictStrategy - How to handle plugin ID conflicts (default: PREFER_BUNDLED)
40
+ */
41
+ constructor(_conflictStrategy = PluginConflictStrategy.PREFER_BUNDLED) {
42
+ this._conflictStrategy = _conflictStrategy;
43
+ }
44
+ /**
45
+ * The conflict resolution strategy in use.
46
+ */
47
+ get conflictStrategy() {
48
+ return this._conflictStrategy;
49
+ }
50
+ /**
51
+ * Discover installed plugins from node_modules and wrap them
52
+ * as PluginRegistrationInput candidates with source='installed'.
53
+ *
54
+ * This is Phase 1 (Discovery) of the loading pipeline.
55
+ *
56
+ * @param options - Plugin discovery options (search paths, etc.)
57
+ * @returns Load result with candidates ready for conflict resolution
58
+ */
59
+ async loadInstalled(options) {
60
+ const discovered = await discoverInstalledPlugins(options);
61
+ return {
62
+ loaded: discovered.plugins.map((plugin) => ({
63
+ plugin,
64
+ source: 'installed',
65
+ })),
66
+ skipped: [],
67
+ errors: discovered.errors,
68
+ };
69
+ }
70
+ /**
71
+ * Resolve conflicts between discovered plugin candidates and
72
+ * already-registered plugins using the configured strategy.
73
+ *
74
+ * This is Phase 2 (Conflict Resolution) of the loading pipeline.
75
+ * Pure function: does not modify the registry.
76
+ *
77
+ * @param existing - The current plugin registry to check for conflicts
78
+ * @param candidates - The load result from loadInstalled()
79
+ * @returns Resolved load result with loaded (ready to register) and skipped plugins
80
+ */
81
+ resolveConflicts(existing, candidates) {
82
+ const loaded = [];
83
+ const skipped = [...candidates.skipped];
84
+ for (const candidate of candidates.loaded) {
85
+ const existingReg = existing.get(candidate.plugin.id);
86
+ if (!existingReg) {
87
+ loaded.push(candidate);
88
+ continue;
89
+ }
90
+ switch (this._conflictStrategy) {
91
+ case PluginConflictStrategy.PREFER_BUNDLED:
92
+ skipped.push({
93
+ plugin: candidate.plugin,
94
+ reason: `Conflict: ${existingReg.source} plugin '${existingReg.plugin.id}' already registered`,
95
+ conflictsWith: candidate.plugin.id,
96
+ });
97
+ break;
98
+ case PluginConflictStrategy.PREFER_INSTALLED:
99
+ loaded.push(candidate);
100
+ break;
101
+ case PluginConflictStrategy.FAIL:
102
+ throw new Error(`Plugin conflict: '${candidate.plugin.id}' is already registered`);
103
+ }
104
+ }
105
+ return {
106
+ loaded,
107
+ skipped,
108
+ errors: candidates.errors,
109
+ };
110
+ }
111
+ }
112
+ //# sourceMappingURL=plugin-loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin-loader.js","sourceRoot":"","sources":["../src/plugin-loader.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,wBAAwB,GAEzB,MAAM,uBAAuB,CAAC;AAE/B;;;GAGG;AACH,MAAM,CAAN,IAAY,sBAOX;AAPD,WAAY,sBAAsB;IAChC,qHAAqH;IACrH,2DAAiC,CAAA;IACjC,uEAAuE;IACvE,+DAAqC,CAAA;IACrC,kDAAkD;IAClD,uCAAa,CAAA;AACf,CAAC,EAPW,sBAAsB,KAAtB,sBAAsB,QAOjC;AA0BD;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,OAAO,YAAY;IAOJ;IANnB;;;;OAIG;IACH,YACmB,oBAA4C,sBAAsB,CAAC,cAAc;QAAjF,sBAAiB,GAAjB,iBAAiB,CAAgE;IACjG,CAAC;IAEJ;;OAEG;IACH,IAAI,gBAAgB;QAClB,OAAO,IAAI,CAAC,iBAAiB,CAAC;IAChC,CAAC;IAED;;;;;;;;OAQG;IACH,KAAK,CAAC,aAAa,CAAC,OAAgC;QAClD,MAAM,UAAU,GAAG,MAAM,wBAAwB,CAAC,OAAO,CAAC,CAAC;QAE3D,OAAO;YACL,MAAM,EAAE,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;gBAC1C,MAAM;gBACN,MAAM,EAAE,WAAoB;aAC7B,CAAC,CAAC;YACH,OAAO,EAAE,EAAE;YACX,MAAM,EAAE,UAAU,CAAC,MAAM;SAC1B,CAAC;IACJ,CAAC;IAED;;;;;;;;;;OAUG;IACH,gBAAgB,CAAC,QAAwB,EAAE,UAA4B;QACrE,MAAM,MAAM,GAA8B,EAAE,CAAC;QAC7C,MAAM,OAAO,GAAoB,CAAC,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;QAEzD,KAAK,MAAM,SAAS,IAAI,UAAU,CAAC,MAAM,EAAE,CAAC;YAC1C,MAAM,WAAW,GAAG,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YAEtD,IAAI,CAAC,WAAW,EAAE,CAAC;gBACjB,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;gBACvB,SAAS;YACX,CAAC;YAED,QAAQ,IAAI,CAAC,iBAAiB,EAAE,CAAC;gBAC/B,KAAK,sBAAsB,CAAC,cAAc;oBACxC,OAAO,CAAC,IAAI,CAAC;wBACX,MAAM,EAAE,SAAS,CAAC,MAAM;wBACxB,MAAM,EAAE,aAAa,WAAW,CAAC,MAAM,YAAY,WAAW,CAAC,MAAM,CAAC,EAAE,sBAAsB;wBAC9F,aAAa,EAAE,SAAS,CAAC,MAAM,CAAC,EAAE;qBACnC,CAAC,CAAC;oBACH,MAAM;gBAER,KAAK,sBAAsB,CAAC,gBAAgB;oBAC1C,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;oBACvB,MAAM;gBAER,KAAK,sBAAsB,CAAC,IAAI;oBAC9B,MAAM,IAAI,KAAK,CAAC,qBAAqB,SAAS,CAAC,MAAM,CAAC,EAAE,yBAAyB,CAAC,CAAC;YACvF,CAAC;QACH,CAAC;QAED,OAAO;YACL,MAAM;YACN,OAAO;YACP,MAAM,EAAE,UAAU,CAAC,MAAM;SAC1B,CAAC;IACJ,CAAC;CACF"}
@@ -0,0 +1,94 @@
1
+ import type { A16nPlugin } from '@a16njs/models';
2
+ /**
3
+ * Full metadata for a registered plugin.
4
+ * Wraps the plugin instance with registration metadata such as
5
+ * source (bundled vs installed), registration timestamp, and
6
+ * optional diagnostic information.
7
+ */
8
+ export interface PluginRegistration {
9
+ /** The plugin instance */
10
+ plugin: A16nPlugin;
11
+ /** Whether this plugin was bundled with the engine or installed from node_modules */
12
+ source: 'bundled' | 'installed';
13
+ /** When this plugin was registered */
14
+ registeredAt: Date;
15
+ /** Semantic version of the installed plugin (for installed plugins) */
16
+ version?: string;
17
+ /** Filesystem path where the plugin was installed from (for diagnostics) */
18
+ installPath?: string;
19
+ }
20
+ /**
21
+ * Input for registering a plugin. Omits `registeredAt` which is
22
+ * automatically set by the registry.
23
+ */
24
+ export type PluginRegistrationInput = Omit<PluginRegistration, 'registeredAt'>;
25
+ /**
26
+ * Unified plugin registry that serves as the single source of truth
27
+ * for all plugin metadata. Replaces the dual-Map pattern
28
+ * (plugins Map + pluginSources Map) with a single registry that
29
+ * tracks all plugin information in one place.
30
+ *
31
+ * @example
32
+ * ```typescript
33
+ * const registry = new PluginRegistry();
34
+ * registry.register({ plugin: cursorPlugin, source: 'bundled' });
35
+ * registry.register({ plugin: claudePlugin, source: 'installed', version: '1.0.0' });
36
+ *
37
+ * const cursor = registry.getPlugin('cursor');
38
+ * const installed = registry.listBySource('installed');
39
+ * ```
40
+ */
41
+ export declare class PluginRegistry {
42
+ private registrations;
43
+ /**
44
+ * Register a plugin with the registry.
45
+ * If a plugin with the same ID is already registered, it will be overwritten.
46
+ *
47
+ * @param input - Plugin and metadata to register (registeredAt is set automatically)
48
+ */
49
+ register(input: PluginRegistrationInput): void;
50
+ /**
51
+ * Get the full registration for a plugin by its ID.
52
+ *
53
+ * @param id - The plugin ID to look up
54
+ * @returns The full PluginRegistration, or undefined if not found
55
+ */
56
+ get(id: string): PluginRegistration | undefined;
57
+ /**
58
+ * Get just the plugin instance by its ID.
59
+ * Convenience method equivalent to `registry.get(id)?.plugin`.
60
+ *
61
+ * @param id - The plugin ID to look up
62
+ * @returns The A16nPlugin instance, or undefined if not found
63
+ */
64
+ getPlugin(id: string): A16nPlugin | undefined;
65
+ /**
66
+ * Check whether a plugin with the given ID is registered.
67
+ *
68
+ * @param id - The plugin ID to check
69
+ * @returns true if the plugin is registered, false otherwise
70
+ */
71
+ has(id: string): boolean;
72
+ /**
73
+ * List all plugin registrations.
74
+ *
75
+ * @returns Array of all PluginRegistration objects in insertion order
76
+ */
77
+ list(): PluginRegistration[];
78
+ /**
79
+ * List plugin registrations filtered by source.
80
+ *
81
+ * @param source - The source to filter by ('bundled' or 'installed')
82
+ * @returns Array of matching PluginRegistration objects
83
+ */
84
+ listBySource(source: 'bundled' | 'installed'): PluginRegistration[];
85
+ /**
86
+ * The number of registered plugins.
87
+ */
88
+ get size(): number;
89
+ /**
90
+ * Remove all plugin registrations.
91
+ */
92
+ clear(): void;
93
+ }
94
+ //# sourceMappingURL=plugin-registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin-registry.d.ts","sourceRoot":"","sources":["../src/plugin-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEjD;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IACjC,0BAA0B;IAC1B,MAAM,EAAE,UAAU,CAAC;IACnB,qFAAqF;IACrF,MAAM,EAAE,SAAS,GAAG,WAAW,CAAC;IAChC,sCAAsC;IACtC,YAAY,EAAE,IAAI,CAAC;IACnB,uEAAuE;IACvE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4EAA4E;IAC5E,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;GAGG;AACH,MAAM,MAAM,uBAAuB,GAAG,IAAI,CAAC,kBAAkB,EAAE,cAAc,CAAC,CAAC;AAE/E;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,aAAa,CAA8C;IAEnE;;;;;OAKG;IACH,QAAQ,CAAC,KAAK,EAAE,uBAAuB,GAAG,IAAI;IAO9C;;;;;OAKG;IACH,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS;IAI/C;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS;IAI7C;;;;;OAKG;IACH,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAIxB;;;;OAIG;IACH,IAAI,IAAI,kBAAkB,EAAE;IAI5B;;;;;OAKG;IACH,YAAY,CAAC,MAAM,EAAE,SAAS,GAAG,WAAW,GAAG,kBAAkB,EAAE;IAInE;;OAEG;IACH,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED;;OAEG;IACH,KAAK,IAAI,IAAI;CAGd"}
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Unified plugin registry that serves as the single source of truth
3
+ * for all plugin metadata. Replaces the dual-Map pattern
4
+ * (plugins Map + pluginSources Map) with a single registry that
5
+ * tracks all plugin information in one place.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * const registry = new PluginRegistry();
10
+ * registry.register({ plugin: cursorPlugin, source: 'bundled' });
11
+ * registry.register({ plugin: claudePlugin, source: 'installed', version: '1.0.0' });
12
+ *
13
+ * const cursor = registry.getPlugin('cursor');
14
+ * const installed = registry.listBySource('installed');
15
+ * ```
16
+ */
17
+ export class PluginRegistry {
18
+ registrations = new Map();
19
+ /**
20
+ * Register a plugin with the registry.
21
+ * If a plugin with the same ID is already registered, it will be overwritten.
22
+ *
23
+ * @param input - Plugin and metadata to register (registeredAt is set automatically)
24
+ */
25
+ register(input) {
26
+ this.registrations.set(input.plugin.id, {
27
+ ...input,
28
+ registeredAt: new Date(),
29
+ });
30
+ }
31
+ /**
32
+ * Get the full registration for a plugin by its ID.
33
+ *
34
+ * @param id - The plugin ID to look up
35
+ * @returns The full PluginRegistration, or undefined if not found
36
+ */
37
+ get(id) {
38
+ return this.registrations.get(id);
39
+ }
40
+ /**
41
+ * Get just the plugin instance by its ID.
42
+ * Convenience method equivalent to `registry.get(id)?.plugin`.
43
+ *
44
+ * @param id - The plugin ID to look up
45
+ * @returns The A16nPlugin instance, or undefined if not found
46
+ */
47
+ getPlugin(id) {
48
+ return this.registrations.get(id)?.plugin;
49
+ }
50
+ /**
51
+ * Check whether a plugin with the given ID is registered.
52
+ *
53
+ * @param id - The plugin ID to check
54
+ * @returns true if the plugin is registered, false otherwise
55
+ */
56
+ has(id) {
57
+ return this.registrations.has(id);
58
+ }
59
+ /**
60
+ * List all plugin registrations.
61
+ *
62
+ * @returns Array of all PluginRegistration objects in insertion order
63
+ */
64
+ list() {
65
+ return Array.from(this.registrations.values());
66
+ }
67
+ /**
68
+ * List plugin registrations filtered by source.
69
+ *
70
+ * @param source - The source to filter by ('bundled' or 'installed')
71
+ * @returns Array of matching PluginRegistration objects
72
+ */
73
+ listBySource(source) {
74
+ return this.list().filter((r) => r.source === source);
75
+ }
76
+ /**
77
+ * The number of registered plugins.
78
+ */
79
+ get size() {
80
+ return this.registrations.size;
81
+ }
82
+ /**
83
+ * Remove all plugin registrations.
84
+ */
85
+ clear() {
86
+ this.registrations.clear();
87
+ }
88
+ }
89
+ //# sourceMappingURL=plugin-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin-registry.js","sourceRoot":"","sources":["../src/plugin-registry.ts"],"names":[],"mappings":"AA2BA;;;;;;;;;;;;;;;GAeG;AACH,MAAM,OAAO,cAAc;IACjB,aAAa,GAAoC,IAAI,GAAG,EAAE,CAAC;IAEnE;;;;;OAKG;IACH,QAAQ,CAAC,KAA8B;QACrC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,EAAE;YACtC,GAAG,KAAK;YACR,YAAY,EAAE,IAAI,IAAI,EAAE;SACzB,CAAC,CAAC;IACL,CAAC;IAED;;;;;OAKG;IACH,GAAG,CAAC,EAAU;QACZ,OAAO,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACpC,CAAC;IAED;;;;;;OAMG;IACH,SAAS,CAAC,EAAU;QAClB,OAAO,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IAC5C,CAAC;IAED;;;;;OAKG;IACH,GAAG,CAAC,EAAU;QACZ,OAAO,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACpC,CAAC;IAED;;;;OAIG;IACH,IAAI;QACF,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,CAAC,CAAC;IACjD,CAAC;IAED;;;;;OAKG;IACH,YAAY,CAAC,MAA+B;QAC1C,OAAO,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC;IACxD,CAAC;IAED;;OAEG;IACH,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC;IACjC,CAAC;IAED;;OAEG;IACH,KAAK;QACH,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE,CAAC;IAC7B,CAAC;CACF"}
@@ -0,0 +1,93 @@
1
+ import type { AgentCustomization, A16nPlugin, EmitResult, Warning } from '@a16njs/models';
2
+ /**
3
+ * Context provided to a content transformation during the conversion pipeline.
4
+ */
5
+ export interface TransformationContext {
6
+ /** The items to transform */
7
+ items: AgentCustomization[];
8
+ /** The source plugin */
9
+ sourcePlugin: A16nPlugin;
10
+ /** The target plugin */
11
+ targetPlugin: A16nPlugin;
12
+ /** Root directory for source (discovery) */
13
+ sourceRoot: string;
14
+ /** Root directory for target (emission) */
15
+ targetRoot: string;
16
+ /**
17
+ * Perform a trial emission (dry-run) to discover file mapping.
18
+ * Only available when dryRun is false; stateful transformations
19
+ * like path rewriting use this to know target paths without
20
+ * actually writing files.
21
+ */
22
+ trialEmit: (items: AgentCustomization[]) => Promise<EmitResult>;
23
+ }
24
+ /**
25
+ * Result of applying a content transformation.
26
+ */
27
+ export interface TransformationResult {
28
+ /** The transformed items */
29
+ items: AgentCustomization[];
30
+ /** Warnings produced by this transformation */
31
+ warnings: Warning[];
32
+ }
33
+ /**
34
+ * A composable content transformation in the conversion pipeline.
35
+ *
36
+ * Transformations receive discovered items and produce transformed items.
37
+ * They run in sequence between discovery and final emission, enabling
38
+ * composable, extensible processing without double emission.
39
+ *
40
+ * @example
41
+ * ```typescript
42
+ * const transform: ContentTransformation = {
43
+ * id: 'path-rewriting',
44
+ * name: 'Path Reference Rewriting',
45
+ * transform: async (context) => {
46
+ * // Transform items...
47
+ * return { items: transformedItems, warnings: [] };
48
+ * },
49
+ * };
50
+ * ```
51
+ */
52
+ export interface ContentTransformation {
53
+ /** Unique identifier for this transformation */
54
+ id: string;
55
+ /** Human-readable name */
56
+ name: string;
57
+ /**
58
+ * Apply this transformation to the items.
59
+ * @param context - The transformation context with items, plugins, and trial emit
60
+ * @returns Transformed items and any warnings
61
+ */
62
+ transform(context: TransformationContext): Promise<TransformationResult>;
63
+ }
64
+ /**
65
+ * Path rewriting transformation.
66
+ *
67
+ * Rewrites file path references in content during format conversion.
68
+ * Uses a trial emission to discover the source-to-target path mapping,
69
+ * then rewrites all path references in content. Also detects orphan
70
+ * references (paths that weren't converted) using plugin-provided
71
+ * path patterns.
72
+ *
73
+ * This replaces the hardcoded path rewriting logic that was previously
74
+ * embedded in the engine's convert() method, eliminating the need for
75
+ * double emission and removing hardcoded plugin knowledge.
76
+ *
77
+ * @example
78
+ * ```typescript
79
+ * const transform = new PathRewritingTransformation();
80
+ * engine.convert({
81
+ * source: 'cursor',
82
+ * target: 'claude',
83
+ * root: '/project',
84
+ * transformations: [transform],
85
+ * });
86
+ * ```
87
+ */
88
+ export declare class PathRewritingTransformation implements ContentTransformation {
89
+ readonly id = "path-rewriting";
90
+ readonly name = "Path Reference Rewriting";
91
+ transform(context: TransformationContext): Promise<TransformationResult>;
92
+ }
93
+ //# sourceMappingURL=transformation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transformation.d.ts","sourceRoot":"","sources":["../src/transformation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,UAAU,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAG1F;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,6BAA6B;IAC7B,KAAK,EAAE,kBAAkB,EAAE,CAAC;IAC5B,wBAAwB;IACxB,YAAY,EAAE,UAAU,CAAC;IACzB,wBAAwB;IACxB,YAAY,EAAE,UAAU,CAAC;IACzB,4CAA4C;IAC5C,UAAU,EAAE,MAAM,CAAC;IACnB,2CAA2C;IAC3C,UAAU,EAAE,MAAM,CAAC;IACnB;;;;;OAKG;IACH,SAAS,EAAE,CAAC,KAAK,EAAE,kBAAkB,EAAE,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;CACjE;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,4BAA4B;IAC5B,KAAK,EAAE,kBAAkB,EAAE,CAAC;IAC5B,+CAA+C;IAC/C,QAAQ,EAAE,OAAO,EAAE,CAAC;CACrB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,WAAW,qBAAqB;IACpC,gDAAgD;IAChD,EAAE,EAAE,MAAM,CAAC;IACX,0BAA0B;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,SAAS,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;CAC1E;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,qBAAa,2BAA4B,YAAW,qBAAqB;IACvE,QAAQ,CAAC,EAAE,oBAAoB;IAC/B,QAAQ,CAAC,IAAI,8BAA8B;IAErC,SAAS,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,oBAAoB,CAAC;CA0C/E"}
@@ -0,0 +1,56 @@
1
+ import { buildMapping, rewriteContent, detectOrphans } from './path-rewriter.js';
2
+ /**
3
+ * Path rewriting transformation.
4
+ *
5
+ * Rewrites file path references in content during format conversion.
6
+ * Uses a trial emission to discover the source-to-target path mapping,
7
+ * then rewrites all path references in content. Also detects orphan
8
+ * references (paths that weren't converted) using plugin-provided
9
+ * path patterns.
10
+ *
11
+ * This replaces the hardcoded path rewriting logic that was previously
12
+ * embedded in the engine's convert() method, eliminating the need for
13
+ * double emission and removing hardcoded plugin knowledge.
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * const transform = new PathRewritingTransformation();
18
+ * engine.convert({
19
+ * source: 'cursor',
20
+ * target: 'claude',
21
+ * root: '/project',
22
+ * transformations: [transform],
23
+ * });
24
+ * ```
25
+ */
26
+ export class PathRewritingTransformation {
27
+ id = 'path-rewriting';
28
+ name = 'Path Reference Rewriting';
29
+ async transform(context) {
30
+ const warnings = [];
31
+ // Trial emit to discover the path mapping
32
+ const trialResult = await context.trialEmit(context.items);
33
+ if (trialResult.written.length === 0) {
34
+ // No files would be written → no mapping → return cloned items
35
+ return {
36
+ items: context.items.map((item) => ({ ...item })),
37
+ warnings,
38
+ };
39
+ }
40
+ // Build mapping from source paths to target paths
41
+ const mapping = buildMapping(context.items, trialResult.written, context.sourceRoot, context.targetRoot);
42
+ // Rewrite path references in content
43
+ const rewriteResult = rewriteContent(context.items, mapping);
44
+ // Detect orphan references using plugin-provided path patterns
45
+ const patterns = context.sourcePlugin.pathPatterns;
46
+ if (patterns && patterns.prefixes.length > 0 && patterns.extensions.length > 0) {
47
+ const orphanWarnings = detectOrphans(rewriteResult.items, mapping, patterns.prefixes, patterns.extensions);
48
+ warnings.push(...orphanWarnings);
49
+ }
50
+ return {
51
+ items: rewriteResult.items,
52
+ warnings,
53
+ };
54
+ }
55
+ }
56
+ //# sourceMappingURL=transformation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transformation.js","sourceRoot":"","sources":["../src/transformation.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAmEjF;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,OAAO,2BAA2B;IAC7B,EAAE,GAAG,gBAAgB,CAAC;IACtB,IAAI,GAAG,0BAA0B,CAAC;IAE3C,KAAK,CAAC,SAAS,CAAC,OAA8B;QAC5C,MAAM,QAAQ,GAAc,EAAE,CAAC;QAE/B,0CAA0C;QAC1C,MAAM,WAAW,GAAG,MAAM,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAE3D,IAAI,WAAW,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACrC,+DAA+D;YAC/D,OAAO;gBACL,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC;gBACjD,QAAQ;aACT,CAAC;QACJ,CAAC;QAED,kDAAkD;QAClD,MAAM,OAAO,GAAG,YAAY,CAC1B,OAAO,CAAC,KAAK,EACb,WAAW,CAAC,OAAO,EACnB,OAAO,CAAC,UAAU,EAClB,OAAO,CAAC,UAAU,CACnB,CAAC;QAEF,qCAAqC;QACrC,MAAM,aAAa,GAAG,cAAc,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QAE7D,+DAA+D;QAC/D,MAAM,QAAQ,GAAG,OAAO,CAAC,YAAY,CAAC,YAAY,CAAC;QACnD,IAAI,QAAQ,IAAI,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,IAAI,QAAQ,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC/E,MAAM,cAAc,GAAG,aAAa,CAClC,aAAa,CAAC,KAAK,EACnB,OAAO,EACP,QAAQ,CAAC,QAAQ,EACjB,QAAQ,CAAC,UAAU,CACpB,CAAC;YACF,QAAQ,CAAC,IAAI,CAAC,GAAG,cAAc,CAAC,CAAC;QACnC,CAAC;QAED,OAAO;YACL,KAAK,EAAE,aAAa,CAAC,KAAK;YAC1B,QAAQ;SACT,CAAC;IACJ,CAAC;CACF"}
@@ -0,0 +1,73 @@
1
+ import type { Workspace, WorkspaceEntry } from '@a16njs/models';
2
+ export type { Workspace, WorkspaceEntry } from '@a16njs/models';
3
+ export { LocalWorkspace, toWorkspace } from '@a16njs/models';
4
+ /**
5
+ * Read-only wrapper around another workspace.
6
+ * Allows read operations but throws on any write operation.
7
+ * Useful for dry-run scenarios.
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * const ws = new LocalWorkspace('source', '/project');
12
+ * const readOnly = new ReadOnlyWorkspace(ws);
13
+ * await readOnly.read('file.md'); // works
14
+ * await readOnly.write('file.md', 'content'); // throws!
15
+ * ```
16
+ */
17
+ export declare class ReadOnlyWorkspace implements Workspace {
18
+ private readonly underlying;
19
+ /**
20
+ * Create a new ReadOnlyWorkspace wrapping another workspace.
21
+ * @param underlying - The workspace to wrap
22
+ */
23
+ constructor(underlying: Workspace);
24
+ get id(): string;
25
+ get root(): string;
26
+ resolve(relativePath: string): string;
27
+ exists(relativePath: string): Promise<boolean>;
28
+ read(relativePath: string): Promise<string>;
29
+ write(_relativePath: string, _content: string): Promise<void>;
30
+ readdir(relativePath: string): Promise<WorkspaceEntry[]>;
31
+ mkdir(_relativePath: string): Promise<void>;
32
+ }
33
+ /**
34
+ * In-memory workspace for testing.
35
+ * Stores files in a Map, no filesystem access.
36
+ *
37
+ * @example
38
+ * ```typescript
39
+ * const ws = new MemoryWorkspace('test');
40
+ * await ws.write('rules/my-rule.md', '# Rule');
41
+ * const content = await ws.read('rules/my-rule.md');
42
+ * const entries = await ws.readdir('rules');
43
+ * // entries: [{ name: 'my-rule.md', isFile: true, isDirectory: false }]
44
+ * ```
45
+ */
46
+ export declare class MemoryWorkspace implements Workspace {
47
+ readonly id: string;
48
+ readonly root: string;
49
+ private files;
50
+ private directories;
51
+ /**
52
+ * Create a new MemoryWorkspace.
53
+ * @param id - Unique identifier for this workspace
54
+ * @param initialFiles - Optional map of relative paths to file contents
55
+ */
56
+ constructor(id: string, initialFiles?: Record<string, string>);
57
+ resolve(relativePath: string): string;
58
+ exists(relativePath: string): Promise<boolean>;
59
+ read(relativePath: string): Promise<string>;
60
+ write(relativePath: string, content: string): Promise<void>;
61
+ readdir(relativePath: string): Promise<WorkspaceEntry[]>;
62
+ mkdir(relativePath: string): Promise<void>;
63
+ /**
64
+ * Get all file paths stored in this workspace (for test assertions).
65
+ * @returns Array of normalized file paths
66
+ */
67
+ getAllPaths(): string[];
68
+ /**
69
+ * Normalize a path to use forward slashes and strip leading slash.
70
+ */
71
+ private normalizePath;
72
+ }
73
+ //# sourceMappingURL=workspace.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../src/workspace.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAGhE,YAAY,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChE,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7D;;;;;;;;;;;;GAYG;AACH,qBAAa,iBAAkB,YAAW,SAAS;IAKrC,OAAO,CAAC,QAAQ,CAAC,UAAU;IAJvC;;;OAGG;gBAC0B,UAAU,EAAE,SAAS;IAElD,IAAI,EAAE,IAAI,MAAM,CAEf;IAED,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,OAAO,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM;IAIrC,MAAM,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAI9C,IAAI,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAIrC,KAAK,CAAC,aAAa,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAInE,OAAO,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IAIlD,KAAK,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAGlD;AAED;;;;;;;;;;;;GAYG;AACH,qBAAa,eAAgB,YAAW,SAAS;aAW7B,EAAE,EAAE,MAAM;IAV5B,SAAgB,IAAI,EAAE,MAAM,CAAa;IACzC,OAAO,CAAC,KAAK,CAAkC;IAC/C,OAAO,CAAC,WAAW,CAA0B;IAE7C;;;;OAIG;gBAEe,EAAE,EAAE,MAAM,EAC1B,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IASvC,OAAO,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM;IAM/B,MAAM,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAe9C,IAAI,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAS3C,KAAK,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAK3D,OAAO,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IA4CxD,KAAK,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOhD;;;OAGG;IACH,WAAW,IAAI,MAAM,EAAE;IAIvB;;OAEG;IACH,OAAO,CAAC,aAAa;CAGtB"}