clinkx 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +70 -0
- package/conf/adapters/claude.json +33 -0
- package/conf/adapters/codex.json +33 -0
- package/conf/adapters/gemini.json +33 -0
- package/conf/adapters/glm.json +39 -0
- package/conf/adapters/hapi/claude.json +36 -0
- package/conf/adapters/hapi/codex.json +36 -0
- package/conf/adapters/hapi/gemini.json +36 -0
- package/conf/adapters/hapi/glm.json +40 -0
- package/conf/prompts/codereviewer.txt +8 -0
- package/conf/prompts/debug.txt +6 -0
- package/conf/prompts/default.txt +8 -0
- package/conf/prompts/json.txt +5 -0
- package/conf/prompts/planner.txt +8 -0
- package/dist/artifacts.d.ts +9 -0
- package/dist/artifacts.js +24 -0
- package/dist/artifacts.js.map +1 -0
- package/dist/concurrency.d.ts +15 -0
- package/dist/concurrency.js +39 -0
- package/dist/concurrency.js.map +1 -0
- package/dist/config.d.ts +103 -0
- package/dist/config.js +40 -0
- package/dist/config.js.map +1 -0
- package/dist/continuation.d.ts +15 -0
- package/dist/continuation.js +42 -0
- package/dist/continuation.js.map +1 -0
- package/dist/env.d.ts +10 -0
- package/dist/env.js +52 -0
- package/dist/env.js.map +1 -0
- package/dist/errors.d.ts +68 -0
- package/dist/errors.js +88 -0
- package/dist/errors.js.map +1 -0
- package/dist/handler.d.ts +21 -0
- package/dist/handler.js +45 -0
- package/dist/handler.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +38 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +16 -0
- package/dist/logger.js +30 -0
- package/dist/logger.js.map +1 -0
- package/dist/parsers/claude-json.d.ts +2 -0
- package/dist/parsers/claude-json.js +58 -0
- package/dist/parsers/claude-json.js.map +1 -0
- package/dist/parsers/codex-jsonl.d.ts +2 -0
- package/dist/parsers/codex-jsonl.js +75 -0
- package/dist/parsers/codex-jsonl.js.map +1 -0
- package/dist/parsers/extract.d.ts +25 -0
- package/dist/parsers/extract.js +87 -0
- package/dist/parsers/extract.js.map +1 -0
- package/dist/parsers/gemini-json.d.ts +2 -0
- package/dist/parsers/gemini-json.js +72 -0
- package/dist/parsers/gemini-json.js.map +1 -0
- package/dist/parsers/json-extract.d.ts +2 -0
- package/dist/parsers/json-extract.js +19 -0
- package/dist/parsers/json-extract.js.map +1 -0
- package/dist/parsers/summary.d.ts +7 -0
- package/dist/parsers/summary.js +29 -0
- package/dist/parsers/summary.js.map +1 -0
- package/dist/parsers/text.d.ts +2 -0
- package/dist/parsers/text.js +14 -0
- package/dist/parsers/text.js.map +1 -0
- package/dist/parsers/types.d.ts +25 -0
- package/dist/parsers/types.js +2 -0
- package/dist/parsers/types.js.map +1 -0
- package/dist/parsers/utils.d.ts +11 -0
- package/dist/parsers/utils.js +116 -0
- package/dist/parsers/utils.js.map +1 -0
- package/dist/paths.d.ts +17 -0
- package/dist/paths.js +87 -0
- package/dist/paths.js.map +1 -0
- package/dist/pipeline.d.ts +37 -0
- package/dist/pipeline.js +232 -0
- package/dist/pipeline.js.map +1 -0
- package/dist/progress.d.ts +28 -0
- package/dist/progress.js +78 -0
- package/dist/progress.js.map +1 -0
- package/dist/prompt-mode.d.ts +15 -0
- package/dist/prompt-mode.js +23 -0
- package/dist/prompt-mode.js.map +1 -0
- package/dist/prompt.d.ts +25 -0
- package/dist/prompt.js +108 -0
- package/dist/prompt.js.map +1 -0
- package/dist/registry.d.ts +27 -0
- package/dist/registry.js +163 -0
- package/dist/registry.js.map +1 -0
- package/dist/result-contract.d.ts +13 -0
- package/dist/result-contract.js +80 -0
- package/dist/result-contract.js.map +1 -0
- package/dist/run-dir.d.ts +12 -0
- package/dist/run-dir.js +32 -0
- package/dist/run-dir.js.map +1 -0
- package/dist/runner.d.ts +39 -0
- package/dist/runner.js +220 -0
- package/dist/runner.js.map +1 -0
- package/dist/safety.d.ts +22 -0
- package/dist/safety.js +47 -0
- package/dist/safety.js.map +1 -0
- package/dist/schema.d.ts +69 -0
- package/dist/schema.js +91 -0
- package/dist/schema.js.map +1 -0
- package/dist/server.d.ts +11 -0
- package/dist/server.js +109 -0
- package/dist/server.js.map +1 -0
- package/package.json +34 -0
package/dist/config.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
const RoleConfigSchema = z.object({
|
|
3
|
+
inline_prompt: z.string().optional(),
|
|
4
|
+
prompt_file: z.string().optional(),
|
|
5
|
+
});
|
|
6
|
+
const ResultContractSchema = z.object({
|
|
7
|
+
enabled: z.boolean().default(false),
|
|
8
|
+
filename: z.enum(["RESULT.md", "RESULT.json"]).default("RESULT.md"),
|
|
9
|
+
});
|
|
10
|
+
/**
|
|
11
|
+
* CLI adapter config schema — defines how ClinkX talks to a particular CLI.
|
|
12
|
+
*
|
|
13
|
+
* All fields from the plan: name, command, runner, args, unsafe_args, env,
|
|
14
|
+
* env_allowlist, timeout_seconds, parser, capabilities_hint, roles,
|
|
15
|
+
* supports_images, requires_tty, result_contract, prompt_mode.
|
|
16
|
+
*/
|
|
17
|
+
export const CliAdapterConfigSchema = z.object({
|
|
18
|
+
name: z.string().min(1),
|
|
19
|
+
command: z.string().min(1),
|
|
20
|
+
runner: z.string().optional(),
|
|
21
|
+
args: z.array(z.string()).default([]),
|
|
22
|
+
unsafe_args: z.array(z.string()).default([]),
|
|
23
|
+
env: z.record(z.string()).default({}),
|
|
24
|
+
env_allowlist: z.array(z.string()).default([]),
|
|
25
|
+
timeout_seconds: z.number().positive().default(600),
|
|
26
|
+
parser: z
|
|
27
|
+
.enum(["text", "json_extract", "gemini_json", "codex_jsonl", "claude_json"])
|
|
28
|
+
.default("text"),
|
|
29
|
+
tolerate_nonzero_exit_for_parse: z.boolean().default(false),
|
|
30
|
+
capabilities_hint: z.string().optional(),
|
|
31
|
+
roles: z.record(RoleConfigSchema).default({}),
|
|
32
|
+
supports_images: z.boolean().default(false),
|
|
33
|
+
requires_tty: z.boolean().default(false),
|
|
34
|
+
result_contract: ResultContractSchema.default({
|
|
35
|
+
enabled: false,
|
|
36
|
+
filename: "RESULT.md",
|
|
37
|
+
}),
|
|
38
|
+
prompt_mode: z.enum(["stdin", "arg", "file"]).default("stdin"),
|
|
39
|
+
});
|
|
40
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IAChC,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACpC,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CACnC,CAAC,CAAC;AAIH,MAAM,oBAAoB,GAAG,CAAC,CAAC,MAAM,CAAC;IACpC,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;IACnC,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC;CACpE,CAAC,CAAC;AAEH;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC7C,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACvB,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1B,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC7B,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;IACrC,WAAW,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;IAC5C,GAAG,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;IACrC,aAAa,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;IAC9C,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC;IACnD,MAAM,EAAE,CAAC;SACN,IAAI,CAAC,CAAC,MAAM,EAAE,cAAc,EAAE,aAAa,EAAE,aAAa,EAAE,aAAa,CAAC,CAAC;SAC3E,OAAO,CAAC,MAAM,CAAC;IAClB,+BAA+B,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;IAC3D,iBAAiB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACxC,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;IAC7C,eAAe,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;IAC3C,YAAY,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;IACxC,eAAe,EAAE,oBAAoB,CAAC,OAAO,CAAC;QAC5C,OAAO,EAAE,KAAK;QACd,QAAQ,EAAE,WAAW;KACtB,CAAC;IACF,WAAW,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC;CAC/D,CAAC,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bounded LRU cache for continuation context.
|
|
3
|
+
*
|
|
4
|
+
* Stores the final output from previous runs, keyed by continuation_id.
|
|
5
|
+
* When capacity is reached, the least-recently-used entry is evicted.
|
|
6
|
+
*/
|
|
7
|
+
export declare class ContinuationCache {
|
|
8
|
+
private readonly maxEntries;
|
|
9
|
+
private readonly cache;
|
|
10
|
+
constructor(maxEntries?: number);
|
|
11
|
+
get(key: string): string | undefined;
|
|
12
|
+
set(key: string, value: string): void;
|
|
13
|
+
get size(): number;
|
|
14
|
+
clear(): void;
|
|
15
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
const DEFAULT_MAX_ENTRIES = 50;
|
|
2
|
+
/**
|
|
3
|
+
* Bounded LRU cache for continuation context.
|
|
4
|
+
*
|
|
5
|
+
* Stores the final output from previous runs, keyed by continuation_id.
|
|
6
|
+
* When capacity is reached, the least-recently-used entry is evicted.
|
|
7
|
+
*/
|
|
8
|
+
export class ContinuationCache {
|
|
9
|
+
maxEntries;
|
|
10
|
+
cache = new Map();
|
|
11
|
+
constructor(maxEntries = DEFAULT_MAX_ENTRIES) {
|
|
12
|
+
this.maxEntries = maxEntries;
|
|
13
|
+
}
|
|
14
|
+
get(key) {
|
|
15
|
+
const value = this.cache.get(key);
|
|
16
|
+
if (value != null) {
|
|
17
|
+
// Move to end (most recently used)
|
|
18
|
+
this.cache.delete(key);
|
|
19
|
+
this.cache.set(key, value);
|
|
20
|
+
}
|
|
21
|
+
return value;
|
|
22
|
+
}
|
|
23
|
+
set(key, value) {
|
|
24
|
+
if (this.cache.has(key)) {
|
|
25
|
+
this.cache.delete(key);
|
|
26
|
+
}
|
|
27
|
+
if (this.cache.size >= this.maxEntries) {
|
|
28
|
+
const oldest = this.cache.keys().next();
|
|
29
|
+
if (!oldest.done) {
|
|
30
|
+
this.cache.delete(oldest.value);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
this.cache.set(key, value);
|
|
34
|
+
}
|
|
35
|
+
get size() {
|
|
36
|
+
return this.cache.size;
|
|
37
|
+
}
|
|
38
|
+
clear() {
|
|
39
|
+
this.cache.clear();
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=continuation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"continuation.js","sourceRoot":"","sources":["../src/continuation.ts"],"names":[],"mappings":"AAAA,MAAM,mBAAmB,GAAG,EAAE,CAAC;AAE/B;;;;;GAKG;AACH,MAAM,OAAO,iBAAiB;IACX,UAAU,CAAS;IACnB,KAAK,GAAG,IAAI,GAAG,EAAkB,CAAC;IAEnD,YAAY,UAAU,GAAG,mBAAmB;QAC1C,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IAC/B,CAAC;IAED,GAAG,CAAC,GAAW;QACb,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAClC,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;YAClB,mCAAmC;YACnC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACvB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAC7B,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,GAAG,CAAC,GAAW,EAAE,KAAa;QAC5B,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YACxB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACzB,CAAC;QACD,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACvC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC;YACxC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;gBACjB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAClC,CAAC;QACH,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAC7B,CAAC;IAED,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;IACzB,CAAC;IAED,KAAK;QACH,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;CACF"}
|
package/dist/env.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { CliAdapterConfig } from "./config.js";
|
|
2
|
+
/**
|
|
3
|
+
* Build a sanitized environment for subprocess execution.
|
|
4
|
+
*
|
|
5
|
+
* Starts from minimal baseline (PATH/HOME/USER/LANG/TMPDIR),
|
|
6
|
+
* adds adapter-defined env, then allowlisted vars from host process.
|
|
7
|
+
*/
|
|
8
|
+
export declare function buildEnv(adapter: CliAdapterConfig, extraEnv?: Record<string, string>): Record<string, string>;
|
|
9
|
+
/** Redact env values that look like secrets (for logging). */
|
|
10
|
+
export declare function redactSecrets(env: Record<string, string>): Record<string, string>;
|
package/dist/env.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
const BASELINE_VARS = ["PATH", "HOME", "USER", "LANG", "TMPDIR"];
|
|
2
|
+
const SECRET_PATTERNS = [
|
|
3
|
+
/KEY/i,
|
|
4
|
+
/SECRET/i,
|
|
5
|
+
/TOKEN/i,
|
|
6
|
+
/PASSWORD/i,
|
|
7
|
+
/CREDENTIAL/i,
|
|
8
|
+
];
|
|
9
|
+
/**
|
|
10
|
+
* Build a sanitized environment for subprocess execution.
|
|
11
|
+
*
|
|
12
|
+
* Starts from minimal baseline (PATH/HOME/USER/LANG/TMPDIR),
|
|
13
|
+
* adds adapter-defined env, then allowlisted vars from host process.
|
|
14
|
+
*/
|
|
15
|
+
export function buildEnv(adapter, extraEnv) {
|
|
16
|
+
const env = {};
|
|
17
|
+
// 1. Baseline vars from current process
|
|
18
|
+
for (const key of BASELINE_VARS) {
|
|
19
|
+
const val = process.env[key];
|
|
20
|
+
if (val != null) {
|
|
21
|
+
env[key] = val;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
// 2. Adapter-defined env
|
|
25
|
+
for (const [key, val] of Object.entries(adapter.env)) {
|
|
26
|
+
env[key] = val;
|
|
27
|
+
}
|
|
28
|
+
// 3. Allowlisted vars from current process
|
|
29
|
+
for (const key of adapter.env_allowlist) {
|
|
30
|
+
const val = process.env[key];
|
|
31
|
+
if (val != null) {
|
|
32
|
+
env[key] = val;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
// 4. Extra env (e.g., run-dir path)
|
|
36
|
+
if (extraEnv) {
|
|
37
|
+
for (const [key, val] of Object.entries(extraEnv)) {
|
|
38
|
+
env[key] = val;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return env;
|
|
42
|
+
}
|
|
43
|
+
/** Redact env values that look like secrets (for logging). */
|
|
44
|
+
export function redactSecrets(env) {
|
|
45
|
+
const redacted = {};
|
|
46
|
+
for (const [key, val] of Object.entries(env)) {
|
|
47
|
+
const isSecret = SECRET_PATTERNS.some((p) => p.test(key));
|
|
48
|
+
redacted[key] = isSecret ? "[REDACTED]" : val;
|
|
49
|
+
}
|
|
50
|
+
return redacted;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=env.js.map
|
package/dist/env.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.js","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AAEA,MAAM,aAAa,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;AAEjE,MAAM,eAAe,GAAG;IACtB,MAAM;IACN,SAAS;IACT,QAAQ;IACR,WAAW;IACX,aAAa;CACd,CAAC;AAEF;;;;;GAKG;AACH,MAAM,UAAU,QAAQ,CACtB,OAAyB,EACzB,QAAiC;IAEjC,MAAM,GAAG,GAA2B,EAAE,CAAC;IAEvC,wCAAwC;IACxC,KAAK,MAAM,GAAG,IAAI,aAAa,EAAE,CAAC;QAChC,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC7B,IAAI,GAAG,IAAI,IAAI,EAAE,CAAC;YAChB,GAAG,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;QACjB,CAAC;IACH,CAAC;IAED,yBAAyB;IACzB,KAAK,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACrD,GAAG,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;IACjB,CAAC;IAED,2CAA2C;IAC3C,KAAK,MAAM,GAAG,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC;QACxC,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC7B,IAAI,GAAG,IAAI,IAAI,EAAE,CAAC;YAChB,GAAG,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;QACjB,CAAC;IACH,CAAC;IAED,oCAAoC;IACpC,IAAI,QAAQ,EAAE,CAAC;QACb,KAAK,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;YAClD,GAAG,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;QACjB,CAAC;IACH,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC;AAED,8DAA8D;AAC9D,MAAM,UAAU,aAAa,CAC3B,GAA2B;IAE3B,MAAM,QAAQ,GAA2B,EAAE,CAAC;IAC5C,KAAK,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QAC7C,MAAM,QAAQ,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;QAC1D,QAAQ,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC;IAChD,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { McpError } from "@modelcontextprotocol/sdk/types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Base error for all ClinkX-specific failures.
|
|
4
|
+
*/
|
|
5
|
+
export declare class ClinkxError extends Error {
|
|
6
|
+
constructor(message: string);
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Invalid parameters — maps to JSON-RPC -32602.
|
|
10
|
+
*
|
|
11
|
+
* Thrown for protocol-level input errors (bad schema, unknown cli_name, etc.).
|
|
12
|
+
* The MCP SDK's McpError with ErrorCode.InvalidParams handles the wire encoding.
|
|
13
|
+
*/
|
|
14
|
+
export declare class InvalidParamsError extends ClinkxError {
|
|
15
|
+
constructor(message: string);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Execution failure — maps to tool response with isError:true.
|
|
19
|
+
*
|
|
20
|
+
* Used for runtime failures (CLI not found, timeout, non-zero exit, etc.).
|
|
21
|
+
* These are NOT JSON-RPC errors; they are valid tool responses that signal failure.
|
|
22
|
+
*/
|
|
23
|
+
export declare class ExecutionError extends ClinkxError {
|
|
24
|
+
constructor(message: string);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Convert an InvalidParamsError to an MCP SDK McpError (-32602).
|
|
28
|
+
*
|
|
29
|
+
* The SDK will serialize this as a proper JSON-RPC error response.
|
|
30
|
+
*/
|
|
31
|
+
export declare function toMcpInvalidParams(err: InvalidParamsError): McpError;
|
|
32
|
+
/**
|
|
33
|
+
* Build an MCP tool result indicating execution failure.
|
|
34
|
+
*
|
|
35
|
+
* Returns { content: [{ type: "text", text }], isError: true }.
|
|
36
|
+
* This is the correct MCP response shape for runtime failures:
|
|
37
|
+
* the tool executed, but produced an error result.
|
|
38
|
+
*/
|
|
39
|
+
export declare function toMcpExecutionError(err: ExecutionError): {
|
|
40
|
+
content: Array<{
|
|
41
|
+
type: "text";
|
|
42
|
+
text: string;
|
|
43
|
+
}>;
|
|
44
|
+
isError: true;
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Cancellation — request was cancelled via MCP notifications/cancelled.
|
|
48
|
+
*
|
|
49
|
+
* Per MCP spec: "The receiver MUST NOT send a response to the request."
|
|
50
|
+
* When this is thrown, the caller should NOT produce any response.
|
|
51
|
+
*/
|
|
52
|
+
export declare class CancellationError extends ClinkxError {
|
|
53
|
+
constructor();
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Classify an unknown error and produce the appropriate MCP response.
|
|
57
|
+
*
|
|
58
|
+
* - InvalidParamsError → throw McpError (JSON-RPC -32602)
|
|
59
|
+
* - ExecutionError → return { isError: true } tool result
|
|
60
|
+
* - Unknown → return { isError: true } tool result with generic message
|
|
61
|
+
*/
|
|
62
|
+
export declare function handleToolError(err: unknown): {
|
|
63
|
+
content: Array<{
|
|
64
|
+
type: "text";
|
|
65
|
+
text: string;
|
|
66
|
+
}>;
|
|
67
|
+
isError: true;
|
|
68
|
+
};
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { McpError, ErrorCode } from "@modelcontextprotocol/sdk/types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Base error for all ClinkX-specific failures.
|
|
4
|
+
*/
|
|
5
|
+
export class ClinkxError extends Error {
|
|
6
|
+
constructor(message) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.name = "ClinkxError";
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Invalid parameters — maps to JSON-RPC -32602.
|
|
13
|
+
*
|
|
14
|
+
* Thrown for protocol-level input errors (bad schema, unknown cli_name, etc.).
|
|
15
|
+
* The MCP SDK's McpError with ErrorCode.InvalidParams handles the wire encoding.
|
|
16
|
+
*/
|
|
17
|
+
export class InvalidParamsError extends ClinkxError {
|
|
18
|
+
constructor(message) {
|
|
19
|
+
super(message);
|
|
20
|
+
this.name = "InvalidParamsError";
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Execution failure — maps to tool response with isError:true.
|
|
25
|
+
*
|
|
26
|
+
* Used for runtime failures (CLI not found, timeout, non-zero exit, etc.).
|
|
27
|
+
* These are NOT JSON-RPC errors; they are valid tool responses that signal failure.
|
|
28
|
+
*/
|
|
29
|
+
export class ExecutionError extends ClinkxError {
|
|
30
|
+
constructor(message) {
|
|
31
|
+
super(message);
|
|
32
|
+
this.name = "ExecutionError";
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Convert an InvalidParamsError to an MCP SDK McpError (-32602).
|
|
37
|
+
*
|
|
38
|
+
* The SDK will serialize this as a proper JSON-RPC error response.
|
|
39
|
+
*/
|
|
40
|
+
export function toMcpInvalidParams(err) {
|
|
41
|
+
return new McpError(ErrorCode.InvalidParams, err.message);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Build an MCP tool result indicating execution failure.
|
|
45
|
+
*
|
|
46
|
+
* Returns { content: [{ type: "text", text }], isError: true }.
|
|
47
|
+
* This is the correct MCP response shape for runtime failures:
|
|
48
|
+
* the tool executed, but produced an error result.
|
|
49
|
+
*/
|
|
50
|
+
export function toMcpExecutionError(err) {
|
|
51
|
+
return {
|
|
52
|
+
content: [{ type: "text", text: err.message }],
|
|
53
|
+
isError: true,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Cancellation — request was cancelled via MCP notifications/cancelled.
|
|
58
|
+
*
|
|
59
|
+
* Per MCP spec: "The receiver MUST NOT send a response to the request."
|
|
60
|
+
* When this is thrown, the caller should NOT produce any response.
|
|
61
|
+
*/
|
|
62
|
+
export class CancellationError extends ClinkxError {
|
|
63
|
+
constructor() {
|
|
64
|
+
super("Request cancelled");
|
|
65
|
+
this.name = "CancellationError";
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Classify an unknown error and produce the appropriate MCP response.
|
|
70
|
+
*
|
|
71
|
+
* - InvalidParamsError → throw McpError (JSON-RPC -32602)
|
|
72
|
+
* - ExecutionError → return { isError: true } tool result
|
|
73
|
+
* - Unknown → return { isError: true } tool result with generic message
|
|
74
|
+
*/
|
|
75
|
+
export function handleToolError(err) {
|
|
76
|
+
if (err instanceof InvalidParamsError) {
|
|
77
|
+
throw toMcpInvalidParams(err);
|
|
78
|
+
}
|
|
79
|
+
if (err instanceof ExecutionError) {
|
|
80
|
+
return toMcpExecutionError(err);
|
|
81
|
+
}
|
|
82
|
+
const message = err instanceof Error ? err.message : "Unknown execution error";
|
|
83
|
+
return {
|
|
84
|
+
content: [{ type: "text", text: message }],
|
|
85
|
+
isError: true,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,oCAAoC,CAAC;AAEzE;;GAEG;AACH,MAAM,OAAO,WAAY,SAAQ,KAAK;IACpC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,aAAa,CAAC;IAC5B,CAAC;CACF;AAED;;;;;GAKG;AACH,MAAM,OAAO,kBAAmB,SAAQ,WAAW;IACjD,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;IACnC,CAAC;CACF;AAED;;;;;GAKG;AACH,MAAM,OAAO,cAAe,SAAQ,WAAW;IAC7C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;IAC/B,CAAC;CACF;AAED;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAuB;IACxD,OAAO,IAAI,QAAQ,CAAC,SAAS,CAAC,aAAa,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;AAC5D,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,mBAAmB,CAAC,GAAmB;IAIrD,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC;QAC9C,OAAO,EAAE,IAAI;KACd,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,OAAO,iBAAkB,SAAQ,WAAW;IAChD;QACE,KAAK,CAAC,mBAAmB,CAAC,CAAC;QAC3B,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;IAClC,CAAC;CACF;AAED;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAAC,GAAY;IAI1C,IAAI,GAAG,YAAY,kBAAkB,EAAE,CAAC;QACtC,MAAM,kBAAkB,CAAC,GAAG,CAAC,CAAC;IAChC,CAAC;IACD,IAAI,GAAG,YAAY,cAAc,EAAE,CAAC;QAClC,OAAO,mBAAmB,CAAC,GAAG,CAAC,CAAC;IAClC,CAAC;IACD,MAAM,OAAO,GACX,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,yBAAyB,CAAC;IACjE,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;QAC1C,OAAO,EAAE,IAAI;KACd,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Handle a clink tool invocation.
|
|
4
|
+
*
|
|
5
|
+
* 1. Validate input against the frozen zod schema.
|
|
6
|
+
* 2. On validation failure: throw InvalidParamsError (→ -32602).
|
|
7
|
+
* 3. Execute the full pipeline: resolve → prompt → exec → parse → return.
|
|
8
|
+
*/
|
|
9
|
+
export declare function handleClink(rawInput: unknown, options?: {
|
|
10
|
+
signal?: AbortSignal;
|
|
11
|
+
progress?: {
|
|
12
|
+
server: Server;
|
|
13
|
+
token: string | number;
|
|
14
|
+
};
|
|
15
|
+
}): Promise<{
|
|
16
|
+
content: Array<{
|
|
17
|
+
type: "text";
|
|
18
|
+
text: string;
|
|
19
|
+
}>;
|
|
20
|
+
isError?: boolean;
|
|
21
|
+
}>;
|
package/dist/handler.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { ClinkInputSchema } from "./schema.js";
|
|
2
|
+
import { InvalidParamsError } from "./errors.js";
|
|
3
|
+
import { executePipeline } from "./pipeline.js";
|
|
4
|
+
import { AdapterRegistry } from "./registry.js";
|
|
5
|
+
import { logger } from "./logger.js";
|
|
6
|
+
function formatZodError(err) {
|
|
7
|
+
return err.issues
|
|
8
|
+
.map((issue) => {
|
|
9
|
+
const path = issue.path.length > 0 ? issue.path.join(".") : "(root)";
|
|
10
|
+
return `${path}: ${issue.message}`;
|
|
11
|
+
})
|
|
12
|
+
.join("; ");
|
|
13
|
+
}
|
|
14
|
+
// Lazy-loaded singleton registry
|
|
15
|
+
let registry;
|
|
16
|
+
function getRegistry() {
|
|
17
|
+
if (!registry) {
|
|
18
|
+
registry = AdapterRegistry.load();
|
|
19
|
+
}
|
|
20
|
+
return registry;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Handle a clink tool invocation.
|
|
24
|
+
*
|
|
25
|
+
* 1. Validate input against the frozen zod schema.
|
|
26
|
+
* 2. On validation failure: throw InvalidParamsError (→ -32602).
|
|
27
|
+
* 3. Execute the full pipeline: resolve → prompt → exec → parse → return.
|
|
28
|
+
*/
|
|
29
|
+
export async function handleClink(rawInput, options) {
|
|
30
|
+
const parseResult = ClinkInputSchema.safeParse(rawInput);
|
|
31
|
+
if (!parseResult.success) {
|
|
32
|
+
const detail = formatZodError(parseResult.error);
|
|
33
|
+
throw new InvalidParamsError(`Invalid clink input: ${detail}`);
|
|
34
|
+
}
|
|
35
|
+
const input = parseResult.data;
|
|
36
|
+
logger.debug({ cli_name: input.cli_name, role: input.role }, "clink invoked");
|
|
37
|
+
const pipelineOptions = options?.signal != null || options?.progress != null
|
|
38
|
+
? {
|
|
39
|
+
...(options?.signal != null ? { signal: options.signal } : {}),
|
|
40
|
+
...(options?.progress != null ? { progress: options.progress } : {}),
|
|
41
|
+
}
|
|
42
|
+
: undefined;
|
|
43
|
+
return await executePipeline(input, getRegistry(), pipelineOptions);
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handler.js","sourceRoot":"","sources":["../src/handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAIrC,SAAS,cAAc,CAAC,GAAa;IACnC,OAAO,GAAG,CAAC,MAAM;SACd,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;QACb,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;QACrE,OAAO,GAAG,IAAI,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC;IACrC,CAAC,CAAC;SACD,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED,iCAAiC;AACjC,IAAI,QAAqC,CAAC;AAE1C,SAAS,WAAW;IAClB,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,QAAQ,GAAG,eAAe,CAAC,IAAI,EAAE,CAAC;IACpC,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,QAAiB,EACjB,OAGC;IAKD,MAAM,WAAW,GAAG,gBAAgB,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IACzD,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC;QACzB,MAAM,MAAM,GAAG,cAAc,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;QACjD,MAAM,IAAI,kBAAkB,CAAC,wBAAwB,MAAM,EAAE,CAAC,CAAC;IACjE,CAAC;IAED,MAAM,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC;IAC/B,MAAM,CAAC,KAAK,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,EAAE,eAAe,CAAC,CAAC;IAE9E,MAAM,eAAe,GACnB,OAAO,EAAE,MAAM,IAAI,IAAI,IAAI,OAAO,EAAE,QAAQ,IAAI,IAAI;QAClD,CAAC,CAAC;YACE,GAAG,CAAC,OAAO,EAAE,MAAM,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC9D,GAAG,CAAC,OAAO,EAAE,QAAQ,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACrE;QACH,CAAC,CAAC,SAAS,CAAC;IAChB,OAAO,MAAM,eAAe,CAAC,KAAK,EAAE,WAAW,EAAE,EAAE,eAAe,CAAC,CAAC;AACtE,CAAC"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
+
import { createServer } from "./server.js";
|
|
4
|
+
import { logger, assertStderrLogger } from "./logger.js";
|
|
5
|
+
import { assertNotRootDir } from "./paths.js";
|
|
6
|
+
import { killAllActive } from "./runner.js";
|
|
7
|
+
/**
|
|
8
|
+
* ClinkX MCP server entry point.
|
|
9
|
+
*
|
|
10
|
+
* 1. Verify logger writes to stderr (STDIO correctness invariant).
|
|
11
|
+
* 2. Create the MCP server with tool handlers.
|
|
12
|
+
* 3. Connect STDIO transport (stdin/stdout for JSON-RPC, stderr for logs).
|
|
13
|
+
*/
|
|
14
|
+
async function main() {
|
|
15
|
+
// Startup self-check: logger must target stderr
|
|
16
|
+
assertStderrLogger();
|
|
17
|
+
// Startup safety guard: refuse running from filesystem root unless explicitly allowlisted
|
|
18
|
+
assertNotRootDir();
|
|
19
|
+
const server = createServer();
|
|
20
|
+
const transport = new StdioServerTransport();
|
|
21
|
+
logger.info("ClinkX MCP server starting (STDIO transport)");
|
|
22
|
+
await server.connect(transport);
|
|
23
|
+
// Graceful shutdown: kill active subprocesses, close server, exit
|
|
24
|
+
const shutdown = async () => {
|
|
25
|
+
logger.info("shutdown signal received, cleaning up");
|
|
26
|
+
killAllActive();
|
|
27
|
+
await server.close();
|
|
28
|
+
process.exit(0);
|
|
29
|
+
};
|
|
30
|
+
process.once("SIGTERM", () => void shutdown().catch(() => process.exit(1)));
|
|
31
|
+
process.once("SIGINT", () => void shutdown().catch(() => process.exit(1)));
|
|
32
|
+
logger.info("ClinkX MCP server connected and ready");
|
|
33
|
+
}
|
|
34
|
+
main().catch((err) => {
|
|
35
|
+
logger.fatal({ err }, "ClinkX failed to start");
|
|
36
|
+
process.exitCode = 1;
|
|
37
|
+
});
|
|
38
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,MAAM,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C;;;;;;GAMG;AACH,KAAK,UAAU,IAAI;IACjB,gDAAgD;IAChD,kBAAkB,EAAE,CAAC;IACrB,0FAA0F;IAC1F,gBAAgB,EAAE,CAAC;IAEnB,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;IAC9B,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAE7C,MAAM,CAAC,IAAI,CAAC,8CAA8C,CAAC,CAAC;IAE5D,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAEhC,kEAAkE;IAClE,MAAM,QAAQ,GAAG,KAAK,IAAI,EAAE;QAC1B,MAAM,CAAC,IAAI,CAAC,uCAAuC,CAAC,CAAC;QACrD,aAAa,EAAE,CAAC;QAChB,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;QACrB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC;IACF,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,KAAK,QAAQ,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5E,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,KAAK,QAAQ,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAE3E,MAAM,CAAC,IAAI,CAAC,uCAAuC,CAAC,CAAC;AACvD,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;IAC5B,MAAM,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,EAAE,wBAAwB,CAAC,CAAC;IAChD,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC,CAAC,CAAC"}
|
package/dist/logger.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import pino from "pino";
|
|
2
|
+
/**
|
|
3
|
+
* ClinkX logger — writes exclusively to stderr (fd 2).
|
|
4
|
+
*
|
|
5
|
+
* STDIO correctness is a hard invariant: stdout is reserved for
|
|
6
|
+
* MCP JSON-RPC frames. All diagnostic output goes to stderr.
|
|
7
|
+
*/
|
|
8
|
+
export declare const logger: pino.Logger<never, boolean>;
|
|
9
|
+
/**
|
|
10
|
+
* Startup self-check: verify logger writes to stderr, not stdout.
|
|
11
|
+
* Fails fast if the invariant is violated.
|
|
12
|
+
*
|
|
13
|
+
* We inspect the pino SonicBoom destination's `fd` property
|
|
14
|
+
* to confirm it points at fd 2 (stderr).
|
|
15
|
+
*/
|
|
16
|
+
export declare function assertStderrLogger(): void;
|
package/dist/logger.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import pino from "pino";
|
|
2
|
+
const LOG_LEVEL = process.env["CLINKX_LOG_LEVEL"] ?? "info";
|
|
3
|
+
// Construct the stderr destination explicitly so we can inspect it.
|
|
4
|
+
const stderrDestination = pino.destination({ fd: 2, sync: false });
|
|
5
|
+
/**
|
|
6
|
+
* ClinkX logger — writes exclusively to stderr (fd 2).
|
|
7
|
+
*
|
|
8
|
+
* STDIO correctness is a hard invariant: stdout is reserved for
|
|
9
|
+
* MCP JSON-RPC frames. All diagnostic output goes to stderr.
|
|
10
|
+
*/
|
|
11
|
+
export const logger = pino({
|
|
12
|
+
name: "clinkx",
|
|
13
|
+
level: LOG_LEVEL,
|
|
14
|
+
}, stderrDestination);
|
|
15
|
+
/**
|
|
16
|
+
* Startup self-check: verify logger writes to stderr, not stdout.
|
|
17
|
+
* Fails fast if the invariant is violated.
|
|
18
|
+
*
|
|
19
|
+
* We inspect the pino SonicBoom destination's `fd` property
|
|
20
|
+
* to confirm it points at fd 2 (stderr).
|
|
21
|
+
*/
|
|
22
|
+
export function assertStderrLogger() {
|
|
23
|
+
const dest = stderrDestination;
|
|
24
|
+
const fd = dest.fd;
|
|
25
|
+
if (fd !== 2) {
|
|
26
|
+
throw new Error(`FATAL: logger destination fd=${String(fd)}, expected fd=2 (stderr). ` +
|
|
27
|
+
"STDIO correctness requires all logging to stderr.");
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,IAAI,MAAM,CAAC;AAE5D,oEAAoE;AACpE,MAAM,iBAAiB,GAAG,IAAI,CAAC,WAAW,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;AAEnE;;;;;GAKG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,IAAI,CACxB;IACE,IAAI,EAAE,QAAQ;IACd,KAAK,EAAE,SAAS;CACjB,EACD,iBAAiB,CAClB,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB;IAChC,MAAM,IAAI,GAAG,iBAA+C,CAAC;IAC7D,MAAM,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC;IACnB,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CACb,gCAAgC,MAAM,CAAC,EAAE,CAAC,4BAA4B;YACpE,mDAAmD,CACtD,CAAC;IACJ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { findFirstJsonBlock, preferredText } from "./utils.js";
|
|
2
|
+
function parseMaybeJson(text) {
|
|
3
|
+
const trimmed = text.trim();
|
|
4
|
+
if (trimmed.length === 0)
|
|
5
|
+
return null;
|
|
6
|
+
try {
|
|
7
|
+
return JSON.parse(trimmed);
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
const block = findFirstJsonBlock(text);
|
|
11
|
+
return block?.value ?? null;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
function extractClaudeResultText(value) {
|
|
15
|
+
if (value == null || typeof value !== "object")
|
|
16
|
+
return null;
|
|
17
|
+
const root = value;
|
|
18
|
+
const result = root["result"];
|
|
19
|
+
if (typeof result === "string")
|
|
20
|
+
return result;
|
|
21
|
+
if (Array.isArray(result)) {
|
|
22
|
+
const texts = result
|
|
23
|
+
.map((item) => {
|
|
24
|
+
if (typeof item === "string")
|
|
25
|
+
return item;
|
|
26
|
+
if (item && typeof item === "object") {
|
|
27
|
+
const r = item;
|
|
28
|
+
if (typeof r["text"] === "string")
|
|
29
|
+
return r["text"];
|
|
30
|
+
if (typeof r["content"] === "string")
|
|
31
|
+
return r["content"];
|
|
32
|
+
}
|
|
33
|
+
return "";
|
|
34
|
+
})
|
|
35
|
+
.filter((t) => t.length > 0);
|
|
36
|
+
return texts.length > 0 ? texts.join("") : null;
|
|
37
|
+
}
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
export const claudeJsonParser = {
|
|
41
|
+
name: "claude_json",
|
|
42
|
+
preferredBuffers: ["stdoutHead", "stdoutTail"],
|
|
43
|
+
parse(input) {
|
|
44
|
+
const text = preferredText(input, ["stdoutHead", "stdoutTail"]);
|
|
45
|
+
const parsed = parseMaybeJson(text);
|
|
46
|
+
if (parsed == null)
|
|
47
|
+
return null;
|
|
48
|
+
const extracted = extractClaudeResultText(parsed);
|
|
49
|
+
if (extracted == null)
|
|
50
|
+
return null;
|
|
51
|
+
return {
|
|
52
|
+
content: extracted,
|
|
53
|
+
source: "parser",
|
|
54
|
+
metadata: { parser: "claude_json" },
|
|
55
|
+
};
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
//# sourceMappingURL=claude-json.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-json.js","sourceRoot":"","sources":["../../src/parsers/claude-json.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE/D,SAAS,cAAc,CAAC,IAAY;IAClC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAC5B,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACtC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAY,CAAC;IACxC,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,KAAK,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC;QACvC,OAAO,KAAK,EAAE,KAAK,IAAI,IAAI,CAAC;IAC9B,CAAC;AACH,CAAC;AAED,SAAS,uBAAuB,CAAC,KAAc;IAC7C,IAAI,KAAK,IAAI,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IAC5D,MAAM,IAAI,GAAG,KAAgC,CAAC;IAC9C,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;IAE9B,IAAI,OAAO,MAAM,KAAK,QAAQ;QAAE,OAAO,MAAM,CAAC;IAE9C,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAC1B,MAAM,KAAK,GAAG,MAAM;aACjB,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;YACZ,IAAI,OAAO,IAAI,KAAK,QAAQ;gBAAE,OAAO,IAAI,CAAC;YAC1C,IAAI,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACrC,MAAM,CAAC,GAAG,IAA+B,CAAC;gBAC1C,IAAI,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,QAAQ;oBAAE,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC;gBACpD,IAAI,OAAO,CAAC,CAAC,SAAS,CAAC,KAAK,QAAQ;oBAAE,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC;YAC5D,CAAC;YACD,OAAO,EAAE,CAAC;QACZ,CAAC,CAAC;aACD,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAC/B,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAClD,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,CAAC,MAAM,gBAAgB,GAAW;IACtC,IAAI,EAAE,aAAa;IACnB,gBAAgB,EAAE,CAAC,YAAY,EAAE,YAAY,CAAC;IAC9C,KAAK,CAAC,KAAK;QACT,MAAM,IAAI,GAAG,aAAa,CAAC,KAAK,EAAE,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC,CAAC;QAChE,MAAM,MAAM,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;QACpC,IAAI,MAAM,IAAI,IAAI;YAAE,OAAO,IAAI,CAAC;QAEhC,MAAM,SAAS,GAAG,uBAAuB,CAAC,MAAM,CAAC,CAAC;QAClD,IAAI,SAAS,IAAI,IAAI;YAAE,OAAO,IAAI,CAAC;QAEnC,OAAO;YACL,OAAO,EAAE,SAAS;YAClB,MAAM,EAAE,QAAQ;YAChB,QAAQ,EAAE,EAAE,MAAM,EAAE,aAAa,EAAE;SACpC,CAAC;IACJ,CAAC;CACF,CAAC"}
|