@sweny-ai/core 0.1.184 → 0.1.185
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/dist/cli/marketplace.d.ts +15 -4
- package/dist/cli/marketplace.js +91 -49
- package/dist/cli/new.d.ts +1 -1
- package/dist/cli/new.js +2 -2
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Marketplace install — fetch workflows from swenyai/
|
|
2
|
+
* Marketplace install — fetch workflows from swenyai/marketplace and
|
|
3
3
|
* adapt them to the user's .sweny.yml providers.
|
|
4
4
|
*
|
|
5
5
|
* Pure functions for fetch/mismatch/adapt; file writes delegate to
|
|
@@ -7,8 +7,13 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import type { Skill, SkillCategory, Workflow, Claude, Logger } from "../types.js";
|
|
9
9
|
import type { FileConfig } from "./config-file.js";
|
|
10
|
-
export declare const MARKETPLACE_REPO = "swenyai/
|
|
11
|
-
export declare const
|
|
10
|
+
export declare const MARKETPLACE_REPO = "swenyai/marketplace";
|
|
11
|
+
export declare const MARKETPLACE_BRANCH = "main";
|
|
12
|
+
export declare const MARKETPLACE_RAW_BASE = "https://raw.githubusercontent.com/swenyai/marketplace/main";
|
|
13
|
+
/** One recursive tree call lists every workflow file; the marketplace publishes no index of its own. */
|
|
14
|
+
export declare const MARKETPLACE_TREE_URL = "https://api.github.com/repos/swenyai/marketplace/git/trees/main?recursive=1";
|
|
15
|
+
/** Directories under `workflows/` in the marketplace repo, in lookup order (official wins on an id clash). */
|
|
16
|
+
export declare const MARKETPLACE_SOURCES: readonly ["official", "community"];
|
|
12
17
|
export interface MarketplaceEntry {
|
|
13
18
|
id: string;
|
|
14
19
|
name: string;
|
|
@@ -23,7 +28,13 @@ export interface FetchedWorkflow {
|
|
|
23
28
|
id: string;
|
|
24
29
|
yaml: string;
|
|
25
30
|
}
|
|
31
|
+
/** Fetch `workflows/official/<id>.yml`, then `workflows/community/<id>.yml`, from swenyai/marketplace. */
|
|
26
32
|
export declare function fetchMarketplaceWorkflow(id: string): Promise<FetchedWorkflow>;
|
|
33
|
+
/**
|
|
34
|
+
* Build the browse list from the marketplace repo itself: one GitHub tree call
|
|
35
|
+
* to list `workflows/{official,community}/*.yml`, then each file's name,
|
|
36
|
+
* description and skills. Files that fail to fetch or parse are skipped.
|
|
37
|
+
*/
|
|
27
38
|
export declare function fetchMarketplaceIndex(opts?: {
|
|
28
39
|
timeoutMs?: number;
|
|
29
40
|
}): Promise<MarketplaceEntry[]>;
|
|
@@ -90,7 +101,7 @@ export interface InstallResult {
|
|
|
90
101
|
alreadyExists?: boolean;
|
|
91
102
|
}
|
|
92
103
|
/**
|
|
93
|
-
* Fetch a workflow from swenyai/
|
|
104
|
+
* Fetch a workflow from swenyai/marketplace, adapt if provider mismatch is detected
|
|
94
105
|
* AND an agent is available, then write files idempotently.
|
|
95
106
|
*
|
|
96
107
|
* When `overwrite` is false (default) and the workflow file already exists,
|
package/dist/cli/marketplace.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// packages/core/src/cli/marketplace.ts
|
|
2
2
|
/**
|
|
3
|
-
* Marketplace install — fetch workflows from swenyai/
|
|
3
|
+
* Marketplace install — fetch workflows from swenyai/marketplace and
|
|
4
4
|
* adapt them to the user's .sweny.yml providers.
|
|
5
5
|
*
|
|
6
6
|
* Pure functions for fetch/mismatch/adapt; file writes delegate to
|
|
@@ -13,67 +13,109 @@ import { DagRenderer } from "./renderer.js";
|
|
|
13
13
|
import { validateParsed } from "../loader.js";
|
|
14
14
|
import { loadConfigFile } from "./config-file.js";
|
|
15
15
|
import { extractSkillsFromYaml, collectCredentialsForSkills, writeSwenyYmlIfMissing, appendMissingEnvKeys, writeWorkflowFile, } from "./new.js";
|
|
16
|
-
export const MARKETPLACE_REPO = "swenyai/
|
|
17
|
-
export const
|
|
18
|
-
export
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
16
|
+
export const MARKETPLACE_REPO = "swenyai/marketplace";
|
|
17
|
+
export const MARKETPLACE_BRANCH = "main";
|
|
18
|
+
export const MARKETPLACE_RAW_BASE = `https://raw.githubusercontent.com/${MARKETPLACE_REPO}/${MARKETPLACE_BRANCH}`;
|
|
19
|
+
/** One recursive tree call lists every workflow file; the marketplace publishes no index of its own. */
|
|
20
|
+
export const MARKETPLACE_TREE_URL = `https://api.github.com/repos/${MARKETPLACE_REPO}/git/trees/${MARKETPLACE_BRANCH}?recursive=1`;
|
|
21
|
+
/** Directories under `workflows/` in the marketplace repo, in lookup order (official wins on an id clash). */
|
|
22
|
+
export const MARKETPLACE_SOURCES = ["official", "community"];
|
|
23
|
+
const WORKFLOW_ID_RE = /^[A-Za-z0-9][A-Za-z0-9_-]*$/;
|
|
24
|
+
const WORKFLOW_PATH_RE = new RegExp(`^workflows/(${MARKETPLACE_SOURCES.join("|")})/([A-Za-z0-9][A-Za-z0-9_-]*)\\.yml$`);
|
|
25
|
+
function fetchError(kind, message) {
|
|
26
|
+
const err = new Error(message);
|
|
27
|
+
err.kind = kind;
|
|
28
|
+
return err;
|
|
29
|
+
}
|
|
30
|
+
/** Throw a typed FetchError for any non-OK response (404 is left to the caller). */
|
|
31
|
+
function assertOk(res) {
|
|
32
|
+
if (res.ok)
|
|
33
|
+
return;
|
|
34
34
|
if (res.status === 403 && res.headers.get("X-RateLimit-Remaining") === "0") {
|
|
35
|
+
const err = fetchError("rate-limit", `GitHub rate limit hit. Set GITHUB_TOKEN to raise the limit, or retry later.`);
|
|
35
36
|
const reset = res.headers.get("X-RateLimit-Reset");
|
|
36
|
-
const err = new Error(`GitHub rate limit hit. Set GITHUB_TOKEN to raise the limit, or retry later.`);
|
|
37
|
-
err.kind = "rate-limit";
|
|
38
37
|
if (reset)
|
|
39
38
|
err.retryAfter = parseInt(reset, 10);
|
|
40
39
|
throw err;
|
|
41
40
|
}
|
|
42
|
-
|
|
43
|
-
const err = new Error(`Fetch failed with status ${res.status}`);
|
|
44
|
-
err.kind = "unknown";
|
|
45
|
-
throw err;
|
|
46
|
-
}
|
|
47
|
-
return { id, yaml: await res.text() };
|
|
41
|
+
throw fetchError("unknown", `Fetch failed with status ${res.status}`);
|
|
48
42
|
}
|
|
49
|
-
|
|
50
|
-
const url = `${MARKETPLACE_RAW_BASE}/index.json`;
|
|
51
|
-
let res;
|
|
43
|
+
async function httpGet(url, init) {
|
|
52
44
|
try {
|
|
53
|
-
|
|
45
|
+
return await (init ? fetch(url, init) : fetch(url));
|
|
54
46
|
}
|
|
55
47
|
catch {
|
|
56
|
-
|
|
57
|
-
err.kind = "network";
|
|
58
|
-
throw err;
|
|
48
|
+
throw fetchError("network", `Could not reach github.com - check your connection`);
|
|
59
49
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
50
|
+
}
|
|
51
|
+
/** Fetch `workflows/official/<id>.yml`, then `workflows/community/<id>.yml`, from swenyai/marketplace. */
|
|
52
|
+
export async function fetchMarketplaceWorkflow(id) {
|
|
53
|
+
if (!WORKFLOW_ID_RE.test(id)) {
|
|
54
|
+
throw fetchError("not-found", `Workflow "${id}" not found in ${MARKETPLACE_REPO}.`);
|
|
64
55
|
}
|
|
65
|
-
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
56
|
+
for (const source of MARKETPLACE_SOURCES) {
|
|
57
|
+
const res = await httpGet(`${MARKETPLACE_RAW_BASE}/workflows/${source}/${id}.yml`);
|
|
58
|
+
if (res.status === 404)
|
|
59
|
+
continue;
|
|
60
|
+
assertOk(res);
|
|
61
|
+
return { id, yaml: await res.text() };
|
|
69
62
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
63
|
+
throw fetchError("not-found", `Workflow "${id}" not found in ${MARKETPLACE_REPO}.`);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Build the browse list from the marketplace repo itself: one GitHub tree call
|
|
67
|
+
* to list `workflows/{official,community}/*.yml`, then each file's name,
|
|
68
|
+
* description and skills. Files that fail to fetch or parse are skipped.
|
|
69
|
+
*/
|
|
70
|
+
export async function fetchMarketplaceIndex(opts = {}) {
|
|
71
|
+
const signal = opts.timeoutMs ? AbortSignal.timeout(opts.timeoutMs) : undefined;
|
|
72
|
+
const headers = { Accept: "application/vnd.github+json" };
|
|
73
|
+
if (process.env.GITHUB_TOKEN)
|
|
74
|
+
headers.Authorization = `Bearer ${process.env.GITHUB_TOKEN}`;
|
|
75
|
+
const treeRes = await httpGet(MARKETPLACE_TREE_URL, { headers, ...(signal ? { signal } : {}) });
|
|
76
|
+
if (treeRes.status === 404)
|
|
77
|
+
throw fetchError("not-found", `Marketplace repo ${MARKETPLACE_REPO} not found`);
|
|
78
|
+
assertOk(treeRes);
|
|
79
|
+
const body = (await treeRes.json());
|
|
80
|
+
if (!body || !Array.isArray(body.tree)) {
|
|
81
|
+
throw fetchError("bad-yaml", `Marketplace tree listing is malformed`);
|
|
82
|
+
}
|
|
83
|
+
const found = [];
|
|
84
|
+
const seen = new Set();
|
|
85
|
+
for (const item of body.tree) {
|
|
86
|
+
if (item.type !== "blob" || typeof item.path !== "string")
|
|
87
|
+
continue;
|
|
88
|
+
const m = WORKFLOW_PATH_RE.exec(item.path);
|
|
89
|
+
if (m)
|
|
90
|
+
found.push({ source: m[1], id: m[2] });
|
|
75
91
|
}
|
|
76
|
-
|
|
92
|
+
// Official first, then community; the first source to claim an id wins.
|
|
93
|
+
found.sort((a, b) => MARKETPLACE_SOURCES.indexOf(a.source) -
|
|
94
|
+
MARKETPLACE_SOURCES.indexOf(b.source));
|
|
95
|
+
const entries = await Promise.all(found.map(async ({ source, id }) => {
|
|
96
|
+
if (seen.has(id))
|
|
97
|
+
return null;
|
|
98
|
+
seen.add(id);
|
|
99
|
+
try {
|
|
100
|
+
const res = await fetch(`${MARKETPLACE_RAW_BASE}/workflows/${source}/${id}.yml`, signal ? { signal } : undefined);
|
|
101
|
+
if (!res.ok)
|
|
102
|
+
return null;
|
|
103
|
+
const yaml = await res.text();
|
|
104
|
+
const parsed = parseYaml(yaml);
|
|
105
|
+
if (!parsed || typeof parsed !== "object")
|
|
106
|
+
return null;
|
|
107
|
+
return {
|
|
108
|
+
id,
|
|
109
|
+
name: typeof parsed.name === "string" && parsed.name ? parsed.name : id,
|
|
110
|
+
description: typeof parsed.description === "string" ? parsed.description : "",
|
|
111
|
+
skills: extractSkillsFromYaml(yaml),
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
}));
|
|
118
|
+
return entries.filter((e) => e !== null);
|
|
77
119
|
}
|
|
78
120
|
const CATEGORY_TO_CONFIG_KEY = {
|
|
79
121
|
git: "source-control-provider",
|
|
@@ -177,7 +219,7 @@ export async function adaptWorkflowInteractive(workflow, options) {
|
|
|
177
219
|
}
|
|
178
220
|
}
|
|
179
221
|
/**
|
|
180
|
-
* Fetch a workflow from swenyai/
|
|
222
|
+
* Fetch a workflow from swenyai/marketplace, adapt if provider mismatch is detected
|
|
181
223
|
* AND an agent is available, then write files idempotently.
|
|
182
224
|
*
|
|
183
225
|
* When `overwrite` is false (default) and the workflow file already exists,
|
package/dist/cli/new.d.ts
CHANGED
|
@@ -145,7 +145,7 @@ export declare function nonInteractiveUsage(): string;
|
|
|
145
145
|
* Flow:
|
|
146
146
|
* 1. Detect git remote (used to infer source-control provider)
|
|
147
147
|
* 2. Pick one of five branches:
|
|
148
|
-
* - `__marketplace` → browse published workflows at swenyai/
|
|
148
|
+
* - `__marketplace` → browse published workflows at swenyai/marketplace, then delegate to `installMarketplaceWorkflow`
|
|
149
149
|
* - A built-in `WORKFLOW_TEMPLATES` entry → write that workflow file
|
|
150
150
|
* - `__custom` → LLM generates a workflow from a user description
|
|
151
151
|
* - `__e2e` → delegate to the e2e browser-testing wizard in `./e2e.ts`
|
package/dist/cli/new.js
CHANGED
|
@@ -523,7 +523,7 @@ function cancel() {
|
|
|
523
523
|
* Flow:
|
|
524
524
|
* 1. Detect git remote (used to infer source-control provider)
|
|
525
525
|
* 2. Pick one of five branches:
|
|
526
|
-
* - `__marketplace` → browse published workflows at swenyai/
|
|
526
|
+
* - `__marketplace` → browse published workflows at swenyai/marketplace, then delegate to `installMarketplaceWorkflow`
|
|
527
527
|
* - A built-in `WORKFLOW_TEMPLATES` entry → write that workflow file
|
|
528
528
|
* - `__custom` → LLM generates a workflow from a user description
|
|
529
529
|
* - `__e2e` → delegate to the e2e browser-testing wizard in `./e2e.ts`
|
|
@@ -669,7 +669,7 @@ export async function runNew(options) {
|
|
|
669
669
|
{
|
|
670
670
|
value: "__marketplace",
|
|
671
671
|
label: "Browse marketplace",
|
|
672
|
-
hint: "install a published workflow from swenyai/
|
|
672
|
+
hint: "install a published workflow from swenyai/marketplace",
|
|
673
673
|
},
|
|
674
674
|
]
|
|
675
675
|
: []),
|