@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.
Files changed (98) hide show
  1. package/dist/cli/commands/index.d.ts +1 -0
  2. package/dist/cli/commands/index.js +3 -1
  3. package/dist/cli/commands/worktrain-await.js +11 -9
  4. package/dist/cli/commands/worktrain-daemon-install.d.ts +35 -0
  5. package/dist/cli/commands/worktrain-daemon-install.js +291 -0
  6. package/dist/cli/commands/worktrain-daemon.d.ts +31 -0
  7. package/dist/cli/commands/worktrain-daemon.js +272 -0
  8. package/dist/cli/commands/worktrain-spawn.js +11 -9
  9. package/dist/cli-worktrain.js +488 -0
  10. package/dist/cli.js +1 -22
  11. package/dist/console/standalone-console.d.ts +28 -0
  12. package/dist/console/standalone-console.js +142 -0
  13. package/dist/{console/assets/index-Cb_LO718.js → console-ui/assets/index-C1JXnwZS.js} +1 -1
  14. package/dist/{console → console-ui}/index.html +1 -1
  15. package/dist/daemon/agent-loop.d.ts +27 -0
  16. package/dist/daemon/agent-loop.js +39 -1
  17. package/dist/daemon/daemon-events.d.ts +63 -1
  18. package/dist/daemon/workflow-runner.d.ts +3 -2
  19. package/dist/daemon/workflow-runner.js +285 -46
  20. package/dist/infrastructure/session/HttpServer.js +133 -34
  21. package/dist/manifest.json +136 -104
  22. package/dist/mcp/handlers/v2-error-mapping.d.ts +3 -0
  23. package/dist/mcp/handlers/v2-error-mapping.js +2 -0
  24. package/dist/mcp/handlers/v2-execution/advance.js +25 -0
  25. package/dist/mcp/handlers/v2-execution/continue-advance.js +7 -0
  26. package/dist/mcp/output-schemas.d.ts +30 -30
  27. package/dist/mcp/transports/fatal-exit.js +4 -0
  28. package/dist/mcp/transports/http-entry.js +0 -5
  29. package/dist/mcp/transports/stdio-entry.js +24 -12
  30. package/dist/mcp/v2/tools.d.ts +4 -4
  31. package/dist/mcp-server.d.ts +0 -2
  32. package/dist/mcp-server.js +1 -42
  33. package/dist/trigger/adapters/github-poller.d.ts +44 -0
  34. package/dist/trigger/adapters/github-poller.js +190 -0
  35. package/dist/trigger/adapters/gitlab-poller.d.ts +27 -0
  36. package/dist/trigger/adapters/gitlab-poller.js +81 -0
  37. package/dist/trigger/index.d.ts +4 -1
  38. package/dist/trigger/index.js +5 -1
  39. package/dist/trigger/polled-event-store.d.ts +22 -0
  40. package/dist/trigger/polled-event-store.js +173 -0
  41. package/dist/trigger/polling-scheduler.d.ts +20 -0
  42. package/dist/trigger/polling-scheduler.js +249 -0
  43. package/dist/trigger/trigger-listener.d.ts +3 -0
  44. package/dist/trigger/trigger-listener.js +47 -3
  45. package/dist/trigger/trigger-store.js +114 -33
  46. package/dist/trigger/types.d.ts +17 -1
  47. package/dist/v2/durable-core/domain/observation-builder.d.ts +3 -0
  48. package/dist/v2/durable-core/domain/observation-builder.js +2 -2
  49. package/dist/v2/durable-core/domain/prompt-renderer.d.ts +2 -1
  50. package/dist/v2/durable-core/domain/prompt-renderer.js +10 -0
  51. package/dist/v2/durable-core/schemas/export-bundle/index.d.ts +224 -224
  52. package/dist/v2/durable-core/schemas/session/events.d.ts +42 -42
  53. package/dist/v2/durable-core/schemas/session/manifest.d.ts +6 -6
  54. package/dist/v2/durable-core/schemas/session/validation-event.d.ts +2 -2
  55. package/dist/v2/durable-core/tokens/payloads.d.ts +52 -52
  56. package/dist/v2/usecases/console-routes.js +3 -3
  57. package/dist/v2/usecases/console-service.js +185 -10
  58. package/dist/v2/usecases/console-types.d.ts +8 -0
  59. package/docs/design/bridge-removal-pr-a-candidates.md +115 -0
  60. package/docs/design/bridge-removal-pr-a-design-review.md +79 -0
  61. package/docs/design/bridge-removal-pr-a-implementation-plan.md +203 -0
  62. package/docs/design/daemon-conversation-logging-plan.md +98 -0
  63. package/docs/design/daemon-conversation-logging-review.md +55 -0
  64. package/docs/design/daemon-conversation-logging.md +129 -0
  65. package/docs/design/github-polling-adapter-design-candidates.md +226 -0
  66. package/docs/design/github-polling-adapter-design-review-findings.md +131 -0
  67. package/docs/design/github-polling-adapter-implementation-plan.md +284 -0
  68. package/docs/design/implementation_plan.md +192 -0
  69. package/docs/design/workflow-id-validation-at-startup.md +146 -0
  70. package/docs/design/workflow-id-validation-design-review.md +87 -0
  71. package/docs/design/workflow-id-validation-implementation-plan.md +185 -0
  72. package/docs/design/worktrain-system-prompt-report-issue-candidates.md +135 -0
  73. package/docs/design/worktrain-system-prompt-report-issue-design-review.md +73 -0
  74. package/docs/discovery/design-candidates.md +180 -0
  75. package/docs/discovery/design-review-findings.md +110 -0
  76. package/docs/discovery/wr-discovery-goal-reframing.md +303 -0
  77. package/docs/ideas/backlog.md +627 -0
  78. package/package.json +1 -1
  79. package/workflows/architecture-scalability-audit.json +1 -1
  80. package/workflows/bug-investigation.agentic.v2.json +3 -3
  81. package/workflows/coding-task-workflow-agentic.json +32 -32
  82. package/workflows/coding-task-workflow-agentic.lean.v2.json +1 -1
  83. package/workflows/coding-task-workflow-agentic.v2.json +7 -7
  84. package/workflows/mr-review-workflow.agentic.v2.json +21 -12
  85. package/workflows/personal-learning-materials-creation-branched.json +2 -2
  86. package/workflows/production-readiness-audit.json +1 -1
  87. package/workflows/relocation-workflow-us.json +2 -2
  88. package/workflows/ui-ux-design-workflow.json +14 -14
  89. package/workflows/workflow-for-workflows.json +3 -3
  90. package/workflows/workflow-for-workflows.v2.json +2 -2
  91. package/workflows/wr.discovery.json +59 -8
  92. package/dist/mcp/transports/bridge-entry.d.ts +0 -102
  93. package/dist/mcp/transports/bridge-entry.js +0 -454
  94. package/dist/mcp/transports/bridge-events.d.ts +0 -51
  95. package/dist/mcp/transports/bridge-events.js +0 -24
  96. package/dist/mcp/transports/primary-tombstone.d.ts +0 -21
  97. package/dist/mcp/transports/primary-tombstone.js +0 -51
  98. /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
- gitBranch: string | null;
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
- gitBranch: string | null;
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
- gitBranch: string | null;
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
- gitBranch: string | null;
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
- console.error(`[Roots] Updated workspace roots: ${result.roots.map((r) => r.uri).join(', ') || '(none)'}`);
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
- console.error('[Roots] Failed to fetch updated roots after change notification');
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
- console.error('[Transport] WorkRail MCP Server running on stdio');
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
- console.error('[Roots] Initial roots probe timed out; workspace context will use server CWD fallback');
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
- console.error(`[Roots] Initial workspace roots: ${result.roots.map((r) => r.uri).join(', ') || '(none)'}`);
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
- console.error('[Roots] Client does not support roots/list; workspace context will use server CWD fallback');
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
  });
@@ -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
  }>;
@@ -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>;
@@ -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.detectHealthyPrimary = exports.startBridgeServer = exports.startHttpServer = exports.startStdioServer = void 0;
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>>;