patchwork-os 0.2.0-alpha.33 → 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 +248 -48
- 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 +35 -1
- package/dist/bridge.js.map +1 -1
- package/dist/commands/recipe.d.ts +11 -0
- package/dist/commands/recipe.js +32 -3
- 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 +107 -25
- 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 +15 -7
- 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 +45 -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/htmlEscape.d.ts +5 -0
- package/dist/connectors/htmlEscape.js +13 -0
- package/dist/connectors/htmlEscape.js.map +1 -0
- package/dist/connectors/linear.js +26 -6
- package/dist/connectors/linear.js.map +1 -1
- package/dist/connectors/mcpOAuth.d.ts +2 -0
- package/dist/connectors/mcpOAuth.js +8 -4
- package/dist/connectors/mcpOAuth.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/sentry.js +3 -2
- package/dist/connectors/sentry.js.map +1 -1
- package/dist/connectors/slack.d.ts +1 -1
- package/dist/connectors/slack.js +7 -4
- 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 +262 -129
- package/dist/index.js.map +1 -1
- package/dist/oauth.js +3 -2
- package/dist/oauth.js.map +1 -1
- package/dist/recipeOrchestration.d.ts +7 -0
- package/dist/recipeOrchestration.js +154 -28
- package/dist/recipeOrchestration.js.map +1 -1
- package/dist/recipes/agentExecutor.d.ts +1 -0
- package/dist/recipes/agentExecutor.js +7 -0
- package/dist/recipes/agentExecutor.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/legacyRecipeCompat.d.ts +8 -0
- package/dist/recipes/legacyRecipeCompat.js +20 -1
- package/dist/recipes/legacyRecipeCompat.js.map +1 -1
- package/dist/recipes/manifest.js +21 -6
- package/dist/recipes/manifest.js.map +1 -1
- package/dist/recipes/migrations/index.d.ts +24 -0
- package/dist/recipes/migrations/index.js +55 -0
- package/dist/recipes/migrations/index.js.map +1 -0
- package/dist/recipes/migrations/types.d.ts +28 -0
- package/dist/recipes/migrations/types.js +2 -0
- package/dist/recipes/migrations/types.js.map +1 -0
- package/dist/recipes/migrations/v1.d.ts +11 -0
- package/dist/recipes/migrations/v1.js +18 -0
- package/dist/recipes/migrations/v1.js.map +1 -0
- 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/templateEngine.js +8 -1
- package/dist/recipes/templateEngine.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/validation.js +54 -15
- package/dist/recipes/validation.js.map +1 -1
- package/dist/recipes/yamlRunner.d.ts +23 -2
- package/dist/recipes/yamlRunner.js +265 -60
- package/dist/recipes/yamlRunner.js.map +1 -1
- package/dist/recipesHttp.d.ts +60 -0
- package/dist/recipesHttp.js +418 -3
- 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 +21 -0
- package/dist/server.js +387 -8
- 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/activityLog.d.ts +2 -0
- package/dist/tools/addLinearComment.d.ts +1 -0
- package/dist/tools/batchLsp.d.ts +3 -0
- package/dist/tools/bridgeDoctor.d.ts +1 -0
- package/dist/tools/bridgeStatus.d.ts +1 -0
- package/dist/tools/cancelClaudeTask.d.ts +1 -0
- package/dist/tools/checkDocumentDirty.d.ts +1 -0
- package/dist/tools/clipboard.d.ts +2 -0
- package/dist/tools/closeTabs.d.ts +2 -0
- package/dist/tools/codeLens.d.ts +1 -0
- package/dist/tools/contextBundle.d.ts +1 -0
- package/dist/tools/createIssueFromAIComment.d.ts +1 -0
- package/dist/tools/createLinearIssue.d.ts +1 -0
- package/dist/tools/ctxGetTaskContext.d.ts +1 -0
- package/dist/tools/ctxQueryTraces.d.ts +1 -0
- package/dist/tools/ctxSaveTrace.d.ts +1 -0
- package/dist/tools/debug.d.ts +4 -0
- package/dist/tools/decorations.d.ts +2 -0
- package/dist/tools/documentLinks.d.ts +1 -0
- package/dist/tools/editText.d.ts +1 -0
- package/dist/tools/enrichCommit.d.ts +1 -0
- package/dist/tools/enrichStackTrace.d.ts +1 -0
- package/dist/tools/explainDiagnostic.d.ts +1 -0
- package/dist/tools/explainSymbol.d.ts +1 -0
- package/dist/tools/fetchCalendarEvents.d.ts +1 -0
- package/dist/tools/fetchGithubIssue.d.ts +1 -0
- package/dist/tools/fetchGithubPR.d.ts +1 -0
- package/dist/tools/fetchLinearIssue.d.ts +1 -0
- package/dist/tools/fetchSentryIssue.d.ts +1 -0
- package/dist/tools/fetchSlackProfile.d.ts +1 -0
- package/dist/tools/fileOperations.d.ts +3 -0
- package/dist/tools/fileWatcher.d.ts +2 -0
- package/dist/tools/findFiles.d.ts +1 -0
- package/dist/tools/findRelatedTests.d.ts +1 -0
- package/dist/tools/fixAllLintErrors.d.ts +1 -0
- package/dist/tools/foldingRanges.d.ts +1 -0
- package/dist/tools/formatDocument.d.ts +1 -0
- package/dist/tools/generateTests.d.ts +1 -0
- package/dist/tools/getAIComments.d.ts +1 -0
- package/dist/tools/getAnalyticsReport.d.ts +1 -0
- package/dist/tools/getArchitectureContext.d.ts +1 -0
- package/dist/tools/getBufferContent.d.ts +1 -0
- package/dist/tools/getChangeImpact.d.ts +1 -0
- package/dist/tools/getClaudeTaskStatus.d.ts +1 -0
- package/dist/tools/getCodeCoverage.d.ts +1 -0
- package/dist/tools/getCommitsForIssue.d.ts +1 -0
- package/dist/tools/getConnectorStatus.d.ts +1 -0
- package/dist/tools/getCurrentSelection.d.ts +2 -0
- package/dist/tools/getDebugState.d.ts +1 -0
- package/dist/tools/getDependencyTree.d.ts +1 -0
- package/dist/tools/getDiagnostics.d.ts +1 -0
- package/dist/tools/getDiffFromHandoff.d.ts +1 -0
- package/dist/tools/getDocumentSymbols.d.ts +1 -0
- package/dist/tools/getFileTree.d.ts +1 -0
- package/dist/tools/getGitDiff.d.ts +1 -0
- package/dist/tools/getGitHotspots.d.ts +1 -0
- package/dist/tools/getGitLog.d.ts +1 -0
- package/dist/tools/getGitStatus.d.ts +1 -0
- package/dist/tools/getImportTree.d.ts +1 -0
- package/dist/tools/getImportedSignatures.d.ts +1 -0
- package/dist/tools/getOpenEditors.d.ts +1 -0
- package/dist/tools/getPRTemplate.d.ts +1 -0
- package/dist/tools/getProjectContext.d.ts +1 -0
- package/dist/tools/getProjectInfo.d.ts +1 -0
- package/dist/tools/getSecurityAdvisories.d.ts +1 -0
- package/dist/tools/getSessionUsage.d.ts +1 -0
- package/dist/tools/getSymbolHistory.d.ts +1 -0
- package/dist/tools/getToolCapabilities.d.ts +1 -0
- package/dist/tools/getTypeSignature.d.ts +1 -0
- package/dist/tools/getWorkspaceFolders.d.ts +1 -0
- package/dist/tools/getWorkspaceSettings.d.ts +1 -0
- package/dist/tools/gitHistory.d.ts +2 -0
- package/dist/tools/gitWrite.d.ts +11 -0
- package/dist/tools/github/actions.d.ts +2 -0
- package/dist/tools/github/composite.d.ts +3 -0
- package/dist/tools/github/issues.d.ts +4 -0
- package/dist/tools/github/pr.d.ts +7 -0
- package/dist/tools/handoffNote.d.ts +2 -0
- package/dist/tools/hoverAtCursor.d.ts +1 -0
- package/dist/tools/httpClient.d.ts +2 -0
- package/dist/tools/inlayHints.d.ts +1 -0
- package/dist/tools/launchQuickTask.d.ts +1 -0
- package/dist/tools/listClaudeTasks.d.ts +1 -0
- package/dist/tools/listTerminals.d.ts +1 -0
- package/dist/tools/lsp.d.ts +14 -0
- package/dist/tools/navigateToSymbolByName.d.ts +1 -0
- package/dist/tools/openDiff.d.ts +1 -0
- package/dist/tools/openFile.d.ts +1 -0
- package/dist/tools/openInBrowser.d.ts +1 -0
- package/dist/tools/organizeImports.d.ts +1 -0
- package/dist/tools/performanceReport.d.ts +1 -0
- package/dist/tools/planPersistence.d.ts +5 -0
- package/dist/tools/previewEdit.d.ts +1 -0
- package/dist/tools/refactorAnalyze.d.ts +1 -0
- package/dist/tools/refactorPreview.d.ts +1 -0
- package/dist/tools/replaceBlock.d.ts +1 -0
- package/dist/tools/resumeClaudeTask.d.ts +1 -0
- package/dist/tools/runClaudeTask.d.ts +1 -0
- package/dist/tools/runCommand.d.ts +1 -0
- package/dist/tools/runTests.d.ts +1 -0
- package/dist/tools/saveDocument.d.ts +1 -0
- package/dist/tools/screenshotAndAnnotate.d.ts +1 -0
- package/dist/tools/searchAndReplace.d.ts +1 -0
- package/dist/tools/searchTools.d.ts +1 -0
- package/dist/tools/searchWorkspace.d.ts +1 -0
- package/dist/tools/selectionRanges.d.ts +1 -0
- package/dist/tools/semanticTokens.d.ts +1 -0
- package/dist/tools/setActiveWorkspaceFolder.d.ts +1 -0
- package/dist/tools/signatureHelp.d.ts +1 -0
- package/dist/tools/slackListChannels.d.ts +1 -0
- package/dist/tools/slackPostMessage.d.ts +1 -0
- package/dist/tools/slackPostMessage.js +1 -1
- package/dist/tools/slackPostMessage.js.map +1 -1
- package/dist/tools/terminal.d.ts +6 -0
- package/dist/tools/testTraceToSource.d.ts +1 -0
- package/dist/tools/transaction.d.ts +4 -0
- package/dist/tools/typeHierarchy.d.ts +1 -0
- package/dist/tools/updateLinearIssue.d.ts +1 -0
- package/dist/tools/utils.d.ts +2 -0
- package/dist/tools/utils.js.map +1 -1
- package/dist/tools/vscodeCommands.d.ts +2 -0
- package/dist/tools/vscodeTasks.d.ts +2 -0
- package/dist/tools/workspaceSettings.d.ts +1 -0
- package/package.json +20 -4
- package/templates/recipes/project-health-check.yaml +1 -1
- package/dist/schemas/dry-run-plan.v1.json +0 -139
- package/dist/schemas/recipe.v1.json +0 -684
package/dist/server.js
CHANGED
|
@@ -97,6 +97,10 @@ export class Server extends EventEmitter {
|
|
|
97
97
|
loadRecipeContentFn = null;
|
|
98
98
|
/** Patchwork: set by bridge to save raw recipe source content by name. */
|
|
99
99
|
saveRecipeContentFn = null;
|
|
100
|
+
/** Patchwork: set by bridge to delete a recipe by name. */
|
|
101
|
+
deleteRecipeContentFn = null;
|
|
102
|
+
/** Patchwork: set by bridge to lint raw recipe content without saving. */
|
|
103
|
+
lintRecipeContentFn = null;
|
|
100
104
|
/** Patchwork: set by bridge to save a new recipe draft to disk. */
|
|
101
105
|
saveRecipeFn = null;
|
|
102
106
|
/** Patchwork: set by bridge to query the recipe run audit log. */
|
|
@@ -105,6 +109,9 @@ export class Server extends EventEmitter {
|
|
|
105
109
|
runDetailFn = null;
|
|
106
110
|
/** Patchwork: set by bridge to generate a dry-run plan for a recipe by name. */
|
|
107
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;
|
|
108
115
|
/** Patchwork: set by bridge to launch a named recipe via the orchestrator. */
|
|
109
116
|
runRecipeFn = null;
|
|
110
117
|
/** Patchwork: admin-controlled managed settings path (highest rule precedence). */
|
|
@@ -439,6 +446,21 @@ export class Server extends EventEmitter {
|
|
|
439
446
|
})();
|
|
440
447
|
return;
|
|
441
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
|
+
}
|
|
442
464
|
if (parsedUrl.pathname === "/connections/slack/callback" &&
|
|
443
465
|
req.method === "GET") {
|
|
444
466
|
void (async () => {
|
|
@@ -1086,6 +1108,177 @@ export class Server extends EventEmitter {
|
|
|
1086
1108
|
res.end(result.body);
|
|
1087
1109
|
return;
|
|
1088
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
|
+
}
|
|
1089
1282
|
// ── Notion routes ──────────────────────────────────────────────
|
|
1090
1283
|
if (parsedUrl.pathname === "/connections/notion/connect" &&
|
|
1091
1284
|
req.method === "POST") {
|
|
@@ -1318,6 +1511,45 @@ export class Server extends EventEmitter {
|
|
|
1318
1511
|
res.end(result.body);
|
|
1319
1512
|
return;
|
|
1320
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
|
+
}
|
|
1321
1553
|
// ── Stripe routes ───────────────────────────────────────────────
|
|
1322
1554
|
if (parsedUrl.pathname === "/connections/stripe/connect" &&
|
|
1323
1555
|
req.method === "POST") {
|
|
@@ -1415,6 +1647,63 @@ export class Server extends EventEmitter {
|
|
|
1415
1647
|
})();
|
|
1416
1648
|
return;
|
|
1417
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
|
+
}
|
|
1418
1707
|
// ── Inbox routes ────────────────────────────────────────────────────
|
|
1419
1708
|
if (parsedUrl.pathname === "/inbox" && req.method === "GET") {
|
|
1420
1709
|
void (async () => {
|
|
@@ -1515,10 +1804,11 @@ export class Server extends EventEmitter {
|
|
|
1515
1804
|
const parsed = body
|
|
1516
1805
|
? JSON.parse(body)
|
|
1517
1806
|
: {};
|
|
1518
|
-
const
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1807
|
+
const varsRaw = parsed.vars ?? parsed.inputs;
|
|
1808
|
+
const vars = varsRaw &&
|
|
1809
|
+
typeof varsRaw === "object" &&
|
|
1810
|
+
!Array.isArray(varsRaw)
|
|
1811
|
+
? varsRaw
|
|
1522
1812
|
: undefined;
|
|
1523
1813
|
if (!this.runRecipeFn) {
|
|
1524
1814
|
res.writeHead(503, { "Content-Type": "application/json" });
|
|
@@ -1652,6 +1942,41 @@ export class Server extends EventEmitter {
|
|
|
1652
1942
|
}
|
|
1653
1943
|
return;
|
|
1654
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
|
+
}
|
|
1655
1980
|
// GET /runs/:seq/plan — dry-run plan for the recipe that produced this run
|
|
1656
1981
|
const runPlanMatch = req.method === "GET"
|
|
1657
1982
|
? /^\/runs\/(\d+)\/plan$/.exec(parsedUrl.pathname)
|
|
@@ -1670,7 +1995,8 @@ export class Server extends EventEmitter {
|
|
|
1670
1995
|
res.end(JSON.stringify({ error: "plan_unavailable" }));
|
|
1671
1996
|
return;
|
|
1672
1997
|
}
|
|
1673
|
-
|
|
1998
|
+
// triggerSource appends ":agent" suffix — strip before file lookup
|
|
1999
|
+
const recipeName = run.recipeName.replace(/:agent$/, "");
|
|
1674
2000
|
const plan = await this.runPlanFn(recipeName);
|
|
1675
2001
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
1676
2002
|
res.end(JSON.stringify({ plan }));
|
|
@@ -1718,7 +2044,7 @@ export class Server extends EventEmitter {
|
|
|
1718
2044
|
}
|
|
1719
2045
|
const recipePatchMatch = /^\/recipes\/([^/]+)$/.exec(parsedUrl.pathname);
|
|
1720
2046
|
if (recipePatchMatch && req.method === "PATCH") {
|
|
1721
|
-
const name = decodeURIComponent(recipePatchMatch[1]);
|
|
2047
|
+
const name = decodeURIComponent(recipePatchMatch[1] ?? "");
|
|
1722
2048
|
const chunks = [];
|
|
1723
2049
|
req.on("data", (c) => chunks.push(c));
|
|
1724
2050
|
req.on("end", () => {
|
|
@@ -1750,9 +2076,42 @@ export class Server extends EventEmitter {
|
|
|
1750
2076
|
});
|
|
1751
2077
|
return;
|
|
1752
2078
|
}
|
|
2079
|
+
if (parsedUrl.pathname === "/recipes/lint" && req.method === "POST") {
|
|
2080
|
+
const chunks = [];
|
|
2081
|
+
req.on("data", (c) => chunks.push(c));
|
|
2082
|
+
req.on("end", () => {
|
|
2083
|
+
try {
|
|
2084
|
+
const body = JSON.parse(Buffer.concat(chunks).toString("utf-8"));
|
|
2085
|
+
if (typeof body?.content !== "string") {
|
|
2086
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
2087
|
+
res.end(JSON.stringify({
|
|
2088
|
+
ok: false,
|
|
2089
|
+
error: "content (string) required",
|
|
2090
|
+
}));
|
|
2091
|
+
return;
|
|
2092
|
+
}
|
|
2093
|
+
if (!this.lintRecipeContentFn) {
|
|
2094
|
+
res.writeHead(503, { "Content-Type": "application/json" });
|
|
2095
|
+
res.end(JSON.stringify({
|
|
2096
|
+
ok: false,
|
|
2097
|
+
error: "Recipe lint unavailable",
|
|
2098
|
+
}));
|
|
2099
|
+
return;
|
|
2100
|
+
}
|
|
2101
|
+
const result = this.lintRecipeContentFn(body.content);
|
|
2102
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
2103
|
+
res.end(JSON.stringify(result));
|
|
2104
|
+
}
|
|
2105
|
+
catch {
|
|
2106
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
2107
|
+
res.end(JSON.stringify({ ok: false, error: "Invalid JSON body" }));
|
|
2108
|
+
}
|
|
2109
|
+
});
|
|
2110
|
+
return;
|
|
2111
|
+
}
|
|
1753
2112
|
const recipeContentMatch = /^\/recipes\/([^/]+)$/.exec(parsedUrl.pathname);
|
|
1754
2113
|
if (recipeContentMatch && req.method === "GET") {
|
|
1755
|
-
const name = decodeURIComponent(recipeContentMatch[1]);
|
|
2114
|
+
const name = decodeURIComponent(recipeContentMatch[1] ?? "");
|
|
1756
2115
|
if (!this.loadRecipeContentFn) {
|
|
1757
2116
|
res.writeHead(503, { "Content-Type": "application/json" });
|
|
1758
2117
|
res.end(JSON.stringify({ ok: false, error: "Recipe content unavailable" }));
|
|
@@ -1769,7 +2128,7 @@ export class Server extends EventEmitter {
|
|
|
1769
2128
|
return;
|
|
1770
2129
|
}
|
|
1771
2130
|
if (recipeContentMatch && req.method === "PUT") {
|
|
1772
|
-
const name = decodeURIComponent(recipeContentMatch[1]);
|
|
2131
|
+
const name = decodeURIComponent(recipeContentMatch[1] ?? "");
|
|
1773
2132
|
const chunks = [];
|
|
1774
2133
|
req.on("data", (c) => chunks.push(c));
|
|
1775
2134
|
req.on("end", () => {
|
|
@@ -1804,6 +2163,26 @@ export class Server extends EventEmitter {
|
|
|
1804
2163
|
});
|
|
1805
2164
|
return;
|
|
1806
2165
|
}
|
|
2166
|
+
if (recipeContentMatch && req.method === "DELETE") {
|
|
2167
|
+
const name = decodeURIComponent(recipeContentMatch[1] ?? "");
|
|
2168
|
+
if (!this.deleteRecipeContentFn) {
|
|
2169
|
+
res.writeHead(503, { "Content-Type": "application/json" });
|
|
2170
|
+
res.end(JSON.stringify({
|
|
2171
|
+
ok: false,
|
|
2172
|
+
error: "Recipe deletion unavailable",
|
|
2173
|
+
}));
|
|
2174
|
+
return;
|
|
2175
|
+
}
|
|
2176
|
+
const result = this.deleteRecipeContentFn(name);
|
|
2177
|
+
const status = result.ok
|
|
2178
|
+
? 200
|
|
2179
|
+
: result.error === "Recipe not found"
|
|
2180
|
+
? 404
|
|
2181
|
+
: 400;
|
|
2182
|
+
res.writeHead(status, { "Content-Type": "application/json" });
|
|
2183
|
+
res.end(JSON.stringify(result));
|
|
2184
|
+
return;
|
|
2185
|
+
}
|
|
1807
2186
|
if (req.url === "/recipes" && req.method === "GET") {
|
|
1808
2187
|
try {
|
|
1809
2188
|
const data = this.recipesFn?.() ?? { recipesDir: null, recipes: [] };
|