@nathapp/nax 0.50.3 → 0.51.2
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.
- package/CHANGELOG.md +30 -0
- package/README.md +177 -104
- package/dist/nax.js +417 -213
- package/package.json +1 -3
- package/bin/nax.ts +0 -1195
- package/src/acceptance/fix-generator.ts +0 -322
- package/src/acceptance/generator.ts +0 -415
- package/src/acceptance/index.ts +0 -42
- package/src/acceptance/refinement.ts +0 -224
- package/src/acceptance/templates/cli.ts +0 -47
- package/src/acceptance/templates/component.ts +0 -78
- package/src/acceptance/templates/e2e.ts +0 -43
- package/src/acceptance/templates/index.ts +0 -21
- package/src/acceptance/templates/snapshot.ts +0 -50
- package/src/acceptance/templates/unit.ts +0 -48
- package/src/acceptance/types.ts +0 -138
- package/src/agents/acp/adapter.ts +0 -888
- package/src/agents/acp/cost.ts +0 -9
- package/src/agents/acp/index.ts +0 -7
- package/src/agents/acp/interaction-bridge.ts +0 -126
- package/src/agents/acp/parser.ts +0 -119
- package/src/agents/acp/spawn-client.ts +0 -373
- package/src/agents/acp/types.ts +0 -22
- package/src/agents/aider/adapter.ts +0 -135
- package/src/agents/claude/adapter.ts +0 -258
- package/src/agents/claude/complete.ts +0 -80
- package/src/agents/claude/cost.ts +0 -16
- package/src/agents/claude/execution.ts +0 -215
- package/src/agents/claude/index.ts +0 -3
- package/src/agents/claude/interactive.ts +0 -77
- package/src/agents/claude/plan.ts +0 -179
- package/src/agents/codex/adapter.ts +0 -153
- package/src/agents/cost/calculate.ts +0 -154
- package/src/agents/cost/index.ts +0 -10
- package/src/agents/cost/parse.ts +0 -97
- package/src/agents/cost/pricing.ts +0 -59
- package/src/agents/cost/types.ts +0 -45
- package/src/agents/gemini/adapter.ts +0 -177
- package/src/agents/index.ts +0 -18
- package/src/agents/opencode/adapter.ts +0 -106
- package/src/agents/registry.ts +0 -136
- package/src/agents/shared/decompose.ts +0 -154
- package/src/agents/shared/model-resolution.ts +0 -43
- package/src/agents/shared/types-extended.ts +0 -164
- package/src/agents/shared/validation.ts +0 -69
- package/src/agents/shared/version-detection.ts +0 -109
- package/src/agents/types.ts +0 -205
- package/src/analyze/classifier.ts +0 -282
- package/src/analyze/index.ts +0 -16
- package/src/analyze/scanner.ts +0 -171
- package/src/analyze/types.ts +0 -51
- package/src/cli/accept.ts +0 -108
- package/src/cli/agents.ts +0 -87
- package/src/cli/analyze-parser.ts +0 -291
- package/src/cli/analyze.ts +0 -352
- package/src/cli/config-descriptions.ts +0 -219
- package/src/cli/config-diff.ts +0 -103
- package/src/cli/config-display.ts +0 -285
- package/src/cli/config-get.ts +0 -55
- package/src/cli/config.ts +0 -14
- package/src/cli/constitution.ts +0 -17
- package/src/cli/diagnose-analysis.ts +0 -159
- package/src/cli/diagnose-formatter.ts +0 -87
- package/src/cli/diagnose.ts +0 -203
- package/src/cli/generate.ts +0 -250
- package/src/cli/index.ts +0 -42
- package/src/cli/init-context.ts +0 -405
- package/src/cli/init-detect.ts +0 -303
- package/src/cli/init.ts +0 -296
- package/src/cli/interact.ts +0 -295
- package/src/cli/plan.ts +0 -509
- package/src/cli/plugins.ts +0 -122
- package/src/cli/prompts-export.ts +0 -58
- package/src/cli/prompts-init.ts +0 -200
- package/src/cli/prompts-main.ts +0 -183
- package/src/cli/prompts-shared.ts +0 -70
- package/src/cli/prompts-tdd.ts +0 -88
- package/src/cli/prompts.ts +0 -17
- package/src/cli/runs.ts +0 -174
- package/src/cli/status-cost.ts +0 -151
- package/src/cli/status-features.ts +0 -405
- package/src/cli/status.ts +0 -13
- package/src/commands/common.ts +0 -171
- package/src/commands/diagnose.ts +0 -17
- package/src/commands/index.ts +0 -9
- package/src/commands/logs-formatter.ts +0 -201
- package/src/commands/logs-reader.ts +0 -171
- package/src/commands/logs.ts +0 -103
- package/src/commands/precheck.ts +0 -86
- package/src/commands/runs.ts +0 -220
- package/src/commands/unlock.ts +0 -96
- package/src/config/defaults.ts +0 -218
- package/src/config/index.ts +0 -22
- package/src/config/loader.ts +0 -143
- package/src/config/merge.ts +0 -106
- package/src/config/merger.ts +0 -147
- package/src/config/path-security.ts +0 -121
- package/src/config/paths.ts +0 -27
- package/src/config/permissions.ts +0 -63
- package/src/config/runtime-types.ts +0 -522
- package/src/config/schema-types.ts +0 -53
- package/src/config/schema.ts +0 -60
- package/src/config/schemas.ts +0 -426
- package/src/config/test-strategy.ts +0 -71
- package/src/config/types.ts +0 -57
- package/src/config/validate.ts +0 -103
- package/src/constitution/generator.ts +0 -158
- package/src/constitution/generators/aider.ts +0 -41
- package/src/constitution/generators/claude.ts +0 -35
- package/src/constitution/generators/cursor.ts +0 -36
- package/src/constitution/generators/opencode.ts +0 -38
- package/src/constitution/generators/types.ts +0 -33
- package/src/constitution/generators/windsurf.ts +0 -36
- package/src/constitution/index.ts +0 -11
- package/src/constitution/loader.ts +0 -121
- package/src/constitution/types.ts +0 -31
- package/src/context/auto-detect.ts +0 -228
- package/src/context/builder.ts +0 -299
- package/src/context/elements.ts +0 -122
- package/src/context/formatter.ts +0 -107
- package/src/context/generator.ts +0 -343
- package/src/context/generators/aider.ts +0 -34
- package/src/context/generators/claude.ts +0 -28
- package/src/context/generators/codex.ts +0 -28
- package/src/context/generators/cursor.ts +0 -28
- package/src/context/generators/gemini.ts +0 -28
- package/src/context/generators/opencode.ts +0 -30
- package/src/context/generators/windsurf.ts +0 -28
- package/src/context/greenfield.ts +0 -114
- package/src/context/index.ts +0 -34
- package/src/context/injector.ts +0 -279
- package/src/context/parent-context.ts +0 -39
- package/src/context/test-scanner.ts +0 -370
- package/src/context/types.ts +0 -98
- package/src/decompose/apply.ts +0 -50
- package/src/decompose/builder.ts +0 -181
- package/src/decompose/index.ts +0 -8
- package/src/decompose/sections/codebase.ts +0 -26
- package/src/decompose/sections/constraints.ts +0 -32
- package/src/decompose/sections/index.ts +0 -4
- package/src/decompose/sections/sibling-stories.ts +0 -25
- package/src/decompose/sections/target-story.ts +0 -31
- package/src/decompose/types.ts +0 -55
- package/src/decompose/validators/complexity.ts +0 -45
- package/src/decompose/validators/coverage.ts +0 -134
- package/src/decompose/validators/dependency.ts +0 -91
- package/src/decompose/validators/index.ts +0 -35
- package/src/decompose/validators/overlap.ts +0 -128
- package/src/errors.ts +0 -67
- package/src/execution/batching.ts +0 -157
- package/src/execution/crash-heartbeat.ts +0 -77
- package/src/execution/crash-recovery.ts +0 -79
- package/src/execution/crash-signals.ts +0 -165
- package/src/execution/crash-writer.ts +0 -154
- package/src/execution/deferred-review.ts +0 -105
- package/src/execution/dry-run.ts +0 -81
- package/src/execution/escalation/escalation.ts +0 -46
- package/src/execution/escalation/index.ts +0 -13
- package/src/execution/escalation/tier-escalation.ts +0 -346
- package/src/execution/escalation/tier-outcome.ts +0 -143
- package/src/execution/executor-types.ts +0 -73
- package/src/execution/helpers.ts +0 -38
- package/src/execution/index.ts +0 -27
- package/src/execution/iteration-runner.ts +0 -160
- package/src/execution/lifecycle/acceptance-loop.ts +0 -309
- package/src/execution/lifecycle/headless-formatter.ts +0 -83
- package/src/execution/lifecycle/index.ts +0 -11
- package/src/execution/lifecycle/parallel-lifecycle.ts +0 -101
- package/src/execution/lifecycle/precheck-runner.ts +0 -140
- package/src/execution/lifecycle/run-cleanup.ts +0 -81
- package/src/execution/lifecycle/run-completion.ts +0 -247
- package/src/execution/lifecycle/run-initialization.ts +0 -187
- package/src/execution/lifecycle/run-regression.ts +0 -305
- package/src/execution/lifecycle/run-setup.ts +0 -240
- package/src/execution/lifecycle/story-size-prompts.ts +0 -123
- package/src/execution/lock.ts +0 -129
- package/src/execution/parallel-coordinator.ts +0 -281
- package/src/execution/parallel-executor-rectification-pass.ts +0 -117
- package/src/execution/parallel-executor-rectify.ts +0 -136
- package/src/execution/parallel-executor.ts +0 -330
- package/src/execution/parallel-worker.ts +0 -149
- package/src/execution/parallel.ts +0 -13
- package/src/execution/pid-registry.ts +0 -275
- package/src/execution/pipeline-result-handler.ts +0 -221
- package/src/execution/progress.ts +0 -27
- package/src/execution/queue-handler.ts +0 -109
- package/src/execution/runner-completion.ts +0 -171
- package/src/execution/runner-execution.ts +0 -243
- package/src/execution/runner-setup.ts +0 -86
- package/src/execution/runner.ts +0 -265
- package/src/execution/sequential-executor.ts +0 -219
- package/src/execution/status-file.ts +0 -264
- package/src/execution/status-writer.ts +0 -181
- package/src/execution/story-context.ts +0 -266
- package/src/execution/story-selector.ts +0 -76
- package/src/execution/test-output-parser.ts +0 -14
- package/src/execution/timeout-handler.ts +0 -100
- package/src/hooks/index.ts +0 -2
- package/src/hooks/runner.ts +0 -280
- package/src/hooks/types.ts +0 -79
- package/src/interaction/chain.ts +0 -170
- package/src/interaction/index.ts +0 -61
- package/src/interaction/init.ts +0 -84
- package/src/interaction/plugins/auto.ts +0 -243
- package/src/interaction/plugins/cli.ts +0 -300
- package/src/interaction/plugins/telegram.ts +0 -384
- package/src/interaction/plugins/webhook.ts +0 -286
- package/src/interaction/state.ts +0 -171
- package/src/interaction/triggers.ts +0 -250
- package/src/interaction/types.ts +0 -170
- package/src/logger/formatters.ts +0 -84
- package/src/logger/index.ts +0 -16
- package/src/logger/logger.ts +0 -296
- package/src/logger/types.ts +0 -48
- package/src/logging/formatter.ts +0 -355
- package/src/logging/index.ts +0 -22
- package/src/logging/types.ts +0 -93
- package/src/metrics/aggregator.ts +0 -191
- package/src/metrics/index.ts +0 -14
- package/src/metrics/tracker.ts +0 -200
- package/src/metrics/types.ts +0 -115
- package/src/optimizer/index.ts +0 -63
- package/src/optimizer/noop.optimizer.ts +0 -24
- package/src/optimizer/rule-based.optimizer.ts +0 -248
- package/src/optimizer/types.ts +0 -53
- package/src/pipeline/event-bus.ts +0 -297
- package/src/pipeline/events.ts +0 -130
- package/src/pipeline/index.ts +0 -19
- package/src/pipeline/runner.ts +0 -149
- package/src/pipeline/stages/acceptance-setup.ts +0 -144
- package/src/pipeline/stages/acceptance.ts +0 -215
- package/src/pipeline/stages/autofix.ts +0 -262
- package/src/pipeline/stages/completion.ts +0 -110
- package/src/pipeline/stages/constitution.ts +0 -63
- package/src/pipeline/stages/context.ts +0 -122
- package/src/pipeline/stages/execution.ts +0 -359
- package/src/pipeline/stages/index.ts +0 -86
- package/src/pipeline/stages/optimizer.ts +0 -74
- package/src/pipeline/stages/prompt.ts +0 -79
- package/src/pipeline/stages/queue-check.ts +0 -103
- package/src/pipeline/stages/rectify.ts +0 -101
- package/src/pipeline/stages/regression.ts +0 -99
- package/src/pipeline/stages/review.ts +0 -94
- package/src/pipeline/stages/routing.ts +0 -276
- package/src/pipeline/stages/verify.ts +0 -286
- package/src/pipeline/subscribers/events-writer.ts +0 -135
- package/src/pipeline/subscribers/hooks.ts +0 -179
- package/src/pipeline/subscribers/interaction.ts +0 -103
- package/src/pipeline/subscribers/registry.ts +0 -73
- package/src/pipeline/subscribers/reporters.ts +0 -174
- package/src/pipeline/types.ts +0 -220
- package/src/plugins/extensions.ts +0 -225
- package/src/plugins/index.ts +0 -33
- package/src/plugins/loader.ts +0 -352
- package/src/plugins/plugin-logger.ts +0 -41
- package/src/plugins/registry.ts +0 -168
- package/src/plugins/types.ts +0 -206
- package/src/plugins/validator.ts +0 -352
- package/src/prd/index.ts +0 -220
- package/src/prd/schema.ts +0 -268
- package/src/prd/types.ts +0 -273
- package/src/prd/validate.ts +0 -41
- package/src/precheck/checks-agents.ts +0 -63
- package/src/precheck/checks-blockers.ts +0 -23
- package/src/precheck/checks-cli.ts +0 -68
- package/src/precheck/checks-config.ts +0 -102
- package/src/precheck/checks-git.ts +0 -117
- package/src/precheck/checks-system.ts +0 -101
- package/src/precheck/checks-warnings.ts +0 -221
- package/src/precheck/checks.ts +0 -36
- package/src/precheck/index.ts +0 -374
- package/src/precheck/story-size-gate.ts +0 -144
- package/src/precheck/types.ts +0 -31
- package/src/prompts/builder.ts +0 -166
- package/src/prompts/index.ts +0 -2
- package/src/prompts/loader.ts +0 -43
- package/src/prompts/sections/conventions.ts +0 -19
- package/src/prompts/sections/hermetic.ts +0 -41
- package/src/prompts/sections/index.ts +0 -12
- package/src/prompts/sections/isolation.ts +0 -70
- package/src/prompts/sections/role-task.ts +0 -182
- package/src/prompts/sections/story.ts +0 -55
- package/src/prompts/sections/verdict.ts +0 -70
- package/src/prompts/types.ts +0 -21
- package/src/queue/index.ts +0 -2
- package/src/queue/manager.ts +0 -254
- package/src/queue/types.ts +0 -54
- package/src/review/index.ts +0 -8
- package/src/review/orchestrator.ts +0 -154
- package/src/review/runner.ts +0 -303
- package/src/review/types.ts +0 -70
- package/src/routing/batch-route.ts +0 -35
- package/src/routing/builder.ts +0 -81
- package/src/routing/chain.ts +0 -75
- package/src/routing/content-hash.ts +0 -25
- package/src/routing/index.ts +0 -20
- package/src/routing/loader.ts +0 -62
- package/src/routing/router.ts +0 -305
- package/src/routing/strategies/adaptive.ts +0 -215
- package/src/routing/strategies/index.ts +0 -8
- package/src/routing/strategies/keyword.ts +0 -180
- package/src/routing/strategies/llm-prompts.ts +0 -224
- package/src/routing/strategies/llm.ts +0 -320
- package/src/routing/strategies/manual.ts +0 -50
- package/src/routing/strategy.ts +0 -102
- package/src/tdd/cleanup.ts +0 -120
- package/src/tdd/index.ts +0 -22
- package/src/tdd/isolation.ts +0 -117
- package/src/tdd/orchestrator.ts +0 -406
- package/src/tdd/prompts.ts +0 -40
- package/src/tdd/rectification-gate.ts +0 -274
- package/src/tdd/session-runner.ts +0 -263
- package/src/tdd/types.ts +0 -84
- package/src/tdd/verdict-reader.ts +0 -266
- package/src/tdd/verdict.ts +0 -152
- package/src/tui/App.tsx +0 -265
- package/src/tui/components/AgentPanel.tsx +0 -75
- package/src/tui/components/CostOverlay.tsx +0 -118
- package/src/tui/components/HelpOverlay.tsx +0 -107
- package/src/tui/components/StatusBar.tsx +0 -63
- package/src/tui/components/StoriesPanel.tsx +0 -177
- package/src/tui/hooks/useKeyboard.ts +0 -142
- package/src/tui/hooks/useLayout.ts +0 -137
- package/src/tui/hooks/usePipelineEvents.ts +0 -183
- package/src/tui/hooks/usePty.ts +0 -189
- package/src/tui/index.tsx +0 -38
- package/src/tui/types.ts +0 -76
- package/src/utils/errors.ts +0 -12
- package/src/utils/git.ts +0 -245
- package/src/utils/json-file.ts +0 -72
- package/src/utils/log-test-output.ts +0 -25
- package/src/utils/path-security.ts +0 -73
- package/src/utils/queue-writer.ts +0 -54
- package/src/verification/crash-detector.ts +0 -34
- package/src/verification/executor.ts +0 -250
- package/src/verification/index.ts +0 -12
- package/src/verification/orchestrator-types.ts +0 -154
- package/src/verification/orchestrator.ts +0 -76
- package/src/verification/parser.ts +0 -220
- package/src/verification/rectification-loop.ts +0 -172
- package/src/verification/rectification.ts +0 -108
- package/src/verification/runners.ts +0 -129
- package/src/verification/smart-runner.ts +0 -307
- package/src/verification/strategies/acceptance.ts +0 -136
- package/src/verification/strategies/regression.ts +0 -90
- package/src/verification/strategies/scoped.ts +0 -154
- package/src/verification/types.ts +0 -117
- package/src/version.ts +0 -40
- package/src/worktree/dispatcher.ts +0 -6
- package/src/worktree/index.ts +0 -2
- package/src/worktree/manager.ts +0 -193
- package/src/worktree/merge.ts +0 -302
- package/src/worktree/types.ts +0 -4
package/src/plugins/loader.ts
DELETED
|
@@ -1,352 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Plugin Loader
|
|
3
|
-
*
|
|
4
|
-
* Discovers, imports, validates, and initializes plugins from:
|
|
5
|
-
* 1. Global directory (~/.nax/plugins/)
|
|
6
|
-
* 2. Project directory (<project>/nax/plugins/)
|
|
7
|
-
* 3. Config entries (explicit module paths)
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import * as fs from "node:fs/promises";
|
|
11
|
-
import * as path from "node:path";
|
|
12
|
-
import { getSafeLogger as _getSafeLoggerFromModule } from "../logger";
|
|
13
|
-
import { errorMessage } from "../utils/errors";
|
|
14
|
-
import { validateModulePath } from "../utils/path-security";
|
|
15
|
-
import { createPluginLogger } from "./plugin-logger";
|
|
16
|
-
import { PluginRegistry } from "./registry";
|
|
17
|
-
import type { NaxPlugin, PluginConfigEntry } from "./types";
|
|
18
|
-
import { validatePlugin } from "./validator";
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Swappable error sink — defaults to console.error.
|
|
22
|
-
* Tests can replace this to capture plugin error output.
|
|
23
|
-
* @internal
|
|
24
|
-
*/
|
|
25
|
-
export let _pluginErrorSink: (...args: unknown[]) => void = (...args) => console.error(...args);
|
|
26
|
-
|
|
27
|
-
/** @internal — for testing only */
|
|
28
|
-
export function _setPluginErrorSink(fn: (...args: unknown[]) => void): void {
|
|
29
|
-
_pluginErrorSink = fn;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/** @internal — reset to default */
|
|
33
|
-
export function _resetPluginErrorSink(): void {
|
|
34
|
-
_pluginErrorSink = (...args) => console.error(...args);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Safely get logger instance, returns null if not initialized.
|
|
39
|
-
* Delegates to the module's getSafeLogger which correctly returns null for noopLogger.
|
|
40
|
-
*/
|
|
41
|
-
function getSafeLogger() {
|
|
42
|
-
return _getSafeLoggerFromModule();
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Plugin source metadata.
|
|
47
|
-
*/
|
|
48
|
-
export interface PluginSource {
|
|
49
|
-
type: "global" | "project" | "config";
|
|
50
|
-
path: string;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Extract plugin name from file path.
|
|
55
|
-
* For index files (e.g., /path/to/plugin/index.ts), returns the parent directory name.
|
|
56
|
-
* For single files (e.g., /path/to/plugin.ts), returns the filename without extension.
|
|
57
|
-
*
|
|
58
|
-
* @param pluginPath - Path to plugin file
|
|
59
|
-
* @returns Plugin name
|
|
60
|
-
*/
|
|
61
|
-
function extractPluginName(pluginPath: string): string {
|
|
62
|
-
const basename = path.basename(pluginPath);
|
|
63
|
-
if (basename === "index.ts" || basename === "index.js" || basename === "index.mjs") {
|
|
64
|
-
// For index files, use the parent directory name
|
|
65
|
-
return path.basename(path.dirname(pluginPath));
|
|
66
|
-
}
|
|
67
|
-
// For single files, use filename without extension
|
|
68
|
-
return basename.replace(/\.(ts|js|mjs)$/, "");
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Plugin with source information.
|
|
73
|
-
*/
|
|
74
|
-
export interface LoadedPlugin {
|
|
75
|
-
plugin: NaxPlugin;
|
|
76
|
-
source: PluginSource;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Load and validate all plugins from global + project + config sources.
|
|
81
|
-
*
|
|
82
|
-
* Load order:
|
|
83
|
-
* 1. Scan ~/.nax/plugins/ (if exists)
|
|
84
|
-
* 2. Scan <project>/nax/plugins/ (if exists)
|
|
85
|
-
* 3. Load explicit modules from config.plugins[]
|
|
86
|
-
*
|
|
87
|
-
* Each plugin is validated, then setup() is called with its config.
|
|
88
|
-
* Plugins can be disabled via config.plugins[].enabled or config.disabledPlugins[].
|
|
89
|
-
*
|
|
90
|
-
* @param globalDir - Global plugins directory (e.g., ~/.nax/plugins)
|
|
91
|
-
* @param projectDir - Project plugins directory (e.g., <project>/nax/plugins)
|
|
92
|
-
* @param configPlugins - Explicit plugin entries from config
|
|
93
|
-
* @param projectRoot - Project root directory for resolving relative paths in config
|
|
94
|
-
* @param disabledPlugins - List of plugin names to disable (auto-discovered plugins only)
|
|
95
|
-
* @returns PluginRegistry with all loaded plugins and their sources
|
|
96
|
-
*/
|
|
97
|
-
export async function loadPlugins(
|
|
98
|
-
globalDir: string,
|
|
99
|
-
projectDir: string,
|
|
100
|
-
configPlugins: PluginConfigEntry[],
|
|
101
|
-
projectRoot?: string,
|
|
102
|
-
disabledPlugins?: string[],
|
|
103
|
-
): Promise<PluginRegistry> {
|
|
104
|
-
const loadedPlugins: LoadedPlugin[] = [];
|
|
105
|
-
const effectiveProjectRoot = projectRoot || projectDir;
|
|
106
|
-
const pluginNames = new Set<string>();
|
|
107
|
-
const disabledSet = new Set(disabledPlugins ?? []);
|
|
108
|
-
const logger = getSafeLogger();
|
|
109
|
-
|
|
110
|
-
// 1. Load plugins from global directory
|
|
111
|
-
const globalPlugins = await discoverPlugins(globalDir);
|
|
112
|
-
for (const plugin of globalPlugins) {
|
|
113
|
-
const pluginName = extractPluginName(plugin.path);
|
|
114
|
-
if (disabledSet.has(pluginName)) {
|
|
115
|
-
logger?.info("plugins", `Skipping disabled plugin: '${pluginName}' (global directory)`);
|
|
116
|
-
continue;
|
|
117
|
-
}
|
|
118
|
-
const validated = await loadAndValidatePlugin(plugin.path, {}, [globalDir]);
|
|
119
|
-
if (validated) {
|
|
120
|
-
if (pluginNames.has(validated.name)) {
|
|
121
|
-
logger?.warn("plugins", `Plugin name collision: '${validated.name}' (global directory)`);
|
|
122
|
-
}
|
|
123
|
-
loadedPlugins.push({
|
|
124
|
-
plugin: validated,
|
|
125
|
-
source: { type: "global", path: plugin.path },
|
|
126
|
-
});
|
|
127
|
-
pluginNames.add(validated.name);
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// 2. Load plugins from project directory
|
|
132
|
-
const projectPlugins = await discoverPlugins(projectDir);
|
|
133
|
-
for (const plugin of projectPlugins) {
|
|
134
|
-
const pluginName = extractPluginName(plugin.path);
|
|
135
|
-
if (disabledSet.has(pluginName)) {
|
|
136
|
-
logger?.info("plugins", `Skipping disabled plugin: '${pluginName}' (project directory)`);
|
|
137
|
-
continue;
|
|
138
|
-
}
|
|
139
|
-
const validated = await loadAndValidatePlugin(plugin.path, {}, [projectDir]);
|
|
140
|
-
if (validated) {
|
|
141
|
-
if (pluginNames.has(validated.name)) {
|
|
142
|
-
logger?.warn("plugins", `Plugin name collision: '${validated.name}' (project directory overrides global)`);
|
|
143
|
-
}
|
|
144
|
-
loadedPlugins.push({
|
|
145
|
-
plugin: validated,
|
|
146
|
-
source: { type: "project", path: plugin.path },
|
|
147
|
-
});
|
|
148
|
-
pluginNames.add(validated.name);
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
// 3. Load plugins from config entries
|
|
153
|
-
for (const entry of configPlugins) {
|
|
154
|
-
// Check if plugin is explicitly disabled in config
|
|
155
|
-
if (entry.enabled === false) {
|
|
156
|
-
logger?.info("plugins", `Skipping disabled plugin: '${entry.module}'`);
|
|
157
|
-
continue;
|
|
158
|
-
}
|
|
159
|
-
// Resolve module path relative to effective project root for relative paths
|
|
160
|
-
const resolvedModule = resolveModulePath(entry.module, effectiveProjectRoot);
|
|
161
|
-
const validated = await loadAndValidatePlugin(
|
|
162
|
-
resolvedModule,
|
|
163
|
-
entry.config ?? {},
|
|
164
|
-
[globalDir, projectDir, effectiveProjectRoot].filter(Boolean),
|
|
165
|
-
entry.module,
|
|
166
|
-
);
|
|
167
|
-
if (validated) {
|
|
168
|
-
if (pluginNames.has(validated.name)) {
|
|
169
|
-
logger?.warn("plugins", `Plugin name collision: '${validated.name}' (config entry overrides previous)`);
|
|
170
|
-
}
|
|
171
|
-
loadedPlugins.push({
|
|
172
|
-
plugin: validated,
|
|
173
|
-
source: { type: "config", path: entry.module },
|
|
174
|
-
});
|
|
175
|
-
pluginNames.add(validated.name);
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
return new PluginRegistry(loadedPlugins);
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
/**
|
|
183
|
-
* Discover plugin files in a directory.
|
|
184
|
-
*
|
|
185
|
-
* Scans for:
|
|
186
|
-
* - Single-file plugins (*.ts, *.js, *.mjs)
|
|
187
|
-
* - Directory plugins with index.ts/index.js/index.mjs
|
|
188
|
-
*
|
|
189
|
-
* @param dir - Directory to scan
|
|
190
|
-
* @returns Array of discovered plugin paths
|
|
191
|
-
*/
|
|
192
|
-
async function discoverPlugins(dir: string): Promise<Array<{ path: string }>> {
|
|
193
|
-
const discovered: Array<{ path: string }> = [];
|
|
194
|
-
|
|
195
|
-
try {
|
|
196
|
-
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
197
|
-
|
|
198
|
-
for (const entry of entries) {
|
|
199
|
-
const fullPath = path.join(dir, entry.name);
|
|
200
|
-
|
|
201
|
-
if (entry.isFile()) {
|
|
202
|
-
// Single-file plugin
|
|
203
|
-
if (isPluginFile(entry.name)) {
|
|
204
|
-
discovered.push({ path: fullPath });
|
|
205
|
-
}
|
|
206
|
-
} else if (entry.isDirectory()) {
|
|
207
|
-
// Directory plugin — check for index file
|
|
208
|
-
const indexPaths = ["index.ts", "index.js", "index.mjs"];
|
|
209
|
-
for (const indexFile of indexPaths) {
|
|
210
|
-
const indexPath = path.join(fullPath, indexFile);
|
|
211
|
-
try {
|
|
212
|
-
await fs.access(indexPath);
|
|
213
|
-
discovered.push({ path: indexPath });
|
|
214
|
-
break;
|
|
215
|
-
} catch {
|
|
216
|
-
// Index file doesn't exist, try next
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
} catch (error) {
|
|
222
|
-
// ERR-1 fix: Only catch ENOENT, re-throw other errors
|
|
223
|
-
if ((error as NodeJS.ErrnoException).code === "ENOENT") {
|
|
224
|
-
// Directory doesn't exist — not an error, just no plugins
|
|
225
|
-
return [];
|
|
226
|
-
}
|
|
227
|
-
// Re-throw permission errors, disk failures, etc.
|
|
228
|
-
throw error;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
return discovered;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
/**
|
|
235
|
-
* Check if a filename is a valid plugin file.
|
|
236
|
-
*
|
|
237
|
-
* @param filename - Filename to check
|
|
238
|
-
* @returns Whether the file could be a plugin
|
|
239
|
-
*/
|
|
240
|
-
function isPluginFile(filename: string): boolean {
|
|
241
|
-
return /\.(ts|js|mjs)$/.test(filename) && !filename.endsWith(".test.ts") && !filename.endsWith(".spec.ts");
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
/**
|
|
245
|
-
* Resolve a module path, handling relative paths, absolute paths, and npm packages.
|
|
246
|
-
*
|
|
247
|
-
* @param modulePath - Module path from config (can be relative, absolute, or npm package)
|
|
248
|
-
* @param projectRoot - Project root directory for resolving relative paths
|
|
249
|
-
* @returns Resolved absolute path or npm package name
|
|
250
|
-
*/
|
|
251
|
-
function resolveModulePath(modulePath: string, projectRoot?: string): string {
|
|
252
|
-
// Absolute paths and npm packages (no leading ./ or ../) work as-is
|
|
253
|
-
if (path.isAbsolute(modulePath) || (!modulePath.startsWith("./") && !modulePath.startsWith("../"))) {
|
|
254
|
-
return modulePath;
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
// Relative paths need to be resolved relative to project root
|
|
258
|
-
if (projectRoot) {
|
|
259
|
-
return path.resolve(projectRoot, modulePath);
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
// Fallback: resolve relative to cwd (shouldn't happen in normal usage)
|
|
263
|
-
return path.resolve(modulePath);
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
/**
|
|
267
|
-
* Load and validate a plugin from a module path.
|
|
268
|
-
*
|
|
269
|
-
* @param modulePath - Path to plugin module (should be resolved)
|
|
270
|
-
* @param config - Plugin-specific config
|
|
271
|
-
* @param originalPath - Original path from config (for error messages)
|
|
272
|
-
* @returns Validated plugin or null if invalid
|
|
273
|
-
*/
|
|
274
|
-
async function loadAndValidatePlugin(
|
|
275
|
-
initialModulePath: string,
|
|
276
|
-
config: Record<string, unknown>,
|
|
277
|
-
allowedRoots: string[] = [],
|
|
278
|
-
originalPath?: string,
|
|
279
|
-
): Promise<NaxPlugin | null> {
|
|
280
|
-
let attemptedPath = initialModulePath;
|
|
281
|
-
try {
|
|
282
|
-
// SEC-1: Validate module path if it's a file path (not an npm package)
|
|
283
|
-
let modulePath = initialModulePath;
|
|
284
|
-
const isFilePath = modulePath.startsWith("/") || modulePath.startsWith("./") || modulePath.startsWith("../");
|
|
285
|
-
|
|
286
|
-
if (isFilePath && allowedRoots.length > 0) {
|
|
287
|
-
const validation = validateModulePath(modulePath, allowedRoots);
|
|
288
|
-
if (!validation.valid) {
|
|
289
|
-
const logger = getSafeLogger();
|
|
290
|
-
logger?.error("plugins", `Security: ${validation.error}`);
|
|
291
|
-
_pluginErrorSink(`[plugins] Security: ${validation.error}`);
|
|
292
|
-
return null;
|
|
293
|
-
}
|
|
294
|
-
// Use the normalized absolute path from the validator
|
|
295
|
-
const validatedPath = validation.absolutePath as string;
|
|
296
|
-
modulePath = validatedPath;
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
// Import the module
|
|
300
|
-
attemptedPath = modulePath;
|
|
301
|
-
const imported = await import(modulePath);
|
|
302
|
-
|
|
303
|
-
// Try default export first, then named exports
|
|
304
|
-
const module = imported.default || imported;
|
|
305
|
-
|
|
306
|
-
// Validate plugin shape
|
|
307
|
-
const validated = validatePlugin(module);
|
|
308
|
-
if (!validated) {
|
|
309
|
-
return null;
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
// Call setup() if defined — pass plugin-scoped logger
|
|
313
|
-
if (validated.setup) {
|
|
314
|
-
try {
|
|
315
|
-
const pluginLogger = createPluginLogger(validated.name);
|
|
316
|
-
await validated.setup(config, pluginLogger);
|
|
317
|
-
} catch (error) {
|
|
318
|
-
const logger = getSafeLogger();
|
|
319
|
-
logger?.error("plugins", `Plugin '${validated.name}' setup failed`, { error });
|
|
320
|
-
return null;
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
return validated;
|
|
325
|
-
} catch (error) {
|
|
326
|
-
const displayPath = originalPath || initialModulePath;
|
|
327
|
-
const errorMsg = errorMessage(error);
|
|
328
|
-
const logger = getSafeLogger();
|
|
329
|
-
|
|
330
|
-
// Provide helpful error message with attempted paths
|
|
331
|
-
if (errorMsg.includes("Cannot find module") || errorMsg.includes("ENOENT")) {
|
|
332
|
-
const msg = `Failed to load plugin module '${displayPath}'`;
|
|
333
|
-
logger?.error("plugins", msg);
|
|
334
|
-
logger?.error("plugins", `Attempted path: ${attemptedPath}`);
|
|
335
|
-
logger?.error(
|
|
336
|
-
"plugins",
|
|
337
|
-
"Ensure the module exists and the path is correct (relative paths are resolved from project root)",
|
|
338
|
-
);
|
|
339
|
-
// Always emit to sink so tests (and headless mode without logger) can capture output
|
|
340
|
-
_pluginErrorSink(`[plugins] ${msg}`);
|
|
341
|
-
_pluginErrorSink(`[plugins] Attempted path: ${attemptedPath}`);
|
|
342
|
-
_pluginErrorSink(
|
|
343
|
-
"[plugins] Ensure the module exists and the path is correct (relative paths are resolved from project root)",
|
|
344
|
-
);
|
|
345
|
-
} else {
|
|
346
|
-
logger?.warn("plugins", `Failed to load plugin from '${displayPath}'`, { error: errorMsg });
|
|
347
|
-
// Always emit to sink
|
|
348
|
-
_pluginErrorSink(`[plugins] Failed to load plugin from '${displayPath}': ${errorMsg}`);
|
|
349
|
-
}
|
|
350
|
-
return null;
|
|
351
|
-
}
|
|
352
|
-
}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Plugin Logger Factory
|
|
3
|
-
*
|
|
4
|
-
* Creates write-only, stage-prefixed loggers for plugins.
|
|
5
|
-
* Each logger auto-tags entries with `plugin:<name>` so plugin
|
|
6
|
-
* output is filterable and cannot impersonate core stages.
|
|
7
|
-
*
|
|
8
|
-
* @module plugins/plugin-logger
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import { getSafeLogger } from "../logger";
|
|
12
|
-
import type { PluginLogger } from "./types";
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Create a PluginLogger scoped to a plugin name.
|
|
16
|
-
*
|
|
17
|
-
* The returned logger delegates to the global nax Logger with
|
|
18
|
-
* `plugin:<pluginName>` as the stage. If the global logger is
|
|
19
|
-
* not initialized (e.g., during tests), calls are silently dropped.
|
|
20
|
-
*
|
|
21
|
-
* @param pluginName - Plugin name used as stage prefix
|
|
22
|
-
* @returns PluginLogger instance
|
|
23
|
-
*/
|
|
24
|
-
export function createPluginLogger(pluginName: string): PluginLogger {
|
|
25
|
-
const stage = `plugin:${pluginName}`;
|
|
26
|
-
|
|
27
|
-
return {
|
|
28
|
-
error(message: string, data?: Record<string, unknown>): void {
|
|
29
|
-
getSafeLogger()?.error(stage, message, data);
|
|
30
|
-
},
|
|
31
|
-
warn(message: string, data?: Record<string, unknown>): void {
|
|
32
|
-
getSafeLogger()?.warn(stage, message, data);
|
|
33
|
-
},
|
|
34
|
-
info(message: string, data?: Record<string, unknown>): void {
|
|
35
|
-
getSafeLogger()?.info(stage, message, data);
|
|
36
|
-
},
|
|
37
|
-
debug(message: string, data?: Record<string, unknown>): void {
|
|
38
|
-
getSafeLogger()?.debug(stage, message, data);
|
|
39
|
-
},
|
|
40
|
-
};
|
|
41
|
-
}
|
package/src/plugins/registry.ts
DELETED
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Plugin Registry
|
|
3
|
-
*
|
|
4
|
-
* Central registry for all loaded plugins with typed getters.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import type { AgentAdapter } from "../agents/types";
|
|
8
|
-
import { getSafeLogger } from "../logger";
|
|
9
|
-
import type { RoutingStrategy } from "../routing/strategy";
|
|
10
|
-
import type { LoadedPlugin, PluginSource } from "./loader";
|
|
11
|
-
import type { IContextProvider, IPromptOptimizer, IReporter, IReviewPlugin, NaxPlugin } from "./types";
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Plugin registry with typed getters for each extension type.
|
|
15
|
-
*
|
|
16
|
-
* Created once at run start and passed through the pipeline context.
|
|
17
|
-
* Provides efficient access to plugins by extension type.
|
|
18
|
-
*/
|
|
19
|
-
export class PluginRegistry {
|
|
20
|
-
/** All loaded plugins (readonly) */
|
|
21
|
-
readonly plugins: ReadonlyArray<NaxPlugin>;
|
|
22
|
-
|
|
23
|
-
/** Plugin source information (maps plugin name to source) */
|
|
24
|
-
private readonly sources: Map<string, PluginSource>;
|
|
25
|
-
|
|
26
|
-
constructor(loadedPlugins: LoadedPlugin[] | NaxPlugin[]) {
|
|
27
|
-
// Support both LoadedPlugin[] and NaxPlugin[] for backward compatibility
|
|
28
|
-
if (loadedPlugins.length > 0 && "plugin" in loadedPlugins[0]) {
|
|
29
|
-
// New format: LoadedPlugin[]
|
|
30
|
-
const typed = loadedPlugins as LoadedPlugin[];
|
|
31
|
-
this.plugins = typed.map((lp) => lp.plugin);
|
|
32
|
-
this.sources = new Map(typed.map((lp) => [lp.plugin.name, lp.source]));
|
|
33
|
-
} else {
|
|
34
|
-
// Legacy format: NaxPlugin[]
|
|
35
|
-
const typed = loadedPlugins as NaxPlugin[];
|
|
36
|
-
this.plugins = typed;
|
|
37
|
-
this.sources = new Map();
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Get the source information for a plugin.
|
|
43
|
-
*
|
|
44
|
-
* @param pluginName - Name of the plugin
|
|
45
|
-
* @returns Plugin source or undefined if not found
|
|
46
|
-
*/
|
|
47
|
-
getSource(pluginName: string): PluginSource | undefined {
|
|
48
|
-
return this.sources.get(pluginName);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Get all prompt optimizers.
|
|
53
|
-
*
|
|
54
|
-
* @returns Array of optimizer implementations
|
|
55
|
-
*/
|
|
56
|
-
getOptimizers(): IPromptOptimizer[] {
|
|
57
|
-
return this.plugins
|
|
58
|
-
.filter((p) => p.provides.includes("optimizer"))
|
|
59
|
-
.map((p) => p.extensions.optimizer)
|
|
60
|
-
.filter((opt): opt is IPromptOptimizer => opt !== undefined);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Get all routing strategies.
|
|
65
|
-
*
|
|
66
|
-
* Plugin routers are returned in load order and should be inserted
|
|
67
|
-
* before built-in strategies in the routing chain.
|
|
68
|
-
*
|
|
69
|
-
* @returns Array of routing strategy implementations
|
|
70
|
-
*/
|
|
71
|
-
getRouters(): RoutingStrategy[] {
|
|
72
|
-
return this.plugins
|
|
73
|
-
.filter((p) => p.provides.includes("router"))
|
|
74
|
-
.map((p) => p.extensions.router)
|
|
75
|
-
.filter((router): router is RoutingStrategy => router !== undefined);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Get agent adapter by name.
|
|
80
|
-
*
|
|
81
|
-
* If multiple plugins provide the same agent name, the last loaded wins.
|
|
82
|
-
*
|
|
83
|
-
* @param name - Agent name to lookup
|
|
84
|
-
* @returns Agent adapter or undefined if not found
|
|
85
|
-
*/
|
|
86
|
-
getAgent(name: string): AgentAdapter | undefined {
|
|
87
|
-
const agents = this.plugins
|
|
88
|
-
.filter((p) => p.provides.includes("agent"))
|
|
89
|
-
.map((p) => p.extensions.agent)
|
|
90
|
-
.filter((agent): agent is AgentAdapter => agent !== undefined);
|
|
91
|
-
|
|
92
|
-
// Last loaded wins on name collision
|
|
93
|
-
for (let i = agents.length - 1; i >= 0; i--) {
|
|
94
|
-
if (agents[i].name === name) {
|
|
95
|
-
return agents[i];
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
return undefined;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* Get all review plugins.
|
|
104
|
-
*
|
|
105
|
-
* Review plugins run after built-in checks (typecheck, lint, test).
|
|
106
|
-
* All plugin checks are additive.
|
|
107
|
-
*
|
|
108
|
-
* @returns Array of review plugin implementations
|
|
109
|
-
*/
|
|
110
|
-
getReviewers(): IReviewPlugin[] {
|
|
111
|
-
return this.plugins
|
|
112
|
-
.filter((p) => p.provides.includes("reviewer"))
|
|
113
|
-
.map((p) => p.extensions.reviewer)
|
|
114
|
-
.filter((reviewer): reviewer is IReviewPlugin => reviewer !== undefined);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Get all context providers.
|
|
119
|
-
*
|
|
120
|
-
* Context providers fetch external data (Jira, Linear, etc.) and
|
|
121
|
-
* inject it into agent prompts. All providers are additive, subject
|
|
122
|
-
* to token budget.
|
|
123
|
-
*
|
|
124
|
-
* @returns Array of context provider implementations
|
|
125
|
-
*/
|
|
126
|
-
getContextProviders(): IContextProvider[] {
|
|
127
|
-
return this.plugins
|
|
128
|
-
.filter((p) => p.provides.includes("context-provider"))
|
|
129
|
-
.map((p) => p.extensions.contextProvider)
|
|
130
|
-
.filter((provider): provider is IContextProvider => provider !== undefined);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* Get all reporters.
|
|
135
|
-
*
|
|
136
|
-
* Reporters receive run lifecycle events for dashboards, CI, etc.
|
|
137
|
-
* All reporters are additive and fire-and-forget.
|
|
138
|
-
*
|
|
139
|
-
* @returns Array of reporter implementations
|
|
140
|
-
*/
|
|
141
|
-
getReporters(): IReporter[] {
|
|
142
|
-
return this.plugins
|
|
143
|
-
.filter((p) => p.provides.includes("reporter"))
|
|
144
|
-
.map((p) => p.extensions.reporter)
|
|
145
|
-
.filter((reporter): reporter is IReporter => reporter !== undefined);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
/**
|
|
149
|
-
* Teardown all plugins.
|
|
150
|
-
*
|
|
151
|
-
* Calls teardown() on each plugin (if defined) in order.
|
|
152
|
-
* Logs errors but continues teardown for all plugins.
|
|
153
|
-
*
|
|
154
|
-
* Called when the nax run ends (success or failure).
|
|
155
|
-
*/
|
|
156
|
-
async teardownAll(): Promise<void> {
|
|
157
|
-
const logger = getSafeLogger();
|
|
158
|
-
for (const plugin of this.plugins) {
|
|
159
|
-
if (plugin.teardown) {
|
|
160
|
-
try {
|
|
161
|
-
await plugin.teardown();
|
|
162
|
-
} catch (error) {
|
|
163
|
-
logger?.error("plugins", `Plugin '${plugin.name}' teardown failed`, { error });
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
}
|