artifact-cafe 0.0.10 → 0.0.11
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 +596 -151
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -182,7 +182,7 @@ var artifactResponseSchema = z3.object({
|
|
|
182
182
|
id: z3.string(),
|
|
183
183
|
slug: z3.string(),
|
|
184
184
|
title: z3.string(),
|
|
185
|
-
visibility: z3.enum(["public", "unlisted", "workspace"]),
|
|
185
|
+
visibility: z3.enum(["public", "unlisted", "workspace", "private"]),
|
|
186
186
|
workspaceId: z3.string().nullable()
|
|
187
187
|
});
|
|
188
188
|
|
|
@@ -396,48 +396,105 @@ var feedbackResponseSchema = z6.object({
|
|
|
396
396
|
sent: z6.literal(true)
|
|
397
397
|
});
|
|
398
398
|
|
|
399
|
-
// ../shared/src/
|
|
399
|
+
// ../shared/src/grants.ts
|
|
400
400
|
import { z as z7 } from "zod";
|
|
401
|
-
var
|
|
401
|
+
var grantRoleSchema = z7.enum(["viewer"]);
|
|
402
|
+
var createGrantSchema = z7.object({
|
|
403
|
+
email: z7.string().trim().toLowerCase().email().optional(),
|
|
404
|
+
role: grantRoleSchema.default("viewer"),
|
|
405
|
+
userId: z7.string().min(1).optional()
|
|
406
|
+
}).refine((body) => Boolean(body.email) !== Boolean(body.userId), {
|
|
407
|
+
message: "provide exactly one of email or userId"
|
|
408
|
+
});
|
|
409
|
+
var grantSchema = z7.object({
|
|
402
410
|
createdAt: z7.string(),
|
|
403
|
-
|
|
404
|
-
// Owned artifacts normally never expire; non-null only while an
|
|
405
|
-
// expiry is still set (e.g. an unclaimed publish surfaced here later).
|
|
411
|
+
email: z7.string().email().nullable(),
|
|
406
412
|
expiresAt: z7.string().nullable(),
|
|
407
|
-
// SPEC-2 §8.4 — the containing folder for workspace-owned artifacts;
|
|
408
|
-
// both null for personal artifacts. `folderId` drives the dashboard's
|
|
409
|
-
// move control and folder filter; `folderName` is the display label.
|
|
410
|
-
folderId: z7.string().nullable(),
|
|
411
|
-
folderName: z7.string().nullable(),
|
|
412
|
-
// Whether a publish token is still active — revocable from the
|
|
413
|
-
// dashboard (§6.18); the token itself is never returned.
|
|
414
|
-
hasPublishToken: z7.boolean(),
|
|
415
413
|
id: z7.string(),
|
|
416
|
-
|
|
417
|
-
|
|
414
|
+
// The subject's avatar once they have an account; null otherwise.
|
|
415
|
+
image: z7.string().nullable(),
|
|
416
|
+
// Present on the invited account after redemption / when granting an
|
|
417
|
+
// existing user; null for a still-pending email invite.
|
|
418
|
+
name: z7.string().nullable(),
|
|
419
|
+
redeemedAt: z7.string().nullable(),
|
|
420
|
+
role: grantRoleSchema,
|
|
421
|
+
// Shown as "· pending" beside the role until the link is redeemed.
|
|
422
|
+
status: z7.enum(["pending", "active"]),
|
|
423
|
+
// Display fragment of the live invitation token, or null once redeemed.
|
|
424
|
+
tokenPrefix: z7.string().nullable(),
|
|
425
|
+
userId: z7.string().nullable()
|
|
426
|
+
});
|
|
427
|
+
var createdGrantSchema = grantSchema.extend({
|
|
428
|
+
url: z7.string().url()
|
|
429
|
+
});
|
|
430
|
+
var grantListResponseSchema = z7.object({
|
|
431
|
+
grants: z7.array(grantSchema),
|
|
432
|
+
// The artifact's current general-access value, so the share surface can
|
|
433
|
+
// render the "General access" line without a second read.
|
|
434
|
+
visibility: z7.enum(["public", "unlisted", "workspace", "private"])
|
|
435
|
+
});
|
|
436
|
+
var revokeGrantResponseSchema = z7.object({
|
|
437
|
+
revoked: z7.literal(true)
|
|
438
|
+
});
|
|
439
|
+
var acceptGrantSchema = z7.object({
|
|
440
|
+
token: z7.string().min(1)
|
|
441
|
+
});
|
|
442
|
+
var acceptGrantResponseSchema = z7.object({
|
|
443
|
+
artifactId: z7.string(),
|
|
444
|
+
// The review shell URL to land on, carrying ?invited=1 for the banner.
|
|
445
|
+
artifactUrl: z7.string().url(),
|
|
418
446
|
slug: z7.string(),
|
|
419
|
-
title: z7.string()
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
447
|
+
title: z7.string()
|
|
448
|
+
});
|
|
449
|
+
var workspaceGuestSchema = z7.object({
|
|
450
|
+
artifacts: z7.array(
|
|
451
|
+
z7.object({
|
|
452
|
+
artifactId: z7.string(),
|
|
453
|
+
grantId: z7.string(),
|
|
454
|
+
slug: z7.string(),
|
|
455
|
+
status: z7.enum(["pending", "active"]),
|
|
456
|
+
title: z7.string()
|
|
457
|
+
})
|
|
458
|
+
),
|
|
459
|
+
email: z7.string().nullable(),
|
|
460
|
+
image: z7.string().nullable(),
|
|
461
|
+
name: z7.string().nullable(),
|
|
462
|
+
userId: z7.string().nullable()
|
|
463
|
+
});
|
|
464
|
+
var workspaceGuestListResponseSchema = z7.object({
|
|
465
|
+
guests: z7.array(workspaceGuestSchema)
|
|
427
466
|
});
|
|
428
|
-
var
|
|
429
|
-
|
|
467
|
+
var sharedWithMeArtifactSchema = z7.object({
|
|
468
|
+
artifactId: z7.string(),
|
|
469
|
+
slug: z7.string(),
|
|
470
|
+
title: z7.string(),
|
|
471
|
+
url: z7.string().url(),
|
|
472
|
+
// Who shared it, for the "Shared with me" list.
|
|
473
|
+
workspaceName: z7.string()
|
|
430
474
|
});
|
|
431
|
-
var
|
|
432
|
-
|
|
475
|
+
var sharedWithMeListResponseSchema = z7.object({
|
|
476
|
+
artifacts: z7.array(sharedWithMeArtifactSchema)
|
|
433
477
|
});
|
|
434
478
|
|
|
435
|
-
// ../shared/src/
|
|
479
|
+
// ../shared/src/me.ts
|
|
436
480
|
import { z as z9 } from "zod";
|
|
437
481
|
|
|
438
482
|
// ../shared/src/workspaces.ts
|
|
439
483
|
import { z as z8 } from "zod";
|
|
440
484
|
var WORKSPACE_HANDLE_PATTERN = /^[a-z0-9](?:[a-z0-9-]{1,30}[a-z0-9])$/;
|
|
485
|
+
var workspaceHandleUnavailableReasonSchema = z8.enum([
|
|
486
|
+
"held",
|
|
487
|
+
"invalid",
|
|
488
|
+
"reserved",
|
|
489
|
+
"taken"
|
|
490
|
+
]);
|
|
491
|
+
var workspaceHandleAvailabilitySchema = z8.object({
|
|
492
|
+
available: z8.boolean(),
|
|
493
|
+
handle: z8.string(),
|
|
494
|
+
// Human-readable sentence for the field hint; null when available.
|
|
495
|
+
message: z8.string().nullable(),
|
|
496
|
+
reason: workspaceHandleUnavailableReasonSchema.nullable()
|
|
497
|
+
});
|
|
441
498
|
var workspaceRoleSchema = z8.enum(["owner", "admin", "member"]);
|
|
442
499
|
var workspaceInviteRoleSchema = z8.enum(["admin", "member"]);
|
|
443
500
|
var workspaceHandleSchema = z8.string().min(3).max(32).regex(WORKSPACE_HANDLE_PATTERN, {
|
|
@@ -456,6 +513,10 @@ var updateWorkspaceSchema = z8.object({
|
|
|
456
513
|
var workspaceSchema = z8.object({
|
|
457
514
|
createdAt: z8.string(),
|
|
458
515
|
handle: z8.string(),
|
|
516
|
+
// ISO timestamp when `{handle}.artifact.cafe` was provisioned, or null.
|
|
517
|
+
// Set by the one-time, self-serve enable flow (§4.4); never auto at
|
|
518
|
+
// create, and always null for personal workspaces.
|
|
519
|
+
hostnameProvisionedAt: z8.string().nullable(),
|
|
459
520
|
id: z8.string(),
|
|
460
521
|
// Auto-provisioned solo workspace, one per user: non-deletable, takes
|
|
461
522
|
// no members, renameable like any workspace.
|
|
@@ -526,7 +587,8 @@ var folderVisibilitySchema = z8.enum(["public", "workspace"]);
|
|
|
526
587
|
var artifactVisibilitySchema = z8.enum([
|
|
527
588
|
"public",
|
|
528
589
|
"unlisted",
|
|
529
|
-
"workspace"
|
|
590
|
+
"workspace",
|
|
591
|
+
"private"
|
|
530
592
|
]);
|
|
531
593
|
var createFolderSchema = z8.object({
|
|
532
594
|
name: z8.string().trim().min(1).max(100),
|
|
@@ -579,143 +641,229 @@ var workspaceArtifactSchema = z8.object({
|
|
|
579
641
|
var workspaceArtifactListResponseSchema = z8.object({
|
|
580
642
|
artifacts: z8.array(workspaceArtifactSchema)
|
|
581
643
|
});
|
|
644
|
+
var workspaceArtifactSearchResultSchema = z8.object({
|
|
645
|
+
id: z8.string(),
|
|
646
|
+
slug: z8.string(),
|
|
647
|
+
title: z8.string()
|
|
648
|
+
});
|
|
649
|
+
var workspaceArtifactSearchResponseSchema = z8.object({
|
|
650
|
+
results: z8.array(workspaceArtifactSearchResultSchema)
|
|
651
|
+
});
|
|
582
652
|
|
|
583
|
-
// ../shared/src/
|
|
584
|
-
var
|
|
585
|
-
|
|
586
|
-
|
|
653
|
+
// ../shared/src/me.ts
|
|
654
|
+
var ownArtifactSchema = z9.object({
|
|
655
|
+
createdAt: z9.string(),
|
|
656
|
+
currentVersionNumber: z9.number().nullable(),
|
|
657
|
+
// Owned artifacts normally never expire; non-null only while an
|
|
658
|
+
// expiry is still set (e.g. an unclaimed publish surfaced here later).
|
|
659
|
+
expiresAt: z9.string().nullable(),
|
|
660
|
+
// SPEC-2 §8.4 — the containing folder for workspace-owned artifacts;
|
|
661
|
+
// both null for personal artifacts. `folderId` drives the dashboard's
|
|
662
|
+
// move control and folder filter; `folderName` is the display label.
|
|
663
|
+
folderId: z9.string().nullable(),
|
|
664
|
+
folderName: z9.string().nullable(),
|
|
665
|
+
// Whether a publish token is still active — revocable from the
|
|
666
|
+
// dashboard (§6.18); the token itself is never returned.
|
|
667
|
+
hasPublishToken: z9.boolean(),
|
|
668
|
+
id: z9.string(),
|
|
669
|
+
openThreads: z9.number(),
|
|
670
|
+
protected: z9.boolean(),
|
|
671
|
+
// Who published the current version (falling back to the claiming
|
|
672
|
+
// owner) — the dashboard shows a name and avatar per artifact so a
|
|
673
|
+
// shared workspace reads as people's work, not anonymous rows. Null
|
|
674
|
+
// when the publish was token-only and the artifact is unclaimed.
|
|
675
|
+
publishedBy: z9.object({ image: z9.string().nullable(), name: z9.string() }).nullable(),
|
|
587
676
|
slug: z9.string(),
|
|
588
677
|
title: z9.string(),
|
|
589
|
-
|
|
678
|
+
totalViews: z9.number(),
|
|
679
|
+
// SPEC §6.20 — messages by others newer than the viewer's last-seen
|
|
680
|
+
// watermark. 0 for signed-out/API-key-less contexts.
|
|
681
|
+
unreadComments: z9.number(),
|
|
682
|
+
updatedAt: z9.string(),
|
|
683
|
+
url: z9.string(),
|
|
684
|
+
versionCount: z9.number(),
|
|
685
|
+
// SPEC-2 §5.1 — whether the caller clears the manage bar for this
|
|
686
|
+
// artifact (workspace admin, or the person who first published it).
|
|
687
|
+
// Only a manager's folder move inherits the folder's visibility, so the
|
|
688
|
+
// dashboard warns exactly the people the change can actually affect, and
|
|
689
|
+
// only a manager is offered the Share entry (§5.7).
|
|
690
|
+
viewerCanManage: z9.boolean(),
|
|
691
|
+
// SPEC-2 §5.2 — the artifact's own visibility, the single enforcement
|
|
692
|
+
// source. The dashboard needs it to tell whether a folder move would
|
|
693
|
+
// widen exposure before it sends the PATCH (§3.4), and to render the lock
|
|
694
|
+
// glyph on `private` rows and cards (§5.7).
|
|
695
|
+
visibility: artifactVisibilitySchema
|
|
696
|
+
});
|
|
697
|
+
var ownArtifactsResponseSchema = z9.object({
|
|
698
|
+
artifacts: z9.array(ownArtifactSchema)
|
|
699
|
+
});
|
|
700
|
+
var revokePublishTokenResponseSchema = z9.object({
|
|
701
|
+
revoked: z9.boolean()
|
|
590
702
|
});
|
|
591
|
-
|
|
703
|
+
|
|
704
|
+
// ../shared/src/owner.ts
|
|
705
|
+
import { z as z10 } from "zod";
|
|
706
|
+
var SLUG_PATTERN = /^[a-z0-9](?:[a-z0-9-]{1,61}[a-z0-9])$/;
|
|
707
|
+
var claimResponseSchema = z10.object({
|
|
708
|
+
artifactId: z10.string(),
|
|
709
|
+
slug: z10.string(),
|
|
710
|
+
title: z10.string(),
|
|
711
|
+
url: z10.string().url()
|
|
712
|
+
});
|
|
713
|
+
var updateArtifactSchema = z10.object({
|
|
592
714
|
// SPEC-2 §6.4 — placement + visibility. `folderId: null` clears the
|
|
593
715
|
// folder; `workspaceId: null` moves the artifact out of its workspace
|
|
594
716
|
// (§5.5 ownership transfer).
|
|
595
|
-
folderId:
|
|
596
|
-
slug:
|
|
717
|
+
folderId: z10.string().min(1).nullable().optional(),
|
|
718
|
+
slug: z10.string().min(3).max(63).regex(SLUG_PATTERN, {
|
|
597
719
|
message: "slug must be lowercase letters, digits, and hyphens, with no leading/trailing hyphen"
|
|
598
720
|
}).optional(),
|
|
599
|
-
title:
|
|
721
|
+
title: z10.string().min(1).max(200).optional(),
|
|
600
722
|
visibility: artifactVisibilitySchema.optional(),
|
|
601
|
-
workspaceId:
|
|
723
|
+
workspaceId: z10.string().min(1).nullable().optional()
|
|
602
724
|
}).refine(
|
|
603
725
|
(body) => body.title !== void 0 || body.slug !== void 0 || body.visibility !== void 0 || body.folderId !== void 0 || body.workspaceId !== void 0,
|
|
604
726
|
{
|
|
605
727
|
message: "provide at least one of title, slug, visibility, folderId, workspaceId"
|
|
606
728
|
}
|
|
607
729
|
);
|
|
608
|
-
var deleteArtifactResponseSchema =
|
|
609
|
-
deleted:
|
|
730
|
+
var deleteArtifactResponseSchema = z10.object({
|
|
731
|
+
deleted: z10.literal(true)
|
|
610
732
|
});
|
|
611
733
|
|
|
612
734
|
// ../shared/src/presence.ts
|
|
613
|
-
import { z as
|
|
735
|
+
import { z as z11 } from "zod";
|
|
736
|
+
var AGENT_STATES = ["listening", "editing", "publishing"];
|
|
737
|
+
var agentStateSchema = z11.enum(AGENT_STATES);
|
|
614
738
|
var AGENT_PRESENCE = {
|
|
739
|
+
editingTtlSeconds: 300,
|
|
615
740
|
heartbeatSeconds: 15,
|
|
616
741
|
shellPollSeconds: 15,
|
|
617
742
|
ttlSeconds: 45
|
|
618
743
|
};
|
|
619
|
-
var
|
|
620
|
-
|
|
621
|
-
|
|
744
|
+
var agentHeartbeatBodySchema = z11.object({
|
|
745
|
+
state: agentStateSchema.optional()
|
|
746
|
+
});
|
|
747
|
+
var agentHeartbeatResponseSchema = z11.object({
|
|
748
|
+
listening: z11.literal(true),
|
|
749
|
+
state: agentStateSchema.optional(),
|
|
750
|
+
ttlSeconds: z11.number().int().positive()
|
|
622
751
|
});
|
|
623
|
-
var agentPresenceSchema =
|
|
624
|
-
listening:
|
|
625
|
-
|
|
752
|
+
var agentPresenceSchema = z11.object({
|
|
753
|
+
listening: z11.boolean(),
|
|
754
|
+
state: agentStateSchema.nullable().optional(),
|
|
755
|
+
versionNumber: z11.number().int().positive().nullable()
|
|
626
756
|
});
|
|
627
757
|
|
|
628
758
|
// ../shared/src/protection.ts
|
|
629
|
-
import { z as
|
|
759
|
+
import { z as z12 } from "zod";
|
|
630
760
|
var PASSWORD_MIN = 6;
|
|
631
761
|
var PASSWORD_MAX = 128;
|
|
632
|
-
var gatePasswordSchema =
|
|
633
|
-
var setProtectionSchema =
|
|
762
|
+
var gatePasswordSchema = z12.string().min(PASSWORD_MIN, `Password must be at least ${PASSWORD_MIN} characters.`).max(PASSWORD_MAX, `Password must be at most ${PASSWORD_MAX} characters.`);
|
|
763
|
+
var setProtectionSchema = z12.object({
|
|
634
764
|
password: gatePasswordSchema.nullable()
|
|
635
765
|
});
|
|
636
|
-
var protectionResponseSchema =
|
|
637
|
-
protected:
|
|
766
|
+
var protectionResponseSchema = z12.object({
|
|
767
|
+
protected: z12.boolean()
|
|
638
768
|
});
|
|
639
|
-
var unlockSchema =
|
|
640
|
-
password:
|
|
769
|
+
var unlockSchema = z12.object({
|
|
770
|
+
password: z12.string().min(1).max(1024)
|
|
641
771
|
});
|
|
642
|
-
var unlockResponseSchema =
|
|
643
|
-
unlocked:
|
|
772
|
+
var unlockResponseSchema = z12.object({
|
|
773
|
+
unlocked: z12.literal(true)
|
|
644
774
|
});
|
|
645
775
|
|
|
646
776
|
// ../shared/src/report.ts
|
|
647
|
-
import { z as
|
|
648
|
-
var reportRequestSchema =
|
|
649
|
-
reason:
|
|
777
|
+
import { z as z13 } from "zod";
|
|
778
|
+
var reportRequestSchema = z13.object({
|
|
779
|
+
reason: z13.string().max(1e3).optional()
|
|
650
780
|
});
|
|
651
|
-
var reportResponseSchema =
|
|
652
|
-
reported:
|
|
781
|
+
var reportResponseSchema = z13.object({
|
|
782
|
+
reported: z13.literal(true)
|
|
783
|
+
});
|
|
784
|
+
|
|
785
|
+
// ../shared/src/reviewers.ts
|
|
786
|
+
import { z as z14 } from "zod";
|
|
787
|
+
var artifactReviewerSchema = z14.object({
|
|
788
|
+
avatarUrl: z14.string().nullable(),
|
|
789
|
+
displayName: z14.string(),
|
|
790
|
+
// Exactly one of userId/guestId is set, per `kind`.
|
|
791
|
+
guestId: z14.string().nullable(),
|
|
792
|
+
// "account", not commentAuthorSchema's "member" — the whole point here is
|
|
793
|
+
// that these people need not be workspace members. A guest can be named in
|
|
794
|
+
// a comment but never notified: guest_identities carries a display name and
|
|
795
|
+
// no email, so there is nowhere to send anything.
|
|
796
|
+
kind: z14.enum(["account", "guest"]),
|
|
797
|
+
userId: z14.string().nullable()
|
|
798
|
+
});
|
|
799
|
+
var artifactReviewerListResponseSchema = z14.object({
|
|
800
|
+
reviewers: z14.array(artifactReviewerSchema)
|
|
653
801
|
});
|
|
654
802
|
|
|
655
803
|
// ../shared/src/stats.ts
|
|
656
|
-
import { z as
|
|
657
|
-
var avgViewSecondsSchema =
|
|
658
|
-
var versionViewStatsSchema =
|
|
804
|
+
import { z as z15 } from "zod";
|
|
805
|
+
var avgViewSecondsSchema = z15.number().int().nonnegative().nullable();
|
|
806
|
+
var versionViewStatsSchema = z15.object({
|
|
659
807
|
avgViewSeconds: avgViewSecondsSchema,
|
|
660
808
|
// Views from inside the review shell's iframe vs. direct visits to
|
|
661
809
|
// the render URL. views = embeddedViews + directViews.
|
|
662
|
-
directViews:
|
|
663
|
-
embeddedViews:
|
|
810
|
+
directViews: z15.number().int().nonnegative(),
|
|
811
|
+
embeddedViews: z15.number().int().nonnegative(),
|
|
664
812
|
// Distinct hashed viewer IPs across the version's lifetime.
|
|
665
|
-
uniqueViewers:
|
|
666
|
-
versionNumber:
|
|
667
|
-
views:
|
|
813
|
+
uniqueViewers: z15.number().int().nonnegative(),
|
|
814
|
+
versionNumber: z15.number().int().positive(),
|
|
815
|
+
views: z15.number().int().nonnegative()
|
|
668
816
|
});
|
|
669
|
-
var dailyViewsSchema =
|
|
817
|
+
var dailyViewsSchema = z15.object({
|
|
670
818
|
avgViewSeconds: avgViewSecondsSchema,
|
|
671
819
|
// UTC day, YYYY-MM-DD.
|
|
672
|
-
day:
|
|
673
|
-
uniqueViewers:
|
|
674
|
-
views:
|
|
820
|
+
day: z15.string(),
|
|
821
|
+
uniqueViewers: z15.number().int().nonnegative(),
|
|
822
|
+
views: z15.number().int().nonnegative()
|
|
675
823
|
});
|
|
676
|
-
var artifactStatsResponseSchema =
|
|
824
|
+
var artifactStatsResponseSchema = z15.object({
|
|
677
825
|
avgViewSeconds: avgViewSecondsSchema,
|
|
678
|
-
daily:
|
|
826
|
+
daily: z15.array(dailyViewsSchema),
|
|
679
827
|
// Distinct hashed viewer IPs across all versions and days.
|
|
680
|
-
totalUniqueViewers:
|
|
681
|
-
totalViews:
|
|
682
|
-
versions:
|
|
828
|
+
totalUniqueViewers: z15.number().int().nonnegative(),
|
|
829
|
+
totalViews: z15.number().int().nonnegative(),
|
|
830
|
+
versions: z15.array(versionViewStatsSchema)
|
|
683
831
|
});
|
|
684
832
|
|
|
685
833
|
// ../shared/src/versions.ts
|
|
686
|
-
import { z as
|
|
687
|
-
var versionSourceSchema =
|
|
688
|
-
agentName:
|
|
689
|
-
type:
|
|
834
|
+
import { z as z16 } from "zod";
|
|
835
|
+
var versionSourceSchema = z16.object({
|
|
836
|
+
agentName: z16.string().nullable(),
|
|
837
|
+
type: z16.string()
|
|
690
838
|
});
|
|
691
|
-
var versionChangesSchema =
|
|
692
|
-
added:
|
|
693
|
-
changed:
|
|
694
|
-
removed:
|
|
839
|
+
var versionChangesSchema = z16.object({
|
|
840
|
+
added: z16.array(z16.string()),
|
|
841
|
+
changed: z16.array(z16.string()),
|
|
842
|
+
removed: z16.array(z16.string())
|
|
695
843
|
});
|
|
696
|
-
var versionSummarySchema =
|
|
844
|
+
var versionSummarySchema = z16.object({
|
|
697
845
|
// Absent for the first version — there is no previous version to diff against.
|
|
698
846
|
changes: versionChangesSchema.nullable(),
|
|
699
|
-
createdAt:
|
|
700
|
-
entryUrl:
|
|
701
|
-
fileCount:
|
|
702
|
-
id:
|
|
703
|
-
isCurrent:
|
|
847
|
+
createdAt: z16.string(),
|
|
848
|
+
entryUrl: z16.string().url(),
|
|
849
|
+
fileCount: z16.number().int().nonnegative(),
|
|
850
|
+
id: z16.string(),
|
|
851
|
+
isCurrent: z16.boolean(),
|
|
704
852
|
// Author-supplied bullet-point changelog; null when the publish omitted it.
|
|
705
|
-
notes:
|
|
853
|
+
notes: z16.string().nullable(),
|
|
706
854
|
source: versionSourceSchema,
|
|
707
|
-
totalSizeBytes:
|
|
708
|
-
versionNumber:
|
|
855
|
+
totalSizeBytes: z16.number().int().nonnegative(),
|
|
856
|
+
versionNumber: z16.number().int().positive()
|
|
709
857
|
});
|
|
710
|
-
var versionListResponseSchema =
|
|
711
|
-
versions:
|
|
858
|
+
var versionListResponseSchema = z16.object({
|
|
859
|
+
versions: z16.array(versionSummarySchema)
|
|
712
860
|
});
|
|
713
861
|
|
|
714
862
|
// src/api.ts
|
|
715
863
|
var ApiRequestError = class extends Error {
|
|
716
|
-
constructor(
|
|
864
|
+
constructor(status2, code, message, retryAfter) {
|
|
717
865
|
super(message);
|
|
718
|
-
this.status =
|
|
866
|
+
this.status = status2;
|
|
719
867
|
this.code = code;
|
|
720
868
|
this.retryAfter = retryAfter;
|
|
721
869
|
this.name = "ApiRequestError";
|
|
@@ -774,13 +922,28 @@ function createApiClient(apiUrl2, publishToken) {
|
|
|
774
922
|
(d) => commentThreadSchema.parse(d)
|
|
775
923
|
);
|
|
776
924
|
},
|
|
777
|
-
async agentHeartbeat(artifactId) {
|
|
925
|
+
async agentHeartbeat(artifactId, state) {
|
|
778
926
|
return request(
|
|
779
927
|
`${base}/api/v1/artifacts/${artifactId}/agent-presence`,
|
|
780
|
-
{
|
|
928
|
+
{
|
|
929
|
+
...state ? { body: JSON.stringify({ state }) } : {},
|
|
930
|
+
headers,
|
|
931
|
+
method: "POST"
|
|
932
|
+
},
|
|
781
933
|
(d) => agentHeartbeatResponseSchema.parse(d)
|
|
782
934
|
);
|
|
783
935
|
},
|
|
936
|
+
// SPEC-2 §6.6 — share an artifact with a person (email or user id).
|
|
937
|
+
// Authorized by this client's credential: the publish token (an agent
|
|
938
|
+
// sharing a private draft) or an account key/session. The invitation
|
|
939
|
+
// URL is returned exactly once, here.
|
|
940
|
+
async createGrant(artifactId, body) {
|
|
941
|
+
return request(
|
|
942
|
+
`${base}/api/v1/artifacts/${artifactId}/grants`,
|
|
943
|
+
{ body: JSON.stringify(body), headers, method: "POST" },
|
|
944
|
+
(d) => createdGrantSchema.parse(d)
|
|
945
|
+
);
|
|
946
|
+
},
|
|
784
947
|
async createSession(body) {
|
|
785
948
|
return request(
|
|
786
949
|
`${base}/api/v1/publish`,
|
|
@@ -859,6 +1022,15 @@ function createApiClient(apiUrl2, publishToken) {
|
|
|
859
1022
|
(d) => folderListResponseSchema.parse(d)
|
|
860
1023
|
);
|
|
861
1024
|
},
|
|
1025
|
+
// SPEC-2 §6.6 — the artifact's grants (no plaintext tokens). Used by
|
|
1026
|
+
// `share --list` and to resolve an email → grant id for `unshare`.
|
|
1027
|
+
async listGrants(artifactId) {
|
|
1028
|
+
return request(
|
|
1029
|
+
`${base}/api/v1/artifacts/${artifactId}/grants`,
|
|
1030
|
+
{ headers, method: "GET" },
|
|
1031
|
+
(d) => grantListResponseSchema.parse(d)
|
|
1032
|
+
);
|
|
1033
|
+
},
|
|
862
1034
|
async listWorkspaces() {
|
|
863
1035
|
return request(
|
|
864
1036
|
`${base}/api/v1/workspaces`,
|
|
@@ -903,6 +1075,14 @@ function createApiClient(apiUrl2, publishToken) {
|
|
|
903
1075
|
(d) => commentThreadSchema.parse(d)
|
|
904
1076
|
);
|
|
905
1077
|
},
|
|
1078
|
+
// SPEC-2 §6.6 — revoke a grant; access is gone within the cookie TTL.
|
|
1079
|
+
async revokeGrant(artifactId, grantId) {
|
|
1080
|
+
await request(
|
|
1081
|
+
`${base}/api/v1/artifacts/${artifactId}/grants/${grantId}`,
|
|
1082
|
+
{ headers, method: "DELETE" },
|
|
1083
|
+
() => void 0
|
|
1084
|
+
);
|
|
1085
|
+
},
|
|
906
1086
|
// SPEC §6.16 — set a password (string) or clear it (null). Authorized
|
|
907
1087
|
// by the publish token this client was created with.
|
|
908
1088
|
async setProtection(artifactId, password) {
|
|
@@ -939,17 +1119,17 @@ import {
|
|
|
939
1119
|
writeFileSync as writeFileSync2
|
|
940
1120
|
} from "fs";
|
|
941
1121
|
import path2 from "path";
|
|
942
|
-
import { z as
|
|
1122
|
+
import { z as z18 } from "zod";
|
|
943
1123
|
|
|
944
1124
|
// src/credentials.ts
|
|
945
1125
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
946
1126
|
import { homedir } from "os";
|
|
947
1127
|
import path from "path";
|
|
948
|
-
import { z as
|
|
1128
|
+
import { z as z17 } from "zod";
|
|
949
1129
|
var DEFAULT_API_URL = "https://artifact.cafe";
|
|
950
|
-
var credentialsSchema =
|
|
951
|
-
keys:
|
|
952
|
-
version:
|
|
1130
|
+
var credentialsSchema = z17.object({
|
|
1131
|
+
keys: z17.record(z17.string(), z17.string()),
|
|
1132
|
+
version: z17.literal(1)
|
|
953
1133
|
});
|
|
954
1134
|
function credentialsPath() {
|
|
955
1135
|
return path.join(homedir(), ".artifactcafe", "credentials");
|
|
@@ -999,24 +1179,24 @@ function resolveApiKey(apiUrl2, flag) {
|
|
|
999
1179
|
}
|
|
1000
1180
|
|
|
1001
1181
|
// src/config.ts
|
|
1002
|
-
var configSchema =
|
|
1003
|
-
apiUrl:
|
|
1004
|
-
artifactId:
|
|
1005
|
-
folder:
|
|
1006
|
-
folderId:
|
|
1182
|
+
var configSchema = z18.object({
|
|
1183
|
+
apiUrl: z18.string(),
|
|
1184
|
+
artifactId: z18.string(),
|
|
1185
|
+
folder: z18.string().optional(),
|
|
1186
|
+
folderId: z18.string().optional(),
|
|
1007
1187
|
// Optional: a folder linked by `link` to an artifact you own carries no
|
|
1008
1188
|
// token — owner actions authorize via your stored login instead. A first
|
|
1009
1189
|
// publish still writes the anonymous-mode token here.
|
|
1010
|
-
publishToken:
|
|
1011
|
-
slug:
|
|
1012
|
-
url:
|
|
1013
|
-
workspace:
|
|
1014
|
-
workspaceId:
|
|
1015
|
-
workspaceKind:
|
|
1016
|
-
});
|
|
1017
|
-
var projectConfigSchema =
|
|
1018
|
-
folder:
|
|
1019
|
-
workspace:
|
|
1190
|
+
publishToken: z18.string().optional(),
|
|
1191
|
+
slug: z18.string(),
|
|
1192
|
+
url: z18.string(),
|
|
1193
|
+
workspace: z18.string().optional(),
|
|
1194
|
+
workspaceId: z18.string().optional(),
|
|
1195
|
+
workspaceKind: z18.enum(["personal", "workspace"]).optional()
|
|
1196
|
+
});
|
|
1197
|
+
var projectConfigSchema = z18.object({
|
|
1198
|
+
folder: z18.string().trim().min(1).optional(),
|
|
1199
|
+
workspace: z18.string().trim().min(1)
|
|
1020
1200
|
}).strict();
|
|
1021
1201
|
var CONFIG_DIR = ".artifactcafe";
|
|
1022
1202
|
var CONFIG_FILE = "config.json";
|
|
@@ -1052,7 +1232,7 @@ function readProjectConfig(dir) {
|
|
|
1052
1232
|
JSON.parse(readFileSync2(file, "utf8"))
|
|
1053
1233
|
);
|
|
1054
1234
|
} catch (error) {
|
|
1055
|
-
const message = error instanceof
|
|
1235
|
+
const message = error instanceof z18.ZodError ? error.issues[0]?.message ?? "invalid project target" : "invalid JSON";
|
|
1056
1236
|
throw new Error(`Invalid ${file}: ${message}.`);
|
|
1057
1237
|
}
|
|
1058
1238
|
}
|
|
@@ -1239,7 +1419,7 @@ async function comments(opts) {
|
|
|
1239
1419
|
`--version must be one of: ${VERSIONS.join(", ")} (got "${opts.version}").`
|
|
1240
1420
|
);
|
|
1241
1421
|
}
|
|
1242
|
-
const
|
|
1422
|
+
const status2 = opts.status;
|
|
1243
1423
|
const version = opts.version;
|
|
1244
1424
|
const dir = path4.resolve(opts.dir);
|
|
1245
1425
|
const target = resolveArtifactTarget(dir, {
|
|
@@ -1252,21 +1432,21 @@ async function comments(opts) {
|
|
|
1252
1432
|
if (opts.wait) {
|
|
1253
1433
|
await waitForFeedback(client, ref, {
|
|
1254
1434
|
json: opts.json,
|
|
1255
|
-
status,
|
|
1435
|
+
status: status2,
|
|
1256
1436
|
timeoutSeconds: opts.timeout,
|
|
1257
1437
|
version
|
|
1258
1438
|
});
|
|
1259
1439
|
return;
|
|
1260
1440
|
}
|
|
1261
1441
|
const data = await client.exportComments(target.artifactId, {
|
|
1262
|
-
status,
|
|
1442
|
+
status: status2,
|
|
1263
1443
|
version
|
|
1264
1444
|
});
|
|
1265
1445
|
if (opts.json) {
|
|
1266
1446
|
console.log(JSON.stringify(data, null, 2));
|
|
1267
1447
|
return;
|
|
1268
1448
|
}
|
|
1269
|
-
printHuman(data, url,
|
|
1449
|
+
printHuman(data, url, status2, version);
|
|
1270
1450
|
}
|
|
1271
1451
|
async function deriveReviewUrl(client, target) {
|
|
1272
1452
|
const artifact = await client.getArtifact(target.artifactId);
|
|
@@ -1328,6 +1508,10 @@ async function waitForFeedback(client, config, opts) {
|
|
|
1328
1508
|
await sleep(settleSeconds());
|
|
1329
1509
|
const settled = await client.exportComments(config.artifactId, query);
|
|
1330
1510
|
const changed = diffThreads(baseline, settled);
|
|
1511
|
+
try {
|
|
1512
|
+
await client.agentHeartbeat(config.artifactId, "editing");
|
|
1513
|
+
} catch {
|
|
1514
|
+
}
|
|
1331
1515
|
printWaitResult(config, settled, changed, opts.json);
|
|
1332
1516
|
return;
|
|
1333
1517
|
}
|
|
@@ -1378,8 +1562,8 @@ ${changed.length} thread${plural} with new feedback \u2014 ${config.url}
|
|
|
1378
1562
|
printThread(thread);
|
|
1379
1563
|
}
|
|
1380
1564
|
}
|
|
1381
|
-
function printHuman(data, url,
|
|
1382
|
-
const statusLabel =
|
|
1565
|
+
function printHuman(data, url, status2, version) {
|
|
1566
|
+
const statusLabel = status2 === "all" ? "" : `${status2} `;
|
|
1383
1567
|
let scope = "across all versions";
|
|
1384
1568
|
if (version === "current") {
|
|
1385
1569
|
scope = data.versionNumber === null ? "on the current version" : `on v${data.versionNumber}`;
|
|
@@ -1638,17 +1822,26 @@ async function publish(opts) {
|
|
|
1638
1822
|
log(
|
|
1639
1823
|
` uploading ${session.filesToUpload.length} file(s)` + (session.skippedFiles.length ? `, ${session.skippedFiles.length} unchanged` : "")
|
|
1640
1824
|
);
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1825
|
+
const presence = startPublishingPresence(client, session.artifactId);
|
|
1826
|
+
try {
|
|
1827
|
+
await inBatches(
|
|
1828
|
+
session.filesToUpload,
|
|
1829
|
+
UPLOAD_CONCURRENCY,
|
|
1830
|
+
async (upload) => {
|
|
1831
|
+
const file = byPath.get(upload.path);
|
|
1832
|
+
if (!file) {
|
|
1833
|
+
throw new Error(`Server asked for unknown file ${upload.path}`);
|
|
1834
|
+
}
|
|
1835
|
+
await uploadFile(
|
|
1836
|
+
upload.uploadUrl,
|
|
1837
|
+
readFileSync4(file.absPath),
|
|
1838
|
+
file.mimeType
|
|
1839
|
+
);
|
|
1840
|
+
}
|
|
1650
1841
|
);
|
|
1651
|
-
}
|
|
1842
|
+
} finally {
|
|
1843
|
+
presence.stop();
|
|
1844
|
+
}
|
|
1652
1845
|
const result = await client.finalize(session.publishSessionId);
|
|
1653
1846
|
const rememberedProjectFile = placement.rememberProjectDefault ? writeProjectConfig(dir, placement.rememberProjectDefault) : null;
|
|
1654
1847
|
const existingToken = config?.artifactId === result.artifactId ? config.publishToken : void 0;
|
|
@@ -1917,6 +2110,16 @@ Publish where? [1-${choices.length}]: `, (answer) => {
|
|
|
1917
2110
|
});
|
|
1918
2111
|
});
|
|
1919
2112
|
}
|
|
2113
|
+
function startPublishingPresence(client, artifactId) {
|
|
2114
|
+
const beat = () => {
|
|
2115
|
+
client.agentHeartbeat(artifactId, "publishing").catch(() => {
|
|
2116
|
+
});
|
|
2117
|
+
};
|
|
2118
|
+
beat();
|
|
2119
|
+
const timer = setInterval(beat, AGENT_PRESENCE.heartbeatSeconds * 1e3);
|
|
2120
|
+
timer.unref();
|
|
2121
|
+
return { stop: () => clearInterval(timer) };
|
|
2122
|
+
}
|
|
1920
2123
|
async function inBatches(items, concurrency, fn) {
|
|
1921
2124
|
let next = 0;
|
|
1922
2125
|
const workers = Array.from(
|
|
@@ -2526,30 +2729,145 @@ async function changeThreadStatus(opts) {
|
|
|
2526
2729
|
console.log(`\u2713 ${verb} ${thread.id} \u2014 now ${thread.status}.`);
|
|
2527
2730
|
}
|
|
2528
2731
|
|
|
2732
|
+
// src/share.ts
|
|
2733
|
+
import path14 from "path";
|
|
2734
|
+
var EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
2735
|
+
async function share(opts) {
|
|
2736
|
+
const dir = path14.resolve(opts.dir);
|
|
2737
|
+
const target = resolveArtifactTarget(dir, {
|
|
2738
|
+
apiKey: opts.apiKey,
|
|
2739
|
+
artifact: opts.artifact
|
|
2740
|
+
});
|
|
2741
|
+
const client = createApiClient(target.apiUrl, target.credential);
|
|
2742
|
+
if (opts.list) {
|
|
2743
|
+
const { grants, visibility } = await client.listGrants(target.artifactId);
|
|
2744
|
+
if (opts.json) {
|
|
2745
|
+
console.log(JSON.stringify({ grants, visibility }, null, 2));
|
|
2746
|
+
return;
|
|
2747
|
+
}
|
|
2748
|
+
console.log(`
|
|
2749
|
+
General access: ${visibility}`);
|
|
2750
|
+
if (grants.length === 0) {
|
|
2751
|
+
console.log("No one has been invited yet.\n");
|
|
2752
|
+
return;
|
|
2753
|
+
}
|
|
2754
|
+
const label = grants.length === 1 ? "person" : "people";
|
|
2755
|
+
console.log(`${grants.length} ${label} with a grant:
|
|
2756
|
+
`);
|
|
2757
|
+
for (const grant of grants) {
|
|
2758
|
+
const who = grant.name && grant.email ? `${grant.name} <${grant.email}>` : grant.name ?? grant.email ?? grant.userId ?? "unknown";
|
|
2759
|
+
console.log(` ${who} \xB7 ${grant.role} \xB7 ${grant.status}`);
|
|
2760
|
+
}
|
|
2761
|
+
console.log("");
|
|
2762
|
+
return;
|
|
2763
|
+
}
|
|
2764
|
+
if (opts.emails.length === 0) {
|
|
2765
|
+
throw new Error(
|
|
2766
|
+
"Provide at least one email to invite, or --list to see current grants."
|
|
2767
|
+
);
|
|
2768
|
+
}
|
|
2769
|
+
for (const email of opts.emails) {
|
|
2770
|
+
if (!EMAIL_RE.test(email)) {
|
|
2771
|
+
throw new Error(`"${email}" is not a valid email address.`);
|
|
2772
|
+
}
|
|
2773
|
+
}
|
|
2774
|
+
const results = [];
|
|
2775
|
+
for (const email of opts.emails) {
|
|
2776
|
+
const grant = await client.createGrant(target.artifactId, { email });
|
|
2777
|
+
results.push({ email, url: grant.url });
|
|
2778
|
+
}
|
|
2779
|
+
if (opts.json) {
|
|
2780
|
+
console.log(JSON.stringify({ invited: results }, null, 2));
|
|
2781
|
+
return;
|
|
2782
|
+
}
|
|
2783
|
+
console.log("");
|
|
2784
|
+
for (const { email, url } of results) {
|
|
2785
|
+
console.log(`\u2713 Invited ${email}`);
|
|
2786
|
+
console.log(` ${url}`);
|
|
2787
|
+
}
|
|
2788
|
+
console.log("");
|
|
2789
|
+
}
|
|
2790
|
+
async function unshare(opts) {
|
|
2791
|
+
const dir = path14.resolve(opts.dir);
|
|
2792
|
+
const target = resolveArtifactTarget(dir, {
|
|
2793
|
+
apiKey: opts.apiKey,
|
|
2794
|
+
artifact: opts.artifact
|
|
2795
|
+
});
|
|
2796
|
+
const client = createApiClient(target.apiUrl, target.credential);
|
|
2797
|
+
const email = opts.email.toLowerCase();
|
|
2798
|
+
const { grants } = await client.listGrants(target.artifactId);
|
|
2799
|
+
const grant = grants.find((g) => g.email?.toLowerCase() === email);
|
|
2800
|
+
if (!grant) {
|
|
2801
|
+
throw new Error(`No active grant for ${opts.email} on this artifact.`);
|
|
2802
|
+
}
|
|
2803
|
+
await client.revokeGrant(target.artifactId, grant.id);
|
|
2804
|
+
if (opts.json) {
|
|
2805
|
+
console.log(JSON.stringify({ email: opts.email, revoked: true }, null, 2));
|
|
2806
|
+
return;
|
|
2807
|
+
}
|
|
2808
|
+
console.log(`
|
|
2809
|
+
\u2713 Revoked access for ${opts.email}
|
|
2810
|
+
`);
|
|
2811
|
+
}
|
|
2812
|
+
|
|
2813
|
+
// src/status.ts
|
|
2814
|
+
import path15 from "path";
|
|
2815
|
+
async function status(opts) {
|
|
2816
|
+
if (!AGENT_STATES.includes(opts.state)) {
|
|
2817
|
+
throw new Error(
|
|
2818
|
+
`State must be one of: ${AGENT_STATES.join(", ")} (got "${opts.state}").`
|
|
2819
|
+
);
|
|
2820
|
+
}
|
|
2821
|
+
const state = opts.state;
|
|
2822
|
+
const dir = path15.resolve(opts.dir);
|
|
2823
|
+
const target = resolveArtifactTarget(dir, {
|
|
2824
|
+
apiKey: opts.apiKey,
|
|
2825
|
+
artifact: opts.artifact
|
|
2826
|
+
});
|
|
2827
|
+
const client = createApiClient(target.apiUrl, target.credential);
|
|
2828
|
+
const res = await client.agentHeartbeat(target.artifactId, state);
|
|
2829
|
+
if (opts.json) {
|
|
2830
|
+
console.log(
|
|
2831
|
+
JSON.stringify(
|
|
2832
|
+
{
|
|
2833
|
+
artifactId: target.artifactId,
|
|
2834
|
+
state,
|
|
2835
|
+
ttlSeconds: res.ttlSeconds
|
|
2836
|
+
},
|
|
2837
|
+
null,
|
|
2838
|
+
2
|
|
2839
|
+
)
|
|
2840
|
+
);
|
|
2841
|
+
return;
|
|
2842
|
+
}
|
|
2843
|
+
const visible = res.ttlSeconds >= 120 ? `~${Math.round(res.ttlSeconds / 60)}m` : `~${res.ttlSeconds}s`;
|
|
2844
|
+
console.log(`\u2713 Presence: ${state} (visible ${visible})`);
|
|
2845
|
+
}
|
|
2846
|
+
|
|
2529
2847
|
// src/update.ts
|
|
2530
2848
|
import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "fs";
|
|
2531
2849
|
import { createRequire } from "module";
|
|
2532
2850
|
import { homedir as homedir2 } from "os";
|
|
2533
|
-
import
|
|
2534
|
-
import { z as
|
|
2851
|
+
import path16 from "path";
|
|
2852
|
+
import { z as z19 } from "zod";
|
|
2535
2853
|
var REGISTRY_LATEST_URL = "https://registry.npmjs.org/artifact-cafe/latest";
|
|
2536
2854
|
var SKILL_SOURCE_URL = "https://raw.githubusercontent.com/Artifact-Cafe/skill/main/artifact-cafe/SKILL.md";
|
|
2537
2855
|
var SKILL_UPDATE_COMMAND = "npx skills add artifact-cafe/skill --skill artifact-cafe -g";
|
|
2538
2856
|
var CHECK_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
2539
2857
|
var FETCH_TIMEOUT_MS = 2e3;
|
|
2540
2858
|
var SKILL_VERSION_PATTERN = /\*\*Skill version:\s*(\d+\.\d+\.\d+)\*\*/;
|
|
2541
|
-
var cacheSchema =
|
|
2542
|
-
checkedAt:
|
|
2543
|
-
cliLatest:
|
|
2544
|
-
skillLatest:
|
|
2545
|
-
version:
|
|
2859
|
+
var cacheSchema = z19.object({
|
|
2860
|
+
checkedAt: z19.number(),
|
|
2861
|
+
cliLatest: z19.string().nullable(),
|
|
2862
|
+
skillLatest: z19.string().nullable(),
|
|
2863
|
+
version: z19.literal(1)
|
|
2546
2864
|
});
|
|
2547
2865
|
function cliVersion() {
|
|
2548
2866
|
const pkg = createRequire(import.meta.url)("../package.json");
|
|
2549
2867
|
return pkg.version;
|
|
2550
2868
|
}
|
|
2551
2869
|
function cachePath() {
|
|
2552
|
-
return
|
|
2870
|
+
return path16.join(homedir2(), ".artifactcafe", "update-check.json");
|
|
2553
2871
|
}
|
|
2554
2872
|
function readCache() {
|
|
2555
2873
|
try {
|
|
@@ -2560,7 +2878,7 @@ function readCache() {
|
|
|
2560
2878
|
}
|
|
2561
2879
|
function writeCache(cache) {
|
|
2562
2880
|
try {
|
|
2563
|
-
mkdirSync3(
|
|
2881
|
+
mkdirSync3(path16.dirname(cachePath()), { mode: 448, recursive: true });
|
|
2564
2882
|
writeFileSync3(cachePath(), `${JSON.stringify(cache, null, 2)}
|
|
2565
2883
|
`);
|
|
2566
2884
|
} catch {
|
|
@@ -2597,7 +2915,7 @@ async function fetchText(url) {
|
|
|
2597
2915
|
}
|
|
2598
2916
|
async function fetchLatestVersions(previous) {
|
|
2599
2917
|
const [cli, skill] = await Promise.all([
|
|
2600
|
-
fetchJson(REGISTRY_LATEST_URL).then((body) =>
|
|
2918
|
+
fetchJson(REGISTRY_LATEST_URL).then((body) => z19.object({ version: z19.string() }).parse(body).version).catch(() => null),
|
|
2601
2919
|
fetchText(SKILL_SOURCE_URL).then((body) => SKILL_VERSION_PATTERN.exec(body)?.[1] ?? null).catch(() => null)
|
|
2602
2920
|
]);
|
|
2603
2921
|
return {
|
|
@@ -2613,7 +2931,7 @@ function installedSkillVersions() {
|
|
|
2613
2931
|
const versions = [];
|
|
2614
2932
|
for (const root of roots) {
|
|
2615
2933
|
for (const dir of dirs) {
|
|
2616
|
-
const file =
|
|
2934
|
+
const file = path16.join(root, dir, "skills", "artifact-cafe", "SKILL.md");
|
|
2617
2935
|
if (!existsSync3(file)) {
|
|
2618
2936
|
continue;
|
|
2619
2937
|
}
|
|
@@ -3076,6 +3394,47 @@ var listen = defineCommand({
|
|
|
3076
3394
|
}
|
|
3077
3395
|
}
|
|
3078
3396
|
});
|
|
3397
|
+
var statusCmd = defineCommand({
|
|
3398
|
+
args: {
|
|
3399
|
+
"api-key": {
|
|
3400
|
+
description: "Authorize with an account API key (default: stored login)",
|
|
3401
|
+
type: "string"
|
|
3402
|
+
},
|
|
3403
|
+
artifact: {
|
|
3404
|
+
description: "Act on an artifact ID instead of the linked folder",
|
|
3405
|
+
type: "string"
|
|
3406
|
+
},
|
|
3407
|
+
dir: {
|
|
3408
|
+
default: ".",
|
|
3409
|
+
description: "Linked directory to authorize from (default: .)",
|
|
3410
|
+
type: "string"
|
|
3411
|
+
},
|
|
3412
|
+
json: { description: "Machine-readable output", type: "boolean" },
|
|
3413
|
+
state: {
|
|
3414
|
+
description: "What the agent is doing: editing | publishing | listening",
|
|
3415
|
+
required: true,
|
|
3416
|
+
type: "positional"
|
|
3417
|
+
}
|
|
3418
|
+
},
|
|
3419
|
+
meta: {
|
|
3420
|
+
description: "Mark what the agent is doing on the linked artifact",
|
|
3421
|
+
name: "status"
|
|
3422
|
+
},
|
|
3423
|
+
async run({ args }) {
|
|
3424
|
+
try {
|
|
3425
|
+
await status({
|
|
3426
|
+
apiKey: args["api-key"],
|
|
3427
|
+
artifact: args.artifact,
|
|
3428
|
+
dir: args.dir,
|
|
3429
|
+
json: Boolean(args.json),
|
|
3430
|
+
state: args.state
|
|
3431
|
+
});
|
|
3432
|
+
} catch (err) {
|
|
3433
|
+
printCliError(err, Boolean(args.json));
|
|
3434
|
+
process.exit(1);
|
|
3435
|
+
}
|
|
3436
|
+
}
|
|
3437
|
+
});
|
|
3079
3438
|
var protect2 = defineCommand({
|
|
3080
3439
|
args: {
|
|
3081
3440
|
"api-key": {
|
|
@@ -3361,6 +3720,89 @@ var del = defineCommand({
|
|
|
3361
3720
|
}
|
|
3362
3721
|
}
|
|
3363
3722
|
});
|
|
3723
|
+
var share2 = defineCommand({
|
|
3724
|
+
args: {
|
|
3725
|
+
"api-key": {
|
|
3726
|
+
description: "Authorize with an account API key (default: stored login)",
|
|
3727
|
+
type: "string"
|
|
3728
|
+
},
|
|
3729
|
+
artifact: {
|
|
3730
|
+
description: "Act on an artifact ID instead of the linked folder",
|
|
3731
|
+
type: "string"
|
|
3732
|
+
},
|
|
3733
|
+
dir: {
|
|
3734
|
+
default: ".",
|
|
3735
|
+
description: "Linked directory to authorize from (default: .)",
|
|
3736
|
+
type: "string"
|
|
3737
|
+
},
|
|
3738
|
+
json: { description: "Machine-readable output", type: "boolean" },
|
|
3739
|
+
list: {
|
|
3740
|
+
description: "List current grants instead of inviting",
|
|
3741
|
+
type: "boolean"
|
|
3742
|
+
}
|
|
3743
|
+
},
|
|
3744
|
+
meta: {
|
|
3745
|
+
description: "Share the linked artifact with people by email",
|
|
3746
|
+
name: "share"
|
|
3747
|
+
},
|
|
3748
|
+
async run({ args }) {
|
|
3749
|
+
try {
|
|
3750
|
+
await share({
|
|
3751
|
+
apiKey: args["api-key"],
|
|
3752
|
+
artifact: args.artifact,
|
|
3753
|
+
dir: args.dir,
|
|
3754
|
+
// citty collects bare positionals (the invited emails) in args._.
|
|
3755
|
+
emails: (args._ ?? []).map(String),
|
|
3756
|
+
json: Boolean(args.json),
|
|
3757
|
+
list: Boolean(args.list)
|
|
3758
|
+
});
|
|
3759
|
+
} catch (err) {
|
|
3760
|
+
printCliError(err, Boolean(args.json));
|
|
3761
|
+
process.exit(1);
|
|
3762
|
+
}
|
|
3763
|
+
}
|
|
3764
|
+
});
|
|
3765
|
+
var unshare2 = defineCommand({
|
|
3766
|
+
args: {
|
|
3767
|
+
"api-key": {
|
|
3768
|
+
description: "Authorize with an account API key (default: stored login)",
|
|
3769
|
+
type: "string"
|
|
3770
|
+
},
|
|
3771
|
+
artifact: {
|
|
3772
|
+
description: "Act on an artifact ID instead of the linked folder",
|
|
3773
|
+
type: "string"
|
|
3774
|
+
},
|
|
3775
|
+
dir: {
|
|
3776
|
+
default: ".",
|
|
3777
|
+
description: "Linked directory to authorize from (default: .)",
|
|
3778
|
+
type: "string"
|
|
3779
|
+
},
|
|
3780
|
+
email: {
|
|
3781
|
+
description: "Email address to revoke",
|
|
3782
|
+
required: true,
|
|
3783
|
+
type: "positional"
|
|
3784
|
+
},
|
|
3785
|
+
json: { description: "Machine-readable output", type: "boolean" }
|
|
3786
|
+
},
|
|
3787
|
+
meta: {
|
|
3788
|
+
description: "Revoke a person's access to the linked artifact",
|
|
3789
|
+
name: "unshare"
|
|
3790
|
+
},
|
|
3791
|
+
async run({ args }) {
|
|
3792
|
+
try {
|
|
3793
|
+
await unshare({
|
|
3794
|
+
apiKey: args["api-key"],
|
|
3795
|
+
artifact: args.artifact,
|
|
3796
|
+
dir: args.dir,
|
|
3797
|
+
email: args.email,
|
|
3798
|
+
json: Boolean(args.json)
|
|
3799
|
+
});
|
|
3800
|
+
} catch (err) {
|
|
3801
|
+
printCliError(err, Boolean(args.json));
|
|
3802
|
+
process.exit(1);
|
|
3803
|
+
}
|
|
3804
|
+
}
|
|
3805
|
+
});
|
|
3364
3806
|
var open = defineCommand({
|
|
3365
3807
|
args: {
|
|
3366
3808
|
"api-key": {
|
|
@@ -3448,6 +3890,9 @@ var main = defineCommand({
|
|
|
3448
3890
|
reopen,
|
|
3449
3891
|
reply,
|
|
3450
3892
|
resolve,
|
|
3893
|
+
share: share2,
|
|
3894
|
+
status: statusCmd,
|
|
3895
|
+
unshare: unshare2,
|
|
3451
3896
|
whoami: whoami2,
|
|
3452
3897
|
workspaces: workspaces2
|
|
3453
3898
|
}
|