@syntropic137/cli 0.20.2 → 0.21.0
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/syn.js +69 -56
- package/package.json +1 -1
package/dist/syn.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// src/config.ts
|
|
4
4
|
var CLI_NAME = "syn";
|
|
5
5
|
var CLI_DESCRIPTION = "Syntropic137 - Event-sourced workflow engine for AI agents";
|
|
6
|
-
var CLI_VERSION = true ? "0.
|
|
6
|
+
var CLI_VERSION = true ? "0.21.0" : "0.0.0-dev";
|
|
7
7
|
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
8
8
|
var SSE_CONNECT_TIMEOUT_MS = 5e3;
|
|
9
9
|
function getApiUrl() {
|
|
@@ -79,40 +79,40 @@ var SynClient = class {
|
|
|
79
79
|
this.timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
80
80
|
this.authHeaders = getAuthHeaders();
|
|
81
81
|
}
|
|
82
|
-
async get(
|
|
83
|
-
const url = this.buildUrl(
|
|
82
|
+
async get(path9, params) {
|
|
83
|
+
const url = this.buildUrl(path9, params);
|
|
84
84
|
return this.request(url, { method: "GET" });
|
|
85
85
|
}
|
|
86
|
-
async post(
|
|
87
|
-
const url = this.buildUrl(
|
|
86
|
+
async post(path9, body, params) {
|
|
87
|
+
const url = this.buildUrl(path9, params);
|
|
88
88
|
return this.request(url, {
|
|
89
89
|
method: "POST",
|
|
90
90
|
headers: { "Content-Type": "application/json" },
|
|
91
91
|
...body !== void 0 ? { body: JSON.stringify(body) } : {}
|
|
92
92
|
});
|
|
93
93
|
}
|
|
94
|
-
async put(
|
|
95
|
-
const url = this.buildUrl(
|
|
94
|
+
async put(path9, body) {
|
|
95
|
+
const url = this.buildUrl(path9);
|
|
96
96
|
return this.request(url, {
|
|
97
97
|
method: "PUT",
|
|
98
98
|
headers: { "Content-Type": "application/json" },
|
|
99
99
|
...body !== void 0 ? { body: JSON.stringify(body) } : {}
|
|
100
100
|
});
|
|
101
101
|
}
|
|
102
|
-
async patch(
|
|
103
|
-
const url = this.buildUrl(
|
|
102
|
+
async patch(path9, body) {
|
|
103
|
+
const url = this.buildUrl(path9);
|
|
104
104
|
return this.request(url, {
|
|
105
105
|
method: "PATCH",
|
|
106
106
|
headers: { "Content-Type": "application/json" },
|
|
107
107
|
...body !== void 0 ? { body: JSON.stringify(body) } : {}
|
|
108
108
|
});
|
|
109
109
|
}
|
|
110
|
-
async delete(
|
|
111
|
-
const url = this.buildUrl(
|
|
110
|
+
async delete(path9) {
|
|
111
|
+
const url = this.buildUrl(path9);
|
|
112
112
|
return this.request(url, { method: "DELETE" });
|
|
113
113
|
}
|
|
114
|
-
async stream(
|
|
115
|
-
const url = this.buildUrl(
|
|
114
|
+
async stream(path9) {
|
|
115
|
+
const url = this.buildUrl(path9);
|
|
116
116
|
const controller = new AbortController();
|
|
117
117
|
const timer = setTimeout(() => controller.abort(), SSE_CONNECT_TIMEOUT_MS);
|
|
118
118
|
const response = await fetch(url.toString(), {
|
|
@@ -126,10 +126,10 @@ var SynClient = class {
|
|
|
126
126
|
}
|
|
127
127
|
return response.body;
|
|
128
128
|
}
|
|
129
|
-
buildUrl(
|
|
129
|
+
buildUrl(path9, params) {
|
|
130
130
|
const base = new URL(this.baseUrl);
|
|
131
131
|
const basePath = base.pathname.replace(/\/+$/, "");
|
|
132
|
-
const reqPath =
|
|
132
|
+
const reqPath = path9.startsWith("/") ? path9 : `/${path9}`;
|
|
133
133
|
const prefix = basePath.endsWith(API_PREFIX) ? "" : API_PREFIX;
|
|
134
134
|
const url = new URL(`${basePath}${prefix}${reqPath}`, base);
|
|
135
135
|
if (params) {
|
|
@@ -181,66 +181,66 @@ async function safeRequest(fn) {
|
|
|
181
181
|
handleConnectError();
|
|
182
182
|
}
|
|
183
183
|
}
|
|
184
|
-
async function apiGet(
|
|
184
|
+
async function apiGet(path9, options) {
|
|
185
185
|
const client = new SynClient();
|
|
186
186
|
const { status, data } = await safeRequest(
|
|
187
|
-
() => client.get(
|
|
187
|
+
() => client.get(path9, options?.params)
|
|
188
188
|
);
|
|
189
189
|
checkResponse(status, data, options?.expected ?? [200]);
|
|
190
190
|
return data;
|
|
191
191
|
}
|
|
192
|
-
async function apiGetList(
|
|
192
|
+
async function apiGetList(path9, options) {
|
|
193
193
|
const client = new SynClient();
|
|
194
194
|
const { status, data } = await safeRequest(
|
|
195
|
-
() => client.get(
|
|
195
|
+
() => client.get(path9, options?.params)
|
|
196
196
|
);
|
|
197
197
|
checkResponse(status, data, options?.expected ?? [200]);
|
|
198
198
|
return data;
|
|
199
199
|
}
|
|
200
|
-
async function apiGetPaginated(
|
|
200
|
+
async function apiGetPaginated(path9, key, options) {
|
|
201
201
|
const client = new SynClient();
|
|
202
202
|
const { status, data } = await safeRequest(
|
|
203
|
-
() => client.get(
|
|
203
|
+
() => client.get(path9, options?.params)
|
|
204
204
|
);
|
|
205
205
|
checkResponse(status, data, options?.expected ?? [200]);
|
|
206
206
|
if (typeof data !== "object" || data === null) {
|
|
207
|
-
throw new CLIError(`Unexpected API response for "${
|
|
207
|
+
throw new CLIError(`Unexpected API response for "${path9}": expected an object containing "${key}".`);
|
|
208
208
|
}
|
|
209
209
|
const items = data[key];
|
|
210
210
|
if (!Array.isArray(items)) {
|
|
211
|
-
throw new CLIError(`Unexpected API response for "${
|
|
211
|
+
throw new CLIError(`Unexpected API response for "${path9}": expected "${key}" to be an array.`);
|
|
212
212
|
}
|
|
213
213
|
return items;
|
|
214
214
|
}
|
|
215
|
-
async function apiPost(
|
|
215
|
+
async function apiPost(path9, options) {
|
|
216
216
|
const client = new SynClient(
|
|
217
217
|
options?.timeoutMs !== void 0 ? { timeoutMs: options.timeoutMs } : void 0
|
|
218
218
|
);
|
|
219
219
|
const { status, data } = await safeRequest(
|
|
220
|
-
() => client.post(
|
|
220
|
+
() => client.post(path9, options?.body, options?.params)
|
|
221
221
|
);
|
|
222
222
|
checkResponse(status, data, options?.expected ?? [200, 201]);
|
|
223
223
|
return data;
|
|
224
224
|
}
|
|
225
|
-
async function apiPut(
|
|
225
|
+
async function apiPut(path9, options) {
|
|
226
226
|
const client = new SynClient();
|
|
227
227
|
const { status, data } = await safeRequest(
|
|
228
|
-
() => client.put(
|
|
228
|
+
() => client.put(path9, options?.body)
|
|
229
229
|
);
|
|
230
230
|
checkResponse(status, data, options?.expected ?? [200]);
|
|
231
231
|
return data;
|
|
232
232
|
}
|
|
233
|
-
async function apiPatch(
|
|
233
|
+
async function apiPatch(path9, options) {
|
|
234
234
|
const client = new SynClient();
|
|
235
235
|
const { status, data } = await safeRequest(
|
|
236
|
-
() => client.patch(
|
|
236
|
+
() => client.patch(path9, options?.body)
|
|
237
237
|
);
|
|
238
238
|
checkResponse(status, data, options?.expected ?? [200]);
|
|
239
239
|
return data;
|
|
240
240
|
}
|
|
241
|
-
async function apiDelete(
|
|
241
|
+
async function apiDelete(path9, options) {
|
|
242
242
|
const client = new SynClient();
|
|
243
|
-
const { status, data } = await safeRequest(() => client.delete(
|
|
243
|
+
const { status, data } = await safeRequest(() => client.delete(path9));
|
|
244
244
|
checkResponse(status, data, options?.expected ?? [200]);
|
|
245
245
|
return data;
|
|
246
246
|
}
|
|
@@ -1103,6 +1103,7 @@ syn workflow run ${wfName}-v1 --task "Your task here"
|
|
|
1103
1103
|
}
|
|
1104
1104
|
|
|
1105
1105
|
// src/commands/workflow/crud.ts
|
|
1106
|
+
import path4 from "path";
|
|
1106
1107
|
var createCommand = {
|
|
1107
1108
|
name: "create",
|
|
1108
1109
|
description: "Create a new workflow",
|
|
@@ -1219,8 +1220,9 @@ var validateCommand = {
|
|
|
1219
1220
|
validatePackageDir(file);
|
|
1220
1221
|
return;
|
|
1221
1222
|
}
|
|
1223
|
+
const content = fs8.readFileSync(file, "utf-8");
|
|
1222
1224
|
const data = await apiPost("/workflows/validate", {
|
|
1223
|
-
body: { file }
|
|
1225
|
+
body: { content, filename: path4.basename(file) }
|
|
1224
1226
|
});
|
|
1225
1227
|
if (data["valid"]) {
|
|
1226
1228
|
printSuccess("Valid workflow definition\n");
|
|
@@ -1492,11 +1494,11 @@ var statusCommand = {
|
|
|
1492
1494
|
|
|
1493
1495
|
// src/commands/workflow/install.ts
|
|
1494
1496
|
import fs5 from "fs";
|
|
1495
|
-
import
|
|
1497
|
+
import path6 from "path";
|
|
1496
1498
|
|
|
1497
1499
|
// src/marketplace/client.ts
|
|
1498
1500
|
import fs4 from "fs";
|
|
1499
|
-
import
|
|
1501
|
+
import path5 from "path";
|
|
1500
1502
|
|
|
1501
1503
|
// src/marketplace/models.ts
|
|
1502
1504
|
import { z as z2 } from "zod";
|
|
@@ -1553,7 +1555,7 @@ function saveRegistries(config) {
|
|
|
1553
1555
|
}
|
|
1554
1556
|
function loadCachedIndex(registryName) {
|
|
1555
1557
|
validateRegistryName(registryName);
|
|
1556
|
-
const cachePath =
|
|
1558
|
+
const cachePath = path5.join(CACHE_DIR, `${registryName}.json`);
|
|
1557
1559
|
if (!fs4.existsSync(cachePath)) return null;
|
|
1558
1560
|
try {
|
|
1559
1561
|
const content = fs4.readFileSync(cachePath, "utf-8");
|
|
@@ -1565,7 +1567,7 @@ function loadCachedIndex(registryName) {
|
|
|
1565
1567
|
function saveCachedIndex(registryName, cached) {
|
|
1566
1568
|
validateRegistryName(registryName);
|
|
1567
1569
|
fs4.mkdirSync(CACHE_DIR, { recursive: true });
|
|
1568
|
-
const cachePath =
|
|
1570
|
+
const cachePath = path5.join(CACHE_DIR, `${registryName}.json`);
|
|
1569
1571
|
writeJsonFile(cachePath, cached);
|
|
1570
1572
|
}
|
|
1571
1573
|
function isCacheStale(cached) {
|
|
@@ -1582,7 +1584,7 @@ async function fetchMarketplaceJson(repo, ref = "main") {
|
|
|
1582
1584
|
const tmpdir = makeTempDir("syn-mkt-");
|
|
1583
1585
|
try {
|
|
1584
1586
|
await gitClone(url, ref, tmpdir);
|
|
1585
|
-
const marketplacePath =
|
|
1587
|
+
const marketplacePath = path5.join(tmpdir, "marketplace.json");
|
|
1586
1588
|
if (!fs4.existsSync(marketplacePath)) {
|
|
1587
1589
|
throw new Error(`No marketplace.json found in ${repo}`);
|
|
1588
1590
|
}
|
|
@@ -1694,7 +1696,7 @@ async function tryMarketplaceResolution(source, ref) {
|
|
|
1694
1696
|
removeTempDir(tmpdir);
|
|
1695
1697
|
throw err;
|
|
1696
1698
|
}
|
|
1697
|
-
const subdir =
|
|
1699
|
+
const subdir = path6.resolve(tmpdir, plugin.source.replace(/^\.\//, ""));
|
|
1698
1700
|
if (!subdir.startsWith(tmpdir)) {
|
|
1699
1701
|
removeTempDir(tmpdir);
|
|
1700
1702
|
throw new Error(`Plugin source path escapes repository: ${plugin.source}`);
|
|
@@ -1710,7 +1712,7 @@ async function resolveSource(source, ref) {
|
|
|
1710
1712
|
const { tmpdir, manifest: manifest2, workflows: workflows2 } = await resolveFromGit(resolved, ref);
|
|
1711
1713
|
return { packagePath: tmpdir, manifest: manifest2, workflows: workflows2, tmpdir };
|
|
1712
1714
|
}
|
|
1713
|
-
const packagePath =
|
|
1715
|
+
const packagePath = path6.resolve(resolved);
|
|
1714
1716
|
const { manifest, workflows } = resolvePackage(packagePath);
|
|
1715
1717
|
return { packagePath, manifest, workflows, tmpdir: null };
|
|
1716
1718
|
}
|
|
@@ -1788,7 +1790,7 @@ var installCommand = {
|
|
|
1788
1790
|
throw new CLIError("No workflows", 1);
|
|
1789
1791
|
}
|
|
1790
1792
|
const fmt = detectFormat(packagePath);
|
|
1791
|
-
const pkgName = manifest?.name ??
|
|
1793
|
+
const pkgName = manifest?.name ?? path6.basename(packagePath);
|
|
1792
1794
|
const pkgVersion = manifest?.version ?? "0.0.0";
|
|
1793
1795
|
printPackagePreview(pkgName, pkgVersion, source, fmt, workflows);
|
|
1794
1796
|
if (dryRun) {
|
|
@@ -1881,11 +1883,11 @@ var initCommand = {
|
|
|
1881
1883
|
},
|
|
1882
1884
|
handler: async (parsed) => {
|
|
1883
1885
|
const directory = parsed.positionals[0] ?? ".";
|
|
1884
|
-
const resolvedDir =
|
|
1886
|
+
const resolvedDir = path6.resolve(directory);
|
|
1885
1887
|
const workflowType = parsed.values["type"] ?? "research";
|
|
1886
1888
|
const numPhases = parseInt(parsed.values["phases"] ?? "3", 10);
|
|
1887
1889
|
const multi = parsed.values["multi"] === true;
|
|
1888
|
-
const wfName = parsed.values["name"] ??
|
|
1890
|
+
const wfName = parsed.values["name"] ?? path6.basename(resolvedDir).replace(/[-_]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
1889
1891
|
if (fs5.existsSync(resolvedDir)) {
|
|
1890
1892
|
const entries = fs5.readdirSync(resolvedDir);
|
|
1891
1893
|
if (entries.length > 0) {
|
|
@@ -1909,7 +1911,7 @@ var initCommand = {
|
|
|
1909
1911
|
|
|
1910
1912
|
// src/commands/workflow/export.ts
|
|
1911
1913
|
import fs6 from "fs";
|
|
1912
|
-
import
|
|
1914
|
+
import path7 from "path";
|
|
1913
1915
|
var exportCommand = {
|
|
1914
1916
|
name: "export",
|
|
1915
1917
|
description: "Export a workflow as a distributable package or Claude Code plugin",
|
|
@@ -1939,7 +1941,7 @@ var exportCommand = {
|
|
|
1939
1941
|
printError("Export returned no files");
|
|
1940
1942
|
throw new CLIError("Export empty", 1);
|
|
1941
1943
|
}
|
|
1942
|
-
const outDir =
|
|
1944
|
+
const outDir = path7.resolve(outputDir);
|
|
1943
1945
|
if (fs6.existsSync(outDir)) {
|
|
1944
1946
|
const entries = fs6.readdirSync(outDir);
|
|
1945
1947
|
if (entries.length > 0) {
|
|
@@ -1952,12 +1954,12 @@ var exportCommand = {
|
|
|
1952
1954
|
printError(`Unsafe file path in export manifest: ${relPath}`);
|
|
1953
1955
|
throw new CLIError("Path traversal", 1);
|
|
1954
1956
|
}
|
|
1955
|
-
const filePath =
|
|
1957
|
+
const filePath = path7.resolve(outDir, relPath);
|
|
1956
1958
|
if (!filePath.startsWith(outDir)) {
|
|
1957
1959
|
printError(`Path escapes output directory: ${relPath}`);
|
|
1958
1960
|
throw new CLIError("Path traversal", 1);
|
|
1959
1961
|
}
|
|
1960
|
-
fs6.mkdirSync(
|
|
1962
|
+
fs6.mkdirSync(path7.dirname(filePath), { recursive: true });
|
|
1961
1963
|
fs6.writeFileSync(filePath, content, "utf-8");
|
|
1962
1964
|
}
|
|
1963
1965
|
const workflowName = data.workflow_name ?? workflowId;
|
|
@@ -1968,7 +1970,7 @@ var exportCommand = {
|
|
|
1968
1970
|
print(` Output: ${outDir}`);
|
|
1969
1971
|
print(` Files: ${Object.keys(files).length}`);
|
|
1970
1972
|
print("");
|
|
1971
|
-
print(style(`${
|
|
1973
|
+
print(style(`${path7.basename(outDir)}/`, CYAN));
|
|
1972
1974
|
const sortedPaths = Object.keys(files).sort();
|
|
1973
1975
|
for (const relPath of sortedPaths) {
|
|
1974
1976
|
const parts = relPath.split("/");
|
|
@@ -2242,7 +2244,7 @@ workflowGroup.command(createCommand).command(listCommand).command(showCommand).c
|
|
|
2242
2244
|
|
|
2243
2245
|
// src/commands/marketplace/registry.ts
|
|
2244
2246
|
import fs7 from "fs";
|
|
2245
|
-
import
|
|
2247
|
+
import path8 from "path";
|
|
2246
2248
|
var addCommand = {
|
|
2247
2249
|
name: "add",
|
|
2248
2250
|
description: "Register a GitHub repo as a workflow marketplace",
|
|
@@ -2347,7 +2349,7 @@ var removeCommand = {
|
|
|
2347
2349
|
saveRegistries({ version: config.version, registries: remaining });
|
|
2348
2350
|
try {
|
|
2349
2351
|
validateRegistryName(name);
|
|
2350
|
-
const cachePath =
|
|
2352
|
+
const cachePath = path8.join(synPath("marketplace", "cache"), `${name}.json`);
|
|
2351
2353
|
if (fs7.existsSync(cachePath)) fs7.unlinkSync(cachePath);
|
|
2352
2354
|
} catch {
|
|
2353
2355
|
}
|
|
@@ -2944,10 +2946,17 @@ function reqSessionId(parsed) {
|
|
|
2944
2946
|
var recentCommand = {
|
|
2945
2947
|
name: "recent",
|
|
2946
2948
|
description: "Show recent domain events across all sessions",
|
|
2947
|
-
options: {
|
|
2949
|
+
options: {
|
|
2950
|
+
limit: { type: "string", description: "Max events (max 200)", default: "50" },
|
|
2951
|
+
type: { type: "string", short: "t", description: "Filter by event type" }
|
|
2952
|
+
},
|
|
2948
2953
|
handler: async (parsed) => {
|
|
2949
2954
|
const limit = parsed.values["limit"] ?? "50";
|
|
2950
|
-
const
|
|
2955
|
+
const params = buildParams({
|
|
2956
|
+
limit,
|
|
2957
|
+
event_type: parsed.values["type"] ?? null
|
|
2958
|
+
});
|
|
2959
|
+
const data = await apiGet("/events/recent", { params });
|
|
2951
2960
|
if (data.events.length === 0) {
|
|
2952
2961
|
printDim("No recent events.");
|
|
2953
2962
|
return;
|
|
@@ -4246,9 +4255,10 @@ var registerCommand2 = {
|
|
|
4246
4255
|
var enablePresetCommand = {
|
|
4247
4256
|
name: "enable",
|
|
4248
4257
|
description: "Enable a built-in trigger preset",
|
|
4249
|
-
args: [{ name: "preset", description: "Preset name (self-healing, review-fix)", required: true }],
|
|
4258
|
+
args: [{ name: "preset", description: "Preset name (self-healing, review-fix, comment-command)", required: true }],
|
|
4250
4259
|
options: {
|
|
4251
|
-
repo: { type: "string", short: "r", description: "Repository ID" }
|
|
4260
|
+
repo: { type: "string", short: "r", description: "Repository ID" },
|
|
4261
|
+
workflow: { type: "string", short: "w", description: "Workflow ID to dispatch (default: preset default)" }
|
|
4252
4262
|
},
|
|
4253
4263
|
handler: async (parsed) => {
|
|
4254
4264
|
const preset = parsed.positionals[0];
|
|
@@ -4261,7 +4271,10 @@ var enablePresetCommand = {
|
|
|
4261
4271
|
printError("Missing --repo");
|
|
4262
4272
|
throw new CLIError("Missing option", 1);
|
|
4263
4273
|
}
|
|
4264
|
-
const
|
|
4274
|
+
const workflow = parsed.values["workflow"];
|
|
4275
|
+
const body = { repository: repo };
|
|
4276
|
+
if (workflow) body["workflow_id"] = workflow;
|
|
4277
|
+
const d = await apiPost(`/triggers/presets/${encodeURIComponent(preset)}`, { body, expected: [200, 201] });
|
|
4265
4278
|
printSuccess(`Preset "${preset}" enabled: ${d["trigger_id"] ?? ""}`);
|
|
4266
4279
|
}
|
|
4267
4280
|
};
|
|
@@ -4444,9 +4457,9 @@ function parseSseLine(line) {
|
|
|
4444
4457
|
return null;
|
|
4445
4458
|
}
|
|
4446
4459
|
}
|
|
4447
|
-
async function* streamSSE(
|
|
4460
|
+
async function* streamSSE(path9) {
|
|
4448
4461
|
const client = new SynClient();
|
|
4449
|
-
const body = await client.stream(
|
|
4462
|
+
const body = await client.stream(path9);
|
|
4450
4463
|
const reader = body.pipeThrough(new TextDecoderStream()).getReader();
|
|
4451
4464
|
let buffer = "";
|
|
4452
4465
|
try {
|