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.
Files changed (132) hide show
  1. package/README.md +41 -46
  2. package/dist/bridge.js +23 -10
  3. package/dist/bridge.js.map +1 -1
  4. package/dist/claudeDriver.d.ts +3 -1
  5. package/dist/claudeDriver.js +48 -0
  6. package/dist/claudeDriver.js.map +1 -1
  7. package/dist/commands/dashboard.d.ts +47 -0
  8. package/dist/commands/dashboard.js +319 -0
  9. package/dist/commands/dashboard.js.map +1 -0
  10. package/dist/config.d.ts +2 -2
  11. package/dist/config.js +5 -2
  12. package/dist/config.js.map +1 -1
  13. package/dist/connectors/github.d.ts +94 -0
  14. package/dist/connectors/github.js +350 -0
  15. package/dist/connectors/github.js.map +1 -0
  16. package/dist/connectors/gmail.d.ts +40 -0
  17. package/dist/connectors/gmail.js +304 -0
  18. package/dist/connectors/gmail.js.map +1 -0
  19. package/dist/connectors/googleCalendar.d.ts +57 -0
  20. package/dist/connectors/googleCalendar.js +308 -0
  21. package/dist/connectors/googleCalendar.js.map +1 -0
  22. package/dist/connectors/linear.d.ts +117 -0
  23. package/dist/connectors/linear.js +248 -0
  24. package/dist/connectors/linear.js.map +1 -0
  25. package/dist/connectors/mcpClient.d.ts +56 -0
  26. package/dist/connectors/mcpClient.js +189 -0
  27. package/dist/connectors/mcpClient.js.map +1 -0
  28. package/dist/connectors/mcpOAuth.d.ts +83 -0
  29. package/dist/connectors/mcpOAuth.js +363 -0
  30. package/dist/connectors/mcpOAuth.js.map +1 -0
  31. package/dist/connectors/sentry.d.ts +43 -0
  32. package/dist/connectors/sentry.js +197 -0
  33. package/dist/connectors/sentry.js.map +1 -0
  34. package/dist/connectors/slack.d.ts +50 -0
  35. package/dist/connectors/slack.js +254 -0
  36. package/dist/connectors/slack.js.map +1 -0
  37. package/dist/drivers/claude/api.d.ts +11 -0
  38. package/dist/drivers/claude/api.js +54 -0
  39. package/dist/drivers/claude/api.js.map +1 -0
  40. package/dist/drivers/claude/envSanitizer.d.ts +7 -0
  41. package/dist/drivers/claude/envSanitizer.js +18 -0
  42. package/dist/drivers/claude/envSanitizer.js.map +1 -0
  43. package/dist/drivers/claude/streamParser.d.ts +38 -0
  44. package/dist/drivers/claude/streamParser.js +34 -0
  45. package/dist/drivers/claude/streamParser.js.map +1 -0
  46. package/dist/drivers/claude/subprocess.d.ts +19 -0
  47. package/dist/drivers/claude/subprocess.js +216 -0
  48. package/dist/drivers/claude/subprocess.js.map +1 -0
  49. package/dist/drivers/claude/subprocessSettings.d.ts +9 -0
  50. package/dist/drivers/claude/subprocessSettings.js +55 -0
  51. package/dist/drivers/claude/subprocessSettings.js.map +1 -0
  52. package/dist/drivers/gemini/index.d.ts +14 -0
  53. package/dist/drivers/gemini/index.js +176 -0
  54. package/dist/drivers/gemini/index.js.map +1 -0
  55. package/dist/drivers/grok/index.d.ts +11 -0
  56. package/dist/drivers/grok/index.js +22 -0
  57. package/dist/drivers/grok/index.js.map +1 -0
  58. package/dist/drivers/index.d.ts +18 -0
  59. package/dist/drivers/index.js +31 -0
  60. package/dist/drivers/index.js.map +1 -0
  61. package/dist/drivers/openai/index.d.ts +24 -0
  62. package/dist/drivers/openai/index.js +110 -0
  63. package/dist/drivers/openai/index.js.map +1 -0
  64. package/dist/drivers/types.d.ts +72 -0
  65. package/dist/drivers/types.js +30 -0
  66. package/dist/drivers/types.js.map +1 -0
  67. package/dist/index.js +116 -22
  68. package/dist/index.js.map +1 -1
  69. package/dist/recipes/yamlRunner.d.ts +95 -0
  70. package/dist/recipes/yamlRunner.js +588 -0
  71. package/dist/recipes/yamlRunner.js.map +1 -0
  72. package/dist/recipesHttp.d.ts +13 -1
  73. package/dist/recipesHttp.js +9 -1
  74. package/dist/recipesHttp.js.map +1 -1
  75. package/dist/server.d.ts +3 -1
  76. package/dist/server.js +490 -2
  77. package/dist/server.js.map +1 -1
  78. package/dist/tools/addLinearComment.d.ts +55 -0
  79. package/dist/tools/addLinearComment.js +70 -0
  80. package/dist/tools/addLinearComment.js.map +1 -0
  81. package/dist/tools/createLinearIssue.d.ts +84 -0
  82. package/dist/tools/createLinearIssue.js +146 -0
  83. package/dist/tools/createLinearIssue.js.map +1 -0
  84. package/dist/tools/ctxGetTaskContext.d.ts +4 -1
  85. package/dist/tools/ctxGetTaskContext.js +45 -2
  86. package/dist/tools/ctxGetTaskContext.js.map +1 -1
  87. package/dist/tools/fetchCalendarEvents.d.ts +94 -0
  88. package/dist/tools/fetchCalendarEvents.js +97 -0
  89. package/dist/tools/fetchCalendarEvents.js.map +1 -0
  90. package/dist/tools/fetchGithubIssue.d.ts +80 -0
  91. package/dist/tools/fetchGithubIssue.js +84 -0
  92. package/dist/tools/fetchGithubIssue.js.map +1 -0
  93. package/dist/tools/fetchGithubPR.d.ts +89 -0
  94. package/dist/tools/fetchGithubPR.js +96 -0
  95. package/dist/tools/fetchGithubPR.js.map +1 -0
  96. package/dist/tools/fetchLinearIssue.d.ts +112 -0
  97. package/dist/tools/fetchLinearIssue.js +129 -0
  98. package/dist/tools/fetchLinearIssue.js.map +1 -0
  99. package/dist/tools/fetchSentryIssue.d.ts +143 -0
  100. package/dist/tools/fetchSentryIssue.js +150 -0
  101. package/dist/tools/fetchSentryIssue.js.map +1 -0
  102. package/dist/tools/fetchSlackProfile.d.ts +43 -0
  103. package/dist/tools/fetchSlackProfile.js +43 -0
  104. package/dist/tools/fetchSlackProfile.js.map +1 -0
  105. package/dist/tools/getConnectorStatus.d.ts +58 -0
  106. package/dist/tools/getConnectorStatus.js +56 -0
  107. package/dist/tools/getConnectorStatus.js.map +1 -0
  108. package/dist/tools/github/index.d.ts +1 -1
  109. package/dist/tools/github/index.js +1 -1
  110. package/dist/tools/github/index.js.map +1 -1
  111. package/dist/tools/github/pr.d.ts +122 -0
  112. package/dist/tools/github/pr.js +152 -0
  113. package/dist/tools/github/pr.js.map +1 -1
  114. package/dist/tools/index.js +27 -1
  115. package/dist/tools/index.js.map +1 -1
  116. package/dist/tools/slackListChannels.d.ts +65 -0
  117. package/dist/tools/slackListChannels.js +70 -0
  118. package/dist/tools/slackListChannels.js.map +1 -0
  119. package/dist/tools/slackPostMessage.d.ts +57 -0
  120. package/dist/tools/slackPostMessage.js +72 -0
  121. package/dist/tools/slackPostMessage.js.map +1 -0
  122. package/dist/tools/updateLinearIssue.d.ts +89 -0
  123. package/dist/tools/updateLinearIssue.js +103 -0
  124. package/dist/tools/updateLinearIssue.js.map +1 -0
  125. package/package.json +1 -1
  126. package/scripts/start-all.sh +56 -19
  127. package/templates/recipes/ctx-loop-test.yaml +75 -0
  128. package/templates/recipes/gmail-health-check.yaml +19 -0
  129. package/templates/recipes/inbox-triage.yaml +15 -0
  130. package/templates/recipes/morning-brief.yaml +72 -0
  131. package/templates/recipes/sentry-to-linear.yaml +77 -0
  132. package/templates/scheduled-tasks/morning-brief/SKILL.md +37 -0
@@ -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 {
@@ -1 +1 @@
1
- {"version":3,"file":"recipesHttp.js","sourceRoot":"","sources":["../src/recipesHttp.ts"],"names":[],"mappings":"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"}
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 || !data.summary) {
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
  }