patchwork-os 0.2.0-alpha.0 → 0.2.0-alpha.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +41 -46
- package/dist/bridge.js +23 -10
- package/dist/bridge.js.map +1 -1
- package/dist/claudeDriver.d.ts +3 -1
- package/dist/claudeDriver.js +48 -0
- package/dist/claudeDriver.js.map +1 -1
- package/dist/commands/dashboard.d.ts +47 -0
- package/dist/commands/dashboard.js +319 -0
- package/dist/commands/dashboard.js.map +1 -0
- package/dist/config.d.ts +2 -2
- package/dist/config.js +5 -2
- package/dist/config.js.map +1 -1
- package/dist/connectors/github.d.ts +94 -0
- package/dist/connectors/github.js +350 -0
- package/dist/connectors/github.js.map +1 -0
- package/dist/connectors/gmail.d.ts +40 -0
- package/dist/connectors/gmail.js +304 -0
- package/dist/connectors/gmail.js.map +1 -0
- package/dist/connectors/googleCalendar.d.ts +57 -0
- package/dist/connectors/googleCalendar.js +308 -0
- package/dist/connectors/googleCalendar.js.map +1 -0
- package/dist/connectors/linear.d.ts +117 -0
- package/dist/connectors/linear.js +248 -0
- package/dist/connectors/linear.js.map +1 -0
- package/dist/connectors/mcpClient.d.ts +56 -0
- package/dist/connectors/mcpClient.js +189 -0
- package/dist/connectors/mcpClient.js.map +1 -0
- package/dist/connectors/mcpOAuth.d.ts +83 -0
- package/dist/connectors/mcpOAuth.js +363 -0
- package/dist/connectors/mcpOAuth.js.map +1 -0
- package/dist/connectors/sentry.d.ts +43 -0
- package/dist/connectors/sentry.js +197 -0
- package/dist/connectors/sentry.js.map +1 -0
- package/dist/connectors/slack.d.ts +50 -0
- package/dist/connectors/slack.js +254 -0
- package/dist/connectors/slack.js.map +1 -0
- package/dist/drivers/claude/api.d.ts +11 -0
- package/dist/drivers/claude/api.js +54 -0
- package/dist/drivers/claude/api.js.map +1 -0
- package/dist/drivers/claude/envSanitizer.d.ts +7 -0
- package/dist/drivers/claude/envSanitizer.js +18 -0
- package/dist/drivers/claude/envSanitizer.js.map +1 -0
- package/dist/drivers/claude/streamParser.d.ts +38 -0
- package/dist/drivers/claude/streamParser.js +34 -0
- package/dist/drivers/claude/streamParser.js.map +1 -0
- package/dist/drivers/claude/subprocess.d.ts +19 -0
- package/dist/drivers/claude/subprocess.js +216 -0
- package/dist/drivers/claude/subprocess.js.map +1 -0
- package/dist/drivers/claude/subprocessSettings.d.ts +9 -0
- package/dist/drivers/claude/subprocessSettings.js +55 -0
- package/dist/drivers/claude/subprocessSettings.js.map +1 -0
- package/dist/drivers/gemini/index.d.ts +14 -0
- package/dist/drivers/gemini/index.js +176 -0
- package/dist/drivers/gemini/index.js.map +1 -0
- package/dist/drivers/grok/index.d.ts +11 -0
- package/dist/drivers/grok/index.js +22 -0
- package/dist/drivers/grok/index.js.map +1 -0
- package/dist/drivers/index.d.ts +18 -0
- package/dist/drivers/index.js +31 -0
- package/dist/drivers/index.js.map +1 -0
- package/dist/drivers/openai/index.d.ts +24 -0
- package/dist/drivers/openai/index.js +110 -0
- package/dist/drivers/openai/index.js.map +1 -0
- package/dist/drivers/types.d.ts +72 -0
- package/dist/drivers/types.js +30 -0
- package/dist/drivers/types.js.map +1 -0
- package/dist/index.js +116 -22
- package/dist/index.js.map +1 -1
- package/dist/recipes/yamlRunner.d.ts +95 -0
- package/dist/recipes/yamlRunner.js +588 -0
- package/dist/recipes/yamlRunner.js.map +1 -0
- package/dist/recipesHttp.d.ts +13 -1
- package/dist/recipesHttp.js +9 -1
- package/dist/recipesHttp.js.map +1 -1
- package/dist/server.d.ts +3 -1
- package/dist/server.js +490 -2
- package/dist/server.js.map +1 -1
- package/dist/tools/addLinearComment.d.ts +55 -0
- package/dist/tools/addLinearComment.js +70 -0
- package/dist/tools/addLinearComment.js.map +1 -0
- package/dist/tools/createLinearIssue.d.ts +84 -0
- package/dist/tools/createLinearIssue.js +146 -0
- package/dist/tools/createLinearIssue.js.map +1 -0
- package/dist/tools/ctxGetTaskContext.d.ts +4 -1
- package/dist/tools/ctxGetTaskContext.js +45 -2
- package/dist/tools/ctxGetTaskContext.js.map +1 -1
- package/dist/tools/fetchCalendarEvents.d.ts +94 -0
- package/dist/tools/fetchCalendarEvents.js +97 -0
- package/dist/tools/fetchCalendarEvents.js.map +1 -0
- package/dist/tools/fetchGithubIssue.d.ts +80 -0
- package/dist/tools/fetchGithubIssue.js +84 -0
- package/dist/tools/fetchGithubIssue.js.map +1 -0
- package/dist/tools/fetchGithubPR.d.ts +89 -0
- package/dist/tools/fetchGithubPR.js +96 -0
- package/dist/tools/fetchGithubPR.js.map +1 -0
- package/dist/tools/fetchLinearIssue.d.ts +112 -0
- package/dist/tools/fetchLinearIssue.js +129 -0
- package/dist/tools/fetchLinearIssue.js.map +1 -0
- package/dist/tools/fetchSentryIssue.d.ts +143 -0
- package/dist/tools/fetchSentryIssue.js +150 -0
- package/dist/tools/fetchSentryIssue.js.map +1 -0
- package/dist/tools/fetchSlackProfile.d.ts +43 -0
- package/dist/tools/fetchSlackProfile.js +43 -0
- package/dist/tools/fetchSlackProfile.js.map +1 -0
- package/dist/tools/getConnectorStatus.d.ts +58 -0
- package/dist/tools/getConnectorStatus.js +56 -0
- package/dist/tools/getConnectorStatus.js.map +1 -0
- package/dist/tools/github/index.d.ts +1 -1
- package/dist/tools/github/index.js +1 -1
- package/dist/tools/github/index.js.map +1 -1
- package/dist/tools/github/pr.d.ts +122 -0
- package/dist/tools/github/pr.js +152 -0
- package/dist/tools/github/pr.js.map +1 -1
- package/dist/tools/index.js +27 -1
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/slackListChannels.d.ts +65 -0
- package/dist/tools/slackListChannels.js +70 -0
- package/dist/tools/slackListChannels.js.map +1 -0
- package/dist/tools/slackPostMessage.d.ts +57 -0
- package/dist/tools/slackPostMessage.js +72 -0
- package/dist/tools/slackPostMessage.js.map +1 -0
- package/dist/tools/updateLinearIssue.d.ts +89 -0
- package/dist/tools/updateLinearIssue.js +103 -0
- package/dist/tools/updateLinearIssue.js.map +1 -0
- package/package.json +1 -1
- package/scripts/start-all.sh +56 -19
- package/templates/recipes/ctx-loop-test.yaml +75 -0
- package/templates/recipes/gmail-health-check.yaml +19 -0
- package/templates/recipes/inbox-triage.yaml +15 -0
- package/templates/recipes/morning-brief.yaml +72 -0
- package/templates/recipes/sentry-to-linear.yaml +77 -0
- package/templates/scheduled-tasks/morning-brief/SKILL.md +37 -0
package/dist/recipesHttp.js
CHANGED
|
@@ -16,7 +16,12 @@ export function saveRecipe(recipesDir, draft) {
|
|
|
16
16
|
name: safeName,
|
|
17
17
|
description: draft.description,
|
|
18
18
|
trigger: draft.trigger,
|
|
19
|
-
steps: draft.steps
|
|
19
|
+
steps: draft.steps.map((s) => ({
|
|
20
|
+
id: s.id,
|
|
21
|
+
agent: s.agent,
|
|
22
|
+
prompt: s.prompt,
|
|
23
|
+
})),
|
|
24
|
+
...(draft.vars && draft.vars.length > 0 ? { vars: draft.vars } : {}),
|
|
20
25
|
createdAt: Date.now(),
|
|
21
26
|
};
|
|
22
27
|
writeFileSync(candidate, JSON.stringify(payload, null, 2), "utf-8");
|
|
@@ -76,6 +81,9 @@ export function listInstalledRecipes(recipesDir) {
|
|
|
76
81
|
installedAt: stat.mtimeMs,
|
|
77
82
|
hasPermissions,
|
|
78
83
|
source,
|
|
84
|
+
...(Array.isArray(parsed.vars) && parsed.vars.length > 0
|
|
85
|
+
? { vars: parsed.vars }
|
|
86
|
+
: {}),
|
|
79
87
|
});
|
|
80
88
|
}
|
|
81
89
|
catch {
|
package/dist/recipesHttp.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"recipesHttp.js","sourceRoot":"","sources":["../src/recipesHttp.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,WAAW,EACX,YAAY,EACZ,QAAQ,EACR,aAAa,GACd,MAAM,SAAS,CAAC;AACjB,OAAO,IAAI,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"recipesHttp.js","sourceRoot":"","sources":["../src/recipesHttp.ts"],"names":[],"mappings":"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"}
|
package/dist/server.d.ts
CHANGED
|
@@ -20,6 +20,8 @@ export interface SessionSummary {
|
|
|
20
20
|
connectedAt: string;
|
|
21
21
|
openedFileCount: number;
|
|
22
22
|
pendingApprovals: number;
|
|
23
|
+
firstTool?: string;
|
|
24
|
+
remoteAddr?: string;
|
|
23
25
|
}
|
|
24
26
|
export declare class Server extends EventEmitter<ServerEvents> {
|
|
25
27
|
private authToken;
|
|
@@ -72,7 +74,7 @@ export declare class Server extends EventEmitter<ServerEvents> {
|
|
|
72
74
|
after?: number;
|
|
73
75
|
}) => Record<string, unknown>[]) | null;
|
|
74
76
|
/** Patchwork: set by bridge to launch a named recipe via the orchestrator. */
|
|
75
|
-
runRecipeFn: ((name: string) => Promise<{
|
|
77
|
+
runRecipeFn: ((name: string, vars?: Record<string, string>) => Promise<{
|
|
76
78
|
ok: boolean;
|
|
77
79
|
taskId?: string;
|
|
78
80
|
error?: string;
|
package/dist/server.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { EventEmitter } from "node:events";
|
|
2
2
|
import http from "node:http";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
3
5
|
import { WebSocket, WebSocketServer as WsServer } from "ws";
|
|
4
6
|
import { routeApprovalRequest } from "./approvalHttp.js";
|
|
5
7
|
import { getApprovalQueue } from "./approvalQueue.js";
|
|
@@ -353,6 +355,80 @@ export class Server extends EventEmitter {
|
|
|
353
355
|
res.end(JSON.stringify({ ok: true, v: PACKAGE_VERSION }));
|
|
354
356
|
return;
|
|
355
357
|
}
|
|
358
|
+
// ── Connector OAuth callbacks (unauthenticated — browser redirect from vendor) ──
|
|
359
|
+
if (parsedUrl.pathname === "/connections/github/callback" &&
|
|
360
|
+
req.method === "GET") {
|
|
361
|
+
void (async () => {
|
|
362
|
+
const { handleGithubCallback } = await import("./connectors/github.js");
|
|
363
|
+
const code = parsedUrl.searchParams.get("code");
|
|
364
|
+
const state = parsedUrl.searchParams.get("state");
|
|
365
|
+
const error = parsedUrl.searchParams.get("error");
|
|
366
|
+
const result = await handleGithubCallback(code, state, error);
|
|
367
|
+
res.writeHead(result.status, {
|
|
368
|
+
"Content-Type": result.contentType ?? "application/json",
|
|
369
|
+
});
|
|
370
|
+
res.end(result.body);
|
|
371
|
+
})();
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
if (parsedUrl.pathname === "/connections/linear/callback" &&
|
|
375
|
+
req.method === "GET") {
|
|
376
|
+
void (async () => {
|
|
377
|
+
const { handleLinearCallback } = await import("./connectors/linear.js");
|
|
378
|
+
const code = parsedUrl.searchParams.get("code");
|
|
379
|
+
const state = parsedUrl.searchParams.get("state");
|
|
380
|
+
const error = parsedUrl.searchParams.get("error");
|
|
381
|
+
const result = await handleLinearCallback(code, state, error);
|
|
382
|
+
res.writeHead(result.status, {
|
|
383
|
+
"Content-Type": result.contentType ?? "application/json",
|
|
384
|
+
});
|
|
385
|
+
res.end(result.body);
|
|
386
|
+
})();
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
if (parsedUrl.pathname === "/connections/sentry/callback" &&
|
|
390
|
+
req.method === "GET") {
|
|
391
|
+
void (async () => {
|
|
392
|
+
const { handleSentryCallback } = await import("./connectors/sentry.js");
|
|
393
|
+
const code = parsedUrl.searchParams.get("code");
|
|
394
|
+
const state = parsedUrl.searchParams.get("state");
|
|
395
|
+
const error = parsedUrl.searchParams.get("error");
|
|
396
|
+
const result = await handleSentryCallback(code, state, error);
|
|
397
|
+
res.writeHead(result.status, {
|
|
398
|
+
"Content-Type": result.contentType ?? "application/json",
|
|
399
|
+
});
|
|
400
|
+
res.end(result.body);
|
|
401
|
+
})();
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
if (parsedUrl.pathname === "/connections/google-calendar/callback" &&
|
|
405
|
+
req.method === "GET") {
|
|
406
|
+
void (async () => {
|
|
407
|
+
const { handleCalendarCallback } = await import("./connectors/googleCalendar.js");
|
|
408
|
+
const code = parsedUrl.searchParams.get("code");
|
|
409
|
+
const state = parsedUrl.searchParams.get("state");
|
|
410
|
+
const error = parsedUrl.searchParams.get("error");
|
|
411
|
+
const result = await handleCalendarCallback(code, state, error);
|
|
412
|
+
res.writeHead(result.status, {
|
|
413
|
+
"Content-Type": result.contentType ?? "application/json",
|
|
414
|
+
});
|
|
415
|
+
res.end(result.body);
|
|
416
|
+
})();
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
if (parsedUrl.pathname === "/connections/slack/callback" &&
|
|
420
|
+
req.method === "GET") {
|
|
421
|
+
void (async () => {
|
|
422
|
+
const { handleSlackCallback } = await import("./connectors/slack.js");
|
|
423
|
+
const code = parsedUrl.searchParams.get("code");
|
|
424
|
+
const state = parsedUrl.searchParams.get("state");
|
|
425
|
+
const error = parsedUrl.searchParams.get("error");
|
|
426
|
+
const result = await handleSlackCallback(code, state, error);
|
|
427
|
+
res.writeHead(result.status, { "Content-Type": result.contentType ?? "application/json" });
|
|
428
|
+
res.end(result.body);
|
|
429
|
+
})();
|
|
430
|
+
return;
|
|
431
|
+
}
|
|
356
432
|
// ── Bearer token authentication ───────────────────────────────────────
|
|
357
433
|
// All other HTTP endpoints require a valid Bearer token.
|
|
358
434
|
// Accepts either:
|
|
@@ -643,6 +719,411 @@ export class Server extends EventEmitter {
|
|
|
643
719
|
});
|
|
644
720
|
return;
|
|
645
721
|
}
|
|
722
|
+
// ── Gmail / Connections endpoints ───────────────────────────────────────
|
|
723
|
+
if (parsedUrl.pathname === "/connections" && req.method === "GET") {
|
|
724
|
+
void (async () => {
|
|
725
|
+
const { handleConnectionsList } = await import("./connectors/gmail.js");
|
|
726
|
+
const result = await handleConnectionsList();
|
|
727
|
+
res.writeHead(result.status, {
|
|
728
|
+
"Content-Type": result.contentType ?? "application/json",
|
|
729
|
+
});
|
|
730
|
+
res.end(result.body);
|
|
731
|
+
})();
|
|
732
|
+
return;
|
|
733
|
+
}
|
|
734
|
+
if (parsedUrl.pathname === "/connections/gmail/auth" &&
|
|
735
|
+
req.method === "GET") {
|
|
736
|
+
void (async () => {
|
|
737
|
+
const { handleGmailAuthRedirect } = await import("./connectors/gmail.js");
|
|
738
|
+
const result = handleGmailAuthRedirect();
|
|
739
|
+
if (result.redirect) {
|
|
740
|
+
res.writeHead(302, { Location: result.redirect });
|
|
741
|
+
res.end();
|
|
742
|
+
}
|
|
743
|
+
else {
|
|
744
|
+
res.writeHead(result.status, {
|
|
745
|
+
"Content-Type": result.contentType ?? "application/json",
|
|
746
|
+
});
|
|
747
|
+
res.end(result.body);
|
|
748
|
+
}
|
|
749
|
+
})();
|
|
750
|
+
return;
|
|
751
|
+
}
|
|
752
|
+
if (parsedUrl.pathname === "/connections/gmail/callback" &&
|
|
753
|
+
req.method === "GET") {
|
|
754
|
+
void (async () => {
|
|
755
|
+
const { handleGmailCallback } = await import("./connectors/gmail.js");
|
|
756
|
+
const code = parsedUrl.searchParams.get("code");
|
|
757
|
+
const state = parsedUrl.searchParams.get("state");
|
|
758
|
+
const error = parsedUrl.searchParams.get("error");
|
|
759
|
+
const result = await handleGmailCallback(code, state, error);
|
|
760
|
+
res.writeHead(result.status, {
|
|
761
|
+
"Content-Type": result.contentType ?? "text/html",
|
|
762
|
+
});
|
|
763
|
+
res.end(result.body);
|
|
764
|
+
})();
|
|
765
|
+
return;
|
|
766
|
+
}
|
|
767
|
+
if (parsedUrl.pathname === "/connections/gmail" &&
|
|
768
|
+
req.method === "DELETE") {
|
|
769
|
+
void (async () => {
|
|
770
|
+
const { handleGmailDisconnect } = await import("./connectors/gmail.js");
|
|
771
|
+
const result = await handleGmailDisconnect();
|
|
772
|
+
res.writeHead(result.status, {
|
|
773
|
+
"Content-Type": result.contentType ?? "application/json",
|
|
774
|
+
});
|
|
775
|
+
res.end(result.body);
|
|
776
|
+
})();
|
|
777
|
+
return;
|
|
778
|
+
}
|
|
779
|
+
if (parsedUrl.pathname === "/connections/gmail/test" &&
|
|
780
|
+
req.method === "POST") {
|
|
781
|
+
void (async () => {
|
|
782
|
+
const { handleGmailTest } = await import("./connectors/gmail.js");
|
|
783
|
+
const result = await handleGmailTest();
|
|
784
|
+
res.writeHead(result.status, {
|
|
785
|
+
"Content-Type": result.contentType ?? "application/json",
|
|
786
|
+
});
|
|
787
|
+
res.end(result.body);
|
|
788
|
+
})();
|
|
789
|
+
return;
|
|
790
|
+
}
|
|
791
|
+
// ── GitHub MCP connector routes ─────────────────────────────────────
|
|
792
|
+
if (parsedUrl.pathname === "/connections/github/auth" &&
|
|
793
|
+
req.method === "GET") {
|
|
794
|
+
void (async () => {
|
|
795
|
+
const { handleGithubAuthorize } = await import("./connectors/github.js");
|
|
796
|
+
const result = await handleGithubAuthorize();
|
|
797
|
+
if (result.redirect) {
|
|
798
|
+
res.writeHead(302, { Location: result.redirect });
|
|
799
|
+
res.end();
|
|
800
|
+
}
|
|
801
|
+
else {
|
|
802
|
+
res.writeHead(result.status, {
|
|
803
|
+
"Content-Type": result.contentType ?? "application/json",
|
|
804
|
+
});
|
|
805
|
+
res.end(result.body);
|
|
806
|
+
}
|
|
807
|
+
})();
|
|
808
|
+
return;
|
|
809
|
+
}
|
|
810
|
+
if (parsedUrl.pathname === "/connections/github/test" &&
|
|
811
|
+
req.method === "POST") {
|
|
812
|
+
void (async () => {
|
|
813
|
+
const { handleGithubTest } = await import("./connectors/github.js");
|
|
814
|
+
const result = await handleGithubTest();
|
|
815
|
+
res.writeHead(result.status, {
|
|
816
|
+
"Content-Type": result.contentType ?? "application/json",
|
|
817
|
+
});
|
|
818
|
+
res.end(result.body);
|
|
819
|
+
})();
|
|
820
|
+
return;
|
|
821
|
+
}
|
|
822
|
+
if (parsedUrl.pathname === "/connections/github" &&
|
|
823
|
+
req.method === "DELETE") {
|
|
824
|
+
void (async () => {
|
|
825
|
+
const { handleGithubDisconnect } = await import("./connectors/github.js");
|
|
826
|
+
const result = await handleGithubDisconnect();
|
|
827
|
+
res.writeHead(result.status, {
|
|
828
|
+
"Content-Type": result.contentType ?? "application/json",
|
|
829
|
+
});
|
|
830
|
+
res.end(result.body);
|
|
831
|
+
})();
|
|
832
|
+
return;
|
|
833
|
+
}
|
|
834
|
+
// ── Sentry MCP connector routes ─────────────────────────────────────
|
|
835
|
+
if (parsedUrl.pathname === "/connections/sentry/auth" &&
|
|
836
|
+
req.method === "GET") {
|
|
837
|
+
void (async () => {
|
|
838
|
+
const { handleSentryAuthorize } = await import("./connectors/sentry.js");
|
|
839
|
+
const result = await handleSentryAuthorize();
|
|
840
|
+
if (result.redirect) {
|
|
841
|
+
res.writeHead(302, { Location: result.redirect });
|
|
842
|
+
res.end();
|
|
843
|
+
}
|
|
844
|
+
else {
|
|
845
|
+
res.writeHead(result.status, {
|
|
846
|
+
"Content-Type": result.contentType ?? "application/json",
|
|
847
|
+
});
|
|
848
|
+
res.end(result.body);
|
|
849
|
+
}
|
|
850
|
+
})();
|
|
851
|
+
return;
|
|
852
|
+
}
|
|
853
|
+
if (parsedUrl.pathname === "/connections/sentry/callback" &&
|
|
854
|
+
req.method === "GET") {
|
|
855
|
+
void (async () => {
|
|
856
|
+
const { handleSentryCallback } = await import("./connectors/sentry.js");
|
|
857
|
+
const code = parsedUrl.searchParams.get("code");
|
|
858
|
+
const state = parsedUrl.searchParams.get("state");
|
|
859
|
+
const error = parsedUrl.searchParams.get("error");
|
|
860
|
+
const result = await handleSentryCallback(code, state, error);
|
|
861
|
+
res.writeHead(result.status, {
|
|
862
|
+
"Content-Type": result.contentType ?? "application/json",
|
|
863
|
+
});
|
|
864
|
+
res.end(result.body);
|
|
865
|
+
})();
|
|
866
|
+
return;
|
|
867
|
+
}
|
|
868
|
+
if (parsedUrl.pathname === "/connections/sentry/test" &&
|
|
869
|
+
req.method === "POST") {
|
|
870
|
+
void (async () => {
|
|
871
|
+
const { handleSentryTest } = await import("./connectors/sentry.js");
|
|
872
|
+
const result = await handleSentryTest();
|
|
873
|
+
res.writeHead(result.status, {
|
|
874
|
+
"Content-Type": result.contentType ?? "application/json",
|
|
875
|
+
});
|
|
876
|
+
res.end(result.body);
|
|
877
|
+
})();
|
|
878
|
+
return;
|
|
879
|
+
}
|
|
880
|
+
if (parsedUrl.pathname === "/connections/sentry" &&
|
|
881
|
+
req.method === "DELETE") {
|
|
882
|
+
void (async () => {
|
|
883
|
+
const { handleSentryDisconnect } = await import("./connectors/sentry.js");
|
|
884
|
+
const result = await handleSentryDisconnect();
|
|
885
|
+
res.writeHead(result.status, {
|
|
886
|
+
"Content-Type": result.contentType ?? "application/json",
|
|
887
|
+
});
|
|
888
|
+
res.end(result.body);
|
|
889
|
+
})();
|
|
890
|
+
return;
|
|
891
|
+
}
|
|
892
|
+
// ── Linear MCP connector routes ─────────────────────────────────────
|
|
893
|
+
if (parsedUrl.pathname === "/connections/linear/auth" &&
|
|
894
|
+
req.method === "GET") {
|
|
895
|
+
void (async () => {
|
|
896
|
+
const { handleLinearAuthorize } = await import("./connectors/linear.js");
|
|
897
|
+
const result = await handleLinearAuthorize();
|
|
898
|
+
if (result.redirect) {
|
|
899
|
+
res.writeHead(302, { Location: result.redirect });
|
|
900
|
+
res.end();
|
|
901
|
+
}
|
|
902
|
+
else {
|
|
903
|
+
res.writeHead(result.status, {
|
|
904
|
+
"Content-Type": result.contentType ?? "application/json",
|
|
905
|
+
});
|
|
906
|
+
res.end(result.body);
|
|
907
|
+
}
|
|
908
|
+
})();
|
|
909
|
+
return;
|
|
910
|
+
}
|
|
911
|
+
if (parsedUrl.pathname === "/connections/linear/callback" &&
|
|
912
|
+
req.method === "GET") {
|
|
913
|
+
void (async () => {
|
|
914
|
+
const { handleLinearCallback } = await import("./connectors/linear.js");
|
|
915
|
+
const code = parsedUrl.searchParams.get("code");
|
|
916
|
+
const state = parsedUrl.searchParams.get("state");
|
|
917
|
+
const error = parsedUrl.searchParams.get("error");
|
|
918
|
+
const result = await handleLinearCallback(code, state, error);
|
|
919
|
+
res.writeHead(result.status, {
|
|
920
|
+
"Content-Type": result.contentType ?? "application/json",
|
|
921
|
+
});
|
|
922
|
+
res.end(result.body);
|
|
923
|
+
})();
|
|
924
|
+
return;
|
|
925
|
+
}
|
|
926
|
+
if (parsedUrl.pathname === "/connections/linear/test" &&
|
|
927
|
+
req.method === "POST") {
|
|
928
|
+
void (async () => {
|
|
929
|
+
const { handleLinearTest } = await import("./connectors/linear.js");
|
|
930
|
+
const result = await handleLinearTest();
|
|
931
|
+
res.writeHead(result.status, {
|
|
932
|
+
"Content-Type": result.contentType ?? "application/json",
|
|
933
|
+
});
|
|
934
|
+
res.end(result.body);
|
|
935
|
+
})();
|
|
936
|
+
return;
|
|
937
|
+
}
|
|
938
|
+
if (parsedUrl.pathname === "/connections/linear" &&
|
|
939
|
+
req.method === "DELETE") {
|
|
940
|
+
void (async () => {
|
|
941
|
+
const { handleLinearDisconnect } = await import("./connectors/linear.js");
|
|
942
|
+
const result = await handleLinearDisconnect();
|
|
943
|
+
res.writeHead(result.status, {
|
|
944
|
+
"Content-Type": result.contentType ?? "application/json",
|
|
945
|
+
});
|
|
946
|
+
res.end(result.body);
|
|
947
|
+
})();
|
|
948
|
+
return;
|
|
949
|
+
}
|
|
950
|
+
// ── Slack connector routes ──────────────────────────────────────
|
|
951
|
+
if ((parsedUrl.pathname === "/connections/slack/auth" || parsedUrl.pathname === "/connections/slack/authorize") &&
|
|
952
|
+
req.method === "GET") {
|
|
953
|
+
const { handleSlackAuthorize } = await import("./connectors/slack.js");
|
|
954
|
+
const result = handleSlackAuthorize();
|
|
955
|
+
if (result.redirect) {
|
|
956
|
+
res.writeHead(302, { Location: result.redirect });
|
|
957
|
+
res.end();
|
|
958
|
+
}
|
|
959
|
+
else {
|
|
960
|
+
res.writeHead(result.status, { "Content-Type": result.contentType ?? "application/json" });
|
|
961
|
+
res.end(result.body);
|
|
962
|
+
}
|
|
963
|
+
return;
|
|
964
|
+
}
|
|
965
|
+
if (parsedUrl.pathname === "/connections/slack/test" &&
|
|
966
|
+
req.method === "POST") {
|
|
967
|
+
void (async () => {
|
|
968
|
+
const { handleSlackTest } = await import("./connectors/slack.js");
|
|
969
|
+
const result = await handleSlackTest();
|
|
970
|
+
res.writeHead(result.status, { "Content-Type": result.contentType ?? "application/json" });
|
|
971
|
+
res.end(result.body);
|
|
972
|
+
})();
|
|
973
|
+
return;
|
|
974
|
+
}
|
|
975
|
+
if (parsedUrl.pathname === "/connections/slack" &&
|
|
976
|
+
req.method === "DELETE") {
|
|
977
|
+
const { handleSlackDisconnect } = await import("./connectors/slack.js");
|
|
978
|
+
const result = handleSlackDisconnect();
|
|
979
|
+
res.writeHead(result.status, { "Content-Type": result.contentType ?? "application/json" });
|
|
980
|
+
res.end(result.body);
|
|
981
|
+
return;
|
|
982
|
+
}
|
|
983
|
+
// ── Google Calendar routes ──────────────────────────────────────
|
|
984
|
+
if (parsedUrl.pathname === "/connections/google-calendar/auth" &&
|
|
985
|
+
req.method === "GET") {
|
|
986
|
+
void (async () => {
|
|
987
|
+
const { handleCalendarAuthRedirect } = await import("./connectors/googleCalendar.js");
|
|
988
|
+
const result = handleCalendarAuthRedirect();
|
|
989
|
+
if (result.redirect) {
|
|
990
|
+
res.writeHead(302, { Location: result.redirect });
|
|
991
|
+
res.end();
|
|
992
|
+
}
|
|
993
|
+
else {
|
|
994
|
+
res.writeHead(result.status, {
|
|
995
|
+
"Content-Type": result.contentType ?? "application/json",
|
|
996
|
+
});
|
|
997
|
+
res.end(result.body);
|
|
998
|
+
}
|
|
999
|
+
})();
|
|
1000
|
+
return;
|
|
1001
|
+
}
|
|
1002
|
+
if (parsedUrl.pathname === "/connections/google-calendar/callback" &&
|
|
1003
|
+
req.method === "GET") {
|
|
1004
|
+
void (async () => {
|
|
1005
|
+
const { handleCalendarCallback } = await import("./connectors/googleCalendar.js");
|
|
1006
|
+
const code = parsedUrl.searchParams.get("code");
|
|
1007
|
+
const state = parsedUrl.searchParams.get("state");
|
|
1008
|
+
const error = parsedUrl.searchParams.get("error");
|
|
1009
|
+
const result = await handleCalendarCallback(code, state, error);
|
|
1010
|
+
res.writeHead(result.status, {
|
|
1011
|
+
"Content-Type": result.contentType ?? "application/json",
|
|
1012
|
+
});
|
|
1013
|
+
res.end(result.body);
|
|
1014
|
+
})();
|
|
1015
|
+
return;
|
|
1016
|
+
}
|
|
1017
|
+
if (parsedUrl.pathname === "/connections/google-calendar/test" &&
|
|
1018
|
+
req.method === "POST") {
|
|
1019
|
+
void (async () => {
|
|
1020
|
+
const { handleCalendarTest } = await import("./connectors/googleCalendar.js");
|
|
1021
|
+
const result = await handleCalendarTest();
|
|
1022
|
+
res.writeHead(result.status, {
|
|
1023
|
+
"Content-Type": result.contentType ?? "application/json",
|
|
1024
|
+
});
|
|
1025
|
+
res.end(result.body);
|
|
1026
|
+
})();
|
|
1027
|
+
return;
|
|
1028
|
+
}
|
|
1029
|
+
if (parsedUrl.pathname === "/connections/google-calendar" &&
|
|
1030
|
+
req.method === "DELETE") {
|
|
1031
|
+
void (async () => {
|
|
1032
|
+
const { handleCalendarDisconnect } = await import("./connectors/googleCalendar.js");
|
|
1033
|
+
const result = await handleCalendarDisconnect();
|
|
1034
|
+
res.writeHead(result.status, {
|
|
1035
|
+
"Content-Type": result.contentType ?? "application/json",
|
|
1036
|
+
});
|
|
1037
|
+
res.end(result.body);
|
|
1038
|
+
})();
|
|
1039
|
+
return;
|
|
1040
|
+
}
|
|
1041
|
+
// ── Inbox routes ────────────────────────────────────────────────────
|
|
1042
|
+
if (parsedUrl.pathname === "/inbox" && req.method === "GET") {
|
|
1043
|
+
void (async () => {
|
|
1044
|
+
try {
|
|
1045
|
+
const { readdir, readFile, stat } = await import("node:fs/promises");
|
|
1046
|
+
const { existsSync } = await import("node:fs");
|
|
1047
|
+
const inboxDir = path.join(os.homedir(), ".patchwork", "inbox");
|
|
1048
|
+
if (!existsSync(inboxDir)) {
|
|
1049
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
1050
|
+
res.end(JSON.stringify({ items: [] }));
|
|
1051
|
+
return;
|
|
1052
|
+
}
|
|
1053
|
+
const files = (await readdir(inboxDir)).filter((f) => f.endsWith(".md"));
|
|
1054
|
+
const items = await Promise.all(files.map(async (name) => {
|
|
1055
|
+
const filePath = path.join(inboxDir, name);
|
|
1056
|
+
const [content, stats] = await Promise.all([
|
|
1057
|
+
readFile(filePath, "utf8"),
|
|
1058
|
+
stat(filePath),
|
|
1059
|
+
]);
|
|
1060
|
+
const stripped = content
|
|
1061
|
+
.split("\n")
|
|
1062
|
+
.filter((l) => !l.startsWith("#"))
|
|
1063
|
+
.join("\n")
|
|
1064
|
+
.trim();
|
|
1065
|
+
return {
|
|
1066
|
+
name,
|
|
1067
|
+
path: filePath,
|
|
1068
|
+
modifiedAt: stats.mtime.toISOString(),
|
|
1069
|
+
preview: stripped.slice(0, 200),
|
|
1070
|
+
};
|
|
1071
|
+
}));
|
|
1072
|
+
items.sort((a, b) => new Date(b.modifiedAt).getTime() -
|
|
1073
|
+
new Date(a.modifiedAt).getTime());
|
|
1074
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
1075
|
+
res.end(JSON.stringify({ items }));
|
|
1076
|
+
}
|
|
1077
|
+
catch (err) {
|
|
1078
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
1079
|
+
res.end(JSON.stringify({
|
|
1080
|
+
error: err instanceof Error ? err.message : String(err),
|
|
1081
|
+
}));
|
|
1082
|
+
}
|
|
1083
|
+
})();
|
|
1084
|
+
return;
|
|
1085
|
+
}
|
|
1086
|
+
const inboxFileMatch = parsedUrl.pathname?.match(/^\/inbox\/([^/]+\.md)$/);
|
|
1087
|
+
if (inboxFileMatch && req.method === "GET") {
|
|
1088
|
+
void (async () => {
|
|
1089
|
+
try {
|
|
1090
|
+
const { readFile, stat } = await import("node:fs/promises");
|
|
1091
|
+
const filename = decodeURIComponent(inboxFileMatch[1] ?? "");
|
|
1092
|
+
// Prevent path traversal — filename must not contain directory separators
|
|
1093
|
+
if (filename.includes("/") || filename.includes("\\")) {
|
|
1094
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
1095
|
+
res.end(JSON.stringify({ error: "Invalid filename" }));
|
|
1096
|
+
return;
|
|
1097
|
+
}
|
|
1098
|
+
const filePath = path.join(os.homedir(), ".patchwork", "inbox", filename);
|
|
1099
|
+
const [content, stats] = await Promise.all([
|
|
1100
|
+
readFile(filePath, "utf8"),
|
|
1101
|
+
stat(filePath),
|
|
1102
|
+
]);
|
|
1103
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
1104
|
+
res.end(JSON.stringify({
|
|
1105
|
+
name: filename,
|
|
1106
|
+
content,
|
|
1107
|
+
modifiedAt: stats.mtime.toISOString(),
|
|
1108
|
+
}));
|
|
1109
|
+
}
|
|
1110
|
+
catch (err) {
|
|
1111
|
+
const code = err.code;
|
|
1112
|
+
if (code === "ENOENT") {
|
|
1113
|
+
res.writeHead(404, { "Content-Type": "application/json" });
|
|
1114
|
+
res.end(JSON.stringify({ error: "Not found" }));
|
|
1115
|
+
}
|
|
1116
|
+
else {
|
|
1117
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
1118
|
+
res.end(JSON.stringify({
|
|
1119
|
+
error: err instanceof Error ? err.message : String(err),
|
|
1120
|
+
}));
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
})();
|
|
1124
|
+
return;
|
|
1125
|
+
}
|
|
1126
|
+
// ── End inbox routes ─────────────────────────────────────────────────
|
|
646
1127
|
if (parsedUrl.pathname === "/recipes/run" && req.method === "POST") {
|
|
647
1128
|
const chunks = [];
|
|
648
1129
|
req.on("data", (c) => chunks.push(c));
|
|
@@ -652,6 +1133,11 @@ export class Server extends EventEmitter {
|
|
|
652
1133
|
const body = Buffer.concat(chunks).toString("utf-8");
|
|
653
1134
|
const parsed = JSON.parse(body || "{}");
|
|
654
1135
|
const name = parsed.name;
|
|
1136
|
+
const vars = parsed.vars &&
|
|
1137
|
+
typeof parsed.vars === "object" &&
|
|
1138
|
+
!Array.isArray(parsed.vars)
|
|
1139
|
+
? parsed.vars
|
|
1140
|
+
: undefined;
|
|
655
1141
|
if (typeof name !== "string" || !name) {
|
|
656
1142
|
res.writeHead(400, { "Content-Type": "application/json" });
|
|
657
1143
|
res.end(JSON.stringify({ ok: false, error: "name required" }));
|
|
@@ -665,7 +1151,7 @@ export class Server extends EventEmitter {
|
|
|
665
1151
|
}));
|
|
666
1152
|
return;
|
|
667
1153
|
}
|
|
668
|
-
const result = await this.runRecipeFn(name);
|
|
1154
|
+
const result = await this.runRecipeFn(name, vars);
|
|
669
1155
|
res.writeHead(result.ok ? 200 : 400, {
|
|
670
1156
|
"Content-Type": "application/json",
|
|
671
1157
|
});
|
|
@@ -759,7 +1245,7 @@ export class Server extends EventEmitter {
|
|
|
759
1245
|
const id = sessionDetailMatch[1];
|
|
760
1246
|
try {
|
|
761
1247
|
const data = this.sessionDetailFn?.(id);
|
|
762
|
-
if (!data
|
|
1248
|
+
if (!data?.summary) {
|
|
763
1249
|
res.writeHead(404, { "Content-Type": "application/json" });
|
|
764
1250
|
res.end(JSON.stringify({ error: "unknown sessionId" }));
|
|
765
1251
|
return;
|
|
@@ -1126,6 +1612,8 @@ export class Server extends EventEmitter {
|
|
|
1126
1612
|
ws.on("error", (err) => {
|
|
1127
1613
|
this.logger.error(`WebSocket client error: ${err.message}`);
|
|
1128
1614
|
});
|
|
1615
|
+
ws.remoteAddr =
|
|
1616
|
+
req.socket.remoteAddress;
|
|
1129
1617
|
this.emit("connection", ws);
|
|
1130
1618
|
});
|
|
1131
1619
|
}
|