@exaudeus/workrail 3.32.0 → 3.34.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/dist/cli/commands/index.d.ts +1 -0
- package/dist/cli/commands/index.js +3 -1
- package/dist/cli/commands/worktrain-await.js +11 -9
- package/dist/cli/commands/worktrain-daemon-install.d.ts +35 -0
- package/dist/cli/commands/worktrain-daemon-install.js +291 -0
- package/dist/cli/commands/worktrain-daemon.d.ts +31 -0
- package/dist/cli/commands/worktrain-daemon.js +272 -0
- package/dist/cli/commands/worktrain-spawn.js +11 -9
- package/dist/cli-worktrain.js +488 -0
- package/dist/cli.js +1 -22
- package/dist/console/standalone-console.d.ts +28 -0
- package/dist/console/standalone-console.js +142 -0
- package/dist/{console/assets/index-Cb_LO718.js → console-ui/assets/index-C1JXnwZS.js} +1 -1
- package/dist/{console → console-ui}/index.html +1 -1
- package/dist/daemon/agent-loop.d.ts +27 -0
- package/dist/daemon/agent-loop.js +39 -1
- package/dist/daemon/daemon-events.d.ts +63 -1
- package/dist/daemon/workflow-runner.d.ts +3 -2
- package/dist/daemon/workflow-runner.js +285 -46
- package/dist/infrastructure/session/HttpServer.js +133 -34
- package/dist/manifest.json +136 -104
- package/dist/mcp/handlers/v2-error-mapping.d.ts +3 -0
- package/dist/mcp/handlers/v2-error-mapping.js +2 -0
- package/dist/mcp/handlers/v2-execution/advance.js +25 -0
- package/dist/mcp/handlers/v2-execution/continue-advance.js +7 -0
- package/dist/mcp/output-schemas.d.ts +30 -30
- package/dist/mcp/transports/fatal-exit.js +4 -0
- package/dist/mcp/transports/http-entry.js +0 -5
- package/dist/mcp/transports/stdio-entry.js +24 -12
- package/dist/mcp/v2/tools.d.ts +4 -4
- package/dist/mcp-server.d.ts +0 -2
- package/dist/mcp-server.js +1 -42
- package/dist/trigger/adapters/github-poller.d.ts +44 -0
- package/dist/trigger/adapters/github-poller.js +190 -0
- package/dist/trigger/adapters/gitlab-poller.d.ts +27 -0
- package/dist/trigger/adapters/gitlab-poller.js +81 -0
- package/dist/trigger/index.d.ts +4 -1
- package/dist/trigger/index.js +5 -1
- package/dist/trigger/polled-event-store.d.ts +22 -0
- package/dist/trigger/polled-event-store.js +173 -0
- package/dist/trigger/polling-scheduler.d.ts +20 -0
- package/dist/trigger/polling-scheduler.js +249 -0
- package/dist/trigger/trigger-listener.d.ts +3 -0
- package/dist/trigger/trigger-listener.js +47 -3
- package/dist/trigger/trigger-store.js +114 -33
- package/dist/trigger/types.d.ts +17 -1
- package/dist/v2/durable-core/domain/observation-builder.d.ts +3 -0
- package/dist/v2/durable-core/domain/observation-builder.js +2 -2
- package/dist/v2/durable-core/domain/prompt-renderer.d.ts +2 -1
- package/dist/v2/durable-core/domain/prompt-renderer.js +10 -0
- package/dist/v2/durable-core/schemas/export-bundle/index.d.ts +224 -224
- package/dist/v2/durable-core/schemas/session/events.d.ts +42 -42
- package/dist/v2/durable-core/schemas/session/manifest.d.ts +6 -6
- package/dist/v2/durable-core/schemas/session/validation-event.d.ts +2 -2
- package/dist/v2/durable-core/tokens/payloads.d.ts +52 -52
- package/dist/v2/usecases/console-routes.js +3 -3
- package/dist/v2/usecases/console-service.js +185 -10
- package/dist/v2/usecases/console-types.d.ts +8 -0
- package/docs/design/bridge-removal-pr-a-candidates.md +115 -0
- package/docs/design/bridge-removal-pr-a-design-review.md +79 -0
- package/docs/design/bridge-removal-pr-a-implementation-plan.md +203 -0
- package/docs/design/daemon-conversation-logging-plan.md +98 -0
- package/docs/design/daemon-conversation-logging-review.md +55 -0
- package/docs/design/daemon-conversation-logging.md +129 -0
- package/docs/design/github-polling-adapter-design-candidates.md +226 -0
- package/docs/design/github-polling-adapter-design-review-findings.md +131 -0
- package/docs/design/github-polling-adapter-implementation-plan.md +284 -0
- package/docs/design/implementation_plan.md +192 -0
- package/docs/design/workflow-id-validation-at-startup.md +146 -0
- package/docs/design/workflow-id-validation-design-review.md +87 -0
- package/docs/design/workflow-id-validation-implementation-plan.md +185 -0
- package/docs/design/worktrain-system-prompt-report-issue-candidates.md +135 -0
- package/docs/design/worktrain-system-prompt-report-issue-design-review.md +73 -0
- package/docs/discovery/design-candidates.md +180 -0
- package/docs/discovery/design-review-findings.md +110 -0
- package/docs/discovery/wr-discovery-goal-reframing.md +303 -0
- package/docs/ideas/backlog.md +627 -0
- package/package.json +1 -1
- package/workflows/architecture-scalability-audit.json +1 -1
- package/workflows/bug-investigation.agentic.v2.json +3 -3
- package/workflows/coding-task-workflow-agentic.json +32 -32
- package/workflows/coding-task-workflow-agentic.lean.v2.json +1 -1
- package/workflows/coding-task-workflow-agentic.v2.json +7 -7
- package/workflows/mr-review-workflow.agentic.v2.json +21 -12
- package/workflows/personal-learning-materials-creation-branched.json +2 -2
- package/workflows/production-readiness-audit.json +1 -1
- package/workflows/relocation-workflow-us.json +2 -2
- package/workflows/ui-ux-design-workflow.json +14 -14
- package/workflows/workflow-for-workflows.json +3 -3
- package/workflows/workflow-for-workflows.v2.json +2 -2
- package/workflows/wr.discovery.json +59 -8
- package/dist/mcp/transports/bridge-entry.d.ts +0 -102
- package/dist/mcp/transports/bridge-entry.js +0 -454
- package/dist/mcp/transports/bridge-events.d.ts +0 -51
- package/dist/mcp/transports/bridge-events.js +0 -24
- package/dist/mcp/transports/primary-tombstone.d.ts +0 -21
- package/dist/mcp/transports/primary-tombstone.js +0 -51
- /package/dist/{console → console-ui}/assets/index-8dh0Psu-.css +0 -0
|
@@ -63,12 +63,12 @@ export declare const WorkflowNextOutputSchema: z.ZodObject<{
|
|
|
63
63
|
next: z.ZodNullable<z.ZodType<JsonValue, z.ZodTypeDef, JsonValue>>;
|
|
64
64
|
isComplete: z.ZodBoolean;
|
|
65
65
|
}, "strip", z.ZodTypeAny, {
|
|
66
|
-
state: import("../domain/execution/state.js").ExecutionState;
|
|
67
66
|
isComplete: boolean;
|
|
67
|
+
state: import("../domain/execution/state.js").ExecutionState;
|
|
68
68
|
next: JsonValue;
|
|
69
69
|
}, {
|
|
70
|
-
state: import("../domain/execution/state.js").ExecutionState;
|
|
71
70
|
isComplete: boolean;
|
|
71
|
+
state: import("../domain/execution/state.js").ExecutionState;
|
|
72
72
|
next: JsonValue;
|
|
73
73
|
}>;
|
|
74
74
|
export declare const WorkflowValidateJsonOutputSchema: z.ZodObject<{
|
|
@@ -1123,22 +1123,22 @@ export declare const V2ResumeNextCallSchema: z.ZodObject<{
|
|
|
1123
1123
|
continueToken: z.ZodString;
|
|
1124
1124
|
intent: z.ZodLiteral<"rehydrate">;
|
|
1125
1125
|
}, "strip", z.ZodTypeAny, {
|
|
1126
|
-
continueToken: string;
|
|
1127
1126
|
intent: "rehydrate";
|
|
1128
|
-
}, {
|
|
1129
1127
|
continueToken: string;
|
|
1128
|
+
}, {
|
|
1130
1129
|
intent: "rehydrate";
|
|
1130
|
+
continueToken: string;
|
|
1131
1131
|
}>;
|
|
1132
1132
|
}, "strip", z.ZodTypeAny, {
|
|
1133
1133
|
params: {
|
|
1134
|
-
continueToken: string;
|
|
1135
1134
|
intent: "rehydrate";
|
|
1135
|
+
continueToken: string;
|
|
1136
1136
|
};
|
|
1137
1137
|
tool: "continue_workflow";
|
|
1138
1138
|
}, {
|
|
1139
1139
|
params: {
|
|
1140
|
-
continueToken: string;
|
|
1141
1140
|
intent: "rehydrate";
|
|
1141
|
+
continueToken: string;
|
|
1142
1142
|
};
|
|
1143
1143
|
tool: "continue_workflow";
|
|
1144
1144
|
}>;
|
|
@@ -2237,66 +2237,66 @@ export declare const V2ResumeSessionOutputSchema: z.ZodObject<{
|
|
|
2237
2237
|
continueToken: z.ZodString;
|
|
2238
2238
|
intent: z.ZodLiteral<"rehydrate">;
|
|
2239
2239
|
}, "strip", z.ZodTypeAny, {
|
|
2240
|
-
continueToken: string;
|
|
2241
2240
|
intent: "rehydrate";
|
|
2242
|
-
}, {
|
|
2243
2241
|
continueToken: string;
|
|
2242
|
+
}, {
|
|
2244
2243
|
intent: "rehydrate";
|
|
2244
|
+
continueToken: string;
|
|
2245
2245
|
}>;
|
|
2246
2246
|
}, "strip", z.ZodTypeAny, {
|
|
2247
2247
|
params: {
|
|
2248
|
-
continueToken: string;
|
|
2249
2248
|
intent: "rehydrate";
|
|
2249
|
+
continueToken: string;
|
|
2250
2250
|
};
|
|
2251
2251
|
tool: "continue_workflow";
|
|
2252
2252
|
}, {
|
|
2253
2253
|
params: {
|
|
2254
|
-
continueToken: string;
|
|
2255
2254
|
intent: "rehydrate";
|
|
2255
|
+
continueToken: string;
|
|
2256
2256
|
};
|
|
2257
2257
|
tool: "continue_workflow";
|
|
2258
2258
|
}>;
|
|
2259
2259
|
}, "strip", z.ZodTypeAny, {
|
|
2260
2260
|
confidence: "strong" | "weak" | "medium";
|
|
2261
2261
|
workflowId: string;
|
|
2262
|
-
runId: string;
|
|
2263
2262
|
sessionId: string;
|
|
2264
|
-
|
|
2263
|
+
runId: string;
|
|
2265
2264
|
isComplete: boolean;
|
|
2265
|
+
sessionTitle: string | null;
|
|
2266
|
+
gitBranch: string | null;
|
|
2267
|
+
lastModifiedMs: number | null;
|
|
2266
2268
|
nextCall: {
|
|
2267
2269
|
params: {
|
|
2268
|
-
continueToken: string;
|
|
2269
2270
|
intent: "rehydrate";
|
|
2271
|
+
continueToken: string;
|
|
2270
2272
|
};
|
|
2271
2273
|
tool: "continue_workflow";
|
|
2272
2274
|
};
|
|
2273
|
-
sessionTitle: string | null;
|
|
2274
2275
|
resumeToken: string;
|
|
2275
2276
|
snippet: string;
|
|
2276
2277
|
matchExplanation: string;
|
|
2277
2278
|
pendingStepId: string | null;
|
|
2278
|
-
lastModifiedMs: number | null;
|
|
2279
2279
|
whyMatched: ("matched_exact_id" | "matched_notes" | "matched_notes_partial" | "matched_workflow_id" | "matched_head_sha" | "matched_branch" | "matched_repo_root" | "recency_fallback")[];
|
|
2280
2280
|
}, {
|
|
2281
2281
|
confidence: "strong" | "weak" | "medium";
|
|
2282
2282
|
workflowId: string;
|
|
2283
|
-
runId: string;
|
|
2284
2283
|
sessionId: string;
|
|
2285
|
-
|
|
2284
|
+
runId: string;
|
|
2286
2285
|
isComplete: boolean;
|
|
2286
|
+
sessionTitle: string | null;
|
|
2287
|
+
gitBranch: string | null;
|
|
2288
|
+
lastModifiedMs: number | null;
|
|
2287
2289
|
nextCall: {
|
|
2288
2290
|
params: {
|
|
2289
|
-
continueToken: string;
|
|
2290
2291
|
intent: "rehydrate";
|
|
2292
|
+
continueToken: string;
|
|
2291
2293
|
};
|
|
2292
2294
|
tool: "continue_workflow";
|
|
2293
2295
|
};
|
|
2294
|
-
sessionTitle: string | null;
|
|
2295
2296
|
resumeToken: string;
|
|
2296
2297
|
snippet: string;
|
|
2297
2298
|
matchExplanation: string;
|
|
2298
2299
|
pendingStepId: string | null;
|
|
2299
|
-
lastModifiedMs: number | null;
|
|
2300
2300
|
whyMatched: ("matched_exact_id" | "matched_notes" | "matched_notes_partial" | "matched_workflow_id" | "matched_head_sha" | "matched_branch" | "matched_repo_root" | "recency_fallback")[];
|
|
2301
2301
|
}>, "many">;
|
|
2302
2302
|
totalEligible: z.ZodNumber;
|
|
@@ -2304,23 +2304,23 @@ export declare const V2ResumeSessionOutputSchema: z.ZodObject<{
|
|
|
2304
2304
|
candidates: {
|
|
2305
2305
|
confidence: "strong" | "weak" | "medium";
|
|
2306
2306
|
workflowId: string;
|
|
2307
|
-
runId: string;
|
|
2308
2307
|
sessionId: string;
|
|
2309
|
-
|
|
2308
|
+
runId: string;
|
|
2310
2309
|
isComplete: boolean;
|
|
2310
|
+
sessionTitle: string | null;
|
|
2311
|
+
gitBranch: string | null;
|
|
2312
|
+
lastModifiedMs: number | null;
|
|
2311
2313
|
nextCall: {
|
|
2312
2314
|
params: {
|
|
2313
|
-
continueToken: string;
|
|
2314
2315
|
intent: "rehydrate";
|
|
2316
|
+
continueToken: string;
|
|
2315
2317
|
};
|
|
2316
2318
|
tool: "continue_workflow";
|
|
2317
2319
|
};
|
|
2318
|
-
sessionTitle: string | null;
|
|
2319
2320
|
resumeToken: string;
|
|
2320
2321
|
snippet: string;
|
|
2321
2322
|
matchExplanation: string;
|
|
2322
2323
|
pendingStepId: string | null;
|
|
2323
|
-
lastModifiedMs: number | null;
|
|
2324
2324
|
whyMatched: ("matched_exact_id" | "matched_notes" | "matched_notes_partial" | "matched_workflow_id" | "matched_head_sha" | "matched_branch" | "matched_repo_root" | "recency_fallback")[];
|
|
2325
2325
|
}[];
|
|
2326
2326
|
totalEligible: number;
|
|
@@ -2328,23 +2328,23 @@ export declare const V2ResumeSessionOutputSchema: z.ZodObject<{
|
|
|
2328
2328
|
candidates: {
|
|
2329
2329
|
confidence: "strong" | "weak" | "medium";
|
|
2330
2330
|
workflowId: string;
|
|
2331
|
-
runId: string;
|
|
2332
2331
|
sessionId: string;
|
|
2333
|
-
|
|
2332
|
+
runId: string;
|
|
2334
2333
|
isComplete: boolean;
|
|
2334
|
+
sessionTitle: string | null;
|
|
2335
|
+
gitBranch: string | null;
|
|
2336
|
+
lastModifiedMs: number | null;
|
|
2335
2337
|
nextCall: {
|
|
2336
2338
|
params: {
|
|
2337
|
-
continueToken: string;
|
|
2338
2339
|
intent: "rehydrate";
|
|
2340
|
+
continueToken: string;
|
|
2339
2341
|
};
|
|
2340
2342
|
tool: "continue_workflow";
|
|
2341
2343
|
};
|
|
2342
|
-
sessionTitle: string | null;
|
|
2343
2344
|
resumeToken: string;
|
|
2344
2345
|
snippet: string;
|
|
2345
2346
|
matchExplanation: string;
|
|
2346
2347
|
pendingStepId: string | null;
|
|
2347
|
-
lastModifiedMs: number | null;
|
|
2348
2348
|
whyMatched: ("matched_exact_id" | "matched_notes" | "matched_notes_partial" | "matched_workflow_id" | "matched_head_sha" | "matched_branch" | "matched_repo_root" | "recency_fallback")[];
|
|
2349
2349
|
}[];
|
|
2350
2350
|
totalEligible: number;
|
|
@@ -86,6 +86,10 @@ function fatalExit(label, reason) {
|
|
|
86
86
|
}
|
|
87
87
|
function registerFatalHandlers(transport) {
|
|
88
88
|
registeredTransport = transport;
|
|
89
|
+
process.stderr.on('error', () => { });
|
|
90
|
+
if (process.stdout.listenerCount('error') === 0) {
|
|
91
|
+
process.stdout.on('error', () => { });
|
|
92
|
+
}
|
|
89
93
|
process.on('uncaughtException', (err) => fatalExit('Uncaught exception', err));
|
|
90
94
|
process.on('unhandledRejection', (reason) => fatalExit('Unhandled promise rejection', reason));
|
|
91
95
|
}
|
|
@@ -41,14 +41,12 @@ const server_js_1 = require("../server.js");
|
|
|
41
41
|
const http_listener_js_1 = require("./http-listener.js");
|
|
42
42
|
const shutdown_hooks_js_1 = require("./shutdown-hooks.js");
|
|
43
43
|
const fatal_exit_js_1 = require("./fatal-exit.js");
|
|
44
|
-
const primary_tombstone_js_1 = require("./primary-tombstone.js");
|
|
45
44
|
const crypto = __importStar(require("crypto"));
|
|
46
45
|
const express_1 = __importDefault(require("express"));
|
|
47
46
|
const HTTP_PORT_SCAN_END = 3199;
|
|
48
47
|
async function startHttpServer(port) {
|
|
49
48
|
(0, fatal_exit_js_1.registerFatalHandlers)('http');
|
|
50
49
|
(0, fatal_exit_js_1.logStartup)('http', { port });
|
|
51
|
-
(0, primary_tombstone_js_1.clearTombstone)();
|
|
52
50
|
const { server, ctx } = await (0, server_js_1.composeServer)();
|
|
53
51
|
const scanEnd = Math.max(port, HTTP_PORT_SCAN_END);
|
|
54
52
|
const listener = await (0, http_listener_js_1.bindWithPortFallback)(port, scanEnd);
|
|
@@ -74,9 +72,6 @@ async function startHttpServer(port) {
|
|
|
74
72
|
console.error(`[Transport] MCP endpoint: http://localhost:${boundPort}/mcp`);
|
|
75
73
|
(0, shutdown_hooks_js_1.wireShutdownHooks)({
|
|
76
74
|
onBeforeTerminate: async () => {
|
|
77
|
-
if (boundPort != null) {
|
|
78
|
-
(0, primary_tombstone_js_1.writeTombstone)(boundPort, process.pid);
|
|
79
|
-
}
|
|
80
75
|
await listener.stop();
|
|
81
76
|
await ctx.httpServer?.stop();
|
|
82
77
|
},
|
|
@@ -37,7 +37,6 @@ exports.startStdioServer = startStdioServer;
|
|
|
37
37
|
const server_js_1 = require("../server.js");
|
|
38
38
|
const shutdown_hooks_js_1 = require("./shutdown-hooks.js");
|
|
39
39
|
const fatal_exit_js_1 = require("./fatal-exit.js");
|
|
40
|
-
const primary_tombstone_js_1 = require("./primary-tombstone.js");
|
|
41
40
|
const INITIAL_ROOTS_TIMEOUT_MS = 1000;
|
|
42
41
|
async function fetchInitialRootsWithTimeout(server) {
|
|
43
42
|
return Promise.race([
|
|
@@ -50,7 +49,6 @@ async function fetchInitialRootsWithTimeout(server) {
|
|
|
50
49
|
async function startStdioServer() {
|
|
51
50
|
(0, fatal_exit_js_1.registerFatalHandlers)('stdio');
|
|
52
51
|
(0, fatal_exit_js_1.logStartup)('stdio');
|
|
53
|
-
(0, primary_tombstone_js_1.clearTombstone)();
|
|
54
52
|
const { server, ctx, rootsManager } = await (0, server_js_1.composeServer)();
|
|
55
53
|
(0, fatal_exit_js_1.registerGracefulShutdown)(async () => { await ctx.httpServer?.stop(); });
|
|
56
54
|
const { StdioServerTransport } = await Promise.resolve().then(() => __importStar(require('@modelcontextprotocol/sdk/server/stdio.js')));
|
|
@@ -59,35 +57,49 @@ async function startStdioServer() {
|
|
|
59
57
|
try {
|
|
60
58
|
const result = await server.listRoots();
|
|
61
59
|
rootsManager.updateRootUris(result.roots.map((r) => r.uri));
|
|
62
|
-
|
|
60
|
+
try {
|
|
61
|
+
process.stderr.write(`[Roots] Updated workspace roots: ${result.roots.map((r) => r.uri).join(', ') || '(none)'}\n`);
|
|
62
|
+
}
|
|
63
|
+
catch { }
|
|
63
64
|
}
|
|
64
65
|
catch {
|
|
65
|
-
|
|
66
|
+
try {
|
|
67
|
+
process.stderr.write('[Roots] Failed to fetch updated roots after change notification\n');
|
|
68
|
+
}
|
|
69
|
+
catch { }
|
|
66
70
|
}
|
|
67
71
|
});
|
|
68
72
|
(0, shutdown_hooks_js_1.wireStdoutShutdown)();
|
|
69
73
|
const transport = new StdioServerTransport();
|
|
70
74
|
await server.connect(transport);
|
|
71
|
-
|
|
75
|
+
try {
|
|
76
|
+
process.stderr.write('[Transport] WorkRail MCP Server running on stdio\n');
|
|
77
|
+
}
|
|
78
|
+
catch { }
|
|
72
79
|
void fetchInitialRootsWithTimeout(server)
|
|
73
80
|
.then((result) => {
|
|
74
81
|
if (result == null) {
|
|
75
|
-
|
|
82
|
+
try {
|
|
83
|
+
process.stderr.write('[Roots] Initial roots probe timed out; workspace context will use server CWD fallback\n');
|
|
84
|
+
}
|
|
85
|
+
catch { }
|
|
76
86
|
return;
|
|
77
87
|
}
|
|
78
88
|
rootsManager.updateRootUris(result.roots.map((r) => r.uri));
|
|
79
|
-
|
|
89
|
+
try {
|
|
90
|
+
process.stderr.write(`[Roots] Initial workspace roots: ${result.roots.map((r) => r.uri).join(', ') || '(none)'}\n`);
|
|
91
|
+
}
|
|
92
|
+
catch { }
|
|
80
93
|
})
|
|
81
94
|
.catch(() => {
|
|
82
|
-
|
|
95
|
+
try {
|
|
96
|
+
process.stderr.write('[Roots] Client does not support roots/list; workspace context will use server CWD fallback\n');
|
|
97
|
+
}
|
|
98
|
+
catch { }
|
|
83
99
|
});
|
|
84
100
|
(0, shutdown_hooks_js_1.wireStdinShutdown)();
|
|
85
101
|
(0, shutdown_hooks_js_1.wireShutdownHooks)({
|
|
86
102
|
onBeforeTerminate: async () => {
|
|
87
|
-
const port = ctx.httpServer?.getPort();
|
|
88
|
-
if (port != null) {
|
|
89
|
-
(0, primary_tombstone_js_1.writeTombstone)(port, process.pid);
|
|
90
|
-
}
|
|
91
103
|
await ctx.httpServer?.stop();
|
|
92
104
|
},
|
|
93
105
|
});
|
package/dist/mcp/v2/tools.d.ts
CHANGED
|
@@ -164,18 +164,18 @@ export declare const V2ResumeSessionInput: z.ZodObject<{
|
|
|
164
164
|
sameWorkspaceOnly: z.ZodOptional<z.ZodBoolean>;
|
|
165
165
|
}, "strict", z.ZodTypeAny, {
|
|
166
166
|
workspacePath: string;
|
|
167
|
-
query?: string | undefined;
|
|
168
|
-
runId?: string | undefined;
|
|
169
167
|
sessionId?: string | undefined;
|
|
168
|
+
runId?: string | undefined;
|
|
170
169
|
gitBranch?: string | undefined;
|
|
170
|
+
query?: string | undefined;
|
|
171
171
|
gitHeadSha?: string | undefined;
|
|
172
172
|
sameWorkspaceOnly?: boolean | undefined;
|
|
173
173
|
}, {
|
|
174
174
|
workspacePath: string;
|
|
175
|
-
query?: string | undefined;
|
|
176
|
-
runId?: string | undefined;
|
|
177
175
|
sessionId?: string | undefined;
|
|
176
|
+
runId?: string | undefined;
|
|
178
177
|
gitBranch?: string | undefined;
|
|
178
|
+
query?: string | undefined;
|
|
179
179
|
gitHeadSha?: string | undefined;
|
|
180
180
|
sameWorkspaceOnly?: boolean | undefined;
|
|
181
181
|
}>;
|
package/dist/mcp-server.d.ts
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
export { startStdioServer } from './mcp/transports/stdio-entry.js';
|
|
3
3
|
export { startHttpServer } from './mcp/transports/http-entry.js';
|
|
4
|
-
export { startBridgeServer, detectHealthyPrimary } from './mcp/transports/bridge-entry.js';
|
|
5
4
|
export { composeServer } from './mcp/server.js';
|
|
6
|
-
export declare function waitForStdinReadable(timeoutMs: number, stdin?: NodeJS.ReadableStream): Promise<boolean>;
|
package/dist/mcp-server.js
CHANGED
|
@@ -1,60 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.composeServer = exports.
|
|
5
|
-
exports.waitForStdinReadable = waitForStdinReadable;
|
|
4
|
+
exports.composeServer = exports.startHttpServer = exports.startStdioServer = void 0;
|
|
6
5
|
const transport_mode_js_1 = require("./mcp/transports/transport-mode.js");
|
|
7
6
|
const stdio_entry_js_1 = require("./mcp/transports/stdio-entry.js");
|
|
8
7
|
const http_entry_js_1 = require("./mcp/transports/http-entry.js");
|
|
9
|
-
const bridge_entry_js_1 = require("./mcp/transports/bridge-entry.js");
|
|
10
8
|
const assert_never_js_1 = require("./runtime/assert-never.js");
|
|
11
9
|
var stdio_entry_js_2 = require("./mcp/transports/stdio-entry.js");
|
|
12
10
|
Object.defineProperty(exports, "startStdioServer", { enumerable: true, get: function () { return stdio_entry_js_2.startStdioServer; } });
|
|
13
11
|
var http_entry_js_2 = require("./mcp/transports/http-entry.js");
|
|
14
12
|
Object.defineProperty(exports, "startHttpServer", { enumerable: true, get: function () { return http_entry_js_2.startHttpServer; } });
|
|
15
|
-
var bridge_entry_js_2 = require("./mcp/transports/bridge-entry.js");
|
|
16
|
-
Object.defineProperty(exports, "startBridgeServer", { enumerable: true, get: function () { return bridge_entry_js_2.startBridgeServer; } });
|
|
17
|
-
Object.defineProperty(exports, "detectHealthyPrimary", { enumerable: true, get: function () { return bridge_entry_js_2.detectHealthyPrimary; } });
|
|
18
13
|
var server_js_1 = require("./mcp/server.js");
|
|
19
14
|
Object.defineProperty(exports, "composeServer", { enumerable: true, get: function () { return server_js_1.composeServer; } });
|
|
20
|
-
const DEFAULT_MCP_PORT = 3100;
|
|
21
|
-
const STDIO_CLIENT_PROBE_MS = 150;
|
|
22
|
-
function waitForStdinReadable(timeoutMs, stdin = process.stdin) {
|
|
23
|
-
return new Promise((resolve) => {
|
|
24
|
-
stdin.pause();
|
|
25
|
-
const timer = setTimeout(() => {
|
|
26
|
-
stdin.removeListener('readable', onReadable);
|
|
27
|
-
resolve(false);
|
|
28
|
-
}, timeoutMs);
|
|
29
|
-
const onReadable = () => {
|
|
30
|
-
clearTimeout(timer);
|
|
31
|
-
stdin.removeListener('readable', onReadable);
|
|
32
|
-
resolve(true);
|
|
33
|
-
};
|
|
34
|
-
stdin.once('readable', onReadable);
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
15
|
async function main() {
|
|
38
16
|
const mode = (0, transport_mode_js_1.resolveTransportMode)(process.env);
|
|
39
|
-
if (mode.kind === 'stdio') {
|
|
40
|
-
const primaryDetected = await (0, bridge_entry_js_1.detectHealthyPrimary)(DEFAULT_MCP_PORT);
|
|
41
|
-
if (primaryDetected != null) {
|
|
42
|
-
const hasClient = await waitForStdinReadable(STDIO_CLIENT_PROBE_MS, process.stdin);
|
|
43
|
-
if (!hasClient) {
|
|
44
|
-
console.error(`[Startup] Primary on :${primaryDetected.port}, no stdio client within ${STDIO_CLIENT_PROBE_MS}ms — exiting`);
|
|
45
|
-
process.exit(0);
|
|
46
|
-
}
|
|
47
|
-
console.error(`[Startup] Primary detected on :${primaryDetected.port} — starting in bridge mode`);
|
|
48
|
-
try {
|
|
49
|
-
await (0, bridge_entry_js_1.startBridgeServer)(primaryDetected.port, undefined, { originalPrimaryPid: primaryDetected.pid });
|
|
50
|
-
}
|
|
51
|
-
catch (error) {
|
|
52
|
-
console.error('[Bridge] Fatal error, falling back to full stdio server:', error);
|
|
53
|
-
await (0, stdio_entry_js_1.startStdioServer)();
|
|
54
|
-
}
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
17
|
switch (mode.kind) {
|
|
59
18
|
case 'stdio':
|
|
60
19
|
await (0, stdio_entry_js_1.startStdioServer)();
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { GitHubPollingSource } from '../types.js';
|
|
2
|
+
import type { Result } from '../../runtime/result.js';
|
|
3
|
+
export interface GitHubLabel {
|
|
4
|
+
readonly name: string;
|
|
5
|
+
}
|
|
6
|
+
export interface GitHubIssue {
|
|
7
|
+
readonly id: number;
|
|
8
|
+
readonly number: number;
|
|
9
|
+
readonly title: string;
|
|
10
|
+
readonly html_url: string;
|
|
11
|
+
readonly updated_at: string;
|
|
12
|
+
readonly state: string;
|
|
13
|
+
readonly user?: {
|
|
14
|
+
readonly login?: string;
|
|
15
|
+
};
|
|
16
|
+
readonly labels?: readonly GitHubLabel[];
|
|
17
|
+
}
|
|
18
|
+
export interface GitHubPR {
|
|
19
|
+
readonly id: number;
|
|
20
|
+
readonly number: number;
|
|
21
|
+
readonly title: string;
|
|
22
|
+
readonly html_url: string;
|
|
23
|
+
readonly updated_at: string;
|
|
24
|
+
readonly state: string;
|
|
25
|
+
readonly user?: {
|
|
26
|
+
readonly login?: string;
|
|
27
|
+
};
|
|
28
|
+
readonly draft?: boolean;
|
|
29
|
+
readonly labels?: readonly GitHubLabel[];
|
|
30
|
+
}
|
|
31
|
+
export type GitHubPollError = {
|
|
32
|
+
readonly kind: 'http_error';
|
|
33
|
+
readonly status: number;
|
|
34
|
+
readonly message: string;
|
|
35
|
+
} | {
|
|
36
|
+
readonly kind: 'network_error';
|
|
37
|
+
readonly message: string;
|
|
38
|
+
} | {
|
|
39
|
+
readonly kind: 'parse_error';
|
|
40
|
+
readonly message: string;
|
|
41
|
+
};
|
|
42
|
+
export type FetchFn = (url: string, init: RequestInit) => Promise<Response>;
|
|
43
|
+
export declare function pollGitHubIssues(source: GitHubPollingSource, since: string, fetchFn?: FetchFn): Promise<Result<GitHubIssue[], GitHubPollError>>;
|
|
44
|
+
export declare function pollGitHubPRs(source: GitHubPollingSource, since: string, fetchFn?: FetchFn): Promise<Result<GitHubPR[], GitHubPollError>>;
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.pollGitHubIssues = pollGitHubIssues;
|
|
4
|
+
exports.pollGitHubPRs = pollGitHubPRs;
|
|
5
|
+
const result_js_1 = require("../../runtime/result.js");
|
|
6
|
+
function checkRateLimit(response) {
|
|
7
|
+
const remainingHeader = response.headers.get('X-RateLimit-Remaining');
|
|
8
|
+
const resetHeader = response.headers.get('X-RateLimit-Reset');
|
|
9
|
+
if (remainingHeader === null)
|
|
10
|
+
return true;
|
|
11
|
+
const remaining = parseInt(remainingHeader, 10);
|
|
12
|
+
if (isNaN(remaining) || remaining >= 100)
|
|
13
|
+
return true;
|
|
14
|
+
const resetTs = parseInt(resetHeader ?? '0', 10);
|
|
15
|
+
const resetAt = resetTs > 0 ? new Date(resetTs * 1000).toISOString() : 'unknown';
|
|
16
|
+
console.warn(`[GitHubPoller] Rate limit low: remaining=${remaining}, resets at ${resetAt}. ` +
|
|
17
|
+
`Skipping poll cycle to avoid exhaustion.`);
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
async function pollGitHubIssues(source, since, fetchFn = globalThis.fetch) {
|
|
21
|
+
const [owner, repo] = source.repo.split('/');
|
|
22
|
+
const url = new URL(`https://api.github.com/repos/${owner}/${repo}/issues`);
|
|
23
|
+
url.searchParams.set('state', 'open');
|
|
24
|
+
url.searchParams.set('since', since);
|
|
25
|
+
url.searchParams.set('sort', 'updated');
|
|
26
|
+
url.searchParams.set('direction', 'desc');
|
|
27
|
+
url.searchParams.set('per_page', '100');
|
|
28
|
+
if (source.labelFilter.length > 0) {
|
|
29
|
+
url.searchParams.set('labels', source.labelFilter.join(','));
|
|
30
|
+
}
|
|
31
|
+
let response;
|
|
32
|
+
try {
|
|
33
|
+
response = await fetchFn(url.toString(), {
|
|
34
|
+
headers: {
|
|
35
|
+
'Authorization': `Bearer ${source.token}`,
|
|
36
|
+
'Accept': 'application/vnd.github+json',
|
|
37
|
+
'X-GitHub-Api-Version': '2022-11-28',
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
catch (e) {
|
|
42
|
+
return (0, result_js_1.err)({
|
|
43
|
+
kind: 'network_error',
|
|
44
|
+
message: e instanceof Error ? e.message : String(e),
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
if (!response.ok) {
|
|
48
|
+
return (0, result_js_1.err)({
|
|
49
|
+
kind: 'http_error',
|
|
50
|
+
status: response.status,
|
|
51
|
+
message: `GitHub API returned HTTP ${response.status}: ${response.statusText}`,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
if (!checkRateLimit(response)) {
|
|
55
|
+
return (0, result_js_1.ok)([]);
|
|
56
|
+
}
|
|
57
|
+
let raw;
|
|
58
|
+
try {
|
|
59
|
+
raw = await response.json();
|
|
60
|
+
}
|
|
61
|
+
catch (e) {
|
|
62
|
+
return (0, result_js_1.err)({
|
|
63
|
+
kind: 'parse_error',
|
|
64
|
+
message: `Failed to parse GitHub Issues API response: ${e instanceof Error ? e.message : String(e)}`,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
if (!Array.isArray(raw)) {
|
|
68
|
+
return (0, result_js_1.err)({
|
|
69
|
+
kind: 'parse_error',
|
|
70
|
+
message: `Expected array from GitHub Issues API, got: ${typeof raw}`,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
const issues = [];
|
|
74
|
+
for (const item of raw) {
|
|
75
|
+
if (isGitHubIssueShape(item)) {
|
|
76
|
+
issues.push(item);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return (0, result_js_1.ok)(applyIssueFilters(issues, source));
|
|
80
|
+
}
|
|
81
|
+
async function pollGitHubPRs(source, since, fetchFn = globalThis.fetch) {
|
|
82
|
+
const [owner, repo] = source.repo.split('/');
|
|
83
|
+
const url = new URL(`https://api.github.com/repos/${owner}/${repo}/pulls`);
|
|
84
|
+
url.searchParams.set('state', 'open');
|
|
85
|
+
url.searchParams.set('sort', 'updated');
|
|
86
|
+
url.searchParams.set('direction', 'desc');
|
|
87
|
+
url.searchParams.set('per_page', '100');
|
|
88
|
+
let response;
|
|
89
|
+
try {
|
|
90
|
+
response = await fetchFn(url.toString(), {
|
|
91
|
+
headers: {
|
|
92
|
+
'Authorization': `Bearer ${source.token}`,
|
|
93
|
+
'Accept': 'application/vnd.github+json',
|
|
94
|
+
'X-GitHub-Api-Version': '2022-11-28',
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
catch (e) {
|
|
99
|
+
return (0, result_js_1.err)({
|
|
100
|
+
kind: 'network_error',
|
|
101
|
+
message: e instanceof Error ? e.message : String(e),
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
if (!response.ok) {
|
|
105
|
+
return (0, result_js_1.err)({
|
|
106
|
+
kind: 'http_error',
|
|
107
|
+
status: response.status,
|
|
108
|
+
message: `GitHub API returned HTTP ${response.status}: ${response.statusText}`,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
if (!checkRateLimit(response)) {
|
|
112
|
+
return (0, result_js_1.ok)([]);
|
|
113
|
+
}
|
|
114
|
+
let raw;
|
|
115
|
+
try {
|
|
116
|
+
raw = await response.json();
|
|
117
|
+
}
|
|
118
|
+
catch (e) {
|
|
119
|
+
return (0, result_js_1.err)({
|
|
120
|
+
kind: 'parse_error',
|
|
121
|
+
message: `Failed to parse GitHub PRs API response: ${e instanceof Error ? e.message : String(e)}`,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
if (!Array.isArray(raw)) {
|
|
125
|
+
return (0, result_js_1.err)({
|
|
126
|
+
kind: 'parse_error',
|
|
127
|
+
message: `Expected array from GitHub PRs API, got: ${typeof raw}`,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
const prs = [];
|
|
131
|
+
for (const item of raw) {
|
|
132
|
+
if (isGitHubPRShape(item)) {
|
|
133
|
+
prs.push(item);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
const filtered = prs.filter(pr => pr.updated_at > since);
|
|
137
|
+
return (0, result_js_1.ok)(applyPRFilters(filtered, source));
|
|
138
|
+
}
|
|
139
|
+
function applyIssueFilters(issues, source) {
|
|
140
|
+
return issues.filter(issue => {
|
|
141
|
+
if (source.excludeAuthors.length > 0) {
|
|
142
|
+
const login = issue.user?.login;
|
|
143
|
+
if (!login || source.excludeAuthors.includes(login))
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
if (source.notLabels.length > 0 && issue.labels) {
|
|
147
|
+
const labelNames = issue.labels.map(l => l.name);
|
|
148
|
+
if (source.notLabels.some(nl => labelNames.includes(nl)))
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
return true;
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
function applyPRFilters(prs, source) {
|
|
155
|
+
return prs.filter(pr => {
|
|
156
|
+
if (source.excludeAuthors.length > 0) {
|
|
157
|
+
const login = pr.user?.login;
|
|
158
|
+
if (!login || source.excludeAuthors.includes(login))
|
|
159
|
+
return false;
|
|
160
|
+
}
|
|
161
|
+
if (source.notLabels.length > 0 && pr.labels) {
|
|
162
|
+
const labelNames = pr.labels.map(l => l.name);
|
|
163
|
+
if (source.notLabels.some(nl => labelNames.includes(nl)))
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
return true;
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
function isGitHubIssueShape(item) {
|
|
170
|
+
if (typeof item !== 'object' || item === null)
|
|
171
|
+
return false;
|
|
172
|
+
const obj = item;
|
|
173
|
+
return (typeof obj['id'] === 'number' &&
|
|
174
|
+
typeof obj['number'] === 'number' &&
|
|
175
|
+
typeof obj['title'] === 'string' &&
|
|
176
|
+
typeof obj['html_url'] === 'string' &&
|
|
177
|
+
typeof obj['updated_at'] === 'string' &&
|
|
178
|
+
typeof obj['state'] === 'string');
|
|
179
|
+
}
|
|
180
|
+
function isGitHubPRShape(item) {
|
|
181
|
+
if (typeof item !== 'object' || item === null)
|
|
182
|
+
return false;
|
|
183
|
+
const obj = item;
|
|
184
|
+
return (typeof obj['id'] === 'number' &&
|
|
185
|
+
typeof obj['number'] === 'number' &&
|
|
186
|
+
typeof obj['title'] === 'string' &&
|
|
187
|
+
typeof obj['html_url'] === 'string' &&
|
|
188
|
+
typeof obj['updated_at'] === 'string' &&
|
|
189
|
+
typeof obj['state'] === 'string');
|
|
190
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { GitLabPollingSource } from '../types.js';
|
|
2
|
+
import type { Result } from '../../runtime/result.js';
|
|
3
|
+
export interface GitLabMR {
|
|
4
|
+
readonly id: number;
|
|
5
|
+
readonly iid: number;
|
|
6
|
+
readonly title: string;
|
|
7
|
+
readonly web_url: string;
|
|
8
|
+
readonly updated_at: string;
|
|
9
|
+
readonly state: string;
|
|
10
|
+
readonly author?: {
|
|
11
|
+
readonly username?: string;
|
|
12
|
+
readonly name?: string;
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
export type GitLabPollError = {
|
|
16
|
+
readonly kind: 'http_error';
|
|
17
|
+
readonly status: number;
|
|
18
|
+
readonly message: string;
|
|
19
|
+
} | {
|
|
20
|
+
readonly kind: 'network_error';
|
|
21
|
+
readonly message: string;
|
|
22
|
+
} | {
|
|
23
|
+
readonly kind: 'parse_error';
|
|
24
|
+
readonly message: string;
|
|
25
|
+
};
|
|
26
|
+
export type FetchFn = (url: string, init: RequestInit) => Promise<Response>;
|
|
27
|
+
export declare function pollGitLabMRs(source: GitLabPollingSource, updatedAfter: string, fetchFn?: FetchFn): Promise<Result<GitLabMR[], GitLabPollError>>;
|