patchwork-os 0.2.0-alpha.26 → 0.2.0-alpha.27
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/deploy/bootstrap-vps.sh +1 -1
- package/deploy/deploy-dashboard.sh +164 -0
- package/deploy/deploy-landing.sh +79 -0
- package/dist/ccPermissions.js +6 -4
- package/dist/ccPermissions.js.map +1 -1
- package/dist/commands/recipe.js +1 -1
- package/dist/commands/recipe.js.map +1 -1
- package/dist/commands/recipeInstall.d.ts +72 -0
- package/dist/commands/recipeInstall.js +339 -0
- package/dist/commands/recipeInstall.js.map +1 -0
- package/dist/connectors/datadog.d.ts +116 -0
- package/dist/connectors/datadog.js +385 -0
- package/dist/connectors/datadog.js.map +1 -0
- package/dist/connectors/hubspot.d.ts +112 -0
- package/dist/connectors/hubspot.js +408 -0
- package/dist/connectors/hubspot.js.map +1 -0
- package/dist/connectors/intercom.d.ts +102 -0
- package/dist/connectors/intercom.js +402 -0
- package/dist/connectors/intercom.js.map +1 -0
- package/dist/connectors/stripe.d.ts +116 -0
- package/dist/connectors/stripe.js +379 -0
- package/dist/connectors/stripe.js.map +1 -0
- package/dist/index.js +33 -26
- package/dist/index.js.map +1 -1
- package/dist/recipes/manifest.d.ts +47 -0
- package/dist/recipes/manifest.js +141 -0
- package/dist/recipes/manifest.js.map +1 -0
- package/dist/recipes/schemaGenerator.js +3 -3
- package/dist/recipes/schemaGenerator.js.map +1 -1
- package/dist/recipes/tools/datadog.d.ts +6 -0
- package/dist/recipes/tools/datadog.js +239 -0
- package/dist/recipes/tools/datadog.js.map +1 -0
- package/dist/recipes/tools/hubspot.d.ts +6 -0
- package/dist/recipes/tools/hubspot.js +232 -0
- package/dist/recipes/tools/hubspot.js.map +1 -0
- package/dist/recipes/tools/index.d.ts +4 -0
- package/dist/recipes/tools/index.js +4 -0
- package/dist/recipes/tools/index.js.map +1 -1
- package/dist/recipes/tools/intercom.d.ts +6 -0
- package/dist/recipes/tools/intercom.js +226 -0
- package/dist/recipes/tools/intercom.js.map +1 -0
- package/dist/recipes/tools/stripe.d.ts +6 -0
- package/dist/recipes/tools/stripe.js +265 -0
- package/dist/recipes/tools/stripe.js.map +1 -0
- package/dist/recipes/yamlRunner.js +28 -0
- package/dist/recipes/yamlRunner.js.map +1 -1
- package/dist/schemas/dry-run-plan.v1.json +1 -1
- package/dist/schemas/recipe.v1.json +1 -1
- package/dist/server.js +155 -1
- package/dist/server.js.map +1 -1
- package/dist/tools/searchTools.js +1 -1
- package/dist/tools/searchTools.js.map +1 -1
- package/dist/tools/testTraceToSource.js +2 -2
- package/dist/tools/testTraceToSource.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stripe connector — read-only access to Stripe data via the Stripe REST API v1.
|
|
3
|
+
*
|
|
4
|
+
* Auth: Basic auth where username=secret_key, password="".
|
|
5
|
+
* - Env var: STRIPE_SECRET_KEY
|
|
6
|
+
* - Stored: getSecretJsonSync("stripe") → StripeTokens
|
|
7
|
+
*
|
|
8
|
+
* Tools: listCharges, getCharge, listCustomers, getCustomer, listSubscriptions, listInvoices
|
|
9
|
+
*
|
|
10
|
+
* Extends BaseConnector for unified auth, retry, rate-limit, error handling.
|
|
11
|
+
*/
|
|
12
|
+
import { BaseConnector, } from "./baseConnector.js";
|
|
13
|
+
import { deleteSecretJsonSync, getSecretJsonSync, storeSecretJsonSync, } from "./tokenStorage.js";
|
|
14
|
+
const BASE_URL = "https://api.stripe.com";
|
|
15
|
+
export class StripeConnector extends BaseConnector {
|
|
16
|
+
providerName = "stripe";
|
|
17
|
+
tokens = null;
|
|
18
|
+
getOAuthConfig() {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
async authenticate() {
|
|
22
|
+
const tokens = loadTokens();
|
|
23
|
+
if (!tokens) {
|
|
24
|
+
throw new Error("Stripe not connected. Run: patchwork-os connect stripe or set STRIPE_SECRET_KEY");
|
|
25
|
+
}
|
|
26
|
+
this.tokens = tokens;
|
|
27
|
+
return {
|
|
28
|
+
token: tokens.secretKey,
|
|
29
|
+
scopes: ["read"],
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
async healthCheck() {
|
|
33
|
+
try {
|
|
34
|
+
const result = await this.apiCall(async () => {
|
|
35
|
+
const res = await fetch(`${BASE_URL}/v1/balance`, {
|
|
36
|
+
headers: this.buildHeaders(),
|
|
37
|
+
});
|
|
38
|
+
if (!res.ok)
|
|
39
|
+
throw new Error(`HTTP ${res.status}`);
|
|
40
|
+
return res.json();
|
|
41
|
+
});
|
|
42
|
+
if ("error" in result)
|
|
43
|
+
return { ok: false, error: result.error };
|
|
44
|
+
return { ok: true };
|
|
45
|
+
}
|
|
46
|
+
catch (err) {
|
|
47
|
+
return { ok: false, error: this.normalizeError(err) };
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
normalizeError(error) {
|
|
51
|
+
if (error instanceof Response) {
|
|
52
|
+
const s = error.status;
|
|
53
|
+
if (s === 401)
|
|
54
|
+
return {
|
|
55
|
+
code: "auth_expired",
|
|
56
|
+
message: "Stripe authentication expired — reconnect",
|
|
57
|
+
retryable: false,
|
|
58
|
+
suggestedAction: "patchwork-os connect stripe",
|
|
59
|
+
};
|
|
60
|
+
if (s === 403)
|
|
61
|
+
return {
|
|
62
|
+
code: "permission_denied",
|
|
63
|
+
message: "Insufficient Stripe permissions",
|
|
64
|
+
retryable: false,
|
|
65
|
+
};
|
|
66
|
+
if (s === 404)
|
|
67
|
+
return {
|
|
68
|
+
code: "not_found",
|
|
69
|
+
message: "Stripe resource not found",
|
|
70
|
+
retryable: false,
|
|
71
|
+
};
|
|
72
|
+
if (s === 429)
|
|
73
|
+
return {
|
|
74
|
+
code: "rate_limited",
|
|
75
|
+
message: "Stripe API rate limit exceeded",
|
|
76
|
+
retryable: true,
|
|
77
|
+
suggestedAction: "Wait and retry",
|
|
78
|
+
};
|
|
79
|
+
return {
|
|
80
|
+
code: "provider_error",
|
|
81
|
+
message: `Stripe API error: HTTP ${s}`,
|
|
82
|
+
retryable: s >= 500,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
if (error instanceof Error) {
|
|
86
|
+
if (error.message.includes("ENOTFOUND") ||
|
|
87
|
+
error.message.includes("ECONNREFUSED")) {
|
|
88
|
+
return {
|
|
89
|
+
code: "network_error",
|
|
90
|
+
message: `Cannot connect to Stripe: ${error.message}`,
|
|
91
|
+
retryable: true,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
code: "provider_error",
|
|
97
|
+
message: error instanceof Error ? error.message : String(error),
|
|
98
|
+
retryable: false,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
getStatus() {
|
|
102
|
+
const tokens = loadTokens();
|
|
103
|
+
return {
|
|
104
|
+
id: "stripe",
|
|
105
|
+
status: tokens ? "connected" : "disconnected",
|
|
106
|
+
lastSync: tokens?.connected_at,
|
|
107
|
+
workspace: tokens?.accountId
|
|
108
|
+
? `Stripe account ${tokens.accountId}`
|
|
109
|
+
: undefined,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
// ── API Methods ────────────────────────────────────────────────────────────
|
|
113
|
+
async listCharges(params = {}) {
|
|
114
|
+
const result = await this.apiCall(async () => {
|
|
115
|
+
const qs = new URLSearchParams();
|
|
116
|
+
if (params.limit)
|
|
117
|
+
qs.set("limit", String(params.limit));
|
|
118
|
+
if (params.customerId)
|
|
119
|
+
qs.set("customer", params.customerId);
|
|
120
|
+
if (params.status)
|
|
121
|
+
qs.set("status", params.status);
|
|
122
|
+
const res = await fetch(`${BASE_URL}/v1/charges?${qs}`, {
|
|
123
|
+
headers: this.buildHeaders(),
|
|
124
|
+
});
|
|
125
|
+
if (!res.ok)
|
|
126
|
+
throw res;
|
|
127
|
+
return res.json();
|
|
128
|
+
});
|
|
129
|
+
if ("error" in result)
|
|
130
|
+
throw new Error(result.error.message);
|
|
131
|
+
return result.data;
|
|
132
|
+
}
|
|
133
|
+
async getCharge(chargeId) {
|
|
134
|
+
const result = await this.apiCall(async () => {
|
|
135
|
+
const res = await fetch(`${BASE_URL}/v1/charges/${chargeId}`, {
|
|
136
|
+
headers: this.buildHeaders(),
|
|
137
|
+
});
|
|
138
|
+
if (!res.ok)
|
|
139
|
+
throw res;
|
|
140
|
+
return res.json();
|
|
141
|
+
});
|
|
142
|
+
if ("error" in result)
|
|
143
|
+
throw new Error(result.error.message);
|
|
144
|
+
return result.data;
|
|
145
|
+
}
|
|
146
|
+
async listCustomers(params = {}) {
|
|
147
|
+
const result = await this.apiCall(async () => {
|
|
148
|
+
const qs = new URLSearchParams();
|
|
149
|
+
if (params.limit)
|
|
150
|
+
qs.set("limit", String(params.limit));
|
|
151
|
+
if (params.email)
|
|
152
|
+
qs.set("email", params.email);
|
|
153
|
+
const res = await fetch(`${BASE_URL}/v1/customers?${qs}`, {
|
|
154
|
+
headers: this.buildHeaders(),
|
|
155
|
+
});
|
|
156
|
+
if (!res.ok)
|
|
157
|
+
throw res;
|
|
158
|
+
return res.json();
|
|
159
|
+
});
|
|
160
|
+
if ("error" in result)
|
|
161
|
+
throw new Error(result.error.message);
|
|
162
|
+
return result.data;
|
|
163
|
+
}
|
|
164
|
+
async getCustomer(customerId) {
|
|
165
|
+
const result = await this.apiCall(async () => {
|
|
166
|
+
const res = await fetch(`${BASE_URL}/v1/customers/${customerId}`, {
|
|
167
|
+
headers: this.buildHeaders(),
|
|
168
|
+
});
|
|
169
|
+
if (!res.ok)
|
|
170
|
+
throw res;
|
|
171
|
+
return res.json();
|
|
172
|
+
});
|
|
173
|
+
if ("error" in result)
|
|
174
|
+
throw new Error(result.error.message);
|
|
175
|
+
return result.data;
|
|
176
|
+
}
|
|
177
|
+
async listSubscriptions(params = {}) {
|
|
178
|
+
const result = await this.apiCall(async () => {
|
|
179
|
+
const qs = new URLSearchParams();
|
|
180
|
+
if (params.limit)
|
|
181
|
+
qs.set("limit", String(params.limit));
|
|
182
|
+
if (params.customerId)
|
|
183
|
+
qs.set("customer", params.customerId);
|
|
184
|
+
if (params.status)
|
|
185
|
+
qs.set("status", params.status);
|
|
186
|
+
const res = await fetch(`${BASE_URL}/v1/subscriptions?${qs}`, {
|
|
187
|
+
headers: this.buildHeaders(),
|
|
188
|
+
});
|
|
189
|
+
if (!res.ok)
|
|
190
|
+
throw res;
|
|
191
|
+
return res.json();
|
|
192
|
+
});
|
|
193
|
+
if ("error" in result)
|
|
194
|
+
throw new Error(result.error.message);
|
|
195
|
+
return result.data;
|
|
196
|
+
}
|
|
197
|
+
async listInvoices(params = {}) {
|
|
198
|
+
const result = await this.apiCall(async () => {
|
|
199
|
+
const qs = new URLSearchParams();
|
|
200
|
+
if (params.limit)
|
|
201
|
+
qs.set("limit", String(params.limit));
|
|
202
|
+
if (params.customerId)
|
|
203
|
+
qs.set("customer", params.customerId);
|
|
204
|
+
if (params.status)
|
|
205
|
+
qs.set("status", params.status);
|
|
206
|
+
const res = await fetch(`${BASE_URL}/v1/invoices?${qs}`, {
|
|
207
|
+
headers: this.buildHeaders(),
|
|
208
|
+
});
|
|
209
|
+
if (!res.ok)
|
|
210
|
+
throw res;
|
|
211
|
+
return res.json();
|
|
212
|
+
});
|
|
213
|
+
if ("error" in result)
|
|
214
|
+
throw new Error(result.error.message);
|
|
215
|
+
return result.data;
|
|
216
|
+
}
|
|
217
|
+
// ── Helpers ────────────────────────────────────────────────────────────────
|
|
218
|
+
buildHeaders() {
|
|
219
|
+
const key = this.tokens?.secretKey ?? "";
|
|
220
|
+
const basic = Buffer.from(`${key}:`).toString("base64");
|
|
221
|
+
return {
|
|
222
|
+
Authorization: `Basic ${basic}`,
|
|
223
|
+
Accept: "application/json",
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
// ── Token persistence ────────────────────────────────────────────────────────
|
|
228
|
+
export function loadTokens() {
|
|
229
|
+
const envKey = process.env.STRIPE_SECRET_KEY;
|
|
230
|
+
if (envKey) {
|
|
231
|
+
return {
|
|
232
|
+
secretKey: envKey,
|
|
233
|
+
connected_at: new Date().toISOString(),
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
return getSecretJsonSync("stripe");
|
|
237
|
+
}
|
|
238
|
+
export function saveTokens(tokens) {
|
|
239
|
+
storeSecretJsonSync("stripe", tokens);
|
|
240
|
+
}
|
|
241
|
+
export function clearTokens() {
|
|
242
|
+
try {
|
|
243
|
+
deleteSecretJsonSync("stripe");
|
|
244
|
+
}
|
|
245
|
+
catch {
|
|
246
|
+
// ignore
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
// ── Singleton instance ───────────────────────────────────────────────────────
|
|
250
|
+
let _instance = null;
|
|
251
|
+
function resetStripeConnector() {
|
|
252
|
+
_instance = null;
|
|
253
|
+
}
|
|
254
|
+
export function getStripeConnector() {
|
|
255
|
+
if (!_instance) {
|
|
256
|
+
_instance = new StripeConnector();
|
|
257
|
+
}
|
|
258
|
+
return _instance;
|
|
259
|
+
}
|
|
260
|
+
export { getStripeConnector as stripe };
|
|
261
|
+
/**
|
|
262
|
+
* POST /connections/stripe/connect { secretKey }
|
|
263
|
+
*/
|
|
264
|
+
export async function handleStripeConnect(body) {
|
|
265
|
+
let secretKey;
|
|
266
|
+
try {
|
|
267
|
+
const parsed = JSON.parse(body);
|
|
268
|
+
if (typeof parsed.secretKey !== "string" || !parsed.secretKey) {
|
|
269
|
+
return {
|
|
270
|
+
status: 400,
|
|
271
|
+
contentType: "application/json",
|
|
272
|
+
body: JSON.stringify({ ok: false, error: "secretKey is required" }),
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
secretKey = parsed.secretKey;
|
|
276
|
+
}
|
|
277
|
+
catch {
|
|
278
|
+
return {
|
|
279
|
+
status: 400,
|
|
280
|
+
contentType: "application/json",
|
|
281
|
+
body: JSON.stringify({ ok: false, error: "Invalid JSON body" }),
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
try {
|
|
285
|
+
const basic = Buffer.from(`${secretKey}:`).toString("base64");
|
|
286
|
+
const res = await fetch(`${BASE_URL}/v1/account`, {
|
|
287
|
+
headers: {
|
|
288
|
+
Authorization: `Basic ${basic}`,
|
|
289
|
+
Accept: "application/json",
|
|
290
|
+
},
|
|
291
|
+
});
|
|
292
|
+
if (!res.ok) {
|
|
293
|
+
return {
|
|
294
|
+
status: 401,
|
|
295
|
+
contentType: "application/json",
|
|
296
|
+
body: JSON.stringify({
|
|
297
|
+
ok: false,
|
|
298
|
+
error: `Credentials rejected by Stripe (HTTP ${res.status}) — check secretKey`,
|
|
299
|
+
}),
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
const account = (await res.json());
|
|
303
|
+
const accountId = account.id ?? undefined;
|
|
304
|
+
const accountName = account.display_name ?? account.business_profile?.name ?? undefined;
|
|
305
|
+
const tokens = {
|
|
306
|
+
secretKey,
|
|
307
|
+
accountId,
|
|
308
|
+
accountName,
|
|
309
|
+
connected_at: new Date().toISOString(),
|
|
310
|
+
};
|
|
311
|
+
saveTokens(tokens);
|
|
312
|
+
resetStripeConnector();
|
|
313
|
+
return {
|
|
314
|
+
status: 200,
|
|
315
|
+
contentType: "application/json",
|
|
316
|
+
body: JSON.stringify({
|
|
317
|
+
ok: true,
|
|
318
|
+
accountId,
|
|
319
|
+
accountName,
|
|
320
|
+
connectedAt: tokens.connected_at,
|
|
321
|
+
}),
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
catch (err) {
|
|
325
|
+
return {
|
|
326
|
+
status: 500,
|
|
327
|
+
contentType: "application/json",
|
|
328
|
+
body: JSON.stringify({
|
|
329
|
+
ok: false,
|
|
330
|
+
error: err instanceof Error ? err.message : String(err),
|
|
331
|
+
}),
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* POST /connections/stripe/test
|
|
337
|
+
*/
|
|
338
|
+
export async function handleStripeTest() {
|
|
339
|
+
const tokens = loadTokens();
|
|
340
|
+
if (!tokens) {
|
|
341
|
+
return {
|
|
342
|
+
status: 400,
|
|
343
|
+
contentType: "application/json",
|
|
344
|
+
body: JSON.stringify({ ok: false, error: "Stripe not connected" }),
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
try {
|
|
348
|
+
const connector = getStripeConnector();
|
|
349
|
+
const check = await connector.healthCheck();
|
|
350
|
+
return {
|
|
351
|
+
status: check.ok ? 200 : 401,
|
|
352
|
+
contentType: "application/json",
|
|
353
|
+
body: JSON.stringify(check.ok ? { ok: true } : { ok: false, error: check.error?.message }),
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
catch (err) {
|
|
357
|
+
return {
|
|
358
|
+
status: 500,
|
|
359
|
+
contentType: "application/json",
|
|
360
|
+
body: JSON.stringify({
|
|
361
|
+
ok: false,
|
|
362
|
+
error: err instanceof Error ? err.message : String(err),
|
|
363
|
+
}),
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* DELETE /connections/stripe
|
|
369
|
+
*/
|
|
370
|
+
export function handleStripeDisconnect() {
|
|
371
|
+
clearTokens();
|
|
372
|
+
resetStripeConnector();
|
|
373
|
+
return {
|
|
374
|
+
status: 200,
|
|
375
|
+
contentType: "application/json",
|
|
376
|
+
body: JSON.stringify({ ok: true }),
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
//# sourceMappingURL=stripe.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stripe.js","sourceRoot":"","sources":["../../src/connectors/stripe.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -586,20 +586,9 @@ export function register(ctx) {
|
|
|
586
586
|
// Patchwork: `patchwork recipe list` — enumerate installed recipes.
|
|
587
587
|
if (process.argv[2] === "recipe" && process.argv[3] === "list") {
|
|
588
588
|
(async () => {
|
|
589
|
-
const {
|
|
590
|
-
const
|
|
591
|
-
|
|
592
|
-
if (recipes.length === 0) {
|
|
593
|
-
process.stdout.write("No recipes installed. Run `patchwork-os patchwork-init` to install the starter set.\n");
|
|
594
|
-
}
|
|
595
|
-
else {
|
|
596
|
-
process.stdout.write(`Installed recipes (${recipes.length}):\n\n`);
|
|
597
|
-
for (const r of recipes) {
|
|
598
|
-
const desc = r.description ? ` ${r.description}` : "";
|
|
599
|
-
process.stdout.write(` ${r.name.padEnd(28)} [${r.trigger}]${desc}\n`);
|
|
600
|
-
}
|
|
601
|
-
process.stdout.write(`\nRun a recipe: patchwork-os recipe run <name>\n`);
|
|
602
|
-
}
|
|
589
|
+
const { listInstalledRecipes, printInstalledList } = await import("./commands/recipeInstall.js");
|
|
590
|
+
const entries = listInstalledRecipes();
|
|
591
|
+
printInstalledList(entries);
|
|
603
592
|
process.exit(0);
|
|
604
593
|
})();
|
|
605
594
|
}
|
|
@@ -752,23 +741,41 @@ if (process.argv[2] === "recipe" && process.argv[3] === "run") {
|
|
|
752
741
|
})();
|
|
753
742
|
}
|
|
754
743
|
// Handle init subcommand — one-command setup: install extension + write CLAUDE.md + print next steps
|
|
755
|
-
// Patchwork: `patchwork recipe install <
|
|
744
|
+
// Patchwork: `patchwork recipe install <source>` subcommand.
|
|
745
|
+
// Supports: github:owner/repo, github:owner/repo/subdir, https://github.com/owner/repo,
|
|
746
|
+
// ./local/path, or legacy <file.json> (single-recipe install).
|
|
756
747
|
if (process.argv[2] === "recipe" && process.argv[3] === "install") {
|
|
757
|
-
const
|
|
758
|
-
if (!
|
|
759
|
-
process.stderr.write("Usage: patchwork recipe install <
|
|
748
|
+
const source = process.argv[4];
|
|
749
|
+
if (!source) {
|
|
750
|
+
process.stderr.write("Usage: patchwork recipe install <source>\n" +
|
|
751
|
+
" <source> can be:\n" +
|
|
752
|
+
" github:owner/repo\n" +
|
|
753
|
+
" github:owner/repo/subdir\n" +
|
|
754
|
+
" https://github.com/owner/repo\n" +
|
|
755
|
+
" ./local/path\n");
|
|
760
756
|
process.exit(1);
|
|
761
757
|
}
|
|
762
758
|
(async () => {
|
|
763
759
|
try {
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
760
|
+
// Legacy path: bare .json file argument → single-file installer
|
|
761
|
+
if (source.endsWith(".json") &&
|
|
762
|
+
!source.startsWith("github:") &&
|
|
763
|
+
!source.startsWith("http")) {
|
|
764
|
+
const { installRecipeFromFile } = await import("./recipes/installer.js");
|
|
765
|
+
const recipesDir = path.join(os.homedir(), ".patchwork", "recipes");
|
|
766
|
+
const result = installRecipeFromFile(path.resolve(source), {
|
|
767
|
+
recipesDir,
|
|
768
|
+
});
|
|
769
|
+
process.stdout.write(` ✓ ${result.action} ${result.installedPath}\n` +
|
|
770
|
+
` ℹ permissions snippet written to ${result.installedPath}.permissions.json\n` +
|
|
771
|
+
` Review + merge into ~/.claude/settings.json to pre-approve recipe steps.\n`);
|
|
772
|
+
}
|
|
773
|
+
else {
|
|
774
|
+
// Marketplace install: github:, https://, ./local/
|
|
775
|
+
const { runRecipeInstall, printInstallResult } = await import("./commands/recipeInstall.js");
|
|
776
|
+
const result = await runRecipeInstall(source);
|
|
777
|
+
printInstallResult(result);
|
|
778
|
+
}
|
|
772
779
|
process.exit(0);
|
|
773
780
|
}
|
|
774
781
|
catch (err) {
|