patchwork-os 0.2.0-alpha.34 → 0.2.0-alpha.35
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 +142 -88
- package/deploy/bootstrap-new-vps.sh +12 -12
- package/deploy/bootstrap-vps.sh +6 -3
- package/deploy/deploy-landing.sh +59 -2
- package/dist/bridge.js +32 -1
- package/dist/bridge.js.map +1 -1
- package/dist/commands/recipe.js +18 -1
- package/dist/commands/recipe.js.map +1 -1
- package/dist/commands/recipeInstall.d.ts +79 -1
- package/dist/commands/recipeInstall.js +241 -13
- package/dist/commands/recipeInstall.js.map +1 -1
- package/dist/connectors/asana.d.ts +198 -0
- package/dist/connectors/asana.js +680 -0
- package/dist/connectors/asana.js.map +1 -0
- package/dist/connectors/baseConnector.d.ts +16 -0
- package/dist/connectors/baseConnector.js +106 -24
- package/dist/connectors/baseConnector.js.map +1 -1
- package/dist/connectors/discord.d.ts +150 -0
- package/dist/connectors/discord.js +544 -0
- package/dist/connectors/discord.js.map +1 -0
- package/dist/connectors/github.js +11 -4
- package/dist/connectors/github.js.map +1 -1
- package/dist/connectors/gitlab.d.ts +180 -0
- package/dist/connectors/gitlab.js +582 -0
- package/dist/connectors/gitlab.js.map +1 -0
- package/dist/connectors/gmail.js +11 -0
- package/dist/connectors/gmail.js.map +1 -1
- package/dist/connectors/googleDrive.d.ts +34 -0
- package/dist/connectors/googleDrive.js +305 -0
- package/dist/connectors/googleDrive.js.map +1 -0
- package/dist/connectors/linear.js +23 -4
- package/dist/connectors/linear.js.map +1 -1
- package/dist/connectors/pagerduty.d.ts +160 -0
- package/dist/connectors/pagerduty.js +464 -0
- package/dist/connectors/pagerduty.js.map +1 -0
- package/dist/connectors/slack.d.ts +1 -1
- package/dist/connectors/slack.js +3 -1
- package/dist/connectors/slack.js.map +1 -1
- package/dist/featureFlags.d.ts +17 -11
- package/dist/featureFlags.js +52 -47
- package/dist/featureFlags.js.map +1 -1
- package/dist/index.js +255 -127
- package/dist/index.js.map +1 -1
- package/dist/recipeOrchestration.d.ts +7 -0
- package/dist/recipeOrchestration.js +149 -28
- package/dist/recipeOrchestration.js.map +1 -1
- package/dist/recipes/captureForRunlog.d.ts +27 -0
- package/dist/recipes/captureForRunlog.js +128 -0
- package/dist/recipes/captureForRunlog.js.map +1 -0
- package/dist/recipes/chainedRunner.d.ts +39 -3
- package/dist/recipes/chainedRunner.js +183 -28
- package/dist/recipes/chainedRunner.js.map +1 -1
- package/dist/recipes/detectSilentFail.d.ts +34 -0
- package/dist/recipes/detectSilentFail.js +105 -0
- package/dist/recipes/detectSilentFail.js.map +1 -0
- package/dist/recipes/manifest.js +21 -6
- package/dist/recipes/manifest.js.map +1 -1
- package/dist/recipes/replayRun.d.ts +62 -0
- package/dist/recipes/replayRun.js +97 -0
- package/dist/recipes/replayRun.js.map +1 -0
- package/dist/recipes/scheduler.js +102 -11
- package/dist/recipes/scheduler.js.map +1 -1
- package/dist/recipes/schemaGenerator.js +3 -3
- package/dist/recipes/schemaGenerator.js.map +1 -1
- package/dist/recipes/toolRegistry.d.ts +5 -0
- package/dist/recipes/toolRegistry.js +9 -0
- package/dist/recipes/toolRegistry.js.map +1 -1
- package/dist/recipes/tools/asana.d.ts +16 -0
- package/dist/recipes/tools/asana.js +524 -0
- package/dist/recipes/tools/asana.js.map +1 -0
- package/dist/recipes/tools/discord.d.ts +18 -0
- package/dist/recipes/tools/discord.js +254 -0
- package/dist/recipes/tools/discord.js.map +1 -0
- package/dist/recipes/tools/github.js +29 -4
- package/dist/recipes/tools/github.js.map +1 -1
- package/dist/recipes/tools/gitlab.d.ts +11 -0
- package/dist/recipes/tools/gitlab.js +285 -0
- package/dist/recipes/tools/gitlab.js.map +1 -0
- package/dist/recipes/tools/gmail.d.ts +1 -1
- package/dist/recipes/tools/gmail.js +230 -6
- package/dist/recipes/tools/gmail.js.map +1 -1
- package/dist/recipes/tools/googleDrive.d.ts +1 -0
- package/dist/recipes/tools/googleDrive.js +55 -0
- package/dist/recipes/tools/googleDrive.js.map +1 -0
- package/dist/recipes/tools/index.d.ts +6 -0
- package/dist/recipes/tools/index.js +6 -0
- package/dist/recipes/tools/index.js.map +1 -1
- package/dist/recipes/tools/linear.d.ts +2 -1
- package/dist/recipes/tools/linear.js +222 -1
- package/dist/recipes/tools/linear.js.map +1 -1
- package/dist/recipes/tools/meetingNotes.d.ts +21 -0
- package/dist/recipes/tools/meetingNotes.js +701 -0
- package/dist/recipes/tools/meetingNotes.js.map +1 -0
- package/dist/recipes/tools/pagerduty.d.ts +15 -0
- package/dist/recipes/tools/pagerduty.js +451 -0
- package/dist/recipes/tools/pagerduty.js.map +1 -0
- package/dist/recipes/tools/slack.js +8 -2
- package/dist/recipes/tools/slack.js.map +1 -1
- package/dist/recipes/yamlRunner.d.ts +23 -2
- package/dist/recipes/yamlRunner.js +263 -58
- package/dist/recipes/yamlRunner.js.map +1 -1
- package/dist/recipesHttp.d.ts +32 -0
- package/dist/recipesHttp.js +310 -1
- package/dist/recipesHttp.js.map +1 -1
- package/dist/runLog.d.ts +64 -2
- package/dist/runLog.js +116 -2
- package/dist/runLog.js.map +1 -1
- package/dist/server.d.ts +8 -0
- package/dist/server.js +331 -9
- package/dist/server.js.map +1 -1
- package/dist/streamableHttp.d.ts +31 -1
- package/dist/streamableHttp.js +20 -2
- package/dist/streamableHttp.js.map +1 -1
- package/dist/tools/slackPostMessage.js +1 -1
- package/dist/tools/slackPostMessage.js.map +1 -1
- package/package.json +19 -4
- package/templates/recipes/project-health-check.yaml +1 -1
package/dist/runLog.js
CHANGED
|
@@ -99,10 +99,49 @@ export class RecipeRunLog {
|
|
|
99
99
|
const limit = Math.min(Math.max(q.limit ?? 100, 1), 500);
|
|
100
100
|
return out.slice(0, limit);
|
|
101
101
|
}
|
|
102
|
-
/**
|
|
102
|
+
/**
|
|
103
|
+
* Return a single run by its monotonic seq, or null if not found.
|
|
104
|
+
*
|
|
105
|
+
* Fast path: in-memory ring lookup (the latest `memoryCap` runs).
|
|
106
|
+
* Slow path: scan `runs.jsonl` once when the seq isn't in memory —
|
|
107
|
+
* this is what makes older runs (evicted from the ring buffer)
|
|
108
|
+
* accessible. The dashboard's `/runs/<seq>` page would otherwise
|
|
109
|
+
* 404 for any recipe older than the last `memoryCap` (default 500).
|
|
110
|
+
*
|
|
111
|
+
* The on-disk scan reads the whole file but doesn't allocate the
|
|
112
|
+
* full set in memory: we parse line-by-line and short-circuit on
|
|
113
|
+
* the first match. Malformed lines are skipped silently, matching
|
|
114
|
+
* `loadExisting` / `syncFromDisk` behaviour.
|
|
115
|
+
*/
|
|
103
116
|
getBySeq(seq) {
|
|
104
117
|
this.syncFromDisk();
|
|
105
|
-
|
|
118
|
+
const inMem = this.runs.find((r) => r.seq === seq);
|
|
119
|
+
if (inMem)
|
|
120
|
+
return inMem;
|
|
121
|
+
return this.readFromDiskBySeq(seq);
|
|
122
|
+
}
|
|
123
|
+
readFromDiskBySeq(seq) {
|
|
124
|
+
let raw;
|
|
125
|
+
try {
|
|
126
|
+
raw = readFileSync(this.file, "utf-8");
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
const lines = raw.split("\n");
|
|
132
|
+
for (const line of lines) {
|
|
133
|
+
if (!line)
|
|
134
|
+
continue;
|
|
135
|
+
try {
|
|
136
|
+
const parsed = JSON.parse(line);
|
|
137
|
+
if (parsed.seq === seq)
|
|
138
|
+
return parsed;
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
// skip malformed line — never let one bad row break lookup
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return null;
|
|
106
145
|
}
|
|
107
146
|
/** Test/inspection helper — current in-memory size. */
|
|
108
147
|
size() {
|
|
@@ -118,6 +157,81 @@ export class RecipeRunLog {
|
|
|
118
157
|
if (this.runs.length > this.memoryCap)
|
|
119
158
|
this.runs.shift();
|
|
120
159
|
}
|
|
160
|
+
/**
|
|
161
|
+
* Begin a run. Allocates a monotonic seq, adds an in-memory entry with
|
|
162
|
+
* `status: "running"`, and returns the seq so the caller can correlate
|
|
163
|
+
* step events. The entry is NOT persisted to disk — running runs are
|
|
164
|
+
* ephemeral and don't survive a bridge restart (recipes-in-flight don't
|
|
165
|
+
* survive restart anyway). Use `completeRun(seq, …)` when the run finishes
|
|
166
|
+
* to upgrade the entry to a terminal status and persist it.
|
|
167
|
+
*/
|
|
168
|
+
startRun(opts) {
|
|
169
|
+
const seq = ++this.seq;
|
|
170
|
+
const run = {
|
|
171
|
+
seq,
|
|
172
|
+
taskId: opts.taskId,
|
|
173
|
+
recipeName: opts.recipeName,
|
|
174
|
+
trigger: opts.trigger,
|
|
175
|
+
status: "running",
|
|
176
|
+
createdAt: opts.createdAt,
|
|
177
|
+
...(opts.startedAt !== undefined && { startedAt: opts.startedAt }),
|
|
178
|
+
...(opts.model !== undefined && { model: opts.model }),
|
|
179
|
+
// doneAt + durationMs are placeholders until completeRun fires —
|
|
180
|
+
// dashboard treats `status:"running"` as the source of truth.
|
|
181
|
+
doneAt: opts.createdAt,
|
|
182
|
+
durationMs: 0,
|
|
183
|
+
stepResults: [],
|
|
184
|
+
};
|
|
185
|
+
this.runs.push(run);
|
|
186
|
+
if (this.runs.length > this.memoryCap)
|
|
187
|
+
this.runs.shift();
|
|
188
|
+
return seq;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Replace the in-memory step list for a running entry. Called as steps
|
|
192
|
+
* complete so the dashboard's `/runs/[seq]` page can render progress
|
|
193
|
+
* without waiting for `completeRun`. No-op if the seq is unknown or
|
|
194
|
+
* already terminal.
|
|
195
|
+
*/
|
|
196
|
+
updateRunSteps(seq, stepResults) {
|
|
197
|
+
const idx = this.runs.findIndex((r) => r.seq === seq);
|
|
198
|
+
if (idx === -1)
|
|
199
|
+
return;
|
|
200
|
+
const run = this.runs[idx];
|
|
201
|
+
if (!run || run.status !== "running")
|
|
202
|
+
return;
|
|
203
|
+
this.runs[idx] = { ...run, stepResults: [...stepResults] };
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Finalize a running entry: update status + duration, append step results,
|
|
207
|
+
* and persist the row to JSONL. No-op if the seq is unknown (e.g. the run
|
|
208
|
+
* was started in a previous process before a restart).
|
|
209
|
+
*/
|
|
210
|
+
completeRun(seq, opts) {
|
|
211
|
+
const idx = this.runs.findIndex((r) => r.seq === seq);
|
|
212
|
+
if (idx === -1)
|
|
213
|
+
return;
|
|
214
|
+
const prev = this.runs[idx];
|
|
215
|
+
if (!prev || prev.status !== "running")
|
|
216
|
+
return;
|
|
217
|
+
const finalized = {
|
|
218
|
+
...prev,
|
|
219
|
+
status: opts.status,
|
|
220
|
+
doneAt: opts.doneAt,
|
|
221
|
+
durationMs: opts.durationMs,
|
|
222
|
+
stepResults: opts.stepResults,
|
|
223
|
+
...(opts.outputTail !== undefined && { outputTail: opts.outputTail }),
|
|
224
|
+
...(opts.errorMessage !== undefined && {
|
|
225
|
+
errorMessage: opts.errorMessage,
|
|
226
|
+
}),
|
|
227
|
+
...(opts.assertionFailures !== undefined && {
|
|
228
|
+
assertionFailures: opts.assertionFailures,
|
|
229
|
+
}),
|
|
230
|
+
};
|
|
231
|
+
this.runs[idx] = finalized;
|
|
232
|
+
mkdirSync(path.dirname(this.file), { recursive: true, mode: 0o700 });
|
|
233
|
+
this.append(finalized);
|
|
234
|
+
}
|
|
121
235
|
append(run) {
|
|
122
236
|
try {
|
|
123
237
|
appendFileSync(this.file, `${JSON.stringify(run)}\n`, { mode: 0o600 });
|
package/dist/runLog.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runLog.js","sourceRoot":"","sources":["../src/runLog.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC5E,OAAO,IAAI,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"runLog.js","sourceRoot":"","sources":["../src/runLog.ts"],"names":[],"mappings":"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"}
|
package/dist/server.d.ts
CHANGED
|
@@ -103,6 +103,14 @@ export declare class Server extends EventEmitter<ServerEvents> {
|
|
|
103
103
|
runDetailFn: ((seq: number) => Record<string, unknown> | null) | null;
|
|
104
104
|
/** Patchwork: set by bridge to generate a dry-run plan for a recipe by name. */
|
|
105
105
|
runPlanFn: ((recipeName: string) => Promise<Record<string, unknown>>) | null;
|
|
106
|
+
/** Patchwork (VD-4): mocked replay of an existing run. Returns the new
|
|
107
|
+
* run's seq plus any unmocked steps the caller may want to surface. */
|
|
108
|
+
runReplayFn: ((seq: number) => Promise<{
|
|
109
|
+
ok: boolean;
|
|
110
|
+
newSeq?: number;
|
|
111
|
+
unmockedSteps?: string[];
|
|
112
|
+
error?: string;
|
|
113
|
+
}>) | null;
|
|
106
114
|
/** Patchwork: set by bridge to launch a named recipe via the orchestrator. */
|
|
107
115
|
runRecipeFn: ((name: string, vars?: Record<string, string>) => Promise<{
|
|
108
116
|
ok: boolean;
|
package/dist/server.js
CHANGED
|
@@ -109,6 +109,9 @@ export class Server extends EventEmitter {
|
|
|
109
109
|
runDetailFn = null;
|
|
110
110
|
/** Patchwork: set by bridge to generate a dry-run plan for a recipe by name. */
|
|
111
111
|
runPlanFn = null;
|
|
112
|
+
/** Patchwork (VD-4): mocked replay of an existing run. Returns the new
|
|
113
|
+
* run's seq plus any unmocked steps the caller may want to surface. */
|
|
114
|
+
runReplayFn = null;
|
|
112
115
|
/** Patchwork: set by bridge to launch a named recipe via the orchestrator. */
|
|
113
116
|
runRecipeFn = null;
|
|
114
117
|
/** Patchwork: admin-controlled managed settings path (highest rule precedence). */
|
|
@@ -443,6 +446,21 @@ export class Server extends EventEmitter {
|
|
|
443
446
|
})();
|
|
444
447
|
return;
|
|
445
448
|
}
|
|
449
|
+
if (parsedUrl.pathname === "/connections/google-drive/callback" &&
|
|
450
|
+
req.method === "GET") {
|
|
451
|
+
void (async () => {
|
|
452
|
+
const { handleDriveCallback } = await import("./connectors/googleDrive.js");
|
|
453
|
+
const code = parsedUrl.searchParams.get("code");
|
|
454
|
+
const state = parsedUrl.searchParams.get("state");
|
|
455
|
+
const error = parsedUrl.searchParams.get("error");
|
|
456
|
+
const result = await handleDriveCallback(code, state, error);
|
|
457
|
+
res.writeHead(result.status, {
|
|
458
|
+
"Content-Type": result.contentType ?? "application/json",
|
|
459
|
+
});
|
|
460
|
+
res.end(result.body);
|
|
461
|
+
})();
|
|
462
|
+
return;
|
|
463
|
+
}
|
|
446
464
|
if (parsedUrl.pathname === "/connections/slack/callback" &&
|
|
447
465
|
req.method === "GET") {
|
|
448
466
|
void (async () => {
|
|
@@ -1090,6 +1108,177 @@ export class Server extends EventEmitter {
|
|
|
1090
1108
|
res.end(result.body);
|
|
1091
1109
|
return;
|
|
1092
1110
|
}
|
|
1111
|
+
// ── Discord connector routes ───────────────────────────────────
|
|
1112
|
+
if ((parsedUrl.pathname === "/connections/discord/auth" ||
|
|
1113
|
+
parsedUrl.pathname === "/connections/discord/authorize") &&
|
|
1114
|
+
req.method === "GET") {
|
|
1115
|
+
const { handleDiscordAuthorize } = await import("./connectors/discord.js");
|
|
1116
|
+
const result = handleDiscordAuthorize();
|
|
1117
|
+
if (result.redirect) {
|
|
1118
|
+
res.writeHead(302, { Location: result.redirect });
|
|
1119
|
+
res.end();
|
|
1120
|
+
}
|
|
1121
|
+
else {
|
|
1122
|
+
res.writeHead(result.status, {
|
|
1123
|
+
"Content-Type": result.contentType ?? "application/json",
|
|
1124
|
+
});
|
|
1125
|
+
res.end(result.body);
|
|
1126
|
+
}
|
|
1127
|
+
return;
|
|
1128
|
+
}
|
|
1129
|
+
if (parsedUrl.pathname === "/connections/discord/callback" &&
|
|
1130
|
+
req.method === "GET") {
|
|
1131
|
+
void (async () => {
|
|
1132
|
+
const { handleDiscordCallback } = await import("./connectors/discord.js");
|
|
1133
|
+
const code = parsedUrl.searchParams.get("code");
|
|
1134
|
+
const state = parsedUrl.searchParams.get("state");
|
|
1135
|
+
const error = parsedUrl.searchParams.get("error");
|
|
1136
|
+
const result = await handleDiscordCallback(code, state, error);
|
|
1137
|
+
res.writeHead(result.status, {
|
|
1138
|
+
"Content-Type": result.contentType ?? "text/html",
|
|
1139
|
+
});
|
|
1140
|
+
res.end(result.body);
|
|
1141
|
+
})();
|
|
1142
|
+
return;
|
|
1143
|
+
}
|
|
1144
|
+
if (parsedUrl.pathname === "/connections/discord/test" &&
|
|
1145
|
+
req.method === "POST") {
|
|
1146
|
+
void (async () => {
|
|
1147
|
+
const { handleDiscordTest } = await import("./connectors/discord.js");
|
|
1148
|
+
const result = await handleDiscordTest();
|
|
1149
|
+
res.writeHead(result.status, {
|
|
1150
|
+
"Content-Type": result.contentType ?? "application/json",
|
|
1151
|
+
});
|
|
1152
|
+
res.end(result.body);
|
|
1153
|
+
})();
|
|
1154
|
+
return;
|
|
1155
|
+
}
|
|
1156
|
+
if (parsedUrl.pathname === "/connections/discord" &&
|
|
1157
|
+
req.method === "DELETE") {
|
|
1158
|
+
void (async () => {
|
|
1159
|
+
const { handleDiscordDisconnect } = await import("./connectors/discord.js");
|
|
1160
|
+
const result = await handleDiscordDisconnect();
|
|
1161
|
+
res.writeHead(result.status, {
|
|
1162
|
+
"Content-Type": result.contentType ?? "application/json",
|
|
1163
|
+
});
|
|
1164
|
+
res.end(result.body);
|
|
1165
|
+
})();
|
|
1166
|
+
return;
|
|
1167
|
+
}
|
|
1168
|
+
// ── Asana connector routes ─────────────────────────────────────
|
|
1169
|
+
if ((parsedUrl.pathname === "/connections/asana/auth" ||
|
|
1170
|
+
parsedUrl.pathname === "/connections/asana/authorize") &&
|
|
1171
|
+
req.method === "GET") {
|
|
1172
|
+
const { handleAsanaAuthorize } = await import("./connectors/asana.js");
|
|
1173
|
+
const result = handleAsanaAuthorize();
|
|
1174
|
+
if (result.redirect) {
|
|
1175
|
+
res.writeHead(302, { Location: result.redirect });
|
|
1176
|
+
res.end();
|
|
1177
|
+
}
|
|
1178
|
+
else {
|
|
1179
|
+
res.writeHead(result.status, {
|
|
1180
|
+
"Content-Type": result.contentType ?? "application/json",
|
|
1181
|
+
});
|
|
1182
|
+
res.end(result.body);
|
|
1183
|
+
}
|
|
1184
|
+
return;
|
|
1185
|
+
}
|
|
1186
|
+
if (parsedUrl.pathname === "/connections/asana/callback" &&
|
|
1187
|
+
req.method === "GET") {
|
|
1188
|
+
void (async () => {
|
|
1189
|
+
const { handleAsanaCallback } = await import("./connectors/asana.js");
|
|
1190
|
+
const code = parsedUrl.searchParams.get("code");
|
|
1191
|
+
const state = parsedUrl.searchParams.get("state");
|
|
1192
|
+
const error = parsedUrl.searchParams.get("error");
|
|
1193
|
+
const result = await handleAsanaCallback(code, state, error);
|
|
1194
|
+
res.writeHead(result.status, {
|
|
1195
|
+
"Content-Type": result.contentType ?? "text/html",
|
|
1196
|
+
});
|
|
1197
|
+
res.end(result.body);
|
|
1198
|
+
})();
|
|
1199
|
+
return;
|
|
1200
|
+
}
|
|
1201
|
+
if (parsedUrl.pathname === "/connections/asana/test" &&
|
|
1202
|
+
req.method === "POST") {
|
|
1203
|
+
void (async () => {
|
|
1204
|
+
const { handleAsanaTest } = await import("./connectors/asana.js");
|
|
1205
|
+
const result = await handleAsanaTest();
|
|
1206
|
+
res.writeHead(result.status, {
|
|
1207
|
+
"Content-Type": result.contentType ?? "application/json",
|
|
1208
|
+
});
|
|
1209
|
+
res.end(result.body);
|
|
1210
|
+
})();
|
|
1211
|
+
return;
|
|
1212
|
+
}
|
|
1213
|
+
if (parsedUrl.pathname === "/connections/asana" &&
|
|
1214
|
+
req.method === "DELETE") {
|
|
1215
|
+
void (async () => {
|
|
1216
|
+
const { handleAsanaDisconnect } = await import("./connectors/asana.js");
|
|
1217
|
+
const result = await handleAsanaDisconnect();
|
|
1218
|
+
res.writeHead(result.status, {
|
|
1219
|
+
"Content-Type": result.contentType ?? "application/json",
|
|
1220
|
+
});
|
|
1221
|
+
res.end(result.body);
|
|
1222
|
+
})();
|
|
1223
|
+
return;
|
|
1224
|
+
}
|
|
1225
|
+
// ── GitLab connector routes ────────────────────────────────────
|
|
1226
|
+
if ((parsedUrl.pathname === "/connections/gitlab/auth" ||
|
|
1227
|
+
parsedUrl.pathname === "/connections/gitlab/authorize") &&
|
|
1228
|
+
req.method === "GET") {
|
|
1229
|
+
const { handleGitLabAuthorize } = await import("./connectors/gitlab.js");
|
|
1230
|
+
const result = handleGitLabAuthorize();
|
|
1231
|
+
if (result.redirect) {
|
|
1232
|
+
res.writeHead(302, { Location: result.redirect });
|
|
1233
|
+
res.end();
|
|
1234
|
+
}
|
|
1235
|
+
else {
|
|
1236
|
+
res.writeHead(result.status, {
|
|
1237
|
+
"Content-Type": result.contentType ?? "application/json",
|
|
1238
|
+
});
|
|
1239
|
+
res.end(result.body);
|
|
1240
|
+
}
|
|
1241
|
+
return;
|
|
1242
|
+
}
|
|
1243
|
+
if (parsedUrl.pathname === "/connections/gitlab/callback" &&
|
|
1244
|
+
req.method === "GET") {
|
|
1245
|
+
void (async () => {
|
|
1246
|
+
const { handleGitLabCallback } = await import("./connectors/gitlab.js");
|
|
1247
|
+
const code = parsedUrl.searchParams.get("code");
|
|
1248
|
+
const state = parsedUrl.searchParams.get("state");
|
|
1249
|
+
const error = parsedUrl.searchParams.get("error");
|
|
1250
|
+
const result = await handleGitLabCallback(code, state, error);
|
|
1251
|
+
res.writeHead(result.status, {
|
|
1252
|
+
"Content-Type": result.contentType ?? "text/html",
|
|
1253
|
+
});
|
|
1254
|
+
res.end(result.body);
|
|
1255
|
+
})();
|
|
1256
|
+
return;
|
|
1257
|
+
}
|
|
1258
|
+
if (parsedUrl.pathname === "/connections/gitlab/test" &&
|
|
1259
|
+
req.method === "POST") {
|
|
1260
|
+
void (async () => {
|
|
1261
|
+
const { handleGitLabTest } = await import("./connectors/gitlab.js");
|
|
1262
|
+
const result = await handleGitLabTest();
|
|
1263
|
+
res.writeHead(result.status, {
|
|
1264
|
+
"Content-Type": result.contentType ?? "application/json",
|
|
1265
|
+
});
|
|
1266
|
+
res.end(result.body);
|
|
1267
|
+
})();
|
|
1268
|
+
return;
|
|
1269
|
+
}
|
|
1270
|
+
if (parsedUrl.pathname === "/connections/gitlab" &&
|
|
1271
|
+
req.method === "DELETE") {
|
|
1272
|
+
void (async () => {
|
|
1273
|
+
const { handleGitLabDisconnect } = await import("./connectors/gitlab.js");
|
|
1274
|
+
const result = await handleGitLabDisconnect();
|
|
1275
|
+
res.writeHead(result.status, {
|
|
1276
|
+
"Content-Type": result.contentType ?? "application/json",
|
|
1277
|
+
});
|
|
1278
|
+
res.end(result.body);
|
|
1279
|
+
})();
|
|
1280
|
+
return;
|
|
1281
|
+
}
|
|
1093
1282
|
// ── Notion routes ──────────────────────────────────────────────
|
|
1094
1283
|
if (parsedUrl.pathname === "/connections/notion/connect" &&
|
|
1095
1284
|
req.method === "POST") {
|
|
@@ -1322,6 +1511,45 @@ export class Server extends EventEmitter {
|
|
|
1322
1511
|
res.end(result.body);
|
|
1323
1512
|
return;
|
|
1324
1513
|
}
|
|
1514
|
+
// ── PagerDuty routes ───────────────────────────────────────────
|
|
1515
|
+
if (parsedUrl.pathname === "/connections/pagerduty/connect" &&
|
|
1516
|
+
req.method === "POST") {
|
|
1517
|
+
const chunks = [];
|
|
1518
|
+
req.on("data", (c) => chunks.push(c));
|
|
1519
|
+
req.on("end", () => {
|
|
1520
|
+
void (async () => {
|
|
1521
|
+
const { handlePagerDutyConnect } = await import("./connectors/pagerduty.js");
|
|
1522
|
+
const result = await handlePagerDutyConnect(Buffer.concat(chunks).toString("utf-8"));
|
|
1523
|
+
res.writeHead(result.status, {
|
|
1524
|
+
"Content-Type": result.contentType ?? "application/json",
|
|
1525
|
+
});
|
|
1526
|
+
res.end(result.body);
|
|
1527
|
+
})();
|
|
1528
|
+
});
|
|
1529
|
+
return;
|
|
1530
|
+
}
|
|
1531
|
+
if (parsedUrl.pathname === "/connections/pagerduty/test" &&
|
|
1532
|
+
req.method === "POST") {
|
|
1533
|
+
void (async () => {
|
|
1534
|
+
const { handlePagerDutyTest } = await import("./connectors/pagerduty.js");
|
|
1535
|
+
const result = await handlePagerDutyTest();
|
|
1536
|
+
res.writeHead(result.status, {
|
|
1537
|
+
"Content-Type": result.contentType ?? "application/json",
|
|
1538
|
+
});
|
|
1539
|
+
res.end(result.body);
|
|
1540
|
+
})();
|
|
1541
|
+
return;
|
|
1542
|
+
}
|
|
1543
|
+
if (parsedUrl.pathname === "/connections/pagerduty" &&
|
|
1544
|
+
req.method === "DELETE") {
|
|
1545
|
+
const { handlePagerDutyDisconnect } = await import("./connectors/pagerduty.js");
|
|
1546
|
+
const result = handlePagerDutyDisconnect();
|
|
1547
|
+
res.writeHead(result.status, {
|
|
1548
|
+
"Content-Type": result.contentType ?? "application/json",
|
|
1549
|
+
});
|
|
1550
|
+
res.end(result.body);
|
|
1551
|
+
return;
|
|
1552
|
+
}
|
|
1325
1553
|
// ── Stripe routes ───────────────────────────────────────────────
|
|
1326
1554
|
if (parsedUrl.pathname === "/connections/stripe/connect" &&
|
|
1327
1555
|
req.method === "POST") {
|
|
@@ -1419,6 +1647,63 @@ export class Server extends EventEmitter {
|
|
|
1419
1647
|
})();
|
|
1420
1648
|
return;
|
|
1421
1649
|
}
|
|
1650
|
+
if (parsedUrl.pathname === "/connections/google-drive/auth" &&
|
|
1651
|
+
req.method === "GET") {
|
|
1652
|
+
void (async () => {
|
|
1653
|
+
const { handleDriveAuthRedirect } = await import("./connectors/googleDrive.js");
|
|
1654
|
+
const result = handleDriveAuthRedirect();
|
|
1655
|
+
if (result.redirect) {
|
|
1656
|
+
res.writeHead(302, { Location: result.redirect });
|
|
1657
|
+
res.end();
|
|
1658
|
+
}
|
|
1659
|
+
else {
|
|
1660
|
+
res.writeHead(result.status, {
|
|
1661
|
+
"Content-Type": result.contentType ?? "application/json",
|
|
1662
|
+
});
|
|
1663
|
+
res.end(result.body);
|
|
1664
|
+
}
|
|
1665
|
+
})();
|
|
1666
|
+
return;
|
|
1667
|
+
}
|
|
1668
|
+
if (parsedUrl.pathname === "/connections/google-drive/callback" &&
|
|
1669
|
+
req.method === "GET") {
|
|
1670
|
+
void (async () => {
|
|
1671
|
+
const { handleDriveCallback } = await import("./connectors/googleDrive.js");
|
|
1672
|
+
const code = parsedUrl.searchParams.get("code");
|
|
1673
|
+
const state = parsedUrl.searchParams.get("state");
|
|
1674
|
+
const error = parsedUrl.searchParams.get("error");
|
|
1675
|
+
const result = await handleDriveCallback(code, state, error);
|
|
1676
|
+
res.writeHead(result.status, {
|
|
1677
|
+
"Content-Type": result.contentType ?? "application/json",
|
|
1678
|
+
});
|
|
1679
|
+
res.end(result.body);
|
|
1680
|
+
})();
|
|
1681
|
+
return;
|
|
1682
|
+
}
|
|
1683
|
+
if (parsedUrl.pathname === "/connections/google-drive/test" &&
|
|
1684
|
+
req.method === "POST") {
|
|
1685
|
+
void (async () => {
|
|
1686
|
+
const { handleDriveTest } = await import("./connectors/googleDrive.js");
|
|
1687
|
+
const result = await handleDriveTest();
|
|
1688
|
+
res.writeHead(result.status, {
|
|
1689
|
+
"Content-Type": result.contentType ?? "application/json",
|
|
1690
|
+
});
|
|
1691
|
+
res.end(result.body);
|
|
1692
|
+
})();
|
|
1693
|
+
return;
|
|
1694
|
+
}
|
|
1695
|
+
if (parsedUrl.pathname === "/connections/google-drive" &&
|
|
1696
|
+
req.method === "DELETE") {
|
|
1697
|
+
void (async () => {
|
|
1698
|
+
const { handleDriveDisconnect } = await import("./connectors/googleDrive.js");
|
|
1699
|
+
const result = await handleDriveDisconnect();
|
|
1700
|
+
res.writeHead(result.status, {
|
|
1701
|
+
"Content-Type": result.contentType ?? "application/json",
|
|
1702
|
+
});
|
|
1703
|
+
res.end(result.body);
|
|
1704
|
+
})();
|
|
1705
|
+
return;
|
|
1706
|
+
}
|
|
1422
1707
|
// ── Inbox routes ────────────────────────────────────────────────────
|
|
1423
1708
|
if (parsedUrl.pathname === "/inbox" && req.method === "GET") {
|
|
1424
1709
|
void (async () => {
|
|
@@ -1519,10 +1804,11 @@ export class Server extends EventEmitter {
|
|
|
1519
1804
|
const parsed = body
|
|
1520
1805
|
? JSON.parse(body)
|
|
1521
1806
|
: {};
|
|
1522
|
-
const
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1807
|
+
const varsRaw = parsed.vars ?? parsed.inputs;
|
|
1808
|
+
const vars = varsRaw &&
|
|
1809
|
+
typeof varsRaw === "object" &&
|
|
1810
|
+
!Array.isArray(varsRaw)
|
|
1811
|
+
? varsRaw
|
|
1526
1812
|
: undefined;
|
|
1527
1813
|
if (!this.runRecipeFn) {
|
|
1528
1814
|
res.writeHead(503, { "Content-Type": "application/json" });
|
|
@@ -1656,6 +1942,41 @@ export class Server extends EventEmitter {
|
|
|
1656
1942
|
}
|
|
1657
1943
|
return;
|
|
1658
1944
|
}
|
|
1945
|
+
// POST /runs/:seq/replay — VD-4 mocked replay. Re-runs the recipe
|
|
1946
|
+
// with all tool/agent execution intercepted to return captured
|
|
1947
|
+
// outputs from the original run. No external IO, no side effects.
|
|
1948
|
+
// Real-mode replay is not exposed here yet — must ship separately
|
|
1949
|
+
// with confirmation UX + kill-switch interaction.
|
|
1950
|
+
const runReplayMatch = req.method === "POST"
|
|
1951
|
+
? /^\/runs\/(\d+)\/replay$/.exec(parsedUrl.pathname)
|
|
1952
|
+
: null;
|
|
1953
|
+
if (runReplayMatch?.[1]) {
|
|
1954
|
+
const seq = Number.parseInt(runReplayMatch[1], 10);
|
|
1955
|
+
try {
|
|
1956
|
+
if (!this.runReplayFn) {
|
|
1957
|
+
res.writeHead(503, { "Content-Type": "application/json" });
|
|
1958
|
+
res.end(JSON.stringify({ error: "replay_unavailable" }));
|
|
1959
|
+
return;
|
|
1960
|
+
}
|
|
1961
|
+
const result = await this.runReplayFn(seq);
|
|
1962
|
+
if (result.error === "run_not_found") {
|
|
1963
|
+
res.writeHead(404, { "Content-Type": "application/json" });
|
|
1964
|
+
}
|
|
1965
|
+
else if (!result.ok) {
|
|
1966
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
1967
|
+
}
|
|
1968
|
+
else {
|
|
1969
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
1970
|
+
}
|
|
1971
|
+
res.end(JSON.stringify(result));
|
|
1972
|
+
}
|
|
1973
|
+
catch (err) {
|
|
1974
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1975
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
1976
|
+
res.end(JSON.stringify({ error: msg }));
|
|
1977
|
+
}
|
|
1978
|
+
return;
|
|
1979
|
+
}
|
|
1659
1980
|
// GET /runs/:seq/plan — dry-run plan for the recipe that produced this run
|
|
1660
1981
|
const runPlanMatch = req.method === "GET"
|
|
1661
1982
|
? /^\/runs\/(\d+)\/plan$/.exec(parsedUrl.pathname)
|
|
@@ -1674,7 +1995,8 @@ export class Server extends EventEmitter {
|
|
|
1674
1995
|
res.end(JSON.stringify({ error: "plan_unavailable" }));
|
|
1675
1996
|
return;
|
|
1676
1997
|
}
|
|
1677
|
-
|
|
1998
|
+
// triggerSource appends ":agent" suffix — strip before file lookup
|
|
1999
|
+
const recipeName = run.recipeName.replace(/:agent$/, "");
|
|
1678
2000
|
const plan = await this.runPlanFn(recipeName);
|
|
1679
2001
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
1680
2002
|
res.end(JSON.stringify({ plan }));
|
|
@@ -1722,7 +2044,7 @@ export class Server extends EventEmitter {
|
|
|
1722
2044
|
}
|
|
1723
2045
|
const recipePatchMatch = /^\/recipes\/([^/]+)$/.exec(parsedUrl.pathname);
|
|
1724
2046
|
if (recipePatchMatch && req.method === "PATCH") {
|
|
1725
|
-
const name = decodeURIComponent(recipePatchMatch[1]);
|
|
2047
|
+
const name = decodeURIComponent(recipePatchMatch[1] ?? "");
|
|
1726
2048
|
const chunks = [];
|
|
1727
2049
|
req.on("data", (c) => chunks.push(c));
|
|
1728
2050
|
req.on("end", () => {
|
|
@@ -1789,7 +2111,7 @@ export class Server extends EventEmitter {
|
|
|
1789
2111
|
}
|
|
1790
2112
|
const recipeContentMatch = /^\/recipes\/([^/]+)$/.exec(parsedUrl.pathname);
|
|
1791
2113
|
if (recipeContentMatch && req.method === "GET") {
|
|
1792
|
-
const name = decodeURIComponent(recipeContentMatch[1]);
|
|
2114
|
+
const name = decodeURIComponent(recipeContentMatch[1] ?? "");
|
|
1793
2115
|
if (!this.loadRecipeContentFn) {
|
|
1794
2116
|
res.writeHead(503, { "Content-Type": "application/json" });
|
|
1795
2117
|
res.end(JSON.stringify({ ok: false, error: "Recipe content unavailable" }));
|
|
@@ -1806,7 +2128,7 @@ export class Server extends EventEmitter {
|
|
|
1806
2128
|
return;
|
|
1807
2129
|
}
|
|
1808
2130
|
if (recipeContentMatch && req.method === "PUT") {
|
|
1809
|
-
const name = decodeURIComponent(recipeContentMatch[1]);
|
|
2131
|
+
const name = decodeURIComponent(recipeContentMatch[1] ?? "");
|
|
1810
2132
|
const chunks = [];
|
|
1811
2133
|
req.on("data", (c) => chunks.push(c));
|
|
1812
2134
|
req.on("end", () => {
|
|
@@ -1842,7 +2164,7 @@ export class Server extends EventEmitter {
|
|
|
1842
2164
|
return;
|
|
1843
2165
|
}
|
|
1844
2166
|
if (recipeContentMatch && req.method === "DELETE") {
|
|
1845
|
-
const name = decodeURIComponent(recipeContentMatch[1]);
|
|
2167
|
+
const name = decodeURIComponent(recipeContentMatch[1] ?? "");
|
|
1846
2168
|
if (!this.deleteRecipeContentFn) {
|
|
1847
2169
|
res.writeHead(503, { "Content-Type": "application/json" });
|
|
1848
2170
|
res.end(JSON.stringify({
|