artifact-cafe 0.0.4 → 0.0.5
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 +355 -119
- package/package.json +9 -9
package/dist/index.js
CHANGED
|
@@ -1,10 +1,37 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import { defineCommand, runMain } from "citty";
|
|
4
|
+
import { defineCommand, runMain, showUsage } from "citty";
|
|
5
|
+
|
|
6
|
+
// src/banner.ts
|
|
7
|
+
var AMBER = "\x1B[38;2;214;138;57m";
|
|
8
|
+
var BOLD = "\x1B[1m";
|
|
9
|
+
var RESET = "\x1B[0m";
|
|
10
|
+
var MUG = [
|
|
11
|
+
" \u2596",
|
|
12
|
+
" \u2598 \u259D",
|
|
13
|
+
" \u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E",
|
|
14
|
+
" \u2502 \u251C\u2500\u256E",
|
|
15
|
+
" \u2502 \u2502 \u2502",
|
|
16
|
+
" \u2502 \u251C\u2500\u256F",
|
|
17
|
+
" \u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F",
|
|
18
|
+
" \u203E\u203E\u203E\u203E\u203E\u203E\u203E\u203E"
|
|
19
|
+
];
|
|
20
|
+
var WORDMARK = " artifact.cafe";
|
|
21
|
+
function printBanner() {
|
|
22
|
+
const color = Boolean(process.stdout.isTTY) && !process.env.NO_COLOR;
|
|
23
|
+
const paint = (line, codes) => color ? `${codes}${line}${RESET}` : line;
|
|
24
|
+
console.log();
|
|
25
|
+
for (const line of MUG) {
|
|
26
|
+
console.log(paint(line, AMBER));
|
|
27
|
+
}
|
|
28
|
+
console.log();
|
|
29
|
+
console.log(paint(WORDMARK, AMBER + BOLD));
|
|
30
|
+
console.log();
|
|
31
|
+
}
|
|
5
32
|
|
|
6
33
|
// src/comments.ts
|
|
7
|
-
import
|
|
34
|
+
import path3 from "path";
|
|
8
35
|
|
|
9
36
|
// ../shared/src/account.ts
|
|
10
37
|
import { z } from "zod";
|
|
@@ -519,37 +546,99 @@ async function uploadFile(uploadUrl, content, mimeType) {
|
|
|
519
546
|
// src/config.ts
|
|
520
547
|
import {
|
|
521
548
|
appendFileSync,
|
|
522
|
-
existsSync,
|
|
523
|
-
mkdirSync,
|
|
524
|
-
readFileSync,
|
|
525
|
-
writeFileSync
|
|
549
|
+
existsSync as existsSync2,
|
|
550
|
+
mkdirSync as mkdirSync2,
|
|
551
|
+
readFileSync as readFileSync2,
|
|
552
|
+
writeFileSync as writeFileSync2
|
|
526
553
|
} from "fs";
|
|
554
|
+
import path2 from "path";
|
|
555
|
+
import { z as z13 } from "zod";
|
|
556
|
+
|
|
557
|
+
// src/credentials.ts
|
|
558
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
559
|
+
import { homedir } from "os";
|
|
527
560
|
import path from "path";
|
|
528
561
|
import { z as z12 } from "zod";
|
|
529
|
-
var
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
562
|
+
var DEFAULT_API_URL = "https://artifact.cafe";
|
|
563
|
+
var credentialsSchema = z12.object({
|
|
564
|
+
keys: z12.record(z12.string(), z12.string()),
|
|
565
|
+
version: z12.literal(1)
|
|
566
|
+
});
|
|
567
|
+
function credentialsPath() {
|
|
568
|
+
return path.join(homedir(), ".artifactcafe", "credentials");
|
|
569
|
+
}
|
|
570
|
+
function apiOrigin(apiUrl2) {
|
|
571
|
+
return new URL(apiUrl2).origin;
|
|
572
|
+
}
|
|
573
|
+
function readCredentials() {
|
|
574
|
+
const file = credentialsPath();
|
|
575
|
+
if (!existsSync(file)) {
|
|
576
|
+
return { keys: {}, version: 1 };
|
|
577
|
+
}
|
|
578
|
+
try {
|
|
579
|
+
return credentialsSchema.parse(JSON.parse(readFileSync(file, "utf8")));
|
|
580
|
+
} catch {
|
|
581
|
+
return { keys: {}, version: 1 };
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
function writeCredentials(credentials) {
|
|
585
|
+
const file = credentialsPath();
|
|
586
|
+
mkdirSync(path.dirname(file), { mode: 448, recursive: true });
|
|
587
|
+
writeFileSync(file, `${JSON.stringify(credentials, null, 2)}
|
|
588
|
+
`, {
|
|
589
|
+
mode: 384
|
|
590
|
+
});
|
|
591
|
+
}
|
|
592
|
+
function storedApiKey(apiUrl2) {
|
|
593
|
+
return readCredentials().keys[apiOrigin(apiUrl2)] ?? null;
|
|
594
|
+
}
|
|
595
|
+
function storeApiKey(apiUrl2, key) {
|
|
596
|
+
const credentials = readCredentials();
|
|
597
|
+
credentials.keys[apiOrigin(apiUrl2)] = key;
|
|
598
|
+
writeCredentials(credentials);
|
|
599
|
+
}
|
|
600
|
+
function removeApiKey(apiUrl2) {
|
|
601
|
+
const credentials = readCredentials();
|
|
602
|
+
const origin = apiOrigin(apiUrl2);
|
|
603
|
+
if (!(origin in credentials.keys)) {
|
|
604
|
+
return false;
|
|
605
|
+
}
|
|
606
|
+
delete credentials.keys[origin];
|
|
607
|
+
writeCredentials(credentials);
|
|
608
|
+
return true;
|
|
609
|
+
}
|
|
610
|
+
function resolveApiKey(apiUrl2, flag) {
|
|
611
|
+
return flag ?? process.env.ARTIFACT_CAFE_API_KEY ?? storedApiKey(apiUrl2) ?? void 0;
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
// src/config.ts
|
|
615
|
+
var configSchema = z13.object({
|
|
616
|
+
apiUrl: z13.string(),
|
|
617
|
+
artifactId: z13.string(),
|
|
618
|
+
// Optional: a folder linked by `link` to an artifact you own carries no
|
|
619
|
+
// token — owner actions authorize via your stored login instead. A first
|
|
620
|
+
// publish still writes the anonymous-mode token here.
|
|
621
|
+
publishToken: z13.string().optional(),
|
|
622
|
+
slug: z13.string(),
|
|
623
|
+
url: z13.string()
|
|
535
624
|
});
|
|
536
625
|
var CONFIG_DIR = ".artifactcafe";
|
|
537
626
|
var CONFIG_FILE = "config.json";
|
|
538
627
|
function readConfig(dir) {
|
|
539
|
-
const file =
|
|
540
|
-
if (!
|
|
628
|
+
const file = path2.join(dir, CONFIG_DIR, CONFIG_FILE);
|
|
629
|
+
if (!existsSync2(file)) {
|
|
541
630
|
return null;
|
|
542
631
|
}
|
|
543
632
|
try {
|
|
544
|
-
return configSchema.parse(JSON.parse(
|
|
633
|
+
return configSchema.parse(JSON.parse(readFileSync2(file, "utf8")));
|
|
545
634
|
} catch {
|
|
546
635
|
return null;
|
|
547
636
|
}
|
|
548
637
|
}
|
|
549
638
|
function writeConfig(dir, config) {
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
639
|
+
mkdirSync2(path2.join(dir, CONFIG_DIR), { recursive: true });
|
|
640
|
+
writeFileSync2(
|
|
641
|
+
path2.join(dir, CONFIG_DIR, CONFIG_FILE),
|
|
553
642
|
`${JSON.stringify(config, null, 2)}
|
|
554
643
|
`,
|
|
555
644
|
{ mode: 384 }
|
|
@@ -557,11 +646,11 @@ function writeConfig(dir, config) {
|
|
|
557
646
|
ensureGitignored(dir);
|
|
558
647
|
}
|
|
559
648
|
function ensureGitignored(dir) {
|
|
560
|
-
const gitignore =
|
|
561
|
-
if (!
|
|
649
|
+
const gitignore = path2.join(dir, ".gitignore");
|
|
650
|
+
if (!existsSync2(gitignore)) {
|
|
562
651
|
return;
|
|
563
652
|
}
|
|
564
|
-
const lines =
|
|
653
|
+
const lines = readFileSync2(gitignore, "utf8").split(/\r?\n/);
|
|
565
654
|
const present = lines.some((l) => {
|
|
566
655
|
const t = l.trim();
|
|
567
656
|
return t === CONFIG_DIR || t === `${CONFIG_DIR}/` || t === `/${CONFIG_DIR}` || t === `/${CONFIG_DIR}/`;
|
|
@@ -576,6 +665,23 @@ ${CONFIG_DIR}/
|
|
|
576
665
|
);
|
|
577
666
|
}
|
|
578
667
|
}
|
|
668
|
+
function reviewUrl(apiUrl2, slug) {
|
|
669
|
+
return `${apiUrl2.replace(/\/$/, "")}/a/${slug}`;
|
|
670
|
+
}
|
|
671
|
+
function resolveArtifactTarget(dir, opts = {}) {
|
|
672
|
+
const config = readConfig(dir);
|
|
673
|
+
const apiUrl2 = process.env.ARTIFACT_CAFE_URL ?? config?.apiUrl ?? DEFAULT_API_URL;
|
|
674
|
+
const artifactId = opts.artifact ?? process.env.ARTIFACT_CAFE_ARTIFACT_ID ?? config?.artifactId ?? null;
|
|
675
|
+
if (!artifactId) {
|
|
676
|
+
throw new Error(
|
|
677
|
+
`No artifact linked in ${dir}. Run \`artifact-cafe publish\` here, \`artifact-cafe link\` to bind one you own, or pass --artifact <id> (or set ARTIFACT_CAFE_ARTIFACT_ID) to act on an artifact linked elsewhere.`
|
|
678
|
+
);
|
|
679
|
+
}
|
|
680
|
+
const folderToken = artifactId === config?.artifactId ? config.publishToken : void 0;
|
|
681
|
+
const credential = folderToken ?? process.env.ARTIFACT_CAFE_TOKEN ?? resolveApiKey(apiUrl2, opts.apiKey);
|
|
682
|
+
const url = artifactId === config?.artifactId ? config.url : void 0;
|
|
683
|
+
return { apiUrl: apiUrl2, artifactId, credential, url };
|
|
684
|
+
}
|
|
579
685
|
|
|
580
686
|
// src/comments.ts
|
|
581
687
|
var STATUSES = ["open", "resolved", "all"];
|
|
@@ -596,17 +702,16 @@ async function comments(opts) {
|
|
|
596
702
|
}
|
|
597
703
|
const status = opts.status;
|
|
598
704
|
const version = opts.version;
|
|
599
|
-
const dir =
|
|
600
|
-
const
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
const
|
|
607
|
-
const client = createApiClient(apiUrl2, config.publishToken);
|
|
705
|
+
const dir = path3.resolve(opts.dir);
|
|
706
|
+
const target = resolveArtifactTarget(dir, {
|
|
707
|
+
apiKey: opts.apiKey,
|
|
708
|
+
artifact: opts.artifact
|
|
709
|
+
});
|
|
710
|
+
const client = createApiClient(target.apiUrl, target.credential);
|
|
711
|
+
const url = target.url ?? (opts.json ? "" : await deriveReviewUrl(client, target));
|
|
712
|
+
const ref = { artifactId: target.artifactId, url };
|
|
608
713
|
if (opts.wait) {
|
|
609
|
-
await waitForFeedback(client,
|
|
714
|
+
await waitForFeedback(client, ref, {
|
|
610
715
|
json: opts.json,
|
|
611
716
|
status,
|
|
612
717
|
timeoutSeconds: opts.timeout,
|
|
@@ -614,7 +719,7 @@ async function comments(opts) {
|
|
|
614
719
|
});
|
|
615
720
|
return;
|
|
616
721
|
}
|
|
617
|
-
const data = await client.exportComments(
|
|
722
|
+
const data = await client.exportComments(target.artifactId, {
|
|
618
723
|
status,
|
|
619
724
|
version
|
|
620
725
|
});
|
|
@@ -622,7 +727,11 @@ async function comments(opts) {
|
|
|
622
727
|
console.log(JSON.stringify(data, null, 2));
|
|
623
728
|
return;
|
|
624
729
|
}
|
|
625
|
-
printHuman(data,
|
|
730
|
+
printHuman(data, url, status, version);
|
|
731
|
+
}
|
|
732
|
+
async function deriveReviewUrl(client, target) {
|
|
733
|
+
const artifact = await client.getArtifact(target.artifactId);
|
|
734
|
+
return reviewUrl(target.apiUrl, artifact.slug);
|
|
626
735
|
}
|
|
627
736
|
var sleep = (s) => new Promise((r) => setTimeout(r, s * 1e3));
|
|
628
737
|
function messageCounts(data) {
|
|
@@ -777,63 +886,6 @@ function indent(text, pad) {
|
|
|
777
886
|
// src/dashboard.ts
|
|
778
887
|
import path6 from "path";
|
|
779
888
|
|
|
780
|
-
// src/credentials.ts
|
|
781
|
-
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
782
|
-
import { homedir } from "os";
|
|
783
|
-
import path3 from "path";
|
|
784
|
-
import { z as z13 } from "zod";
|
|
785
|
-
var DEFAULT_API_URL = "https://artifact.cafe";
|
|
786
|
-
var credentialsSchema = z13.object({
|
|
787
|
-
keys: z13.record(z13.string(), z13.string()),
|
|
788
|
-
version: z13.literal(1)
|
|
789
|
-
});
|
|
790
|
-
function credentialsPath() {
|
|
791
|
-
return path3.join(homedir(), ".artifactcafe", "credentials");
|
|
792
|
-
}
|
|
793
|
-
function apiOrigin(apiUrl2) {
|
|
794
|
-
return new URL(apiUrl2).origin;
|
|
795
|
-
}
|
|
796
|
-
function readCredentials() {
|
|
797
|
-
const file = credentialsPath();
|
|
798
|
-
if (!existsSync2(file)) {
|
|
799
|
-
return { keys: {}, version: 1 };
|
|
800
|
-
}
|
|
801
|
-
try {
|
|
802
|
-
return credentialsSchema.parse(JSON.parse(readFileSync2(file, "utf8")));
|
|
803
|
-
} catch {
|
|
804
|
-
return { keys: {}, version: 1 };
|
|
805
|
-
}
|
|
806
|
-
}
|
|
807
|
-
function writeCredentials(credentials) {
|
|
808
|
-
const file = credentialsPath();
|
|
809
|
-
mkdirSync2(path3.dirname(file), { mode: 448, recursive: true });
|
|
810
|
-
writeFileSync2(file, `${JSON.stringify(credentials, null, 2)}
|
|
811
|
-
`, {
|
|
812
|
-
mode: 384
|
|
813
|
-
});
|
|
814
|
-
}
|
|
815
|
-
function storedApiKey(apiUrl2) {
|
|
816
|
-
return readCredentials().keys[apiOrigin(apiUrl2)] ?? null;
|
|
817
|
-
}
|
|
818
|
-
function storeApiKey(apiUrl2, key) {
|
|
819
|
-
const credentials = readCredentials();
|
|
820
|
-
credentials.keys[apiOrigin(apiUrl2)] = key;
|
|
821
|
-
writeCredentials(credentials);
|
|
822
|
-
}
|
|
823
|
-
function removeApiKey(apiUrl2) {
|
|
824
|
-
const credentials = readCredentials();
|
|
825
|
-
const origin = apiOrigin(apiUrl2);
|
|
826
|
-
if (!(origin in credentials.keys)) {
|
|
827
|
-
return false;
|
|
828
|
-
}
|
|
829
|
-
delete credentials.keys[origin];
|
|
830
|
-
writeCredentials(credentials);
|
|
831
|
-
return true;
|
|
832
|
-
}
|
|
833
|
-
function resolveApiKey(apiUrl2, flag) {
|
|
834
|
-
return flag ?? process.env.ARTIFACT_CAFE_API_KEY ?? storedApiKey(apiUrl2) ?? void 0;
|
|
835
|
-
}
|
|
836
|
-
|
|
837
889
|
// src/publish.ts
|
|
838
890
|
import { exec } from "child_process";
|
|
839
891
|
import { readFileSync as readFileSync4 } from "fs";
|
|
@@ -1169,6 +1221,102 @@ function printCliError(err, json) {
|
|
|
1169
1221
|
}
|
|
1170
1222
|
}
|
|
1171
1223
|
|
|
1224
|
+
// src/link.ts
|
|
1225
|
+
import path7 from "path";
|
|
1226
|
+
import { createInterface } from "readline";
|
|
1227
|
+
async function link(opts) {
|
|
1228
|
+
const apiUrl2 = (process.env.ARTIFACT_CAFE_URL ?? DEFAULT_API_URL).replace(
|
|
1229
|
+
/\/$/,
|
|
1230
|
+
""
|
|
1231
|
+
);
|
|
1232
|
+
const key = resolveApiKey(apiUrl2, opts.apiKey);
|
|
1233
|
+
if (!key) {
|
|
1234
|
+
throw new Error(
|
|
1235
|
+
`Linking needs an account \u2014 run \`artifact-cafe login\` first (no API key for ${apiOrigin(apiUrl2)}).`
|
|
1236
|
+
);
|
|
1237
|
+
}
|
|
1238
|
+
const { artifacts } = await createApiClient(apiUrl2, key).listArtifacts();
|
|
1239
|
+
if (artifacts.length === 0) {
|
|
1240
|
+
throw new Error(
|
|
1241
|
+
"No artifacts in your account yet \u2014 publish one first, or claim one via its claim link."
|
|
1242
|
+
);
|
|
1243
|
+
}
|
|
1244
|
+
const selector = opts.artifact ?? opts.slug;
|
|
1245
|
+
let chosen;
|
|
1246
|
+
if (opts.artifact) {
|
|
1247
|
+
chosen = artifacts.find((a) => a.id === opts.artifact);
|
|
1248
|
+
} else if (opts.slug) {
|
|
1249
|
+
chosen = artifacts.find((a) => a.slug === opts.slug);
|
|
1250
|
+
}
|
|
1251
|
+
if (selector && !chosen) {
|
|
1252
|
+
throw new Error(
|
|
1253
|
+
`No artifact "${selector}" in your account \u2014 run \`artifact-cafe list\` to see them.`
|
|
1254
|
+
);
|
|
1255
|
+
}
|
|
1256
|
+
if (opts.json && !chosen) {
|
|
1257
|
+
console.log(JSON.stringify({ artifacts }, null, 2));
|
|
1258
|
+
return;
|
|
1259
|
+
}
|
|
1260
|
+
if (!chosen) {
|
|
1261
|
+
if (!process.stdin.isTTY) {
|
|
1262
|
+
throw new Error(
|
|
1263
|
+
"Pick an artifact with --artifact <id> or --slug <slug> (or --json to list them). Interactive selection needs a terminal."
|
|
1264
|
+
);
|
|
1265
|
+
}
|
|
1266
|
+
chosen = await pickArtifact(artifacts);
|
|
1267
|
+
}
|
|
1268
|
+
const dir = path7.resolve(opts.dir);
|
|
1269
|
+
writeConfig(dir, {
|
|
1270
|
+
apiUrl: apiUrl2,
|
|
1271
|
+
artifactId: chosen.id,
|
|
1272
|
+
slug: chosen.slug,
|
|
1273
|
+
url: chosen.url
|
|
1274
|
+
// No publishToken — this folder authorizes via your login, not a secret.
|
|
1275
|
+
});
|
|
1276
|
+
if (opts.json) {
|
|
1277
|
+
console.log(
|
|
1278
|
+
JSON.stringify(
|
|
1279
|
+
{
|
|
1280
|
+
artifactId: chosen.id,
|
|
1281
|
+
linked: true,
|
|
1282
|
+
slug: chosen.slug,
|
|
1283
|
+
url: chosen.url
|
|
1284
|
+
},
|
|
1285
|
+
null,
|
|
1286
|
+
2
|
|
1287
|
+
)
|
|
1288
|
+
);
|
|
1289
|
+
return;
|
|
1290
|
+
}
|
|
1291
|
+
console.log(`
|
|
1292
|
+
\u2713 Linked ${dir} \u2192 "${chosen.title}" \u2014 ${chosen.url}`);
|
|
1293
|
+
console.log(
|
|
1294
|
+
" Owner actions (publish, comments --wait, protect) use your login.\n"
|
|
1295
|
+
);
|
|
1296
|
+
}
|
|
1297
|
+
function pickArtifact(artifacts) {
|
|
1298
|
+
console.log("Your artifacts:\n");
|
|
1299
|
+
artifacts.forEach((a, i) => {
|
|
1300
|
+
const v = a.currentVersionNumber ? `v${a.currentVersionNumber}` : "\u2014";
|
|
1301
|
+
console.log(
|
|
1302
|
+
` ${String(i + 1).padStart(2)}. ${a.title} \xB7 ${v} \xB7 ${a.url}`
|
|
1303
|
+
);
|
|
1304
|
+
});
|
|
1305
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
1306
|
+
return new Promise((resolve, reject) => {
|
|
1307
|
+
rl.question(`
|
|
1308
|
+
Link which? [1-${artifacts.length}]: `, (answer) => {
|
|
1309
|
+
rl.close();
|
|
1310
|
+
const n = Number(answer.trim());
|
|
1311
|
+
if (!(Number.isInteger(n) && n >= 1 && n <= artifacts.length)) {
|
|
1312
|
+
reject(new Error(`Enter a number between 1 and ${artifacts.length}.`));
|
|
1313
|
+
return;
|
|
1314
|
+
}
|
|
1315
|
+
resolve(artifacts[n - 1]);
|
|
1316
|
+
});
|
|
1317
|
+
});
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1172
1320
|
// src/list.ts
|
|
1173
1321
|
async function list(opts) {
|
|
1174
1322
|
const apiUrl2 = (process.env.ARTIFACT_CAFE_URL ?? DEFAULT_API_URL).replace(
|
|
@@ -1226,13 +1374,13 @@ function relativeTime(iso) {
|
|
|
1226
1374
|
}
|
|
1227
1375
|
|
|
1228
1376
|
// src/login.ts
|
|
1229
|
-
import { createInterface } from "readline";
|
|
1377
|
+
import { createInterface as createInterface2 } from "readline";
|
|
1230
1378
|
function apiUrl() {
|
|
1231
1379
|
return (process.env.ARTIFACT_CAFE_URL ?? DEFAULT_API_URL).replace(/\/$/, "");
|
|
1232
1380
|
}
|
|
1233
1381
|
function promptSecret(question) {
|
|
1234
1382
|
return new Promise((resolve) => {
|
|
1235
|
-
const rl =
|
|
1383
|
+
const rl = createInterface2({
|
|
1236
1384
|
input: process.stdin,
|
|
1237
1385
|
output: process.stdout
|
|
1238
1386
|
});
|
|
@@ -1340,23 +1488,27 @@ function logout(opts) {
|
|
|
1340
1488
|
}
|
|
1341
1489
|
|
|
1342
1490
|
// src/open.ts
|
|
1343
|
-
import
|
|
1344
|
-
function openArtifact(opts) {
|
|
1345
|
-
const dir =
|
|
1346
|
-
const
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1491
|
+
import path8 from "path";
|
|
1492
|
+
async function openArtifact(opts) {
|
|
1493
|
+
const dir = path8.resolve(opts.dir);
|
|
1494
|
+
const target = resolveArtifactTarget(dir, {
|
|
1495
|
+
apiKey: opts.apiKey,
|
|
1496
|
+
artifact: opts.artifact
|
|
1497
|
+
});
|
|
1498
|
+
const url = target.url ?? reviewUrl(
|
|
1499
|
+
target.apiUrl,
|
|
1500
|
+
(await createApiClient(target.apiUrl, target.credential).getArtifact(
|
|
1501
|
+
target.artifactId
|
|
1502
|
+
)).slug
|
|
1503
|
+
);
|
|
1504
|
+
console.log(url);
|
|
1353
1505
|
if (process.stdout.isTTY) {
|
|
1354
|
-
openInBrowser(
|
|
1506
|
+
openInBrowser(url);
|
|
1355
1507
|
}
|
|
1356
1508
|
}
|
|
1357
1509
|
|
|
1358
1510
|
// src/protect.ts
|
|
1359
|
-
import
|
|
1511
|
+
import path9 from "path";
|
|
1360
1512
|
async function protect(opts) {
|
|
1361
1513
|
if (opts.off && opts.password !== void 0) {
|
|
1362
1514
|
throw new Error("Pass either --password or --off, not both.");
|
|
@@ -1373,26 +1525,26 @@ async function protect(opts) {
|
|
|
1373
1525
|
throw new Error(parsed.error.issues[0]?.message ?? "Invalid password.");
|
|
1374
1526
|
}
|
|
1375
1527
|
}
|
|
1376
|
-
const dir =
|
|
1377
|
-
const
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
const apiUrl2 = process.env.ARTIFACT_CAFE_URL ?? config.apiUrl;
|
|
1384
|
-
const token = config.publishToken ?? process.env.ARTIFACT_CAFE_TOKEN;
|
|
1385
|
-
const client = createApiClient(apiUrl2, token);
|
|
1386
|
-
const res = await client.setProtection(config.artifactId, password);
|
|
1528
|
+
const dir = path9.resolve(opts.dir);
|
|
1529
|
+
const target = resolveArtifactTarget(dir, {
|
|
1530
|
+
apiKey: opts.apiKey,
|
|
1531
|
+
artifact: opts.artifact
|
|
1532
|
+
});
|
|
1533
|
+
const client = createApiClient(target.apiUrl, target.credential);
|
|
1534
|
+
const res = await client.setProtection(target.artifactId, password);
|
|
1387
1535
|
if (opts.json) {
|
|
1388
1536
|
console.log(JSON.stringify({ protected: res.protected }, null, 2));
|
|
1389
1537
|
return;
|
|
1390
1538
|
}
|
|
1539
|
+
const url = target.url ?? reviewUrl(
|
|
1540
|
+
target.apiUrl,
|
|
1541
|
+
(await client.getArtifact(target.artifactId)).slug
|
|
1542
|
+
);
|
|
1391
1543
|
console.log(
|
|
1392
1544
|
res.protected ? `
|
|
1393
|
-
\u2713 Password protection on \u2014 ${
|
|
1545
|
+
\u2713 Password protection on \u2014 ${url}
|
|
1394
1546
|
` : `
|
|
1395
|
-
\u2713 Password protection removed \u2014 ${
|
|
1547
|
+
\u2713 Password protection removed \u2014 ${url}
|
|
1396
1548
|
`
|
|
1397
1549
|
);
|
|
1398
1550
|
}
|
|
@@ -1517,8 +1669,56 @@ var list2 = defineCommand({
|
|
|
1517
1669
|
}
|
|
1518
1670
|
}
|
|
1519
1671
|
});
|
|
1672
|
+
var link2 = defineCommand({
|
|
1673
|
+
args: {
|
|
1674
|
+
"api-key": {
|
|
1675
|
+
description: "Link with this API key (default: stored login)",
|
|
1676
|
+
type: "string"
|
|
1677
|
+
},
|
|
1678
|
+
artifact: {
|
|
1679
|
+
description: "Link this artifact id (skip the picker)",
|
|
1680
|
+
type: "string"
|
|
1681
|
+
},
|
|
1682
|
+
dir: {
|
|
1683
|
+
default: ".",
|
|
1684
|
+
description: "Directory to link",
|
|
1685
|
+
type: "positional"
|
|
1686
|
+
},
|
|
1687
|
+
json: { description: "Machine-readable output", type: "boolean" },
|
|
1688
|
+
slug: {
|
|
1689
|
+
description: "Link this artifact slug (skip the picker)",
|
|
1690
|
+
type: "string"
|
|
1691
|
+
}
|
|
1692
|
+
},
|
|
1693
|
+
meta: {
|
|
1694
|
+
description: "Link a folder to one of your artifacts (pick from your account)",
|
|
1695
|
+
name: "link"
|
|
1696
|
+
},
|
|
1697
|
+
async run({ args }) {
|
|
1698
|
+
try {
|
|
1699
|
+
await link({
|
|
1700
|
+
apiKey: args["api-key"],
|
|
1701
|
+
artifact: args.artifact,
|
|
1702
|
+
dir: args.dir,
|
|
1703
|
+
json: Boolean(args.json),
|
|
1704
|
+
slug: args.slug
|
|
1705
|
+
});
|
|
1706
|
+
} catch (err) {
|
|
1707
|
+
printCliError(err, Boolean(args.json));
|
|
1708
|
+
process.exit(1);
|
|
1709
|
+
}
|
|
1710
|
+
}
|
|
1711
|
+
});
|
|
1520
1712
|
var comments2 = defineCommand({
|
|
1521
1713
|
args: {
|
|
1714
|
+
"api-key": {
|
|
1715
|
+
description: "Authorize with an account API key (default: stored login)",
|
|
1716
|
+
type: "string"
|
|
1717
|
+
},
|
|
1718
|
+
artifact: {
|
|
1719
|
+
description: "Act on an artifact ID instead of the linked folder",
|
|
1720
|
+
type: "string"
|
|
1721
|
+
},
|
|
1522
1722
|
dir: {
|
|
1523
1723
|
default: ".",
|
|
1524
1724
|
description: "Published directory",
|
|
@@ -1558,6 +1758,8 @@ var comments2 = defineCommand({
|
|
|
1558
1758
|
);
|
|
1559
1759
|
}
|
|
1560
1760
|
await comments({
|
|
1761
|
+
apiKey: args["api-key"],
|
|
1762
|
+
artifact: args.artifact,
|
|
1561
1763
|
dir: args.dir,
|
|
1562
1764
|
json: Boolean(args.json),
|
|
1563
1765
|
status: args.status,
|
|
@@ -1573,6 +1775,14 @@ var comments2 = defineCommand({
|
|
|
1573
1775
|
});
|
|
1574
1776
|
var protect2 = defineCommand({
|
|
1575
1777
|
args: {
|
|
1778
|
+
"api-key": {
|
|
1779
|
+
description: "Authorize with an account API key (default: stored login)",
|
|
1780
|
+
type: "string"
|
|
1781
|
+
},
|
|
1782
|
+
artifact: {
|
|
1783
|
+
description: "Act on an artifact ID instead of the linked folder",
|
|
1784
|
+
type: "string"
|
|
1785
|
+
},
|
|
1576
1786
|
dir: {
|
|
1577
1787
|
default: ".",
|
|
1578
1788
|
description: "Published directory",
|
|
@@ -1589,6 +1799,8 @@ var protect2 = defineCommand({
|
|
|
1589
1799
|
async run({ args }) {
|
|
1590
1800
|
try {
|
|
1591
1801
|
await protect({
|
|
1802
|
+
apiKey: args["api-key"],
|
|
1803
|
+
artifact: args.artifact,
|
|
1592
1804
|
dir: args.dir,
|
|
1593
1805
|
json: Boolean(args.json),
|
|
1594
1806
|
off: Boolean(args.off),
|
|
@@ -1602,6 +1814,14 @@ var protect2 = defineCommand({
|
|
|
1602
1814
|
});
|
|
1603
1815
|
var open = defineCommand({
|
|
1604
1816
|
args: {
|
|
1817
|
+
"api-key": {
|
|
1818
|
+
description: "Authorize with an account API key (default: stored login)",
|
|
1819
|
+
type: "string"
|
|
1820
|
+
},
|
|
1821
|
+
artifact: {
|
|
1822
|
+
description: "Open an artifact ID instead of the linked folder",
|
|
1823
|
+
type: "string"
|
|
1824
|
+
},
|
|
1605
1825
|
dir: {
|
|
1606
1826
|
default: ".",
|
|
1607
1827
|
description: "Published directory",
|
|
@@ -1609,9 +1829,13 @@ var open = defineCommand({
|
|
|
1609
1829
|
}
|
|
1610
1830
|
},
|
|
1611
1831
|
meta: { description: "Open the linked artifact's review URL", name: "open" },
|
|
1612
|
-
run({ args }) {
|
|
1832
|
+
async run({ args }) {
|
|
1613
1833
|
try {
|
|
1614
|
-
openArtifact({
|
|
1834
|
+
await openArtifact({
|
|
1835
|
+
apiKey: args["api-key"],
|
|
1836
|
+
artifact: args.artifact,
|
|
1837
|
+
dir: args.dir
|
|
1838
|
+
});
|
|
1615
1839
|
} catch (err) {
|
|
1616
1840
|
printCliError(err, false);
|
|
1617
1841
|
process.exit(1);
|
|
@@ -1644,9 +1868,21 @@ var main = defineCommand({
|
|
|
1644
1868
|
description: "Publish AI-generated artifacts for review \u2014 https://artifact.cafe",
|
|
1645
1869
|
name: "artifact-cafe"
|
|
1646
1870
|
},
|
|
1871
|
+
// Bare `artifact-cafe` (no subcommand) → brand banner + usage. citty
|
|
1872
|
+
// still calls this parent run *after* a matched subcommand, so bail when
|
|
1873
|
+
// a subcommand token is present (any non-flag arg; citty has already
|
|
1874
|
+
// rejected unknown ones with E_UNKNOWN_COMMAND before we get here).
|
|
1875
|
+
async run({ cmd, rawArgs }) {
|
|
1876
|
+
if (rawArgs.some((arg) => !arg.startsWith("-"))) {
|
|
1877
|
+
return;
|
|
1878
|
+
}
|
|
1879
|
+
printBanner();
|
|
1880
|
+
await showUsage(cmd);
|
|
1881
|
+
},
|
|
1647
1882
|
subCommands: {
|
|
1648
1883
|
comments: comments2,
|
|
1649
1884
|
dashboard,
|
|
1885
|
+
link: link2,
|
|
1650
1886
|
list: list2,
|
|
1651
1887
|
login: login2,
|
|
1652
1888
|
logout: logout2,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "artifact-cafe",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
4
4
|
"description": "Publish AI-generated artifacts for review on artifact.cafe",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -9,19 +9,19 @@
|
|
|
9
9
|
"files": [
|
|
10
10
|
"dist"
|
|
11
11
|
],
|
|
12
|
-
"scripts": {
|
|
13
|
-
"build": "tsup",
|
|
14
|
-
"typecheck": "tsc --noEmit",
|
|
15
|
-
"dev": "tsup --watch"
|
|
16
|
-
},
|
|
17
12
|
"dependencies": {
|
|
18
13
|
"citty": "^0.1.6",
|
|
19
14
|
"zod": "^4.1.0"
|
|
20
15
|
},
|
|
21
16
|
"devDependencies": {
|
|
22
|
-
"@artifact-cafe/shared": "workspace:*",
|
|
23
17
|
"@types/node": "^24.0.0",
|
|
24
18
|
"tsup": "^8.5.0",
|
|
25
|
-
"typescript": "^5.9.0"
|
|
19
|
+
"typescript": "^5.9.0",
|
|
20
|
+
"@artifact-cafe/shared": "0.1.0"
|
|
21
|
+
},
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "tsup",
|
|
24
|
+
"typecheck": "tsc --noEmit",
|
|
25
|
+
"dev": "tsup --watch"
|
|
26
26
|
}
|
|
27
|
-
}
|
|
27
|
+
}
|