artifact-cafe 0.0.12 → 0.0.13
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/index.js +374 -28
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -180,7 +180,13 @@ var finalizeResponseSchema = z4.object({
|
|
|
180
180
|
publishToken: z4.string().optional(),
|
|
181
181
|
url: z4.string().url(),
|
|
182
182
|
versionId: z4.string(),
|
|
183
|
-
versionNumber: z4.number().int().positive()
|
|
183
|
+
versionNumber: z4.number().int().positive(),
|
|
184
|
+
// SPEC-2 §5.2 — who can open the review URL. A publish into a folder
|
|
185
|
+
// inherits that folder's visibility, so this is the only place the CLI
|
|
186
|
+
// learns that a link it just printed is members-only. Optional so a new
|
|
187
|
+
// CLI against an older API degrades to "unknown" instead of failing the
|
|
188
|
+
// publish over a field that only shapes the closing message.
|
|
189
|
+
visibility: z4.enum(["public", "unlisted", "workspace", "private"]).optional()
|
|
184
190
|
});
|
|
185
191
|
var artifactResponseSchema = z4.object({
|
|
186
192
|
claimed: z4.boolean(),
|
|
@@ -445,7 +451,15 @@ var grantListResponseSchema = z8.object({
|
|
|
445
451
|
grants: z8.array(grantSchema),
|
|
446
452
|
// The artifact's current general-access value, so the share surface can
|
|
447
453
|
// render the "General access" line without a second read.
|
|
448
|
-
visibility: z8.enum(["public", "unlisted", "workspace", "private"])
|
|
454
|
+
visibility: z8.enum(["public", "unlisted", "workspace", "private"]),
|
|
455
|
+
// The owning workspace's logo, so the share modal can draw the workspace
|
|
456
|
+
// itself rather than a generic glyph. Null when none was uploaded.
|
|
457
|
+
workspaceLogo: z8.string().nullable().optional(),
|
|
458
|
+
// The owning workspace's display name, so "People with access" can name the
|
|
459
|
+
// audience `workspace` visibility actually admits ("All Acme members") rather
|
|
460
|
+
// than leaving an empty list to imply nobody. Null for a workspace-less
|
|
461
|
+
// artifact; optional so an older server still parses.
|
|
462
|
+
workspaceName: z8.string().nullable().optional()
|
|
449
463
|
});
|
|
450
464
|
var revokeGrantResponseSchema = z8.object({
|
|
451
465
|
revoked: z8.literal(true)
|
|
@@ -951,6 +965,15 @@ function createApiClient(apiUrl2, publishToken) {
|
|
|
951
965
|
(d) => agentHeartbeatResponseSchema.parse(d)
|
|
952
966
|
);
|
|
953
967
|
},
|
|
968
|
+
// SPEC-2 §6.3 — create a folder in a workspace. Account key required
|
|
969
|
+
// (owner/admin; in a personal workspace that's always the user).
|
|
970
|
+
async createFolder(workspaceId, body) {
|
|
971
|
+
return request(
|
|
972
|
+
`${base}/api/v1/workspaces/${workspaceId}/folders`,
|
|
973
|
+
{ body: JSON.stringify(body), headers, method: "POST" },
|
|
974
|
+
(d) => folderSchema.parse(d)
|
|
975
|
+
);
|
|
976
|
+
},
|
|
954
977
|
// SPEC-2 §6.6 — share an artifact with a person (email or user id).
|
|
955
978
|
// Authorized by this client's credential: the publish token (an agent
|
|
956
979
|
// sharing a private draft) or an account key/session. The invitation
|
|
@@ -1049,6 +1072,15 @@ function createApiClient(apiUrl2, publishToken) {
|
|
|
1049
1072
|
(d) => grantListResponseSchema.parse(d)
|
|
1050
1073
|
);
|
|
1051
1074
|
},
|
|
1075
|
+
// SPEC-2 §6.4 — every artifact in a workspace (members see all, with
|
|
1076
|
+
// each artifact's folderId). The only folder-aware artifact listing.
|
|
1077
|
+
async listWorkspaceArtifacts(workspaceId) {
|
|
1078
|
+
return request(
|
|
1079
|
+
`${base}/api/v1/workspaces/${workspaceId}/artifacts`,
|
|
1080
|
+
{ headers, method: "GET" },
|
|
1081
|
+
(d) => workspaceArtifactListResponseSchema.parse(d)
|
|
1082
|
+
);
|
|
1083
|
+
},
|
|
1052
1084
|
async listWorkspaces() {
|
|
1053
1085
|
return request(
|
|
1054
1086
|
`${base}/api/v1/workspaces`,
|
|
@@ -1119,6 +1151,16 @@ function createApiClient(apiUrl2, publishToken) {
|
|
|
1119
1151
|
{ body: JSON.stringify({ mode }), headers, method: "PUT" },
|
|
1120
1152
|
(d) => reviewModeResponseSchema.parse(d)
|
|
1121
1153
|
);
|
|
1154
|
+
},
|
|
1155
|
+
// SPEC.md §6.11 / SPEC-2 §6.4 — update an artifact (folder placement,
|
|
1156
|
+
// title, slug, visibility). Workspace-member action: account key only,
|
|
1157
|
+
// a publish token can't re-file.
|
|
1158
|
+
async updateArtifact(artifactId, body) {
|
|
1159
|
+
return request(
|
|
1160
|
+
`${base}/api/v1/artifacts/${artifactId}`,
|
|
1161
|
+
{ body: JSON.stringify(body), headers, method: "PATCH" },
|
|
1162
|
+
(d) => artifactResponseSchema.parse(d)
|
|
1163
|
+
);
|
|
1122
1164
|
}
|
|
1123
1165
|
};
|
|
1124
1166
|
}
|
|
@@ -1927,6 +1969,7 @@ async function publish(opts) {
|
|
|
1927
1969
|
folderId: placement.folderId ?? null,
|
|
1928
1970
|
url: result.url,
|
|
1929
1971
|
versionNumber: result.versionNumber,
|
|
1972
|
+
visibility: result.visibility ?? null,
|
|
1930
1973
|
workspace: placement.workspace ?? null,
|
|
1931
1974
|
workspaceId: placement.workspaceId ?? null,
|
|
1932
1975
|
...result.claimUrl ? { claimUrl: result.claimUrl } : {},
|
|
@@ -1951,6 +1994,11 @@ async function publish(opts) {
|
|
|
1951
1994
|
console.log(`Review URL:
|
|
1952
1995
|
${result.url}
|
|
1953
1996
|
`);
|
|
1997
|
+
const access = accessNote(result.visibility);
|
|
1998
|
+
if (access) {
|
|
1999
|
+
console.log(`${access}
|
|
2000
|
+
`);
|
|
2001
|
+
}
|
|
1954
2002
|
if (result.claimUrl) {
|
|
1955
2003
|
console.log(
|
|
1956
2004
|
`Claim URL (shown once \u2014 claim to keep this artifact):
|
|
@@ -1979,6 +2027,11 @@ ${result.claimUrl}
|
|
|
1979
2027
|
}
|
|
1980
2028
|
console.log(`${result.url}
|
|
1981
2029
|
`);
|
|
2030
|
+
const access = accessNote(result.visibility);
|
|
2031
|
+
if (access) {
|
|
2032
|
+
console.log(`${access}
|
|
2033
|
+
`);
|
|
2034
|
+
}
|
|
1982
2035
|
if (opts.password !== void 0) {
|
|
1983
2036
|
console.log("Password protection: on\n");
|
|
1984
2037
|
}
|
|
@@ -1991,6 +2044,15 @@ ${result.claimUrl}
|
|
|
1991
2044
|
openInBrowser(result.url);
|
|
1992
2045
|
}
|
|
1993
2046
|
}
|
|
2047
|
+
function accessNote(visibility) {
|
|
2048
|
+
if (visibility === "workspace") {
|
|
2049
|
+
return "Access: workspace members only \u2014 anyone else needs `artifact-cafe share <email>` to open it.";
|
|
2050
|
+
}
|
|
2051
|
+
if (visibility === "private") {
|
|
2052
|
+
return "Access: private \u2014 you, the workspace's admins, and anyone you `artifact-cafe share` it with.";
|
|
2053
|
+
}
|
|
2054
|
+
return null;
|
|
2055
|
+
}
|
|
1994
2056
|
async function resolvePlacement(params) {
|
|
1995
2057
|
const { apiKey, apiUrl: apiUrl2, config, isNewArtifact, opts } = params;
|
|
1996
2058
|
const hasPlacementFlag = opts.workspace !== void 0 || opts.folder !== void 0;
|
|
@@ -2257,6 +2319,24 @@ function printCliError(err, json) {
|
|
|
2257
2319
|
|
|
2258
2320
|
// src/folders.ts
|
|
2259
2321
|
async function folders(opts) {
|
|
2322
|
+
if (opts.action !== void 0 && opts.action !== "create") {
|
|
2323
|
+
throw new Error(
|
|
2324
|
+
`Unknown folders action "${opts.action}" \u2014 run \`folders\` to list, or \`folders create <name>\` to create one.`
|
|
2325
|
+
);
|
|
2326
|
+
}
|
|
2327
|
+
if (opts.action === "create") {
|
|
2328
|
+
if (!opts.name?.trim()) {
|
|
2329
|
+
throw new Error(
|
|
2330
|
+
`Pass the folder name \u2014 e.g. \`artifact-cafe folders create "Design specs" --workspace ${opts.workspace}\`.`
|
|
2331
|
+
);
|
|
2332
|
+
}
|
|
2333
|
+
const visibility = opts.visibility ?? "workspace";
|
|
2334
|
+
if (visibility !== "workspace" && visibility !== "public") {
|
|
2335
|
+
throw new Error(
|
|
2336
|
+
`--visibility must be "workspace" or "public" (got "${opts.visibility}").`
|
|
2337
|
+
);
|
|
2338
|
+
}
|
|
2339
|
+
}
|
|
2260
2340
|
const apiUrl2 = (process.env.ARTIFACT_CAFE_URL ?? DEFAULT_API_URL).replace(
|
|
2261
2341
|
/\/$/,
|
|
2262
2342
|
""
|
|
@@ -2264,7 +2344,7 @@ async function folders(opts) {
|
|
|
2264
2344
|
const key = resolveApiKey(apiUrl2, opts.apiKey);
|
|
2265
2345
|
if (!key) {
|
|
2266
2346
|
throw new Error(
|
|
2267
|
-
`
|
|
2347
|
+
`Folder commands need an account \u2014 run \`artifact-cafe login\` first (no API key for ${apiOrigin(apiUrl2)}).`
|
|
2268
2348
|
);
|
|
2269
2349
|
}
|
|
2270
2350
|
const client = createApiClient(apiUrl2, key);
|
|
@@ -2277,6 +2357,10 @@ async function folders(opts) {
|
|
|
2277
2357
|
`No workspace with handle "${opts.workspace}" belongs to this account.`
|
|
2278
2358
|
);
|
|
2279
2359
|
}
|
|
2360
|
+
if (opts.action === "create") {
|
|
2361
|
+
await createFolder(client, workspace, opts);
|
|
2362
|
+
return;
|
|
2363
|
+
}
|
|
2280
2364
|
const data = await client.listFolders(workspace.id);
|
|
2281
2365
|
if (opts.json) {
|
|
2282
2366
|
console.log(JSON.stringify(data, null, 2));
|
|
@@ -2295,6 +2379,33 @@ async function folders(opts) {
|
|
|
2295
2379
|
printFolder(folder);
|
|
2296
2380
|
}
|
|
2297
2381
|
}
|
|
2382
|
+
async function createFolder(client, workspace, opts) {
|
|
2383
|
+
const name = opts.name.trim();
|
|
2384
|
+
const visibility = opts.visibility ?? "workspace";
|
|
2385
|
+
const existing = await client.listFolders(workspace.id);
|
|
2386
|
+
const duplicate = existing.folders.find(
|
|
2387
|
+
(candidate) => candidate.name.toLowerCase() === name.toLowerCase()
|
|
2388
|
+
);
|
|
2389
|
+
if (duplicate) {
|
|
2390
|
+
throw new Error(
|
|
2391
|
+
`A folder named "${duplicate.name}" already exists in ${workspace.handle} (${duplicate.id}) \u2014 publish into it with --folder, or pick a different name.`
|
|
2392
|
+
);
|
|
2393
|
+
}
|
|
2394
|
+
const folder = await client.createFolder(workspace.id, { name, visibility });
|
|
2395
|
+
if (opts.json) {
|
|
2396
|
+
console.log(JSON.stringify(folder, null, 2));
|
|
2397
|
+
return;
|
|
2398
|
+
}
|
|
2399
|
+
console.log(
|
|
2400
|
+
`\u2713 Created folder "${folder.name}" (${folder.visibility}) in ${workspace.handle}`
|
|
2401
|
+
);
|
|
2402
|
+
console.log(` ${folder.id}`);
|
|
2403
|
+
if (folder.visibility === "public") {
|
|
2404
|
+
console.log(
|
|
2405
|
+
" Artifacts placed in it default to public \u2014 visible to anyone."
|
|
2406
|
+
);
|
|
2407
|
+
}
|
|
2408
|
+
}
|
|
2298
2409
|
function printFolder(folder) {
|
|
2299
2410
|
console.log(`${folder.name} (${folder.visibility})`);
|
|
2300
2411
|
console.log(` ${folder.id}
|
|
@@ -2409,7 +2520,12 @@ async function list(opts) {
|
|
|
2409
2520
|
`Listing your artifacts needs an account \u2014 run \`artifact-cafe login\` first (no API key for ${apiOrigin(apiUrl2)}).`
|
|
2410
2521
|
);
|
|
2411
2522
|
}
|
|
2412
|
-
const
|
|
2523
|
+
const client = createApiClient(apiUrl2, key);
|
|
2524
|
+
if (opts.workspace !== void 0) {
|
|
2525
|
+
await listWorkspace(client, opts);
|
|
2526
|
+
return;
|
|
2527
|
+
}
|
|
2528
|
+
const data = await client.listArtifacts();
|
|
2413
2529
|
if (opts.json) {
|
|
2414
2530
|
console.log(JSON.stringify(data, null, 2));
|
|
2415
2531
|
return;
|
|
@@ -2427,6 +2543,70 @@ async function list(opts) {
|
|
|
2427
2543
|
printArtifact(artifact);
|
|
2428
2544
|
}
|
|
2429
2545
|
}
|
|
2546
|
+
async function listWorkspace(client, opts) {
|
|
2547
|
+
const workspaceData = await client.listWorkspaces();
|
|
2548
|
+
const workspace = workspaceData.workspaces.find(
|
|
2549
|
+
(candidate) => candidate.handle === opts.workspace
|
|
2550
|
+
);
|
|
2551
|
+
if (!workspace) {
|
|
2552
|
+
throw new Error(
|
|
2553
|
+
`No workspace with handle "${opts.workspace}" belongs to this account.`
|
|
2554
|
+
);
|
|
2555
|
+
}
|
|
2556
|
+
const [artifactData, folderData] = await Promise.all([
|
|
2557
|
+
client.listWorkspaceArtifacts(workspace.id),
|
|
2558
|
+
client.listFolders(workspace.id)
|
|
2559
|
+
]);
|
|
2560
|
+
if (opts.json) {
|
|
2561
|
+
console.log(
|
|
2562
|
+
JSON.stringify(
|
|
2563
|
+
{ artifacts: artifactData.artifacts, folders: folderData.folders },
|
|
2564
|
+
null,
|
|
2565
|
+
2
|
|
2566
|
+
)
|
|
2567
|
+
);
|
|
2568
|
+
return;
|
|
2569
|
+
}
|
|
2570
|
+
if (artifactData.artifacts.length === 0) {
|
|
2571
|
+
console.log(`No artifacts in workspace ${workspace.handle}.`);
|
|
2572
|
+
return;
|
|
2573
|
+
}
|
|
2574
|
+
const plural = artifactData.artifacts.length === 1 ? "" : "s";
|
|
2575
|
+
console.log(
|
|
2576
|
+
`${artifactData.artifacts.length} artifact${plural} in ${workspace.handle}
|
|
2577
|
+
`
|
|
2578
|
+
);
|
|
2579
|
+
for (const folder of folderData.folders) {
|
|
2580
|
+
const inFolder = artifactData.artifacts.filter(
|
|
2581
|
+
(artifact) => artifact.folderId === folder.id
|
|
2582
|
+
);
|
|
2583
|
+
if (inFolder.length === 0) {
|
|
2584
|
+
continue;
|
|
2585
|
+
}
|
|
2586
|
+
console.log(`${folder.name} (${folder.visibility})`);
|
|
2587
|
+
for (const artifact of inFolder) {
|
|
2588
|
+
printWorkspaceArtifact(artifact);
|
|
2589
|
+
}
|
|
2590
|
+
}
|
|
2591
|
+
const unfiled = artifactData.artifacts.filter(
|
|
2592
|
+
(artifact) => artifact.folderId === null
|
|
2593
|
+
);
|
|
2594
|
+
if (unfiled.length > 0) {
|
|
2595
|
+
console.log("Unfiled");
|
|
2596
|
+
for (const artifact of unfiled) {
|
|
2597
|
+
printWorkspaceArtifact(artifact);
|
|
2598
|
+
}
|
|
2599
|
+
}
|
|
2600
|
+
}
|
|
2601
|
+
function printWorkspaceArtifact(a) {
|
|
2602
|
+
const version = a.currentVersionNumber === null ? "no version" : `v${a.currentVersionNumber}`;
|
|
2603
|
+
const open2 = a.openCommentCount === 0 ? "no open comments" : `${a.openCommentCount} open comment${a.openCommentCount === 1 ? "" : "s"}`;
|
|
2604
|
+
const marker = a.openCommentCount > 0 ? "\u25CF" : "\u25CB";
|
|
2605
|
+
console.log(
|
|
2606
|
+
` ${marker} ${a.title} \u2014 ${version} \xB7 ${open2} \xB7 ${a.visibility}`
|
|
2607
|
+
);
|
|
2608
|
+
console.log(` ${a.url}`);
|
|
2609
|
+
}
|
|
2430
2610
|
function printArtifact(a) {
|
|
2431
2611
|
const version = a.currentVersionNumber === null ? "no version" : `v${a.currentVersionNumber}`;
|
|
2432
2612
|
const open2 = a.openCommentCount === 0 ? "no open comments" : `${a.openCommentCount} open comment${a.openCommentCount === 1 ? "" : "s"}`;
|
|
@@ -2626,14 +2806,109 @@ async function deleteMessage(opts) {
|
|
|
2626
2806
|
console.log(`\u2713 Deleted ${messageId}.`);
|
|
2627
2807
|
}
|
|
2628
2808
|
|
|
2629
|
-
// src/
|
|
2809
|
+
// src/move.ts
|
|
2630
2810
|
import path10 from "path";
|
|
2631
|
-
async function
|
|
2811
|
+
async function move(opts) {
|
|
2812
|
+
if (Boolean(opts.folder) === Boolean(opts.unfiled)) {
|
|
2813
|
+
throw new Error("Pass exactly one of --folder <name-or-id> or --unfiled.");
|
|
2814
|
+
}
|
|
2632
2815
|
const dir = path10.resolve(opts.dir);
|
|
2633
2816
|
const target = resolveArtifactTarget(dir, {
|
|
2634
2817
|
apiKey: opts.apiKey,
|
|
2635
2818
|
artifact: opts.artifact
|
|
2636
2819
|
});
|
|
2820
|
+
const key = resolveApiKey(target.apiUrl, opts.apiKey);
|
|
2821
|
+
if (!key) {
|
|
2822
|
+
throw new Error(
|
|
2823
|
+
`Moving an artifact needs an account \u2014 run \`artifact-cafe login\` first (no API key for ${apiOrigin(target.apiUrl)}).`
|
|
2824
|
+
);
|
|
2825
|
+
}
|
|
2826
|
+
const client = createApiClient(target.apiUrl, key);
|
|
2827
|
+
const artifact = await client.getArtifact(target.artifactId);
|
|
2828
|
+
if (!artifact.workspaceId) {
|
|
2829
|
+
throw new Error(
|
|
2830
|
+
"This artifact isn't in a workspace \u2014 folders live in workspaces. Claim it (or publish it while logged in) first."
|
|
2831
|
+
);
|
|
2832
|
+
}
|
|
2833
|
+
let folderId = null;
|
|
2834
|
+
let folderName = null;
|
|
2835
|
+
if (opts.folder) {
|
|
2836
|
+
const data = await client.listFolders(artifact.workspaceId);
|
|
2837
|
+
const matches = data.folders.filter(
|
|
2838
|
+
(candidate) => candidate.name === opts.folder || candidate.id === opts.folder
|
|
2839
|
+
);
|
|
2840
|
+
if (matches.length === 0) {
|
|
2841
|
+
throw new Error(
|
|
2842
|
+
`No folder named "${opts.folder}" exists in this workspace \u2014 list them with \`artifact-cafe folders --workspace <handle>\`, or create it with \`folders create\`.`
|
|
2843
|
+
);
|
|
2844
|
+
}
|
|
2845
|
+
if (matches.length > 1) {
|
|
2846
|
+
throw new Error(
|
|
2847
|
+
`More than one folder is named "${opts.folder}"; pass the folder id instead.`
|
|
2848
|
+
);
|
|
2849
|
+
}
|
|
2850
|
+
folderId = matches[0].id;
|
|
2851
|
+
folderName = matches[0].name;
|
|
2852
|
+
}
|
|
2853
|
+
if (artifact.folderId === folderId) {
|
|
2854
|
+
const where = folderName ? `folder "${folderName}"` : "no folder";
|
|
2855
|
+
if (opts.json) {
|
|
2856
|
+
console.log(
|
|
2857
|
+
JSON.stringify(
|
|
2858
|
+
{
|
|
2859
|
+
artifactId: artifact.id,
|
|
2860
|
+
folder: folderName ? { id: folderId, name: folderName } : null,
|
|
2861
|
+
moved: false,
|
|
2862
|
+
title: artifact.title,
|
|
2863
|
+
visibility: artifact.visibility
|
|
2864
|
+
},
|
|
2865
|
+
null,
|
|
2866
|
+
2
|
|
2867
|
+
)
|
|
2868
|
+
);
|
|
2869
|
+
return;
|
|
2870
|
+
}
|
|
2871
|
+
console.log(`"${artifact.title}" is already in ${where} \u2014 nothing to do.`);
|
|
2872
|
+
return;
|
|
2873
|
+
}
|
|
2874
|
+
const updated = await client.updateArtifact(artifact.id, { folderId });
|
|
2875
|
+
if (opts.json) {
|
|
2876
|
+
console.log(
|
|
2877
|
+
JSON.stringify(
|
|
2878
|
+
{
|
|
2879
|
+
artifactId: updated.id,
|
|
2880
|
+
folder: folderName ? { id: folderId, name: folderName } : null,
|
|
2881
|
+
moved: true,
|
|
2882
|
+
previousVisibility: artifact.visibility,
|
|
2883
|
+
title: updated.title,
|
|
2884
|
+
visibility: updated.visibility
|
|
2885
|
+
},
|
|
2886
|
+
null,
|
|
2887
|
+
2
|
|
2888
|
+
)
|
|
2889
|
+
);
|
|
2890
|
+
return;
|
|
2891
|
+
}
|
|
2892
|
+
const destination = folderName ? `"${folderName}"` : "Unfiled";
|
|
2893
|
+
console.log(`\u2713 Moved "${updated.title}" \u2192 ${destination}`);
|
|
2894
|
+
if (updated.visibility !== artifact.visibility) {
|
|
2895
|
+
console.log(
|
|
2896
|
+
` Visibility: ${artifact.visibility} \u2192 ${updated.visibility} (folder default)`
|
|
2897
|
+
);
|
|
2898
|
+
if (updated.visibility === "public") {
|
|
2899
|
+
console.log(" Now public \u2014 visible to anyone.");
|
|
2900
|
+
}
|
|
2901
|
+
}
|
|
2902
|
+
}
|
|
2903
|
+
|
|
2904
|
+
// src/open.ts
|
|
2905
|
+
import path11 from "path";
|
|
2906
|
+
async function openArtifact(opts) {
|
|
2907
|
+
const dir = path11.resolve(opts.dir);
|
|
2908
|
+
const target = resolveArtifactTarget(dir, {
|
|
2909
|
+
apiKey: opts.apiKey,
|
|
2910
|
+
artifact: opts.artifact
|
|
2911
|
+
});
|
|
2637
2912
|
const url = target.url ?? reviewUrl(
|
|
2638
2913
|
target.apiUrl,
|
|
2639
2914
|
(await createApiClient(target.apiUrl, target.credential).getArtifact(
|
|
@@ -2647,7 +2922,7 @@ async function openArtifact(opts) {
|
|
|
2647
2922
|
}
|
|
2648
2923
|
|
|
2649
2924
|
// src/protect.ts
|
|
2650
|
-
import
|
|
2925
|
+
import path12 from "path";
|
|
2651
2926
|
async function protect(opts) {
|
|
2652
2927
|
if (opts.off && opts.password !== void 0) {
|
|
2653
2928
|
throw new Error("Pass either --password or --off, not both.");
|
|
@@ -2664,7 +2939,7 @@ async function protect(opts) {
|
|
|
2664
2939
|
throw new Error(parsed.error.issues[0]?.message ?? "Invalid password.");
|
|
2665
2940
|
}
|
|
2666
2941
|
}
|
|
2667
|
-
const dir =
|
|
2942
|
+
const dir = path12.resolve(opts.dir);
|
|
2668
2943
|
const target = resolveArtifactTarget(dir, {
|
|
2669
2944
|
apiKey: opts.apiKey,
|
|
2670
2945
|
artifact: opts.artifact
|
|
@@ -2689,7 +2964,7 @@ async function protect(opts) {
|
|
|
2689
2964
|
}
|
|
2690
2965
|
|
|
2691
2966
|
// src/reply.ts
|
|
2692
|
-
import
|
|
2967
|
+
import path13 from "path";
|
|
2693
2968
|
async function readStdin3() {
|
|
2694
2969
|
if (process.stdin.isTTY) {
|
|
2695
2970
|
return "";
|
|
@@ -2713,7 +2988,7 @@ async function replyToThread(opts) {
|
|
|
2713
2988
|
'Nothing to post. Pass the reply with --body "\u2026", or pipe it on stdin.'
|
|
2714
2989
|
);
|
|
2715
2990
|
}
|
|
2716
|
-
const dir =
|
|
2991
|
+
const dir = path13.resolve(opts.dir);
|
|
2717
2992
|
const target = resolveArtifactTarget(dir, {
|
|
2718
2993
|
apiKey: opts.apiKey,
|
|
2719
2994
|
artifact: opts.artifact
|
|
@@ -2742,7 +3017,7 @@ async function replyToThread(opts) {
|
|
|
2742
3017
|
}
|
|
2743
3018
|
|
|
2744
3019
|
// src/resolve.ts
|
|
2745
|
-
import
|
|
3020
|
+
import path14 from "path";
|
|
2746
3021
|
async function changeThreadStatus(opts) {
|
|
2747
3022
|
const threadId = opts.thread?.trim();
|
|
2748
3023
|
if (!threadId) {
|
|
@@ -2750,7 +3025,7 @@ async function changeThreadStatus(opts) {
|
|
|
2750
3025
|
`Pass the thread id to ${opts.action} \u2014 get it from \`artifact-cafe comments --json\`.`
|
|
2751
3026
|
);
|
|
2752
3027
|
}
|
|
2753
|
-
const dir =
|
|
3028
|
+
const dir = path14.resolve(opts.dir);
|
|
2754
3029
|
const target = resolveArtifactTarget(dir, {
|
|
2755
3030
|
apiKey: opts.apiKey,
|
|
2756
3031
|
artifact: opts.artifact
|
|
@@ -2787,7 +3062,7 @@ async function changeThreadStatus(opts) {
|
|
|
2787
3062
|
}
|
|
2788
3063
|
|
|
2789
3064
|
// src/review.ts
|
|
2790
|
-
import
|
|
3065
|
+
import path15 from "path";
|
|
2791
3066
|
var OUTCOME = {
|
|
2792
3067
|
off: "Plain artifact \u2014 the review tools are hidden entirely",
|
|
2793
3068
|
open: "Open for review \u2014 anyone who can open it can comment",
|
|
@@ -2801,7 +3076,7 @@ async function review(opts) {
|
|
|
2801
3076
|
);
|
|
2802
3077
|
}
|
|
2803
3078
|
const mode = parsed.data;
|
|
2804
|
-
const dir =
|
|
3079
|
+
const dir = path15.resolve(opts.dir);
|
|
2805
3080
|
const target = resolveArtifactTarget(dir, {
|
|
2806
3081
|
apiKey: opts.apiKey,
|
|
2807
3082
|
artifact: opts.artifact
|
|
@@ -2823,10 +3098,10 @@ async function review(opts) {
|
|
|
2823
3098
|
}
|
|
2824
3099
|
|
|
2825
3100
|
// src/share.ts
|
|
2826
|
-
import
|
|
3101
|
+
import path16 from "path";
|
|
2827
3102
|
var EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
2828
3103
|
async function share(opts) {
|
|
2829
|
-
const dir =
|
|
3104
|
+
const dir = path16.resolve(opts.dir);
|
|
2830
3105
|
const target = resolveArtifactTarget(dir, {
|
|
2831
3106
|
apiKey: opts.apiKey,
|
|
2832
3107
|
artifact: opts.artifact
|
|
@@ -2881,7 +3156,7 @@ General access: ${visibility}`);
|
|
|
2881
3156
|
console.log("");
|
|
2882
3157
|
}
|
|
2883
3158
|
async function unshare(opts) {
|
|
2884
|
-
const dir =
|
|
3159
|
+
const dir = path16.resolve(opts.dir);
|
|
2885
3160
|
const target = resolveArtifactTarget(dir, {
|
|
2886
3161
|
apiKey: opts.apiKey,
|
|
2887
3162
|
artifact: opts.artifact
|
|
@@ -2904,7 +3179,7 @@ async function unshare(opts) {
|
|
|
2904
3179
|
}
|
|
2905
3180
|
|
|
2906
3181
|
// src/status.ts
|
|
2907
|
-
import
|
|
3182
|
+
import path17 from "path";
|
|
2908
3183
|
async function status(opts) {
|
|
2909
3184
|
if (!AGENT_STATES.includes(opts.state)) {
|
|
2910
3185
|
throw new Error(
|
|
@@ -2912,7 +3187,7 @@ async function status(opts) {
|
|
|
2912
3187
|
);
|
|
2913
3188
|
}
|
|
2914
3189
|
const state = opts.state;
|
|
2915
|
-
const dir =
|
|
3190
|
+
const dir = path17.resolve(opts.dir);
|
|
2916
3191
|
const target = resolveArtifactTarget(dir, {
|
|
2917
3192
|
apiKey: opts.apiKey,
|
|
2918
3193
|
artifact: opts.artifact
|
|
@@ -2941,7 +3216,7 @@ async function status(opts) {
|
|
|
2941
3216
|
import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "fs";
|
|
2942
3217
|
import { createRequire } from "module";
|
|
2943
3218
|
import { homedir as homedir2 } from "os";
|
|
2944
|
-
import
|
|
3219
|
+
import path18 from "path";
|
|
2945
3220
|
import { z as z20 } from "zod";
|
|
2946
3221
|
var REGISTRY_LATEST_URL = "https://registry.npmjs.org/artifact-cafe/latest";
|
|
2947
3222
|
var SKILL_SOURCE_URL = "https://raw.githubusercontent.com/Artifact-Cafe/skill/main/artifact-cafe/SKILL.md";
|
|
@@ -2960,7 +3235,7 @@ function cliVersion() {
|
|
|
2960
3235
|
return pkg.version;
|
|
2961
3236
|
}
|
|
2962
3237
|
function cachePath() {
|
|
2963
|
-
return
|
|
3238
|
+
return path18.join(homedir2(), ".artifactcafe", "update-check.json");
|
|
2964
3239
|
}
|
|
2965
3240
|
function readCache() {
|
|
2966
3241
|
try {
|
|
@@ -2971,7 +3246,7 @@ function readCache() {
|
|
|
2971
3246
|
}
|
|
2972
3247
|
function writeCache(cache) {
|
|
2973
3248
|
try {
|
|
2974
|
-
mkdirSync3(
|
|
3249
|
+
mkdirSync3(path18.dirname(cachePath()), { mode: 448, recursive: true });
|
|
2975
3250
|
writeFileSync3(cachePath(), `${JSON.stringify(cache, null, 2)}
|
|
2976
3251
|
`);
|
|
2977
3252
|
} catch {
|
|
@@ -3024,7 +3299,7 @@ function installedSkillVersions() {
|
|
|
3024
3299
|
const versions = [];
|
|
3025
3300
|
for (const root of roots) {
|
|
3026
3301
|
for (const dir of dirs) {
|
|
3027
|
-
const file =
|
|
3302
|
+
const file = path18.join(root, dir, "skills", "artifact-cafe", "SKILL.md");
|
|
3028
3303
|
if (!existsSync3(file)) {
|
|
3029
3304
|
continue;
|
|
3030
3305
|
}
|
|
@@ -3259,7 +3534,11 @@ var list2 = defineCommand({
|
|
|
3259
3534
|
description: "List with this API key (default: stored login)",
|
|
3260
3535
|
type: "string"
|
|
3261
3536
|
},
|
|
3262
|
-
json: { description: "Machine-readable output", type: "boolean" }
|
|
3537
|
+
json: { description: "Machine-readable output", type: "boolean" },
|
|
3538
|
+
workspace: {
|
|
3539
|
+
description: "List this workspace's artifacts, grouped by folder",
|
|
3540
|
+
type: "string"
|
|
3541
|
+
}
|
|
3263
3542
|
},
|
|
3264
3543
|
meta: {
|
|
3265
3544
|
description: "List the artifacts your account owns",
|
|
@@ -3267,7 +3546,11 @@ var list2 = defineCommand({
|
|
|
3267
3546
|
},
|
|
3268
3547
|
async run({ args }) {
|
|
3269
3548
|
try {
|
|
3270
|
-
await list({
|
|
3549
|
+
await list({
|
|
3550
|
+
apiKey: args["api-key"],
|
|
3551
|
+
json: Boolean(args.json),
|
|
3552
|
+
workspace: args.workspace
|
|
3553
|
+
});
|
|
3271
3554
|
} catch (err) {
|
|
3272
3555
|
printCliError(err, Boolean(args.json));
|
|
3273
3556
|
process.exit(1);
|
|
@@ -3276,26 +3559,43 @@ var list2 = defineCommand({
|
|
|
3276
3559
|
});
|
|
3277
3560
|
var folders2 = defineCommand({
|
|
3278
3561
|
args: {
|
|
3562
|
+
action: {
|
|
3563
|
+
description: 'Optional action: "create"',
|
|
3564
|
+
required: false,
|
|
3565
|
+
type: "positional"
|
|
3566
|
+
},
|
|
3279
3567
|
"api-key": {
|
|
3280
|
-
description: "
|
|
3568
|
+
description: "Authorize with an account API key (default: stored login)",
|
|
3281
3569
|
type: "string"
|
|
3282
3570
|
},
|
|
3283
3571
|
json: { description: "Machine-readable output", type: "boolean" },
|
|
3572
|
+
name: {
|
|
3573
|
+
description: "Folder name (with create)",
|
|
3574
|
+
required: false,
|
|
3575
|
+
type: "positional"
|
|
3576
|
+
},
|
|
3577
|
+
visibility: {
|
|
3578
|
+
description: "With create: workspace (default) | public",
|
|
3579
|
+
type: "string"
|
|
3580
|
+
},
|
|
3284
3581
|
workspace: {
|
|
3285
|
-
description: "Workspace handle
|
|
3582
|
+
description: "Workspace handle to list or create in",
|
|
3286
3583
|
required: true,
|
|
3287
3584
|
type: "string"
|
|
3288
3585
|
}
|
|
3289
3586
|
},
|
|
3290
3587
|
meta: {
|
|
3291
|
-
description: "List folders
|
|
3588
|
+
description: "List a workspace's folders, or create one (folders create)",
|
|
3292
3589
|
name: "folders"
|
|
3293
3590
|
},
|
|
3294
3591
|
async run({ args }) {
|
|
3295
3592
|
try {
|
|
3296
3593
|
await folders({
|
|
3594
|
+
action: args.action,
|
|
3297
3595
|
apiKey: args["api-key"],
|
|
3298
3596
|
json: Boolean(args.json),
|
|
3597
|
+
name: args.name,
|
|
3598
|
+
visibility: args.visibility,
|
|
3299
3599
|
workspace: args.workspace
|
|
3300
3600
|
});
|
|
3301
3601
|
} catch (err) {
|
|
@@ -3304,6 +3604,51 @@ var folders2 = defineCommand({
|
|
|
3304
3604
|
}
|
|
3305
3605
|
}
|
|
3306
3606
|
});
|
|
3607
|
+
var move2 = defineCommand({
|
|
3608
|
+
args: {
|
|
3609
|
+
"api-key": {
|
|
3610
|
+
description: "Authorize with an account API key (default: stored login)",
|
|
3611
|
+
type: "string"
|
|
3612
|
+
},
|
|
3613
|
+
artifact: {
|
|
3614
|
+
description: "Move this artifact ID instead of the linked folder",
|
|
3615
|
+
type: "string"
|
|
3616
|
+
},
|
|
3617
|
+
dir: {
|
|
3618
|
+
default: ".",
|
|
3619
|
+
description: "Linked directory to resolve the artifact from (default: .)",
|
|
3620
|
+
type: "string"
|
|
3621
|
+
},
|
|
3622
|
+
folder: {
|
|
3623
|
+
description: "Target folder name (or id) in the artifact's workspace",
|
|
3624
|
+
type: "string"
|
|
3625
|
+
},
|
|
3626
|
+
json: { description: "Machine-readable output", type: "boolean" },
|
|
3627
|
+
unfiled: {
|
|
3628
|
+
description: "Move out of its folder (workspace root)",
|
|
3629
|
+
type: "boolean"
|
|
3630
|
+
}
|
|
3631
|
+
},
|
|
3632
|
+
meta: {
|
|
3633
|
+
description: "Move an artifact into a workspace folder (or --unfiled)",
|
|
3634
|
+
name: "move"
|
|
3635
|
+
},
|
|
3636
|
+
async run({ args }) {
|
|
3637
|
+
try {
|
|
3638
|
+
await move({
|
|
3639
|
+
apiKey: args["api-key"],
|
|
3640
|
+
artifact: args.artifact,
|
|
3641
|
+
dir: args.dir,
|
|
3642
|
+
folder: args.folder,
|
|
3643
|
+
json: Boolean(args.json),
|
|
3644
|
+
unfiled: Boolean(args.unfiled)
|
|
3645
|
+
});
|
|
3646
|
+
} catch (err) {
|
|
3647
|
+
printCliError(err, Boolean(args.json));
|
|
3648
|
+
process.exit(1);
|
|
3649
|
+
}
|
|
3650
|
+
}
|
|
3651
|
+
});
|
|
3307
3652
|
var workspaces2 = defineCommand({
|
|
3308
3653
|
args: {
|
|
3309
3654
|
"api-key": {
|
|
@@ -4023,6 +4368,7 @@ var main = defineCommand({
|
|
|
4023
4368
|
listen,
|
|
4024
4369
|
login: login2,
|
|
4025
4370
|
logout: logout2,
|
|
4371
|
+
move: move2,
|
|
4026
4372
|
open,
|
|
4027
4373
|
protect: protect2,
|
|
4028
4374
|
publish: publish2,
|