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/index.js
CHANGED
|
@@ -3,10 +3,15 @@
|
|
|
3
3
|
// Uses Node 20.6+ native dotenv loader; falls back to manual parse for older Node.
|
|
4
4
|
{
|
|
5
5
|
const { fileURLToPath: _fileURLToPath } = await import("node:url");
|
|
6
|
-
const envPath = _fileURLToPath(new URL("../.env", import.meta.url));
|
|
7
6
|
try {
|
|
8
7
|
const { readFileSync, existsSync } = await import("node:fs");
|
|
9
|
-
|
|
8
|
+
// Try both "../.env" (compiled dist/) and ".env" (tsx src/ dev run)
|
|
9
|
+
const candidates = [
|
|
10
|
+
_fileURLToPath(new URL("../.env", import.meta.url)),
|
|
11
|
+
_fileURLToPath(new URL(".env", import.meta.url)),
|
|
12
|
+
];
|
|
13
|
+
const envPath = candidates.find(existsSync);
|
|
14
|
+
if (envPath) {
|
|
10
15
|
for (const line of readFileSync(envPath, "utf-8").split("\n")) {
|
|
11
16
|
const m = /^([A-Z_][A-Z0-9_]*)=(.*)$/.exec(line.trim());
|
|
12
17
|
if (m?.[1] && !process.env[m[1]]) {
|
|
@@ -87,6 +92,59 @@ async function downloadVsixFromOpenVsx() {
|
|
|
87
92
|
writeFileSync(tmpPath, Buffer.from(buf));
|
|
88
93
|
return tmpPath;
|
|
89
94
|
}
|
|
95
|
+
// Closes the race where bridge.start() began initialising in parallel with
|
|
96
|
+
// a subcommand's async work — observed in the 2026-04-29 dogfood pass
|
|
97
|
+
// where `recipe install` errors interleaved with bridge "Tools: full"
|
|
98
|
+
// startup logs.
|
|
99
|
+
//
|
|
100
|
+
// Every subcommand `if`-block below dispatches via an `(async () => {...})()`
|
|
101
|
+
// IIFE that ends with `process.exit`. The IIFE invocation returns
|
|
102
|
+
// synchronously, so without this gate, control immediately falls through
|
|
103
|
+
// to the bridge.start() block at end-of-file and starts initialising
|
|
104
|
+
// alongside the subcommand's async work. process.exit fires *eventually*
|
|
105
|
+
// after the await chain, but the bridge has already begun in parallel.
|
|
106
|
+
// Two IIFEs (patchwork no-args dashboard, recipe watch) lack process.exit
|
|
107
|
+
// entirely — without this gate they would run alongside the bridge
|
|
108
|
+
// indefinitely.
|
|
109
|
+
//
|
|
110
|
+
// Single source of truth for "is this argv invoking a subcommand?" — the
|
|
111
|
+
// same list is also used by the unknown-command suggester at L2570.
|
|
112
|
+
const KNOWN_SUBCOMMANDS = [
|
|
113
|
+
"init",
|
|
114
|
+
"patchwork-init",
|
|
115
|
+
"start-all",
|
|
116
|
+
"install-extension",
|
|
117
|
+
"gen-claude-md",
|
|
118
|
+
"print-token",
|
|
119
|
+
"gen-plugin-stub",
|
|
120
|
+
"notify",
|
|
121
|
+
"install",
|
|
122
|
+
"marketplace",
|
|
123
|
+
"status",
|
|
124
|
+
"shim",
|
|
125
|
+
"recipe",
|
|
126
|
+
"dashboard",
|
|
127
|
+
"launchd",
|
|
128
|
+
];
|
|
129
|
+
const __invokedSubcommand = (() => {
|
|
130
|
+
const sub = process.argv[2];
|
|
131
|
+
if (!sub || sub.startsWith("-"))
|
|
132
|
+
return null;
|
|
133
|
+
// Treat KNOWN_SUBCOMMANDS as the dispatch source. The bare-binary
|
|
134
|
+
// dashboard launcher (no argv) is handled separately below.
|
|
135
|
+
return KNOWN_SUBCOMMANDS.includes(sub)
|
|
136
|
+
? sub
|
|
137
|
+
: null;
|
|
138
|
+
})();
|
|
139
|
+
const __invokedBareBinaryDashboard = (() => {
|
|
140
|
+
if (process.argv[2])
|
|
141
|
+
return false;
|
|
142
|
+
const binName = path.basename(process.argv[1] ?? "");
|
|
143
|
+
return (binName === "patchwork-os" ||
|
|
144
|
+
binName === "patchwork" ||
|
|
145
|
+
binName === "patchwork.js");
|
|
146
|
+
})();
|
|
147
|
+
const __subcommandWillRun = __invokedSubcommand !== null || __invokedBareBinaryDashboard;
|
|
90
148
|
// Handle --version flag — print package version and exit.
|
|
91
149
|
if (process.argv[2] === "--version" || process.argv[2] === "-v") {
|
|
92
150
|
console.log(`claude-ide-bridge ${PACKAGE_VERSION}`);
|
|
@@ -592,6 +650,68 @@ if (process.argv[2] === "recipe" && process.argv[3] === "list") {
|
|
|
592
650
|
process.exit(0);
|
|
593
651
|
})();
|
|
594
652
|
}
|
|
653
|
+
// Patchwork: `patchwork recipe enable <name>` / `recipe disable <name>` —
|
|
654
|
+
// flip the disabled marker so scheduled triggers (cron/file-watch) take
|
|
655
|
+
// effect (or stop). Manual `recipe run` is unaffected.
|
|
656
|
+
if (process.argv[2] === "recipe" &&
|
|
657
|
+
(process.argv[3] === "enable" || process.argv[3] === "disable")) {
|
|
658
|
+
const subcommand = process.argv[3];
|
|
659
|
+
const name = process.argv[4];
|
|
660
|
+
if (!name) {
|
|
661
|
+
process.stderr.write(`Usage: patchwork recipe ${subcommand} <name>\n` +
|
|
662
|
+
` See \`patchwork recipe list\` for installed recipe names.\n`);
|
|
663
|
+
process.exit(1);
|
|
664
|
+
}
|
|
665
|
+
(async () => {
|
|
666
|
+
try {
|
|
667
|
+
const { runRecipeEnable, runRecipeDisable } = await import("./commands/recipeInstall.js");
|
|
668
|
+
if (subcommand === "enable") {
|
|
669
|
+
const r = runRecipeEnable(name);
|
|
670
|
+
process.stdout.write(r.alreadyEnabled
|
|
671
|
+
? ` ℹ ${r.name} is already enabled\n`
|
|
672
|
+
: ` ✓ enabled ${r.name}\n`);
|
|
673
|
+
}
|
|
674
|
+
else {
|
|
675
|
+
const r = runRecipeDisable(name);
|
|
676
|
+
process.stdout.write(r.alreadyDisabled
|
|
677
|
+
? ` ℹ ${r.name} is already disabled\n`
|
|
678
|
+
: ` ✓ disabled ${r.name}\n`);
|
|
679
|
+
}
|
|
680
|
+
process.exit(0);
|
|
681
|
+
}
|
|
682
|
+
catch (err) {
|
|
683
|
+
process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
684
|
+
process.exit(1);
|
|
685
|
+
}
|
|
686
|
+
})();
|
|
687
|
+
}
|
|
688
|
+
// Patchwork: `patchwork recipe uninstall <name>` — remove an installed recipe
|
|
689
|
+
// directory and all its files. Sister to `recipe install`. Idempotent on
|
|
690
|
+
// success (subsequent uninstalls error with "no installed recipe").
|
|
691
|
+
if (process.argv[2] === "recipe" && process.argv[3] === "uninstall") {
|
|
692
|
+
const name = process.argv[4];
|
|
693
|
+
if (!name) {
|
|
694
|
+
process.stderr.write("Usage: patchwork recipe uninstall <name>\n" +
|
|
695
|
+
" See `patchwork recipe list` for installed recipe names.\n");
|
|
696
|
+
process.exit(1);
|
|
697
|
+
}
|
|
698
|
+
(async () => {
|
|
699
|
+
try {
|
|
700
|
+
const { runRecipeUninstall } = await import("./commands/recipeInstall.js");
|
|
701
|
+
const r = runRecipeUninstall(name);
|
|
702
|
+
if (!r.ok) {
|
|
703
|
+
process.stderr.write(`Error: ${r.error}\n`);
|
|
704
|
+
process.exit(1);
|
|
705
|
+
}
|
|
706
|
+
process.stdout.write(` ✓ Uninstalled ${name} (${r.installDir})\n`);
|
|
707
|
+
process.exit(0);
|
|
708
|
+
}
|
|
709
|
+
catch (err) {
|
|
710
|
+
process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
711
|
+
process.exit(1);
|
|
712
|
+
}
|
|
713
|
+
})();
|
|
714
|
+
}
|
|
595
715
|
// Patchwork: `patchwork recipe run <name>` — runs a recipe locally or via
|
|
596
716
|
// a running bridge's /recipes/run endpoint if one is available.
|
|
597
717
|
if (process.argv[2] === "recipe" && process.argv[3] === "run") {
|
|
@@ -831,7 +951,10 @@ if (process.argv[2] === "recipe" && process.argv[3] === "new") {
|
|
|
831
951
|
const args = process.argv.slice(4);
|
|
832
952
|
const recipeName = args[0];
|
|
833
953
|
if (!recipeName) {
|
|
834
|
-
process.stderr.write("Usage: patchwork recipe new <name> [--template <name>] [--desc <description>]\n"
|
|
954
|
+
process.stderr.write("Usage: patchwork recipe new <name> [--template <name>] [--desc <description>] [--out <dir>]\n" +
|
|
955
|
+
" --out <dir> Write the recipe to <dir>/<name>.yaml.\n" +
|
|
956
|
+
" Defaults to ~/.patchwork/recipes/ — pass `--out .` to\n" +
|
|
957
|
+
" write into the current directory instead.\n");
|
|
835
958
|
process.stderr.write("\nTemplates:\n");
|
|
836
959
|
(async () => {
|
|
837
960
|
const { listTemplates } = await import("./commands/recipe.js");
|
|
@@ -850,10 +973,16 @@ if (process.argv[2] === "recipe" && process.argv[3] === "new") {
|
|
|
850
973
|
const descIdx = args.indexOf("--desc");
|
|
851
974
|
const description = (descIdx >= 0 ? args[descIdx + 1] : undefined) ??
|
|
852
975
|
`Recipe: ${recipeName}`;
|
|
976
|
+
const outIdx = args.indexOf("--out");
|
|
977
|
+
const outRaw = outIdx >= 0 ? args[outIdx + 1] : undefined;
|
|
978
|
+
// `--out .` is the common case for "scaffold in cwd" — resolve so
|
|
979
|
+
// the success message shows the absolute path the user can open.
|
|
980
|
+
const outputDir = outRaw ? path.resolve(outRaw) : undefined;
|
|
853
981
|
const result = runNew({
|
|
854
982
|
name: recipeName,
|
|
855
983
|
description,
|
|
856
984
|
...(template ? { template } : {}),
|
|
985
|
+
...(outputDir ? { outputDir } : {}),
|
|
857
986
|
});
|
|
858
987
|
process.stdout.write(` ✓ Created ${result.path}\n`);
|
|
859
988
|
process.exit(0);
|
|
@@ -1957,27 +2086,12 @@ if (process.argv[2] === "launchd") {
|
|
|
1957
2086
|
}
|
|
1958
2087
|
}
|
|
1959
2088
|
{
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
"patchwork-init",
|
|
1963
|
-
"start-all",
|
|
1964
|
-
"install-extension",
|
|
1965
|
-
"gen-claude-md",
|
|
1966
|
-
"print-token",
|
|
1967
|
-
"gen-plugin-stub",
|
|
1968
|
-
"notify",
|
|
1969
|
-
"install",
|
|
1970
|
-
"marketplace",
|
|
1971
|
-
"status",
|
|
1972
|
-
"shim",
|
|
1973
|
-
"recipe",
|
|
1974
|
-
"dashboard",
|
|
1975
|
-
"launchd",
|
|
1976
|
-
];
|
|
2089
|
+
// Reuses the KNOWN_SUBCOMMANDS list from the top of this file as a single
|
|
2090
|
+
// source of truth for "what subcommand argv tokens are recognized".
|
|
1977
2091
|
const unknownSub = process.argv[2];
|
|
1978
2092
|
if (unknownSub &&
|
|
1979
2093
|
!unknownSub.startsWith("-") &&
|
|
1980
|
-
!
|
|
2094
|
+
!KNOWN_SUBCOMMANDS.includes(unknownSub)) {
|
|
1981
2095
|
const lev = (a, b) => {
|
|
1982
2096
|
const dp = Array.from({ length: a.length + 1 }, (_, i) => Array.from({ length: b.length + 1 }, (_, j) => i === 0 ? j : j === 0 ? i : 0));
|
|
1983
2097
|
for (let i = 1; i <= a.length; i++)
|
|
@@ -1993,127 +2107,146 @@ if (process.argv[2] === "launchd") {
|
|
|
1993
2107
|
// biome-ignore lint/style/noNonNullAssertion: dp is fully pre-allocated
|
|
1994
2108
|
return dp[a.length][b.length];
|
|
1995
2109
|
};
|
|
1996
|
-
const closest = [...
|
|
2110
|
+
const closest = [...KNOWN_SUBCOMMANDS].sort((a, b) => lev(unknownSub, a) - lev(unknownSub, b))[0];
|
|
1997
2111
|
console.error(`Unknown command: '${unknownSub}'. Did you mean: ${closest}?`);
|
|
1998
2112
|
process.exit(1);
|
|
1999
2113
|
}
|
|
2000
2114
|
}
|
|
2001
|
-
|
|
2002
|
-
//
|
|
2003
|
-
//
|
|
2004
|
-
//
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
resolved.adapter;
|
|
2011
|
-
process.stderr.write(`[patchwork] model adapter initialized: ${resolved.adapter.name}\n`);
|
|
2012
|
-
}
|
|
2013
|
-
}
|
|
2014
|
-
catch (err) {
|
|
2015
|
-
process.stderr.write(`[patchwork] adapter init failed: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
2115
|
+
// Skip the bridge-mode tail entirely when a subcommand IIFE will own the
|
|
2116
|
+
// process. `parseConfig` validates argv against the bridge's known-flag list
|
|
2117
|
+
// and raises "Unknown option" for subcommand-specific flags (e.g. `recipe
|
|
2118
|
+
// new --out .`); without this guard that throw kills the process before
|
|
2119
|
+
// the IIFE's microtask runs. The subcommand handles its own arg parsing.
|
|
2120
|
+
if (__subcommandWillRun) {
|
|
2121
|
+
// Subcommand IIFE is in flight or about to fire; sit tight until it
|
|
2122
|
+
// process.exits. Empty body — control naturally falls past end-of-file
|
|
2123
|
+
// and Node keeps the process alive on the IIFE's pending microtask.
|
|
2016
2124
|
}
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
//
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
.createHash("sha256")
|
|
2030
|
-
.update(config.workspace)
|
|
2031
|
-
.digest("hex")
|
|
2032
|
-
.slice(0, 6);
|
|
2033
|
-
const sessionName = `claude-bridge-${ws}${hash}`;
|
|
2034
|
-
// Check if tmux is available
|
|
2035
|
-
const tmuxCheck = spawnSync("which", ["tmux"], { stdio: "ignore" });
|
|
2036
|
-
if (tmuxCheck.status !== 0) {
|
|
2037
|
-
process.stderr.write("WARNING: --auto-tmux requested but tmux is not installed. Running without tmux.\n");
|
|
2038
|
-
}
|
|
2039
|
-
else {
|
|
2040
|
-
// Strip --auto-tmux from argv to avoid infinite re-exec loop
|
|
2041
|
-
const newArgv = process.argv.filter((a) => a !== "--auto-tmux");
|
|
2042
|
-
// Pass each argv token as a separate tmux argument so paths with spaces work correctly
|
|
2043
|
-
const result = spawnSync("tmux", ["new-session", "-d", "-s", sessionName, ...newArgv], { stdio: "inherit", timeout: 5000 });
|
|
2044
|
-
if (result.status === 0) {
|
|
2045
|
-
process.stderr.write(`Bridge launched in tmux session '${sessionName}'.\n`);
|
|
2046
|
-
process.stderr.write(` Attach with: tmux attach -t ${sessionName}\n`);
|
|
2047
|
-
process.exit(0);
|
|
2048
|
-
}
|
|
2049
|
-
else {
|
|
2050
|
-
// tmux session likely already exists — attach to it or fall through
|
|
2051
|
-
process.stderr.write(`WARNING: Could not create tmux session '${sessionName}' (already exists?). Running without auto-tmux.\n`);
|
|
2125
|
+
else {
|
|
2126
|
+
const config = parseConfig(process.argv);
|
|
2127
|
+
// Patchwork: resolve --model flag (optional, non-invasive) — stashes the
|
|
2128
|
+
// configured adapter on globalThis for consumers that opt into the adapter
|
|
2129
|
+
// layer. Bridge subprocess driver still works when --model is absent.
|
|
2130
|
+
try {
|
|
2131
|
+
const { resolveModel } = await import("./patchworkCli.js");
|
|
2132
|
+
const resolved = resolveModel(process.argv);
|
|
2133
|
+
if (resolved) {
|
|
2134
|
+
globalThis.__patchworkAdapter =
|
|
2135
|
+
resolved.adapter;
|
|
2136
|
+
process.stderr.write(`[patchwork] model adapter initialized: ${resolved.adapter.name}\n`);
|
|
2052
2137
|
}
|
|
2053
2138
|
}
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
const
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
}
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
});
|
|
2139
|
+
catch (err) {
|
|
2140
|
+
process.stderr.write(`[patchwork] adapter init failed: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
2141
|
+
}
|
|
2142
|
+
// If --analytics flag was passed, persist the preference immediately
|
|
2143
|
+
if (config.analyticsEnabled !== null) {
|
|
2144
|
+
setAnalyticsPref(config.analyticsEnabled);
|
|
2145
|
+
}
|
|
2146
|
+
// Auto-tmux: if requested and not already inside tmux or screen, re-exec inside a tmux session
|
|
2147
|
+
if (config.autoTmux &&
|
|
2148
|
+
!process.env.TMUX &&
|
|
2149
|
+
!process.env.STY &&
|
|
2150
|
+
!process.env.ZELLIJ &&
|
|
2151
|
+
!process.env.ZELLIJ_SESSION_NAME) {
|
|
2152
|
+
const ws = config.workspace.replace(/[^a-zA-Z0-9]/g, "").slice(-8);
|
|
2153
|
+
const hash = crypto
|
|
2154
|
+
.createHash("sha256")
|
|
2155
|
+
.update(config.workspace)
|
|
2156
|
+
.digest("hex")
|
|
2157
|
+
.slice(0, 6);
|
|
2158
|
+
const sessionName = `claude-bridge-${ws}${hash}`;
|
|
2159
|
+
// Check if tmux is available
|
|
2160
|
+
const tmuxCheck = spawnSync("which", ["tmux"], { stdio: "ignore" });
|
|
2161
|
+
if (tmuxCheck.status !== 0) {
|
|
2162
|
+
process.stderr.write("WARNING: --auto-tmux requested but tmux is not installed. Running without tmux.\n");
|
|
2079
2163
|
}
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2164
|
+
else {
|
|
2165
|
+
// Strip --auto-tmux from argv to avoid infinite re-exec loop
|
|
2166
|
+
const newArgv = process.argv.filter((a) => a !== "--auto-tmux");
|
|
2167
|
+
// Pass each argv token as a separate tmux argument so paths with spaces work correctly
|
|
2168
|
+
const result = spawnSync("tmux", ["new-session", "-d", "-s", sessionName, ...newArgv], { stdio: "inherit", timeout: 5000 });
|
|
2169
|
+
if (result.status === 0) {
|
|
2170
|
+
process.stderr.write(`Bridge launched in tmux session '${sessionName}'.\n`);
|
|
2171
|
+
process.stderr.write(` Attach with: tmux attach -t ${sessionName}\n`);
|
|
2083
2172
|
process.exit(0);
|
|
2084
2173
|
}
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2174
|
+
else {
|
|
2175
|
+
// tmux session likely already exists — attach to it or fall through
|
|
2176
|
+
process.stderr.write(`WARNING: Could not create tmux session '${sessionName}' (already exists?). Running without auto-tmux.\n`);
|
|
2088
2177
|
}
|
|
2089
|
-
|
|
2090
|
-
setTimeout(() => {
|
|
2091
|
-
delay = Math.min(delay * 2, MAX_DELAY_MS);
|
|
2092
|
-
runChild();
|
|
2093
|
-
}, delay);
|
|
2094
|
-
});
|
|
2178
|
+
}
|
|
2095
2179
|
}
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2180
|
+
// Skip bridge boot when a subcommand IIFE is doing the work — avoids the
|
|
2181
|
+
// race where bridge.start() began initialising in parallel with the
|
|
2182
|
+
// subcommand's async path. See the KNOWN_SUBCOMMANDS / __subcommandWillRun
|
|
2183
|
+
// gate at the top of this file.
|
|
2184
|
+
if (__subcommandWillRun) {
|
|
2185
|
+
// intentionally empty — subcommand IIFE owns the process from here.
|
|
2186
|
+
}
|
|
2187
|
+
// --watch: supervisor mode — spawn this binary as a child (without --watch) and restart on crash
|
|
2188
|
+
else if (config.watch) {
|
|
2189
|
+
const childArgv = process.argv.filter((a) => a !== "--watch");
|
|
2190
|
+
const STABLE_THRESHOLD_MS = 60_000;
|
|
2191
|
+
const BASE_DELAY_MS = 2_000;
|
|
2192
|
+
const MAX_DELAY_MS = 30_000;
|
|
2193
|
+
let delay = BASE_DELAY_MS;
|
|
2194
|
+
let stopping = false;
|
|
2195
|
+
function runChild() {
|
|
2196
|
+
if (stopping)
|
|
2197
|
+
return;
|
|
2198
|
+
const startAt = Date.now();
|
|
2199
|
+
process.stderr.write("[supervisor] starting bridge\n");
|
|
2200
|
+
const [cmd, ...args] = childArgv;
|
|
2201
|
+
if (!cmd)
|
|
2110
2202
|
return;
|
|
2111
|
-
const
|
|
2112
|
-
|
|
2113
|
-
|
|
2203
|
+
const child = spawn(cmd, args, {
|
|
2204
|
+
stdio: "inherit",
|
|
2205
|
+
});
|
|
2206
|
+
for (const sig of ["SIGTERM", "SIGINT"]) {
|
|
2207
|
+
process.once(sig, () => {
|
|
2208
|
+
stopping = true;
|
|
2209
|
+
child.kill(sig);
|
|
2210
|
+
});
|
|
2114
2211
|
}
|
|
2212
|
+
child.on("exit", (code, signal) => {
|
|
2213
|
+
if (stopping) {
|
|
2214
|
+
process.stderr.write("[supervisor] bridge stopped\n");
|
|
2215
|
+
process.exit(0);
|
|
2216
|
+
}
|
|
2217
|
+
const uptime = Date.now() - startAt;
|
|
2218
|
+
if (uptime >= STABLE_THRESHOLD_MS) {
|
|
2219
|
+
delay = BASE_DELAY_MS; // reset backoff after a stable run
|
|
2220
|
+
}
|
|
2221
|
+
process.stderr.write(`[supervisor] bridge exited (code=${code ?? signal}), restarting in ${delay / 1000}s\n`);
|
|
2222
|
+
setTimeout(() => {
|
|
2223
|
+
delay = Math.min(delay * 2, MAX_DELAY_MS);
|
|
2224
|
+
runChild();
|
|
2225
|
+
}, delay);
|
|
2226
|
+
});
|
|
2227
|
+
}
|
|
2228
|
+
runChild();
|
|
2229
|
+
}
|
|
2230
|
+
else {
|
|
2231
|
+
const bridge = new Bridge(config);
|
|
2232
|
+
bridge.start().catch((err) => {
|
|
2233
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
2234
|
+
process.stderr.write(`Error: ${message}\n`);
|
|
2235
|
+
process.exit(1);
|
|
2115
2236
|
});
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
}
|
|
2237
|
+
// F5: Silent self-update nudge (fire-and-forget)
|
|
2238
|
+
import("node:child_process")
|
|
2239
|
+
.then(({ exec }) => {
|
|
2240
|
+
exec("npm view claude-ide-bridge version", { timeout: 5000 }, (err, stdout) => {
|
|
2241
|
+
if (err || !stdout)
|
|
2242
|
+
return;
|
|
2243
|
+
const latest = stdout.trim();
|
|
2244
|
+
if (latest && semverGt(latest, PACKAGE_VERSION)) {
|
|
2245
|
+
console.log(`\n Bridge v${latest} available — run: npm update -g claude-ide-bridge\n`);
|
|
2246
|
+
}
|
|
2247
|
+
});
|
|
2248
|
+
})
|
|
2249
|
+
.catch(() => { });
|
|
2250
|
+
}
|
|
2251
|
+
} // end of `else` for `if (__subcommandWillRun)` (bridge-mode block)
|
|
2119
2252
|
//# sourceMappingURL=index.js.map
|