@runtypelabs/cli 2.59.1 → 2.59.4
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/chunk-0x7UKC1U.js +17 -0
- package/dist/chunk-2ySxXtcg.js +418 -0
- package/dist/chunk-3An_BRHv.js +501 -0
- package/dist/chunk-6uTxgdiY.js +16218 -0
- package/dist/chunk-87nRnNRG.js +1363 -0
- package/dist/chunk-B3wo8uRx.js +322 -0
- package/dist/chunk-BGp3ZdBy.js +560 -0
- package/dist/chunk-BJQv9Elp.js +107 -0
- package/dist/chunk-BOpO6xE-.js +6053 -0
- package/dist/chunk-BQXXCL8B.js +102 -0
- package/dist/chunk-BV-8isOd.js +34 -0
- package/dist/chunk-BVMhjGVe.js +826 -0
- package/dist/chunk-BW2fg46T.js +141 -0
- package/dist/chunk-BWJdY5Ag.js +36 -0
- package/dist/chunk-BYJOrLhh.js +302 -0
- package/dist/chunk-BYab8EVL.js +127 -0
- package/dist/chunk-BfEKvp7h.js +82 -0
- package/dist/chunk-BhgLSfH6.js +1123 -0
- package/dist/chunk-BirUxTtH.js +296 -0
- package/dist/chunk-BmB6UVZ9.js +1559 -0
- package/dist/chunk-BnWhIqW1.js +109 -0
- package/dist/chunk-Bpfnfk0t.js +123 -0
- package/dist/chunk-BrhgdnM3.js +108 -0
- package/dist/chunk-Bt0XAgX5.js +327 -0
- package/dist/chunk-Bu0FJr6S.js +84 -0
- package/dist/chunk-BvEoKpN3.js +255 -0
- package/dist/chunk-BxNJgYbE.js +28 -0
- package/dist/chunk-C1OFhd7F.js +6131 -0
- package/dist/chunk-C7e7WwbU.js +331 -0
- package/dist/chunk-CDTYP6bN.js +558 -0
- package/dist/chunk-CGDQoqDC.js +24 -0
- package/dist/chunk-CJraEBVd.js +127 -0
- package/dist/chunk-CQrNhOtv.js +40 -0
- package/dist/chunk-CW6AzBH6.js +128 -0
- package/dist/chunk-CXgL4w-9.js +317 -0
- package/dist/chunk-CZrqoPyf.js +233 -0
- package/dist/chunk-CcFCyqbB.js +83 -0
- package/dist/chunk-CdaIvO-y.js +485 -0
- package/dist/chunk-CehSXtgK.js +624 -0
- package/dist/chunk-Ciqkop65.js +218 -0
- package/dist/chunk-CoAWdSiE.js +43 -0
- package/dist/chunk-Crb4y7t4.js +830 -0
- package/dist/chunk-CrlqIfmb.js +337 -0
- package/dist/chunk-Cs4pwCQ-.js +324 -0
- package/dist/chunk-CwM_9y01.js +519 -0
- package/dist/chunk-CyRbIJg8.js +440 -0
- package/dist/chunk-D0OHsyMy.js +212 -0
- package/dist/chunk-D3y2bURs.js +1347 -0
- package/dist/chunk-D4_mJk03.js +2338 -0
- package/dist/chunk-D6C8rned.js +578 -0
- package/dist/chunk-D9ZbUnks.js +11 -0
- package/dist/chunk-DEPmLshX.js +834 -0
- package/dist/chunk-DFj1UPB2.js +330 -0
- package/dist/chunk-DGdFdZVf.js +197 -0
- package/dist/chunk-DGv7X9S_.js +63 -0
- package/dist/chunk-DJQ47WYZ.js +664 -0
- package/dist/chunk-DJw3O61j.js +1974 -0
- package/dist/chunk-DK4FbWVK.js +100 -0
- package/dist/chunk-DPuofXMp.js +3907 -0
- package/dist/chunk-DSRYhUus.js +993 -0
- package/dist/chunk-DajZ9Eg4.js +299 -0
- package/dist/chunk-Df4dunvU.js +195 -0
- package/dist/chunk-DjNTPhfO.js +481 -0
- package/dist/chunk-Dn8eaJuu.js +1042 -0
- package/dist/chunk-DwDWqSxM.js +637 -0
- package/dist/chunk-Dz7cEtxl.js +84 -0
- package/dist/chunk-E_0bgjrS.js +359 -0
- package/dist/chunk-KPYN2vUp.js +776 -0
- package/dist/chunk-KcqPQJBi.js +86 -0
- package/dist/chunk-N9H0JnoG.js +349 -0
- package/dist/chunk-NONFcXkn.js +728 -0
- package/dist/chunk-PrFjcpmH.js +256 -0
- package/dist/chunk-QSfNYiw9.js +11 -0
- package/dist/chunk-R265bzj9.js +226 -0
- package/dist/chunk-X9V_r6jM.js +166 -0
- package/dist/chunk-ZBtPUtyA.js +55 -0
- package/dist/chunk-ZCTfmOs7.js +4939 -0
- package/dist/chunk-h6oavj0t.js +97 -0
- package/dist/chunk-i7DwkvvD.js +42 -0
- package/dist/chunk-mG-4eZ6S.js +203 -0
- package/dist/chunk-o0ygUbCf.js +313 -0
- package/dist/chunk-ucu5lrDZ.js +5715 -0
- package/dist/index.js +11367 -73789
- package/package.json +5 -5
|
@@ -0,0 +1,519 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { t as isTTY } from "./index.js";
|
|
3
|
+
import { DataList, EntityCard, MutationResult, React, render, useEffect, useState } from "./chunk-CoAWdSiE.js";
|
|
4
|
+
import { p as buildDashboardUrl } from "./chunk-ucu5lrDZ.js";
|
|
5
|
+
import { r as createCliClient, s as getDashboardUrl } from "./chunk-BW2fg46T.js";
|
|
6
|
+
import { n as ensureAuth } from "./chunk-CJraEBVd.js";
|
|
7
|
+
import { a as printJson, i as printDetail, n as buildListParams, r as getTotalCount, s as printNextCursorHint } from "./chunk-CcFCyqbB.js";
|
|
8
|
+
import { t as readJsonFile } from "./chunk-DGv7X9S_.js";
|
|
9
|
+
import { c as buildEntityPullCommand, d as productPullFpoCommand, r as PRODUCT_ENSURE_SPEC, s as buildEntityEnsureCommand, u as productEnsureFpoCommand } from "./chunk-BirUxTtH.js";
|
|
10
|
+
import { t as getCurrentAccountId } from "./chunk-BV-8isOd.js";
|
|
11
|
+
import { n as validateQuickStartUrl, t as createQuickStartProduct } from "./chunk-i7DwkvvD.js";
|
|
12
|
+
import { Command } from "commander";
|
|
13
|
+
import chalk from "chalk";
|
|
14
|
+
import open from "open";
|
|
15
|
+
// src/commands/products.ts
|
|
16
|
+
function displayAgentCard(agentCard) {
|
|
17
|
+
console.log(chalk.cyan("\nAgent Details:"));
|
|
18
|
+
console.log(` Name: ${agentCard.name}`);
|
|
19
|
+
if (agentCard.description) console.log(` Description: ${agentCard.description}`);
|
|
20
|
+
console.log(` URL: ${agentCard.url}`);
|
|
21
|
+
if (agentCard.skills && agentCard.skills.length > 0) {
|
|
22
|
+
console.log(" Skills:");
|
|
23
|
+
agentCard.skills.forEach((skill) => {
|
|
24
|
+
const desc = skill.description ? ` - ${skill.description}` : "";
|
|
25
|
+
console.log(` ${chalk.cyan("•")} ${skill.name}${desc}`);
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
async function createProduct(apiKey, templateId, agentCard, sourceUrl, productName, apiUrl) {
|
|
30
|
+
return createQuickStartProduct(apiKey, {
|
|
31
|
+
templateId,
|
|
32
|
+
agentCard,
|
|
33
|
+
productName,
|
|
34
|
+
sourceUrl
|
|
35
|
+
}, apiUrl);
|
|
36
|
+
}
|
|
37
|
+
function displayCreationSuccess(result, agentCard, dashboardBaseUrl, jsonOutput, account) {
|
|
38
|
+
const productUrl = buildDashboardUrl({
|
|
39
|
+
baseUrl: dashboardBaseUrl,
|
|
40
|
+
path: `/products/${result.product.id}`,
|
|
41
|
+
account,
|
|
42
|
+
searchParams: { launch: "true" }
|
|
43
|
+
});
|
|
44
|
+
if (jsonOutput) {
|
|
45
|
+
console.log(JSON.stringify({
|
|
46
|
+
status: "created",
|
|
47
|
+
product: result.product,
|
|
48
|
+
agentCard,
|
|
49
|
+
dashboardUrl: productUrl
|
|
50
|
+
}, null, 2));
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
console.log(`\nProduct ID: ${result.product.id}`);
|
|
54
|
+
console.log(`Name: ${result.product.name}`);
|
|
55
|
+
console.log(`Dashboard: ${productUrl}`);
|
|
56
|
+
console.log(chalk.cyan("\nNext steps:"));
|
|
57
|
+
console.log(" 1. Visit the dashboard to configure surfaces");
|
|
58
|
+
console.log(" 2. Or run: runtype products init --from <another-url>");
|
|
59
|
+
}
|
|
60
|
+
async function validateUrl(url, apiUrl) {
|
|
61
|
+
return validateQuickStartUrl(url, apiUrl);
|
|
62
|
+
}
|
|
63
|
+
const productsCommand = new Command("products").description("Manage products");
|
|
64
|
+
productsCommand.addCommand(buildEntityEnsureCommand(PRODUCT_ENSURE_SPEC));
|
|
65
|
+
productsCommand.addCommand(buildEntityPullCommand(PRODUCT_ENSURE_SPEC));
|
|
66
|
+
productsCommand.addCommand(productEnsureFpoCommand);
|
|
67
|
+
productsCommand.addCommand(productPullFpoCommand);
|
|
68
|
+
productsCommand.command("init").description("Initialize a product from an external resource").option("--from <url>", "URL to validate and import").option("--name <name>", "Custom product name (defaults to agent name)").option("--open", "Open browser to dashboard instead of creating via API").option("--json", "Output as JSON").option("--api-url <url>", "Override API URL").option("--tty", "Force TTY mode").option("--no-tty", "Force non-TTY mode").action(async (options) => {
|
|
69
|
+
const isJsonMode = !!options.json;
|
|
70
|
+
if (!isTTY(options) || isJsonMode) {
|
|
71
|
+
let sourceUrl = options.from;
|
|
72
|
+
if (!sourceUrl) {
|
|
73
|
+
if (isJsonMode) {
|
|
74
|
+
console.log(JSON.stringify({
|
|
75
|
+
status: "error",
|
|
76
|
+
error: "Missing --from URL",
|
|
77
|
+
code: "MISSING_URL"
|
|
78
|
+
}, null, 2));
|
|
79
|
+
process.exit(1);
|
|
80
|
+
}
|
|
81
|
+
console.error(chalk.red("--from URL required in non-TTY mode"));
|
|
82
|
+
process.exit(1);
|
|
83
|
+
}
|
|
84
|
+
try {
|
|
85
|
+
const result = await validateUrl(sourceUrl, options.apiUrl);
|
|
86
|
+
if (!result.valid) {
|
|
87
|
+
if (isJsonMode) console.log(JSON.stringify({
|
|
88
|
+
status: "error",
|
|
89
|
+
error: result.error,
|
|
90
|
+
code: result.code
|
|
91
|
+
}, null, 2));
|
|
92
|
+
else console.error(chalk.red(result.error));
|
|
93
|
+
process.exit(1);
|
|
94
|
+
}
|
|
95
|
+
displayAgentCard(result.agentCard);
|
|
96
|
+
const productName = options.name;
|
|
97
|
+
const apiKey = isJsonMode ? await getApiKeyOrExit(isJsonMode, result.agentCard) : await ensureAuth({ apiUrl: options.apiUrl });
|
|
98
|
+
if (!apiKey) process.exit(1);
|
|
99
|
+
if (options.open) {
|
|
100
|
+
const targetUrl = `${getDashboardUrl()}/now?from=${encodeURIComponent(sourceUrl)}&cli=true`;
|
|
101
|
+
if (isJsonMode) console.log(JSON.stringify({
|
|
102
|
+
status: "browser_opened",
|
|
103
|
+
agentCard: result.agentCard,
|
|
104
|
+
url: targetUrl
|
|
105
|
+
}, null, 2));
|
|
106
|
+
else console.log(chalk.cyan("\nOpening browser to complete setup..."));
|
|
107
|
+
await open(targetUrl);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
const createResult = await createProduct(apiKey, result.templateId, result.agentCard, sourceUrl, productName, options.apiUrl);
|
|
111
|
+
if (!createResult.success) {
|
|
112
|
+
if (isJsonMode) console.log(JSON.stringify({
|
|
113
|
+
status: "error",
|
|
114
|
+
error: createResult.error,
|
|
115
|
+
code: createResult.code
|
|
116
|
+
}, null, 2));
|
|
117
|
+
else console.error(chalk.red(createResult.error));
|
|
118
|
+
process.exit(1);
|
|
119
|
+
}
|
|
120
|
+
const account = await getCurrentAccountId();
|
|
121
|
+
displayCreationSuccess(createResult, result.agentCard, getDashboardUrl(), isJsonMode, account);
|
|
122
|
+
} catch (error) {
|
|
123
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
124
|
+
console.error(chalk.red(`Failed: ${message}`));
|
|
125
|
+
process.exit(1);
|
|
126
|
+
}
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
const ProductInitApp = () => {
|
|
130
|
+
const [loading, setLoading] = useState(!!options.from);
|
|
131
|
+
const [loadingLabel, setLoadingLabel] = useState("Validating URL...");
|
|
132
|
+
const [success, setSuccess] = useState(null);
|
|
133
|
+
const [error, setError] = useState(null);
|
|
134
|
+
const [resultNode, setResultNode] = useState(void 0);
|
|
135
|
+
useEffect(() => {
|
|
136
|
+
if (!options.from) return void 0;
|
|
137
|
+
const run = async () => {
|
|
138
|
+
try {
|
|
139
|
+
const result = await validateUrl(options.from, options.apiUrl);
|
|
140
|
+
if (!result.valid) {
|
|
141
|
+
setError(new Error(result.error));
|
|
142
|
+
setSuccess(false);
|
|
143
|
+
setLoading(false);
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
const productName = options.name || result.agentCard.name;
|
|
147
|
+
const apiKey = await ensureAuth({ apiUrl: options.apiUrl });
|
|
148
|
+
if (!apiKey) {
|
|
149
|
+
setError(/* @__PURE__ */ new Error("Authentication required"));
|
|
150
|
+
setSuccess(false);
|
|
151
|
+
setLoading(false);
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
if (options.open) {
|
|
155
|
+
const targetUrl = `${getDashboardUrl()}/now?from=${encodeURIComponent(options.from)}&cli=true`;
|
|
156
|
+
await open(targetUrl);
|
|
157
|
+
setSuccess(true);
|
|
158
|
+
setLoading(false);
|
|
159
|
+
setResultNode(React.createElement(EntityCard, { fields: [{
|
|
160
|
+
label: "Status",
|
|
161
|
+
value: "Browser opened"
|
|
162
|
+
}, {
|
|
163
|
+
label: "URL",
|
|
164
|
+
value: targetUrl
|
|
165
|
+
}] }));
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
setLoadingLabel("Creating product...");
|
|
169
|
+
const createResult = await createProduct(apiKey, result.templateId, result.agentCard, options.from, productName, options.apiUrl);
|
|
170
|
+
if (!createResult.success) {
|
|
171
|
+
setError(new Error(createResult.error));
|
|
172
|
+
setSuccess(false);
|
|
173
|
+
setLoading(false);
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
const dashboardUrl = getDashboardUrl();
|
|
177
|
+
const account = await getCurrentAccountId();
|
|
178
|
+
setResultNode(React.createElement(EntityCard, { fields: [
|
|
179
|
+
{
|
|
180
|
+
label: "Product ID",
|
|
181
|
+
value: createResult.product.id,
|
|
182
|
+
color: "green"
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
label: "Name",
|
|
186
|
+
value: createResult.product.name
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
label: "Dashboard",
|
|
190
|
+
value: buildDashboardUrl({
|
|
191
|
+
baseUrl: dashboardUrl,
|
|
192
|
+
path: `/products/${createResult.product.id}`,
|
|
193
|
+
account
|
|
194
|
+
})
|
|
195
|
+
}
|
|
196
|
+
] }));
|
|
197
|
+
setSuccess(true);
|
|
198
|
+
setLoading(false);
|
|
199
|
+
} catch (err) {
|
|
200
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
201
|
+
setSuccess(false);
|
|
202
|
+
setLoading(false);
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
run();
|
|
206
|
+
}, []);
|
|
207
|
+
if (!options.from) return React.createElement(MutationResult, {
|
|
208
|
+
loading: false,
|
|
209
|
+
success: false,
|
|
210
|
+
error: /* @__PURE__ */ new Error("Use \"runtype init\" for interactive product setup, or provide --from <url>")
|
|
211
|
+
});
|
|
212
|
+
return React.createElement(MutationResult, {
|
|
213
|
+
loading,
|
|
214
|
+
loadingLabel,
|
|
215
|
+
success,
|
|
216
|
+
successMessage: "Product Created",
|
|
217
|
+
error,
|
|
218
|
+
result: resultNode
|
|
219
|
+
});
|
|
220
|
+
};
|
|
221
|
+
const { waitUntilExit } = render(React.createElement(ProductInitApp));
|
|
222
|
+
await waitUntilExit();
|
|
223
|
+
});
|
|
224
|
+
productsCommand.command("list").description("List your products").option("--limit <n>", "Limit results (defaults to the API page size)").option("--cursor <cursor>", "Pagination cursor for the next page").option("--json", "Output as JSON").option("--tty", "Force TTY mode").option("--no-tty", "Force non-TTY mode").action(async (options) => {
|
|
225
|
+
const apiKey = await ensureAuth();
|
|
226
|
+
if (!apiKey) return;
|
|
227
|
+
const client = createCliClient(apiKey);
|
|
228
|
+
const params = buildListParams(options);
|
|
229
|
+
if (!isTTY(options) || options.json) {
|
|
230
|
+
try {
|
|
231
|
+
const data = await client.get("/products", params);
|
|
232
|
+
if (options.json) {
|
|
233
|
+
printJson(data);
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
const products = data.data ?? [];
|
|
237
|
+
if (products.length === 0) {
|
|
238
|
+
console.log(chalk.gray("No products found"));
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
console.log(chalk.cyan("Your Products:"));
|
|
242
|
+
for (const p of products) {
|
|
243
|
+
const meta = `${p.capabilityCount ?? 0} capabilities, ${p.surfaceCount ?? 0} surfaces`;
|
|
244
|
+
console.log(` ${chalk.green(p.id)} ${p.name} ${chalk.gray(`(${meta})`)}`);
|
|
245
|
+
}
|
|
246
|
+
const total = getTotalCount(data.pagination);
|
|
247
|
+
if (total !== void 0) console.log(chalk.dim(`\n Total: ${total} products`));
|
|
248
|
+
printNextCursorHint("runtype products list", data.pagination);
|
|
249
|
+
} catch (error) {
|
|
250
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
251
|
+
console.error(chalk.red(`Failed to fetch products: ${message}`));
|
|
252
|
+
process.exit(1);
|
|
253
|
+
}
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
const App = () => {
|
|
257
|
+
const [items, setItems] = useState(null);
|
|
258
|
+
const [error, setError] = useState(null);
|
|
259
|
+
const [total, setTotal] = useState();
|
|
260
|
+
useEffect(() => {
|
|
261
|
+
client.get("/products", params).then((res) => {
|
|
262
|
+
setItems(res.data ?? []);
|
|
263
|
+
setTotal(getTotalCount(res.pagination));
|
|
264
|
+
}).catch((err) => setError(err instanceof Error ? err : new Error(String(err))));
|
|
265
|
+
}, []);
|
|
266
|
+
return React.createElement(DataList, {
|
|
267
|
+
title: "Your Products",
|
|
268
|
+
items,
|
|
269
|
+
error,
|
|
270
|
+
loading: items === null && error === null,
|
|
271
|
+
total,
|
|
272
|
+
emptyMessage: "No products found",
|
|
273
|
+
renderCard: (item) => {
|
|
274
|
+
const p = item;
|
|
275
|
+
return React.createElement(EntityCard, { fields: [
|
|
276
|
+
{
|
|
277
|
+
label: "ID",
|
|
278
|
+
value: p.id,
|
|
279
|
+
color: "green"
|
|
280
|
+
},
|
|
281
|
+
{
|
|
282
|
+
label: "Name",
|
|
283
|
+
value: p.name
|
|
284
|
+
},
|
|
285
|
+
{
|
|
286
|
+
label: "Description",
|
|
287
|
+
value: p.description,
|
|
288
|
+
color: "gray"
|
|
289
|
+
},
|
|
290
|
+
{
|
|
291
|
+
label: "Capabilities",
|
|
292
|
+
value: p.capabilityCount
|
|
293
|
+
},
|
|
294
|
+
{
|
|
295
|
+
label: "Surfaces",
|
|
296
|
+
value: p.surfaceCount
|
|
297
|
+
}
|
|
298
|
+
] });
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
};
|
|
302
|
+
const { waitUntilExit } = render(React.createElement(App));
|
|
303
|
+
await waitUntilExit();
|
|
304
|
+
});
|
|
305
|
+
productsCommand.command("get <id>").description("Get product details").option("--json", "Output as JSON").option("--tty", "Force TTY mode").option("--no-tty", "Force non-TTY mode").action(async (id, options) => {
|
|
306
|
+
const apiKey = await ensureAuth();
|
|
307
|
+
if (!apiKey) return;
|
|
308
|
+
const client = createCliClient(apiKey);
|
|
309
|
+
if (!isTTY(options) || options.json) {
|
|
310
|
+
try {
|
|
311
|
+
const data = await client.get(`/products/${id}`);
|
|
312
|
+
if (options.json) {
|
|
313
|
+
printJson(data);
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
printDetail("Product", [
|
|
317
|
+
{
|
|
318
|
+
label: "ID",
|
|
319
|
+
value: data.id
|
|
320
|
+
},
|
|
321
|
+
{
|
|
322
|
+
label: "Name",
|
|
323
|
+
value: data.name
|
|
324
|
+
},
|
|
325
|
+
{
|
|
326
|
+
label: "Description",
|
|
327
|
+
value: data.description
|
|
328
|
+
},
|
|
329
|
+
{
|
|
330
|
+
label: "Icon",
|
|
331
|
+
value: data.icon
|
|
332
|
+
},
|
|
333
|
+
{
|
|
334
|
+
label: "Capabilities",
|
|
335
|
+
value: data.capabilities?.length ?? 0
|
|
336
|
+
},
|
|
337
|
+
{
|
|
338
|
+
label: "Surfaces",
|
|
339
|
+
value: data.surfaces?.length ?? 0
|
|
340
|
+
},
|
|
341
|
+
{
|
|
342
|
+
label: "Created",
|
|
343
|
+
value: data.createdAt
|
|
344
|
+
},
|
|
345
|
+
{
|
|
346
|
+
label: "Updated",
|
|
347
|
+
value: data.updatedAt
|
|
348
|
+
},
|
|
349
|
+
{
|
|
350
|
+
label: "Dashboard",
|
|
351
|
+
value: data.dashboardUrl
|
|
352
|
+
}
|
|
353
|
+
]);
|
|
354
|
+
} catch (error) {
|
|
355
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
356
|
+
console.error(chalk.red(`Failed to fetch product: ${message}`));
|
|
357
|
+
process.exit(1);
|
|
358
|
+
}
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
const App = () => {
|
|
362
|
+
const [loading, setLoading] = useState(true);
|
|
363
|
+
const [success, setSuccess] = useState(null);
|
|
364
|
+
const [error, setError] = useState(null);
|
|
365
|
+
const [resultNode, setResultNode] = useState(void 0);
|
|
366
|
+
useEffect(() => {
|
|
367
|
+
const run = async () => {
|
|
368
|
+
try {
|
|
369
|
+
const data = await client.get(`/products/${id}`);
|
|
370
|
+
setResultNode(React.createElement(EntityCard, { fields: [
|
|
371
|
+
{
|
|
372
|
+
label: "ID",
|
|
373
|
+
value: data.id,
|
|
374
|
+
color: "green"
|
|
375
|
+
},
|
|
376
|
+
{
|
|
377
|
+
label: "Name",
|
|
378
|
+
value: data.name
|
|
379
|
+
},
|
|
380
|
+
{
|
|
381
|
+
label: "Description",
|
|
382
|
+
value: data.description,
|
|
383
|
+
color: "gray"
|
|
384
|
+
},
|
|
385
|
+
{
|
|
386
|
+
label: "Icon",
|
|
387
|
+
value: data.icon
|
|
388
|
+
},
|
|
389
|
+
{
|
|
390
|
+
label: "Capabilities",
|
|
391
|
+
value: data.capabilities?.length ?? 0
|
|
392
|
+
},
|
|
393
|
+
{
|
|
394
|
+
label: "Surfaces",
|
|
395
|
+
value: data.surfaces?.length ?? 0
|
|
396
|
+
},
|
|
397
|
+
{
|
|
398
|
+
label: "Created",
|
|
399
|
+
value: data.createdAt
|
|
400
|
+
},
|
|
401
|
+
{
|
|
402
|
+
label: "Dashboard",
|
|
403
|
+
value: data.dashboardUrl
|
|
404
|
+
}
|
|
405
|
+
] }));
|
|
406
|
+
setSuccess(true);
|
|
407
|
+
setLoading(false);
|
|
408
|
+
} catch (err) {
|
|
409
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
410
|
+
setSuccess(false);
|
|
411
|
+
setLoading(false);
|
|
412
|
+
}
|
|
413
|
+
};
|
|
414
|
+
run();
|
|
415
|
+
}, []);
|
|
416
|
+
return React.createElement(MutationResult, {
|
|
417
|
+
loading,
|
|
418
|
+
loadingLabel: "Fetching product...",
|
|
419
|
+
success,
|
|
420
|
+
successMessage: "Product",
|
|
421
|
+
error,
|
|
422
|
+
result: resultNode
|
|
423
|
+
});
|
|
424
|
+
};
|
|
425
|
+
const { waitUntilExit } = render(React.createElement(App));
|
|
426
|
+
await waitUntilExit();
|
|
427
|
+
});
|
|
428
|
+
/** Reads `{ "items": [...] }` from `--file` (or `-` for stdin), exiting with a clear error when it has no item list. */
|
|
429
|
+
function readStackFile(path) {
|
|
430
|
+
const items = readJsonFile(path, { label: "stack file" }).items;
|
|
431
|
+
if (Array.isArray(items)) return items;
|
|
432
|
+
console.error(chalk.red("stack file must be a JSON object with an \"items\" array"));
|
|
433
|
+
process.exit(1);
|
|
434
|
+
}
|
|
435
|
+
productsCommand.command("stack").description("Manage what a product is built on, as shown on its Overview").command("declare <id>").description("Declare what the product is built on (frameworks, vector databases, services), replacing the previous CLI declaration").requiredOption("--file <path>", "JSON file with { \"items\": [{ \"key\", \"label\", ... }] }, or - for stdin").option("--json", "Output as JSON").option("--tty", "Force TTY mode").option("--no-tty", "Force non-TTY mode").action(async (id, options) => {
|
|
436
|
+
const items = readStackFile(options.file);
|
|
437
|
+
if (!items) return;
|
|
438
|
+
const apiKey = await ensureAuth();
|
|
439
|
+
if (!apiKey) return;
|
|
440
|
+
const client = createCliClient(apiKey);
|
|
441
|
+
const declare = () => client.put(`/products/${encodeURIComponent(id)}/stack/declared`, {
|
|
442
|
+
source: "cli",
|
|
443
|
+
items
|
|
444
|
+
});
|
|
445
|
+
if (!isTTY(options) || options.json) {
|
|
446
|
+
try {
|
|
447
|
+
const data = await declare();
|
|
448
|
+
if (options.json) {
|
|
449
|
+
printJson(data);
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
452
|
+
console.log(chalk.green("Stack declared"));
|
|
453
|
+
console.log(` Product: ${chalk.green(data.productId)}`);
|
|
454
|
+
console.log(` Items: ${data.declaration.items.length}`);
|
|
455
|
+
console.log(` Declared by: ${data.declaration.actorLabel}`);
|
|
456
|
+
} catch (error) {
|
|
457
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
458
|
+
console.error(chalk.red(`Failed to declare the stack: ${message}`));
|
|
459
|
+
process.exit(1);
|
|
460
|
+
}
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
const App = () => {
|
|
464
|
+
const [loading, setLoading] = useState(true);
|
|
465
|
+
const [success, setSuccess] = useState(null);
|
|
466
|
+
const [error, setError] = useState(null);
|
|
467
|
+
const [result, setResult] = useState(null);
|
|
468
|
+
useEffect(() => {
|
|
469
|
+
declare().then((data) => {
|
|
470
|
+
setResult(data);
|
|
471
|
+
setSuccess(true);
|
|
472
|
+
setLoading(false);
|
|
473
|
+
}).catch((err) => {
|
|
474
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
475
|
+
setSuccess(false);
|
|
476
|
+
setLoading(false);
|
|
477
|
+
});
|
|
478
|
+
}, []);
|
|
479
|
+
return React.createElement(MutationResult, {
|
|
480
|
+
loading,
|
|
481
|
+
loadingLabel: "Declaring stack...",
|
|
482
|
+
success,
|
|
483
|
+
successMessage: "Stack declared",
|
|
484
|
+
error,
|
|
485
|
+
result: result ? React.createElement(EntityCard, { fields: [
|
|
486
|
+
{
|
|
487
|
+
label: "Product",
|
|
488
|
+
value: result.productId,
|
|
489
|
+
color: "green"
|
|
490
|
+
},
|
|
491
|
+
{
|
|
492
|
+
label: "Items",
|
|
493
|
+
value: result.declaration.items.map((item) => item.label).join(", ") || "None"
|
|
494
|
+
},
|
|
495
|
+
{
|
|
496
|
+
label: "Declared by",
|
|
497
|
+
value: result.declaration.actorLabel
|
|
498
|
+
}
|
|
499
|
+
] }) : void 0
|
|
500
|
+
});
|
|
501
|
+
};
|
|
502
|
+
const { waitUntilExit } = render(React.createElement(App));
|
|
503
|
+
await waitUntilExit();
|
|
504
|
+
});
|
|
505
|
+
async function getApiKeyOrExit(isJsonMode, agentCard) {
|
|
506
|
+
const { CredentialStore } = await import("./index.js").then((n) => n.x);
|
|
507
|
+
const apiKey = await new CredentialStore().getApiKey();
|
|
508
|
+
if (!apiKey) {
|
|
509
|
+
if (isJsonMode) console.log(JSON.stringify({
|
|
510
|
+
status: "unauthenticated",
|
|
511
|
+
agentCard,
|
|
512
|
+
message: "Authentication required to create product"
|
|
513
|
+
}, null, 2));
|
|
514
|
+
return null;
|
|
515
|
+
}
|
|
516
|
+
return apiKey;
|
|
517
|
+
}
|
|
518
|
+
export { productsCommand };
|
|
519
|
+
|