@j0hanz/prompt-tuner-mcp-server 1.0.8 → 1.0.10
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/AGENTS.md +70 -27
- package/CONFIGURATION.md +15 -9
- package/README.md +28 -29
- package/dist/config/constants.d.ts +0 -1
- package/dist/config/constants.js +0 -2
- package/dist/config/env.d.ts +0 -1
- package/dist/config/env.js +0 -6
- package/dist/config/instructions.d.ts +0 -1
- package/dist/config/instructions.js +0 -1
- package/dist/config/patterns.d.ts +0 -8
- package/dist/config/patterns.js +0 -8
- package/dist/config/types.d.ts +15 -22
- package/dist/config/types.js +0 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +35 -69
- package/dist/index.js.map +1 -1
- package/dist/lib/abort-signals.d.ts +0 -1
- package/dist/lib/abort-signals.js +0 -1
- package/dist/lib/errors.d.ts +0 -1
- package/dist/lib/errors.js +0 -6
- package/dist/lib/llm-client.d.ts +0 -1
- package/dist/lib/llm-client.js +0 -1
- package/dist/lib/llm-json/scan.d.ts +1 -0
- package/dist/lib/llm-json/scan.d.ts.map +1 -0
- package/dist/lib/llm-json/scan.js +93 -0
- package/dist/lib/llm-json/scan.js.map +1 -0
- package/dist/lib/llm-json.d.ts +0 -1
- package/dist/lib/llm-json.d.ts.map +1 -1
- package/dist/lib/llm-json.js +56 -93
- package/dist/lib/llm-json.js.map +1 -1
- package/dist/lib/llm-providers/helpers.d.ts +0 -1
- package/dist/lib/llm-providers/helpers.js +0 -1
- package/dist/lib/llm-providers.d.ts +11 -32
- package/dist/lib/llm-providers.d.ts.map +1 -1
- package/dist/lib/llm-providers.js +16 -33
- package/dist/lib/llm-providers.js.map +1 -1
- package/dist/lib/llm-runtime.d.ts +0 -1
- package/dist/lib/llm-runtime.d.ts.map +1 -1
- package/dist/lib/llm-runtime.js +95 -54
- package/dist/lib/llm-runtime.js.map +1 -1
- package/dist/lib/llm.d.ts +0 -1
- package/dist/lib/llm.js +0 -1
- package/dist/lib/output-normalization.d.ts +0 -1
- package/dist/lib/output-normalization.d.ts.map +1 -1
- package/dist/lib/output-normalization.js +15 -40
- package/dist/lib/output-normalization.js.map +1 -1
- package/dist/lib/output-validation.d.ts +0 -1
- package/dist/lib/output-validation.d.ts.map +1 -1
- package/dist/lib/output-validation.js +37 -120
- package/dist/lib/output-validation.js.map +1 -1
- package/dist/lib/prompt-analysis/format.d.ts +3 -3
- package/dist/lib/prompt-analysis/format.d.ts.map +1 -1
- package/dist/lib/prompt-analysis/format.js +18 -14
- package/dist/lib/prompt-analysis/format.js.map +1 -1
- package/dist/lib/prompt-analysis.d.ts +1 -2
- package/dist/lib/prompt-analysis.d.ts.map +1 -1
- package/dist/lib/prompt-analysis.js +1 -2
- package/dist/lib/prompt-analysis.js.map +1 -1
- package/dist/lib/prompt-policy.d.ts +1 -2
- package/dist/lib/prompt-policy.d.ts.map +1 -1
- package/dist/lib/prompt-policy.js +11 -5
- package/dist/lib/prompt-policy.js.map +1 -1
- package/dist/lib/retry.d.ts.map +1 -1
- package/dist/lib/retry.js +37 -56
- package/dist/lib/retry.js.map +1 -1
- package/dist/lib/technique-templates/format-instructions.d.ts +0 -1
- package/dist/lib/technique-templates/format-instructions.js +0 -1
- package/dist/lib/technique-templates/templates-advanced.d.ts +0 -1
- package/dist/lib/technique-templates/templates-advanced.js +0 -1
- package/dist/lib/technique-templates/templates-basic.d.ts +0 -1
- package/dist/lib/technique-templates/templates-basic.js +0 -1
- package/dist/lib/technique-templates.d.ts +0 -1
- package/dist/lib/technique-templates.js +0 -1
- package/dist/lib/tool-context.d.ts +0 -1
- package/dist/lib/tool-context.js +0 -1
- package/dist/lib/tool-formatters.d.ts +0 -1
- package/dist/lib/tool-formatters.js +0 -1
- package/dist/lib/tool-helpers.d.ts +5 -6
- package/dist/lib/tool-helpers.d.ts.map +1 -1
- package/dist/lib/tool-helpers.js +38 -31
- package/dist/lib/tool-helpers.js.map +1 -1
- package/dist/lib/tool-resources.d.ts +0 -1
- package/dist/lib/tool-resources.js +2 -7
- package/dist/lib/validation.d.ts +0 -5
- package/dist/lib/validation.js +0 -37
- package/dist/prompts/index.d.ts +0 -1
- package/dist/prompts/index.js +0 -1
- package/dist/prompts/quick-workflows.d.ts +0 -1
- package/dist/prompts/quick-workflows.js +3 -4
- package/dist/schemas/index.d.ts +0 -1
- package/dist/schemas/index.js +0 -2
- package/dist/schemas/inputs.d.ts +8 -9
- package/dist/schemas/inputs.d.ts.map +1 -1
- package/dist/schemas/inputs.js +16 -9
- package/dist/schemas/inputs.js.map +1 -1
- package/dist/schemas/llm-responses.d.ts +20 -21
- package/dist/schemas/llm-responses.js +0 -8
- package/dist/schemas/outputs.d.ts +66 -67
- package/dist/schemas/outputs.js +0 -1
- package/dist/server.d.ts +1 -2
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +15 -58
- package/dist/server.js.map +1 -1
- package/dist/tools/analyze-prompt.d.ts +0 -1
- package/dist/tools/analyze-prompt.d.ts.map +1 -1
- package/dist/tools/analyze-prompt.js +31 -31
- package/dist/tools/analyze-prompt.js.map +1 -1
- package/dist/tools/index.d.ts +0 -1
- package/dist/tools/index.js +0 -1
- package/dist/tools/optimize-prompt/constants.d.ts +5 -0
- package/dist/tools/optimize-prompt/constants.d.ts.map +1 -0
- package/dist/tools/optimize-prompt/constants.js +60 -0
- package/dist/tools/optimize-prompt/constants.js.map +1 -0
- package/dist/tools/optimize-prompt/formatters.d.ts +0 -1
- package/dist/tools/optimize-prompt/formatters.d.ts.map +1 -1
- package/dist/tools/optimize-prompt/formatters.js +33 -12
- package/dist/tools/optimize-prompt/formatters.js.map +1 -1
- package/dist/tools/optimize-prompt/inputs.d.ts +4 -0
- package/dist/tools/optimize-prompt/inputs.d.ts.map +1 -0
- package/dist/tools/optimize-prompt/inputs.js +21 -0
- package/dist/tools/optimize-prompt/inputs.js.map +1 -0
- package/dist/tools/optimize-prompt/output.d.ts +7 -0
- package/dist/tools/optimize-prompt/output.d.ts.map +1 -0
- package/dist/tools/optimize-prompt/output.js +57 -0
- package/dist/tools/optimize-prompt/output.js.map +1 -0
- package/dist/tools/optimize-prompt/prompt.d.ts +2 -0
- package/dist/tools/optimize-prompt/prompt.d.ts.map +1 -0
- package/dist/tools/optimize-prompt/prompt.js +5 -0
- package/dist/tools/optimize-prompt/prompt.js.map +1 -0
- package/dist/tools/optimize-prompt/run.d.ts +2 -0
- package/dist/tools/optimize-prompt/run.d.ts.map +1 -0
- package/dist/tools/optimize-prompt/run.js +14 -0
- package/dist/tools/optimize-prompt/run.js.map +1 -0
- package/dist/tools/optimize-prompt/types.d.ts +25 -0
- package/dist/tools/optimize-prompt/types.d.ts.map +1 -0
- package/dist/tools/optimize-prompt/types.js +1 -0
- package/dist/tools/optimize-prompt/types.js.map +1 -0
- package/dist/tools/optimize-prompt/validation.d.ts +7 -0
- package/dist/tools/optimize-prompt/validation.d.ts.map +1 -0
- package/dist/tools/optimize-prompt/validation.js +71 -0
- package/dist/tools/optimize-prompt/validation.js.map +1 -0
- package/dist/tools/optimize-prompt.d.ts +0 -1
- package/dist/tools/optimize-prompt.d.ts.map +1 -1
- package/dist/tools/optimize-prompt.js +154 -251
- package/dist/tools/optimize-prompt.js.map +1 -1
- package/dist/tools/refine-prompt/formatters.d.ts +10 -0
- package/dist/tools/refine-prompt/formatters.d.ts.map +1 -0
- package/dist/tools/refine-prompt/formatters.js +39 -0
- package/dist/tools/refine-prompt/formatters.js.map +1 -0
- package/dist/tools/refine-prompt/types.d.ts +16 -0
- package/dist/tools/refine-prompt/types.d.ts.map +1 -0
- package/dist/tools/refine-prompt/types.js +1 -0
- package/dist/tools/refine-prompt/types.js.map +1 -0
- package/dist/tools/refine-prompt.d.ts +0 -1
- package/dist/tools/refine-prompt.d.ts.map +1 -1
- package/dist/tools/refine-prompt.js +85 -48
- package/dist/tools/refine-prompt.js.map +1 -1
- package/dist/tools/validate-prompt/constants.d.ts +3 -0
- package/dist/tools/validate-prompt/constants.js +13 -0
- package/dist/tools/validate-prompt/formatters.d.ts +6 -0
- package/dist/tools/validate-prompt/formatters.d.ts.map +1 -0
- package/dist/tools/validate-prompt/formatters.js +45 -0
- package/dist/tools/validate-prompt/formatters.js.map +1 -0
- package/dist/tools/validate-prompt/prompt.d.ts +1 -2
- package/dist/tools/validate-prompt/prompt.d.ts.map +1 -1
- package/dist/tools/validate-prompt/prompt.js +2 -2
- package/dist/tools/validate-prompt/types.d.ts +1 -0
- package/dist/tools/validate-prompt/types.d.ts.map +1 -0
- package/dist/tools/validate-prompt/types.js +1 -0
- package/dist/tools/validate-prompt/types.js.map +1 -0
- package/dist/tools/validate-prompt.d.ts +0 -1
- package/dist/tools/validate-prompt.d.ts.map +1 -1
- package/dist/tools/validate-prompt.js +67 -68
- package/dist/tools/validate-prompt.js.map +1 -1
- package/eslint.config.mjs +7 -0
- package/package.json +6 -6
- package/src/config/constants.ts +0 -2
- package/src/config/env.ts +0 -5
- package/src/config/patterns.ts +0 -28
- package/src/config/types.ts +19 -33
- package/src/index.ts +37 -76
- package/src/lib/errors.ts +0 -5
- package/src/lib/llm-json/scan.ts +123 -0
- package/src/lib/llm-json.ts +95 -117
- package/src/lib/llm-providers.ts +37 -77
- package/src/lib/llm-runtime.ts +155 -87
- package/src/lib/output-normalization.ts +19 -43
- package/src/lib/output-validation.ts +42 -140
- package/src/lib/prompt-analysis/format.ts +23 -13
- package/src/lib/prompt-policy.ts +12 -4
- package/src/lib/tool-helpers.ts +90 -40
- package/src/lib/tool-resources.ts +2 -8
- package/src/lib/validation.ts +0 -76
- package/src/prompts/quick-workflows.ts +3 -3
- package/src/schemas/index.ts +0 -2
- package/src/schemas/inputs.ts +52 -44
- package/src/schemas/llm-responses.ts +0 -7
- package/src/server.ts +16 -67
- package/src/tools/analyze-prompt.ts +59 -45
- package/src/tools/optimize-prompt.ts +281 -418
- package/src/tools/refine-prompt.ts +160 -91
- package/src/tools/validate-prompt.ts +91 -107
- package/tests/input-schema.test.ts +59 -0
- package/tests/integration.test.ts +0 -2
- package/tests/llm-json.test.ts +19 -0
- package/tests/output-validation.test.ts +43 -0
- package/tsconfig.build.json +7 -0
- package/src/lib/prompt-analysis.ts +0 -1
- package/src/lib/retry.ts +0 -271
- package/src/lib/tool-context.ts +0 -21
- package/src/tools/index.ts +0 -22
- package/src/tools/optimize-prompt/formatters.ts +0 -70
- package/src/tools/validate-prompt/prompt.ts +0 -40
- package/src/types/regexp-escape.d.ts +0 -3
- package/tests/retry.test.ts +0 -42
package/AGENTS.md
CHANGED
|
@@ -1,39 +1,82 @@
|
|
|
1
|
-
#
|
|
1
|
+
# AGENTS.md
|
|
2
2
|
|
|
3
|
-
## Project
|
|
3
|
+
## Project Overview
|
|
4
4
|
|
|
5
|
-
-
|
|
6
|
-
-
|
|
7
|
-
-
|
|
8
|
-
- `docs/` stores static assets. `CONFIGURATION.md` documents runtime environment variables.
|
|
5
|
+
- **Goal**: MCP server for refining, analyzing, optimizing, and validating AI prompts.
|
|
6
|
+
- **Stack**: Node.js (>=20), TypeScript, Model Context Protocol (MCP), Zod, Vitest.
|
|
7
|
+
- **Key Libraries**: `@modelcontextprotocol/sdk`, `openai`, `@anthropic-ai/sdk`, `@google/genai`, `zod`.
|
|
9
8
|
|
|
10
|
-
##
|
|
9
|
+
## Repo Map / Structure
|
|
11
10
|
|
|
12
|
-
- `
|
|
13
|
-
- `
|
|
14
|
-
- `
|
|
15
|
-
- `
|
|
16
|
-
- `
|
|
17
|
-
- `
|
|
11
|
+
- `src/`: TypeScript source code.
|
|
12
|
+
- `index.ts`: CLI entry point.
|
|
13
|
+
- `server.ts`: MCP server initialization and tool registration.
|
|
14
|
+
- `config/`: Environment variables, constants, and configuration logic.
|
|
15
|
+
- `lib/`: Core logic (LLM clients, retry mechanisms, validation, prompt analysis).
|
|
16
|
+
- `tools/`: Tool implementations (`refine_prompt`, `analyze_prompt`, etc.).
|
|
17
|
+
- `schemas/`: Zod schemas for inputs and outputs.
|
|
18
|
+
- `prompts/`: Internal prompt templates used by the server.
|
|
19
|
+
- `tests/`: Integration and unit tests (`*.test.ts`).
|
|
20
|
+
- `dist/`: Compiled JavaScript output (generated).
|
|
21
|
+
- `docs/`: Documentation assets.
|
|
22
|
+
- `CONFIGURATION.md`: Detailed environment variable reference.
|
|
18
23
|
|
|
19
|
-
##
|
|
24
|
+
## Setup & Environment
|
|
20
25
|
|
|
21
|
-
-
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
-
|
|
26
|
+
- **Install dependencies**: `npm install`
|
|
27
|
+
- **Environment variables**:
|
|
28
|
+
- Defined in `src/config/env.ts` and documented in `CONFIGURATION.md`.
|
|
29
|
+
- Key variables: `LLM_PROVIDER`, `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `GOOGLE_API_KEY`.
|
|
30
|
+
- **Node.js Version**: `>=20.0.0` (enforced in `package.json`).
|
|
25
31
|
|
|
26
|
-
##
|
|
32
|
+
## Development Workflow
|
|
27
33
|
|
|
28
|
-
-
|
|
29
|
-
-
|
|
34
|
+
- **Dev mode**: `npm run dev` (runs `src/index.ts` with `tsx watch`).
|
|
35
|
+
- **Build**: `npm run build` (compiles to `dist/` and sets executable permissions).
|
|
36
|
+
- **Start production**: `npm run start` (runs `dist/index.js`).
|
|
37
|
+
- **MCP Inspector**: `npm run inspector` (debugs the server using the MCP inspector).
|
|
30
38
|
|
|
31
|
-
##
|
|
39
|
+
## Testing
|
|
32
40
|
|
|
33
|
-
-
|
|
34
|
-
-
|
|
41
|
+
- **Run all tests**: `npm run test` (uses Vitest).
|
|
42
|
+
- **Watch mode**: `npm run test:watch`.
|
|
43
|
+
- **Coverage**: `npm run test:coverage`.
|
|
44
|
+
- **Test files**: Located in `tests/` directory, matching `*.test.ts`.
|
|
35
45
|
|
|
36
|
-
##
|
|
46
|
+
## Code Style & Conventions
|
|
37
47
|
|
|
38
|
-
-
|
|
39
|
-
-
|
|
48
|
+
- **Language**: TypeScript (ES2022 target, NodeNext module resolution).
|
|
49
|
+
- **Linting**: `npm run lint` (ESLint with `typescript-eslint` and `unused-imports`).
|
|
50
|
+
- **Formatting**: `npm run format` (Prettier).
|
|
51
|
+
- **Type Checking**: `npm run type-check` (runs `tsc --noEmit`).
|
|
52
|
+
- **Naming Conventions**:
|
|
53
|
+
- Variables/Functions: `camelCase`.
|
|
54
|
+
- Types/Interfaces/Classes: `PascalCase`.
|
|
55
|
+
- Constants: `UPPER_CASE`.
|
|
56
|
+
- Files: `kebab-case`.
|
|
57
|
+
- **Rules**:
|
|
58
|
+
- No `any` types (`@typescript-eslint/no-explicit-any`).
|
|
59
|
+
- Explicit function return types required.
|
|
60
|
+
- Unused imports are forbidden.
|
|
61
|
+
- Prefer `type` imports.
|
|
62
|
+
|
|
63
|
+
## Build / Release
|
|
64
|
+
|
|
65
|
+
- **Output Directory**: `dist/` (cleared and regenerated on build).
|
|
66
|
+
- **Process**: `npm run build` compiles TS to JS and makes `dist/index.js` executable.
|
|
67
|
+
|
|
68
|
+
## Security & Safety
|
|
69
|
+
|
|
70
|
+
- **Secrets**: API keys must be passed via environment variables; never committed.
|
|
71
|
+
- **Validation**: All tool inputs are validated using Zod schemas in `src/schemas/`.
|
|
72
|
+
- **Error Handling**: Error context is sanitized to prevent leaking sensitive info (controlled by `INCLUDE_ERROR_CONTEXT`).
|
|
73
|
+
|
|
74
|
+
## Pull Request / Commit Guidelines
|
|
75
|
+
|
|
76
|
+
- **Commit Messages**: Imperative mood (e.g., "Add feature", "Fix bug").
|
|
77
|
+
- **Required Checks**: Ensure `npm run lint`, `npm run type-check`, and `npm run test` pass before submitting.
|
|
78
|
+
|
|
79
|
+
## Troubleshooting
|
|
80
|
+
|
|
81
|
+
- **Missing API Key**: Ensure `LLM_PROVIDER` matches the set API key (e.g., `OPENAI_API_KEY` for `openai`).
|
|
82
|
+
- **Build Errors**: Run `npm run type-check` to identify TypeScript issues.
|
package/CONFIGURATION.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# PromptTuner MCP Configuration Guide
|
|
2
2
|
|
|
3
|
-
PromptTuner MCP is configured entirely via environment variables. Set them in your MCP client configuration (for example `mcp.json`, `claude_desktop_config.json`) or a `.env` file.
|
|
3
|
+
PromptTuner MCP is configured entirely via environment variables. Set them in your MCP client configuration (for example `mcp.json`, `claude_desktop_config.json`) or a `.env` file. Node.js >= 22.0.0 is required (see `package.json` engines).
|
|
4
4
|
|
|
5
5
|
## Required configuration
|
|
6
6
|
|
|
@@ -33,6 +33,10 @@ Set `LLM_MODEL` to override the default model for the chosen provider.
|
|
|
33
33
|
| `LLM_MAX_TOKENS` | `8000` | Upper bound for model output tokens. |
|
|
34
34
|
| `LLM_TIMEOUT_MS` | `60000` | Per-request timeout (ms). |
|
|
35
35
|
|
|
36
|
+
All numeric values are parsed as integers. Invalid values or values below the minimum thresholds will fail startup validation.
|
|
37
|
+
|
|
38
|
+
Minimums: `MAX_PROMPT_LENGTH` >= 1, `LLM_MAX_TOKENS` >= 1, `LLM_TIMEOUT_MS` >= 1000.
|
|
39
|
+
|
|
36
40
|
### Prompt length enforcement
|
|
37
41
|
|
|
38
42
|
- Input is trimmed before validation.
|
|
@@ -61,13 +65,15 @@ Tool max tokens are derived from `LLM_MAX_TOKENS`:
|
|
|
61
65
|
|
|
62
66
|
Retries use exponential backoff with jitter and stop when the total timeout is exceeded.
|
|
63
67
|
|
|
68
|
+
Minimums: `RETRY_MAX_ATTEMPTS` >= 0, `RETRY_BASE_DELAY_MS` >= 100, `RETRY_MAX_DELAY_MS` >= 1000, `RETRY_TOTAL_TIMEOUT_MS` >= 10000.
|
|
69
|
+
|
|
64
70
|
## Logging and error context (optional)
|
|
65
71
|
|
|
66
|
-
| Variable | Default | Description
|
|
67
|
-
| ----------------------- | ------- |
|
|
68
|
-
| `DEBUG` | `false` | Enables debug logging. Logs are written to stderr.
|
|
69
|
-
| `LOG_FORMAT` | `text` |
|
|
70
|
-
| `INCLUDE_ERROR_CONTEXT` | `false` | Adds a sanitized prompt snippet (up to 200 chars) to errors.
|
|
72
|
+
| Variable | Default | Description |
|
|
73
|
+
| ----------------------- | ------- | ---------------------------------------------------------------------------------------- |
|
|
74
|
+
| `DEBUG` | `false` | Enables debug logging (set to the string `true` or `false`). Logs are written to stderr. |
|
|
75
|
+
| `LOG_FORMAT` | `text` | Accepted values: `json`, `text`. Currently ignored; output is always JSON via pino. |
|
|
76
|
+
| `INCLUDE_ERROR_CONTEXT` | `false` | Adds a sanitized prompt snippet (up to 200 chars) to errors. |
|
|
71
77
|
|
|
72
78
|
## Provider-specific settings
|
|
73
79
|
|
|
@@ -179,7 +185,7 @@ The following behaviors are hardcoded for stability:
|
|
|
179
185
|
|
|
180
186
|
If you have an old `.env` file, remove unused settings:
|
|
181
187
|
|
|
182
|
-
- `PORT`, `HOST`, `CORS_ORIGIN` (stdio transport only;
|
|
188
|
+
- `PORT`, `HOST`, `CORS_ORIGIN` (stdio transport only; no HTTP listener).
|
|
183
189
|
- `API_KEY` (no server-level auth).
|
|
184
190
|
- `LOG_LEVEL` (use `DEBUG=true` or false).
|
|
185
191
|
- `RATE_LIMIT`, `RATE_WINDOW_MS` (no server-side rate limiting).
|
|
@@ -192,7 +198,7 @@ If you have an old `.env` file, remove unused settings:
|
|
|
192
198
|
|
|
193
199
|
### Prompt rejected
|
|
194
200
|
|
|
195
|
-
-
|
|
201
|
+
- Shorten the prompt, remove excessive whitespace, or increase `MAX_PROMPT_LENGTH`.
|
|
196
202
|
|
|
197
203
|
### Timeout errors
|
|
198
204
|
|
|
@@ -215,4 +221,4 @@ If you have an old `.env` file, remove unused settings:
|
|
|
215
221
|
2. Use input variables for secrets (for example `"OPENAI_API_KEY": "${input:openai-api-key}"`).
|
|
216
222
|
3. Start with defaults and tune only when needed.
|
|
217
223
|
4. Enable `DEBUG=true` temporarily for troubleshooting.
|
|
218
|
-
5.
|
|
224
|
+
5. Logs are JSON via pino; plan parsing/collection accordingly.
|
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/@j0hanz/prompt-tuner-mcp-server)
|
|
6
6
|
[](LICENSE)
|
|
7
|
-
[](https://nodejs.org/)
|
|
8
8
|
|
|
9
9
|
PromptTuner MCP is an MCP server that refines, analyzes, optimizes, and validates prompts using OpenAI, Anthropic, or Google Gemini.
|
|
10
10
|
|
|
@@ -14,7 +14,7 @@ PromptTuner MCP is an MCP server that refines, analyzes, optimizes, and validate
|
|
|
14
14
|
2. Resolves the target format (`auto` uses heuristics; falls back to `gpt` if no format is detected).
|
|
15
15
|
3. Calls the selected provider with retry and timeout controls.
|
|
16
16
|
4. Validates and normalizes LLM output, falling back to stricter prompts or the `basic` technique when needed.
|
|
17
|
-
5. Returns human-readable text plus machine-friendly `structuredContent` (and
|
|
17
|
+
5. Returns human-readable text plus machine-friendly `structuredContent` (and resource blocks for refined/optimized outputs).
|
|
18
18
|
|
|
19
19
|
## Features
|
|
20
20
|
|
|
@@ -27,7 +27,7 @@ PromptTuner MCP is an MCP server that refines, analyzes, optimizes, and validate
|
|
|
27
27
|
|
|
28
28
|
## Quick Start
|
|
29
29
|
|
|
30
|
-
PromptTuner runs over stdio
|
|
30
|
+
PromptTuner runs over stdio only. The `dev:http` and `start:http` scripts are compatibility aliases (no HTTP transport yet).
|
|
31
31
|
|
|
32
32
|
### Claude Desktop
|
|
33
33
|
|
|
@@ -95,11 +95,11 @@ Returns: `ok`, `hasTypos`, `isVague`, `missingContext`, `suggestions`, `score`,
|
|
|
95
95
|
|
|
96
96
|
Apply multiple techniques sequentially and return before/after scores.
|
|
97
97
|
|
|
98
|
-
| Parameter | Type | Required | Default | Notes
|
|
99
|
-
| -------------- | -------- | -------- | ----------- |
|
|
100
|
-
| `prompt` | string | Yes | - | Trimmed and length-checked.
|
|
101
|
-
| `techniques` | string[] | No | `["basic"]` | 1-6 techniques; duplicates removed. |
|
|
102
|
-
| `targetFormat` | string | No | `auto` | `auto`, `claude`, `gpt`, `json`.
|
|
98
|
+
| Parameter | Type | Required | Default | Notes |
|
|
99
|
+
| -------------- | -------- | -------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------- |
|
|
100
|
+
| `prompt` | string | Yes | - | Trimmed and length-checked. |
|
|
101
|
+
| `techniques` | string[] | No | `["basic"]` | 1-6 techniques; duplicates removed. `comprehensive` expands to `basic -> roleBased -> structured -> fewShot -> chainOfThought`. |
|
|
102
|
+
| `targetFormat` | string | No | `auto` | `auto`, `claude`, `gpt`, `json`. |
|
|
103
103
|
|
|
104
104
|
Returns: `ok`, `original`, `optimized`, `techniquesApplied`, `targetFormat`, `beforeScore`, `afterScore`, `scoreDelta`, `improvements`, `usedFallback`, `scoreAdjusted`, `overallSource`, `provider`, `model`.
|
|
105
105
|
|
|
@@ -119,10 +119,10 @@ Token limits used for `validate_prompt`: `claude` 200000, `gpt` 128000, `gemini`
|
|
|
119
119
|
|
|
120
120
|
## Response Format
|
|
121
121
|
|
|
122
|
-
- `content`: human-readable Markdown
|
|
122
|
+
- `content`: array of content blocks (human-readable Markdown text plus optional resources).
|
|
123
123
|
- `structuredContent`: machine-parseable results.
|
|
124
124
|
- Errors return `structuredContent.ok=false` and an `error` object with `code`, `message`, optional `context` (sanitized, up to 200 chars), `details`, and `recoveryHint`.
|
|
125
|
-
- `refine_prompt` and `optimize_prompt` include a `resource` content block with a `file:///` URI
|
|
125
|
+
- `refine_prompt` and `optimize_prompt` include a `resource` content block with a `file:///` URI and the prompt text in `resource.text` (Markdown).
|
|
126
126
|
|
|
127
127
|
## Prompts
|
|
128
128
|
|
|
@@ -159,27 +159,27 @@ Token limits used for `validate_prompt`: `claude` 200000, `gpt` 128000, `gemini`
|
|
|
159
159
|
|
|
160
160
|
### Prerequisites
|
|
161
161
|
|
|
162
|
-
- Node.js >=
|
|
162
|
+
- Node.js >= 22.0.0
|
|
163
163
|
- npm
|
|
164
164
|
|
|
165
165
|
### Scripts
|
|
166
166
|
|
|
167
|
-
| Command | Description
|
|
168
|
-
| ------------------------ |
|
|
169
|
-
| `npm run build` | Compile TypeScript and set permissions.
|
|
170
|
-
| `npm run dev` | Run from source in watch mode.
|
|
171
|
-
| `npm run dev:http` |
|
|
172
|
-
| `npm run start` | Run the compiled server from `dist/`.
|
|
173
|
-
| `npm run start:http` |
|
|
174
|
-
| `npm run test` | Run Vitest once.
|
|
175
|
-
| `npm run test:coverage` | Run tests with coverage.
|
|
176
|
-
| `npm run test:watch` | Run Vitest in watch mode.
|
|
177
|
-
| `npm run lint` | Run ESLint.
|
|
178
|
-
| `npm run format` | Run Prettier.
|
|
179
|
-
| `npm run type-check` | TypeScript type checking.
|
|
180
|
-
| `npm run inspector` | Run MCP Inspector against `dist/index.js`.
|
|
181
|
-
| `npm run inspector:http` |
|
|
182
|
-
| `npm run duplication` | Run jscpd duplication report.
|
|
167
|
+
| Command | Description |
|
|
168
|
+
| ------------------------ | ----------------------------------------------------- |
|
|
169
|
+
| `npm run build` | Compile TypeScript and set permissions. |
|
|
170
|
+
| `npm run dev` | Run from source in watch mode. |
|
|
171
|
+
| `npm run dev:http` | Alias of `npm run dev` (no HTTP transport yet). |
|
|
172
|
+
| `npm run start` | Run the compiled server from `dist/`. |
|
|
173
|
+
| `npm run start:http` | Alias of `npm run start` (no HTTP transport yet). |
|
|
174
|
+
| `npm run test` | Run Vitest once. |
|
|
175
|
+
| `npm run test:coverage` | Run tests with coverage. |
|
|
176
|
+
| `npm run test:watch` | Run Vitest in watch mode. |
|
|
177
|
+
| `npm run lint` | Run ESLint. |
|
|
178
|
+
| `npm run format` | Run Prettier. |
|
|
179
|
+
| `npm run type-check` | TypeScript type checking. |
|
|
180
|
+
| `npm run inspector` | Run MCP Inspector against `dist/index.js`. |
|
|
181
|
+
| `npm run inspector:http` | Alias of `npm run inspector` (no HTTP transport yet). |
|
|
182
|
+
| `npm run duplication` | Run jscpd duplication report. |
|
|
183
183
|
|
|
184
184
|
## Project Structure
|
|
185
185
|
|
|
@@ -190,8 +190,7 @@ src/
|
|
|
190
190
|
config/ Configuration and constants
|
|
191
191
|
lib/ Shared utilities (LLM, retry, validation)
|
|
192
192
|
tools/ Tool implementations
|
|
193
|
-
prompts/
|
|
194
|
-
resources/ Resource registration (currently none)
|
|
193
|
+
prompts/ MCP prompt templates
|
|
195
194
|
schemas/ Zod input/output schemas
|
|
196
195
|
types/ Shared types
|
|
197
196
|
|
package/dist/config/constants.js
CHANGED
|
@@ -11,7 +11,6 @@ export const SCORING_WEIGHTS = {
|
|
|
11
11
|
};
|
|
12
12
|
export const SERVER_NAME = 'prompttuner-mcp';
|
|
13
13
|
export const SERVER_VERSION = packageJson.version;
|
|
14
|
-
// Configurable via environment variables
|
|
15
14
|
const { MAX_PROMPT_LENGTH: ENV_MAX_PROMPT_LENGTH, LLM_TIMEOUT_MS: ENV_LLM_TIMEOUT_MS, LLM_MAX_TOKENS: ENV_LLM_MAX_TOKENS, } = config;
|
|
16
15
|
export const MAX_PROMPT_LENGTH = ENV_MAX_PROMPT_LENGTH;
|
|
17
16
|
export const MIN_PROMPT_LENGTH = 1;
|
|
@@ -28,4 +27,3 @@ export const DEFAULT_MODELS = {
|
|
|
28
27
|
anthropic: 'claude-3-5-sonnet-20241022',
|
|
29
28
|
google: 'gemini-2.0-flash-exp',
|
|
30
29
|
};
|
|
31
|
-
//# sourceMappingURL=constants.js.map
|
package/dist/config/env.d.ts
CHANGED
package/dist/config/env.js
CHANGED
|
@@ -11,11 +11,9 @@ const numberString = (def, min = 0) => z
|
|
|
11
11
|
.transform((v) => parseInt(v, 10))
|
|
12
12
|
.refine((n) => n >= min, { message: `Must be >= ${min}` });
|
|
13
13
|
const envSchema = z.object({
|
|
14
|
-
// Server
|
|
15
14
|
LOG_FORMAT: z.enum(['json', 'text']).optional().default('text'),
|
|
16
15
|
DEBUG: booleanString,
|
|
17
16
|
INCLUDE_ERROR_CONTEXT: booleanString,
|
|
18
|
-
// LLM
|
|
19
17
|
LLM_PROVIDER: z
|
|
20
18
|
.enum(['openai', 'anthropic', 'google'])
|
|
21
19
|
.optional()
|
|
@@ -28,17 +26,13 @@ const envSchema = z.object({
|
|
|
28
26
|
.optional()
|
|
29
27
|
.default('false')
|
|
30
28
|
.transform((v) => v === 'true'),
|
|
31
|
-
// Keys
|
|
32
29
|
OPENAI_API_KEY: z.string().optional(),
|
|
33
30
|
ANTHROPIC_API_KEY: z.string().optional(),
|
|
34
31
|
GOOGLE_API_KEY: z.string().optional(),
|
|
35
|
-
// Constraints
|
|
36
32
|
MAX_PROMPT_LENGTH: numberString(10000, 1),
|
|
37
|
-
// Retry
|
|
38
33
|
RETRY_MAX_ATTEMPTS: numberString(3, 0),
|
|
39
34
|
RETRY_BASE_DELAY_MS: numberString(1000, 100),
|
|
40
35
|
RETRY_MAX_DELAY_MS: numberString(10000, 1000),
|
|
41
36
|
RETRY_TOTAL_TIMEOUT_MS: numberString(180000, 10000),
|
|
42
37
|
});
|
|
43
38
|
export const config = envSchema.parse(process.env);
|
|
44
|
-
//# sourceMappingURL=env.js.map
|
|
@@ -1,2 +1 @@
|
|
|
1
1
|
export declare const SERVER_INSTRUCTIONS = "# PromptTuner MCP\n\nA lean prompt optimization toolkit for refining, analyzing, and validating prompts.\n\n## Quick Start\n\n| Goal | Tool | When to Use |\n|------|------|-------------|\n| Quick fix | `refine_prompt` | Fix typos and clarity issues |\n| Deep optimization | `optimize_prompt` | Apply multiple techniques |\n| Quality check | `analyze_prompt` | Get scores and suggestions |\n| Safety check | `validate_prompt` | Find issues and estimate tokens |\n\n## Tools\n\n### refine_prompt\nImproves a prompt using a single optimization technique.\n\n**Techniques:**\n- `basic` (default) - Fix grammar, spelling, and clarity\n- `chainOfThought` - Add step-by-step reasoning guidance\n- `fewShot` - Add input/output examples\n- `roleBased` - Add expert persona/role context\n- `structured` - Add XML (Claude) or Markdown (GPT) structure\n- `comprehensive` - Apply all techniques intelligently\n\n**Example:**\n```json\n{ \"prompt\": \"help me code\", \"technique\": \"roleBased\", \"targetFormat\": \"claude\" }\n```\n\n### analyze_prompt\nScores your prompt (0-100) across clarity, specificity, completeness, structure, and effectiveness.\n\n### optimize_prompt\nChains multiple techniques for maximum improvement and returns before/after scores plus improvements.\n\n**Example:**\n```json\n{ \"prompt\": \"write code\", \"techniques\": [\"basic\", \"roleBased\", \"structured\"] }\n```\n\n### validate_prompt\nChecks for prompt issues, estimates token usage, and optionally detects injection risks.\n\n## Target Formats\n\n| Format | Best For | Structure |\n|--------|----------|-----------|\n| `claude` | Anthropic Claude | XML tags: `<context>`, `<task>`, `<requirements>` |\n| `gpt` | OpenAI GPT | Markdown: `## Context`, `## Task`, `**bold**` |\n| `json` | Structured output | JSON schema specification |\n| `auto` | Auto-detect | Uses prompt heuristics to pick format |\n\n## Technique Selection Guide\n\n| Task Type | Recommended Techniques |\n|-----------|----------------------|\n| Simple query | `basic` only |\n| Code task | `roleBased` + `structured` |\n| Complex analysis | `roleBased` + `chainOfThought` |\n| Data extraction | `structured` + `fewShot` |\n| Creative writing | `roleBased` + `fewShot` |\n| Maximum quality | `comprehensive` |\n\n## Workflow Prompts\n- `quick-optimize` - Single-step refinement\n- `deep-optimize` - Comprehensive optimization\n- `analyze` - Quality analysis\n\n## Modern Best Practices (2024-2025)\n\n1. **Be Specific** - Replace vague words with concrete terms\n2. **Add Role Context** - Use specific expert personas\n3. **Use Structure** - XML for Claude, Markdown for GPT (never mix)\n4. **Show Examples** - 2-3 diverse examples for pattern tasks\n5. **Add Constraints** - Clear ALWAYS/NEVER rules\n6. **Specify Output** - Define the expected format explicitly\n7. **Enable Reasoning** - Add task-specific reasoning triggers when needed\n8. **Place Key Instructions Twice** - Start and end for long prompts\n\n## Prompt Architecture (Recommended Order)\n```\n1. Role/Identity (if applicable)\n2. Context/Background\n3. Task/Objective\n4. Instructions/Steps\n5. Requirements/Constraints (ALWAYS/NEVER)\n6. Output Format\n7. Examples (if helpful)\n8. Final Reminder (reiterate critical instruction)\n```";
|
|
2
|
-
//# sourceMappingURL=instructions.d.ts.map
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
export declare const PATTERNS: {
|
|
2
|
-
readonly roleIndicators: RegExp;
|
|
3
2
|
readonly exampleIndicators: RegExp;
|
|
4
3
|
readonly stepByStepIndicators: RegExp;
|
|
5
4
|
readonly xmlStructure: RegExp;
|
|
@@ -8,13 +7,6 @@ export declare const PATTERNS: {
|
|
|
8
7
|
readonly claudePatterns: RegExp;
|
|
9
8
|
readonly gptPatterns: RegExp;
|
|
10
9
|
readonly vagueWords: RegExp;
|
|
11
|
-
readonly needsReasoning: RegExp;
|
|
12
|
-
readonly hasStepByStep: RegExp;
|
|
13
10
|
readonly hasRole: RegExp;
|
|
14
|
-
readonly constraintPatterns: RegExp;
|
|
15
|
-
readonly outputSpecPatterns: RegExp;
|
|
16
11
|
readonly fewShotStructure: RegExp;
|
|
17
|
-
readonly qualityIndicators: RegExp;
|
|
18
|
-
readonly antiPatterns: RegExp;
|
|
19
12
|
};
|
|
20
|
-
//# sourceMappingURL=patterns.d.ts.map
|
package/dist/config/patterns.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
export const PATTERNS = {
|
|
2
|
-
roleIndicators: /\b(you are|act as|pretend to be|as a|role:|persona:|imagine you are|your role is|you're an?)\b/i,
|
|
3
2
|
exampleIndicators: /(?:^|\s|[([{])(example:|for example|e\.g\.|such as|here's an example|input:|output:|sample:|demonstration:)(?:$|\s|[)\]}.!?,])/i,
|
|
4
3
|
stepByStepIndicators: /(?:^|\s|[([{])(step by step|step-by-step|first,|then,|finally,|1\.|2\.|3\.|let's think|let's work through|let's analyze|let's break|systematically)(?:$|\s|[)\]}.!?,])/i,
|
|
5
4
|
xmlStructure: /<[a-z_]+>[^<]*<\/[a-z_]+>/is,
|
|
@@ -8,13 +7,6 @@ export const PATTERNS = {
|
|
|
8
7
|
claudePatterns: /<(thinking|response|context|instructions|example|task|requirements|output_format|rules|constraints)>/i,
|
|
9
8
|
gptPatterns: /^##\s|^###\s|\*\*[^*]+\*\*|^>\s/m,
|
|
10
9
|
vagueWords: /\b(something|stuff|things|maybe|kind of|sort of|etc|whatever|somehow|certain|various)\b/gi,
|
|
11
|
-
needsReasoning: /\b(calculate|analyze|compare|evaluate|explain|solve|debug|review|reason|deduce|derive|prove|assess|investigate|examine|determine)\b/i,
|
|
12
|
-
hasStepByStep: /step[- ]by[- ]step|first,|then,|finally,|let's think|let's work through|let's analyze/i,
|
|
13
10
|
hasRole: /\b(you are|act as|as a|role:|persona:|your role|you're an?|imagine you are)\b/i,
|
|
14
|
-
constraintPatterns: /\b(NEVER|ALWAYS|MUST|MUST NOT|DO NOT|RULES:|CONSTRAINTS:|REQUIREMENTS:)\b/,
|
|
15
|
-
outputSpecPatterns: /\b(output format|respond with|return as|format:|expected output|response format|<output|## Output)\b/i,
|
|
16
11
|
fewShotStructure: /<example>|Example \d+:|Input:|Output:|###\s*Example|Q:|A:/i,
|
|
17
|
-
qualityIndicators: /\b(specific|detailed|comprehensive|thorough|clear|concise|precise|accurate)\b/i,
|
|
18
|
-
antiPatterns: /\b(do whatever|anything|everything|all of it|any way you want)\b/i,
|
|
19
12
|
};
|
|
20
|
-
//# sourceMappingURL=patterns.js.map
|
package/dist/config/types.d.ts
CHANGED
|
@@ -1,31 +1,28 @@
|
|
|
1
1
|
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
2
|
export type ToolRegistrar = (server: McpServer) => void;
|
|
3
|
-
interface
|
|
4
|
-
type: 'text';
|
|
5
|
-
text: string;
|
|
6
|
-
}
|
|
7
|
-
interface TextResourcePayload {
|
|
3
|
+
interface ResourceTextPayload {
|
|
8
4
|
uri: string;
|
|
9
|
-
mimeType?: string;
|
|
10
5
|
text: string;
|
|
6
|
+
mimeType?: string;
|
|
11
7
|
}
|
|
12
|
-
interface
|
|
8
|
+
interface ResourceBlobPayload {
|
|
13
9
|
uri: string;
|
|
14
|
-
mimeType?: string;
|
|
15
10
|
blob: string;
|
|
11
|
+
mimeType?: string;
|
|
16
12
|
}
|
|
17
|
-
|
|
13
|
+
export type ContentBlock = {
|
|
14
|
+
type: 'text';
|
|
15
|
+
text: string;
|
|
16
|
+
} | {
|
|
18
17
|
type: 'resource';
|
|
19
|
-
resource:
|
|
20
|
-
}
|
|
21
|
-
interface ResourceLinkContentBlock {
|
|
18
|
+
resource: ResourceTextPayload | ResourceBlobPayload;
|
|
19
|
+
} | {
|
|
22
20
|
type: 'resource_link';
|
|
23
21
|
uri: string;
|
|
24
22
|
name: string;
|
|
25
23
|
description?: string;
|
|
26
24
|
mimeType?: string;
|
|
27
|
-
}
|
|
28
|
-
export type ContentBlock = TextContentBlock | ResourceContentBlock | ResourceLinkContentBlock;
|
|
25
|
+
};
|
|
29
26
|
export interface ErrorResponse {
|
|
30
27
|
[key: string]: unknown;
|
|
31
28
|
content: ContentBlock[];
|
|
@@ -64,6 +61,10 @@ export interface PatternCache {
|
|
|
64
61
|
hasBoldOrHeaders: boolean;
|
|
65
62
|
hasAngleBrackets: boolean;
|
|
66
63
|
hasJsonChars: boolean;
|
|
64
|
+
hasRole: boolean;
|
|
65
|
+
hasExamples: boolean;
|
|
66
|
+
hasStepByStep: boolean;
|
|
67
|
+
isVague: boolean;
|
|
67
68
|
}
|
|
68
69
|
export interface FormatScoringConfig {
|
|
69
70
|
positive: {
|
|
@@ -82,7 +83,6 @@ export interface FormatResult {
|
|
|
82
83
|
rawScore: number;
|
|
83
84
|
}
|
|
84
85
|
export type LLMProvider = 'openai' | 'anthropic' | 'google';
|
|
85
|
-
export type ValidProvider = 'openai' | 'anthropic' | 'google';
|
|
86
86
|
export interface SafeErrorDetails {
|
|
87
87
|
status?: number;
|
|
88
88
|
code?: string;
|
|
@@ -109,12 +109,6 @@ export interface LLMToolOptions {
|
|
|
109
109
|
timeoutMs?: number;
|
|
110
110
|
signal?: AbortSignal;
|
|
111
111
|
}
|
|
112
|
-
export interface RetryOptions {
|
|
113
|
-
maxRetries?: number;
|
|
114
|
-
baseDelayMs?: number;
|
|
115
|
-
maxDelayMs?: number;
|
|
116
|
-
totalTimeoutMs?: number;
|
|
117
|
-
}
|
|
118
112
|
export interface McpErrorOptions {
|
|
119
113
|
context?: string;
|
|
120
114
|
details?: Record<string, unknown>;
|
|
@@ -171,4 +165,3 @@ export interface ValidationResponse {
|
|
|
171
165
|
issues: ValidationIssue[];
|
|
172
166
|
}
|
|
173
167
|
export {};
|
|
174
|
-
//# sourceMappingURL=types.d.ts.map
|
package/dist/config/types.js
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,103 +1,69 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { logger } from './lib/errors.js';
|
|
3
|
-
import {
|
|
3
|
+
import { startServer, validateApiKeys } from './server.js';
|
|
4
4
|
const SHUTDOWN_DELAY_MS = 500;
|
|
5
|
-
const SIGNALS = [
|
|
6
|
-
'SIGHUP',
|
|
7
|
-
'SIGINT',
|
|
8
|
-
'SIGQUIT',
|
|
9
|
-
'SIGILL',
|
|
10
|
-
'SIGTRAP',
|
|
11
|
-
'SIGABRT',
|
|
12
|
-
'SIGBUS',
|
|
13
|
-
'SIGFPE',
|
|
14
|
-
'SIGSEGV',
|
|
15
|
-
'SIGUSR2',
|
|
16
|
-
'SIGTERM',
|
|
17
|
-
];
|
|
18
|
-
const ERROR_EVENTS = ['uncaughtException', 'unhandledRejection'];
|
|
19
|
-
const EXIT_EVENTS = ['beforeExit'];
|
|
20
|
-
let shuttingDown = false;
|
|
5
|
+
const SIGNALS = ['SIGHUP', 'SIGINT', 'SIGTERM'];
|
|
21
6
|
let server = null;
|
|
7
|
+
let shuttingDown = false;
|
|
22
8
|
function logSecondShutdown(reason) {
|
|
23
|
-
|
|
24
|
-
logger.error({ signal: reason.signal }, `Second ${reason.signal}, exiting`);
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
if (reason.err) {
|
|
28
|
-
logger.error({ err: reason.err }, 'Second error, exiting');
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
logger.error('Second shutdown event, exiting');
|
|
9
|
+
logger.error({ reason }, 'Second shutdown, exiting');
|
|
32
10
|
}
|
|
33
|
-
function
|
|
34
|
-
if (
|
|
35
|
-
logger.error({ err
|
|
36
|
-
}
|
|
37
|
-
if (reason.signal) {
|
|
38
|
-
logger.info({ signal: reason.signal }, 'Server shutting down gracefully');
|
|
11
|
+
function logShutdown(reason, err) {
|
|
12
|
+
if (err) {
|
|
13
|
+
logger.error({ err, reason }, 'Server shutting down due to error');
|
|
39
14
|
}
|
|
40
|
-
|
|
41
|
-
logger.info({
|
|
15
|
+
else {
|
|
16
|
+
logger.info({ reason }, 'Server shutting down');
|
|
42
17
|
}
|
|
43
18
|
}
|
|
44
|
-
function resolveExitCode(reason) {
|
|
45
|
-
return reason.err ? 1 : 0;
|
|
46
|
-
}
|
|
47
19
|
function startForcedShutdownTimer() {
|
|
48
20
|
return setTimeout(() => {
|
|
49
21
|
logger.error({ delayMs: SHUTDOWN_DELAY_MS }, 'Forced shutdown due to timeout');
|
|
50
22
|
process.exit(1);
|
|
51
23
|
}, SHUTDOWN_DELAY_MS);
|
|
52
24
|
}
|
|
53
|
-
async function
|
|
54
|
-
if (server?.isConnected())
|
|
25
|
+
async function closeServer() {
|
|
26
|
+
if (!server?.isConnected())
|
|
27
|
+
return true;
|
|
28
|
+
try {
|
|
55
29
|
await server.close();
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
catch (closeError) {
|
|
33
|
+
logger.error({ err: closeError }, 'Error during shutdown');
|
|
34
|
+
return false;
|
|
56
35
|
}
|
|
57
36
|
}
|
|
58
|
-
async function
|
|
37
|
+
async function shutdown(reason, err) {
|
|
59
38
|
if (shuttingDown) {
|
|
60
39
|
logSecondShutdown(reason);
|
|
61
40
|
process.exit(1);
|
|
62
41
|
return;
|
|
63
42
|
}
|
|
64
43
|
shuttingDown = true;
|
|
65
|
-
|
|
66
|
-
let exitCode = resolveExitCode(reason);
|
|
44
|
+
logShutdown(reason, err);
|
|
67
45
|
const timeout = startForcedShutdownTimer();
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}
|
|
71
|
-
catch (error) {
|
|
46
|
+
let exitCode = err ? 1 : 0;
|
|
47
|
+
if (!(await closeServer()))
|
|
72
48
|
exitCode = 1;
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
finally {
|
|
76
|
-
clearTimeout(timeout);
|
|
77
|
-
process.exit(exitCode);
|
|
78
|
-
}
|
|
49
|
+
clearTimeout(timeout);
|
|
50
|
+
process.exit(exitCode);
|
|
79
51
|
}
|
|
80
52
|
for (const signal of SIGNALS) {
|
|
81
|
-
process.once(signal, (
|
|
82
|
-
void
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
for (const event of ERROR_EVENTS) {
|
|
86
|
-
process.once(event, (err) => {
|
|
87
|
-
void beginShutdown({ err });
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
for (const event of EXIT_EVENTS) {
|
|
91
|
-
process.once(event, () => {
|
|
92
|
-
void beginShutdown({ event });
|
|
53
|
+
process.once(signal, () => {
|
|
54
|
+
void shutdown(signal);
|
|
93
55
|
});
|
|
94
56
|
}
|
|
57
|
+
process.once('uncaughtException', (err) => {
|
|
58
|
+
void shutdown('uncaughtException', err);
|
|
59
|
+
});
|
|
60
|
+
process.once('unhandledRejection', (err) => {
|
|
61
|
+
void shutdown('unhandledRejection', err);
|
|
62
|
+
});
|
|
95
63
|
async function main() {
|
|
96
64
|
await validateApiKeys();
|
|
97
|
-
server =
|
|
98
|
-
await startServer(server);
|
|
65
|
+
server = await startServer();
|
|
99
66
|
}
|
|
100
|
-
main().catch((
|
|
101
|
-
void
|
|
67
|
+
main().catch((err) => {
|
|
68
|
+
void shutdown('startup', err);
|
|
102
69
|
});
|
|
103
|
-
//# sourceMappingURL=index.js.map
|