artifact-cafe 0.0.9 → 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 +963 -420
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -83,11 +83,27 @@ var artifactListResponseSchema = z.object({
|
|
|
83
83
|
artifacts: z.array(artifactListItemSchema)
|
|
84
84
|
});
|
|
85
85
|
|
|
86
|
+
// ../shared/src/avatars.ts
|
|
87
|
+
import { z as z2 } from "zod";
|
|
88
|
+
var AVATAR_CONTENT_TYPES = [
|
|
89
|
+
"image/png",
|
|
90
|
+
"image/jpeg",
|
|
91
|
+
"image/webp"
|
|
92
|
+
];
|
|
93
|
+
var AVATAR_MAX_BYTES = 2 * 1024 * 1024;
|
|
94
|
+
var avatarContentTypeSchema = z2.enum(AVATAR_CONTENT_TYPES);
|
|
95
|
+
var userAvatarResponseSchema = z2.object({
|
|
96
|
+
image: z2.string().nullable()
|
|
97
|
+
});
|
|
98
|
+
var workspaceAvatarResponseSchema = z2.object({
|
|
99
|
+
logo: z2.string().nullable()
|
|
100
|
+
});
|
|
101
|
+
|
|
86
102
|
// ../shared/src/comments.ts
|
|
87
|
-
import { z as
|
|
103
|
+
import { z as z4 } from "zod";
|
|
88
104
|
|
|
89
105
|
// ../shared/src/publish.ts
|
|
90
|
-
import { z as
|
|
106
|
+
import { z as z3 } from "zod";
|
|
91
107
|
function isSafeArtifactPath(p) {
|
|
92
108
|
if (p.length === 0 || p.length > 1024) {
|
|
93
109
|
return false;
|
|
@@ -100,244 +116,258 @@ function isSafeArtifactPath(p) {
|
|
|
100
116
|
}
|
|
101
117
|
return p.split("/").every((seg) => seg.length > 0 && seg !== "." && seg !== "..");
|
|
102
118
|
}
|
|
103
|
-
var manifestFileSchema =
|
|
104
|
-
hash:
|
|
105
|
-
mimeType:
|
|
106
|
-
path:
|
|
119
|
+
var manifestFileSchema = z3.object({
|
|
120
|
+
hash: z3.string().regex(/^sha256_[a-f0-9]{64}$/),
|
|
121
|
+
mimeType: z3.string().regex(/^[-\w.+]+\/[-\w.+]+$/, { message: "invalid MIME type" }),
|
|
122
|
+
path: z3.string().min(1).max(1024).refine(isSafeArtifactPath, {
|
|
107
123
|
message: "path must be a safe relative path"
|
|
108
124
|
}),
|
|
109
|
-
size:
|
|
125
|
+
size: z3.number().int().positive()
|
|
110
126
|
});
|
|
111
|
-
var publishSourceSchema =
|
|
112
|
-
agent:
|
|
113
|
-
runId:
|
|
114
|
-
type:
|
|
127
|
+
var publishSourceSchema = z3.object({
|
|
128
|
+
agent: z3.string().optional(),
|
|
129
|
+
runId: z3.string().optional(),
|
|
130
|
+
type: z3.literal("cli")
|
|
115
131
|
});
|
|
116
|
-
var createPublishSessionSchema =
|
|
117
|
-
artifactId:
|
|
118
|
-
entryPath:
|
|
119
|
-
files:
|
|
132
|
+
var createPublishSessionSchema = z3.object({
|
|
133
|
+
artifactId: z3.string().nullable(),
|
|
134
|
+
entryPath: z3.string().optional(),
|
|
135
|
+
files: z3.array(manifestFileSchema).min(1).max(1e3),
|
|
120
136
|
// SPEC-2 §6.4 — workspace placement is available only to authenticated
|
|
121
137
|
// members; the API enforces membership and folder ownership. folderId
|
|
122
138
|
// without workspaceId resolves against the account's personal workspace.
|
|
123
|
-
folderId:
|
|
139
|
+
folderId: z3.string().min(1).optional(),
|
|
140
|
+
// Bullet-point changelog for this version, authored by the publisher.
|
|
141
|
+
// Optional on every publish (incl. v1); stored immutably on the version.
|
|
142
|
+
notes: z3.string().max(4e3).optional(),
|
|
124
143
|
source: publishSourceSchema,
|
|
125
|
-
title:
|
|
126
|
-
workspaceId:
|
|
127
|
-
});
|
|
128
|
-
var publishSessionResponseSchema =
|
|
129
|
-
artifactId:
|
|
130
|
-
expiresAt:
|
|
131
|
-
filesToUpload:
|
|
132
|
-
|
|
133
|
-
method:
|
|
134
|
-
path:
|
|
135
|
-
uploadUrl:
|
|
144
|
+
title: z3.string().max(200).optional(),
|
|
145
|
+
workspaceId: z3.string().min(1).optional()
|
|
146
|
+
});
|
|
147
|
+
var publishSessionResponseSchema = z3.object({
|
|
148
|
+
artifactId: z3.string(),
|
|
149
|
+
expiresAt: z3.string(),
|
|
150
|
+
filesToUpload: z3.array(
|
|
151
|
+
z3.object({
|
|
152
|
+
method: z3.literal("PUT"),
|
|
153
|
+
path: z3.string(),
|
|
154
|
+
uploadUrl: z3.string().url()
|
|
136
155
|
})
|
|
137
156
|
),
|
|
138
|
-
publishSessionId:
|
|
139
|
-
skippedFiles:
|
|
140
|
-
versionId:
|
|
157
|
+
publishSessionId: z3.string(),
|
|
158
|
+
skippedFiles: z3.array(z3.string()),
|
|
159
|
+
versionId: z3.string()
|
|
141
160
|
});
|
|
142
|
-
var finalizeResponseSchema =
|
|
143
|
-
artifactId:
|
|
161
|
+
var finalizeResponseSchema = z3.object({
|
|
162
|
+
artifactId: z3.string(),
|
|
144
163
|
// API-key publishes create the artifact already claimed (SPEC §5.4) —
|
|
145
164
|
// the CLI uses this to tell "claim URL pending" from "already yours".
|
|
146
|
-
claimed:
|
|
165
|
+
claimed: z3.boolean(),
|
|
147
166
|
// Returned only on first publish of a new artifact (one-time).
|
|
148
|
-
claimUrl:
|
|
149
|
-
publishToken:
|
|
150
|
-
url:
|
|
151
|
-
versionId:
|
|
152
|
-
versionNumber:
|
|
153
|
-
});
|
|
154
|
-
var artifactResponseSchema =
|
|
155
|
-
claimed:
|
|
156
|
-
currentVersion:
|
|
157
|
-
entryUrl:
|
|
158
|
-
id:
|
|
159
|
-
versionNumber:
|
|
167
|
+
claimUrl: z3.string().url().optional(),
|
|
168
|
+
publishToken: z3.string().optional(),
|
|
169
|
+
url: z3.string().url(),
|
|
170
|
+
versionId: z3.string(),
|
|
171
|
+
versionNumber: z3.number().int().positive()
|
|
172
|
+
});
|
|
173
|
+
var artifactResponseSchema = z3.object({
|
|
174
|
+
claimed: z3.boolean(),
|
|
175
|
+
currentVersion: z3.object({
|
|
176
|
+
entryUrl: z3.string().url(),
|
|
177
|
+
id: z3.string(),
|
|
178
|
+
versionNumber: z3.number().int().positive()
|
|
160
179
|
}).nullable(),
|
|
161
180
|
// SPEC-2 §6.4 — placement + visibility surface on the artifact.
|
|
162
|
-
folderId:
|
|
163
|
-
id:
|
|
164
|
-
slug:
|
|
165
|
-
title:
|
|
166
|
-
visibility:
|
|
167
|
-
workspaceId:
|
|
181
|
+
folderId: z3.string().nullable(),
|
|
182
|
+
id: z3.string(),
|
|
183
|
+
slug: z3.string(),
|
|
184
|
+
title: z3.string(),
|
|
185
|
+
visibility: z3.enum(["public", "unlisted", "workspace", "private"]),
|
|
186
|
+
workspaceId: z3.string().nullable()
|
|
168
187
|
});
|
|
169
188
|
|
|
170
189
|
// ../shared/src/comments.ts
|
|
171
|
-
var anchorPageSchema =
|
|
190
|
+
var anchorPageSchema = z4.string().max(1024).refine(isSafeArtifactPath, {
|
|
172
191
|
message: "page must be a safe relative path"
|
|
173
192
|
}).optional();
|
|
174
|
-
var elementSnapshotSchema =
|
|
175
|
-
classes:
|
|
176
|
-
id:
|
|
177
|
-
tag:
|
|
178
|
-
text:
|
|
193
|
+
var elementSnapshotSchema = z4.object({
|
|
194
|
+
classes: z4.string().max(256).optional(),
|
|
195
|
+
id: z4.string().max(256).optional(),
|
|
196
|
+
tag: z4.string().min(1).max(128),
|
|
197
|
+
text: z4.string().max(200).optional()
|
|
179
198
|
});
|
|
180
|
-
var pointAnchorSchema =
|
|
199
|
+
var pointAnchorSchema = z4.object({
|
|
181
200
|
element: elementSnapshotSchema.optional(),
|
|
182
201
|
// elementPath is the primary anchor; x/y are offsets within the
|
|
183
202
|
// element's box, normalized 0..1 (SPEC.md §8.1).
|
|
184
|
-
elementPath:
|
|
203
|
+
elementPath: z4.string().max(2048),
|
|
185
204
|
page: anchorPageSchema,
|
|
186
|
-
type:
|
|
187
|
-
viewportHeight:
|
|
188
|
-
viewportWidth:
|
|
189
|
-
x:
|
|
190
|
-
y:
|
|
191
|
-
});
|
|
192
|
-
var textAnchorSchema =
|
|
193
|
-
elementPath:
|
|
194
|
-
endOffset:
|
|
205
|
+
type: z4.literal("point"),
|
|
206
|
+
viewportHeight: z4.number().int().positive().max(1e5),
|
|
207
|
+
viewportWidth: z4.number().int().positive().max(1e5),
|
|
208
|
+
x: z4.number().min(0).max(1),
|
|
209
|
+
y: z4.number().min(0).max(1)
|
|
210
|
+
});
|
|
211
|
+
var textAnchorSchema = z4.object({
|
|
212
|
+
elementPath: z4.string().max(2048),
|
|
213
|
+
endOffset: z4.number().int().nonnegative().max(1e8),
|
|
195
214
|
page: anchorPageSchema,
|
|
196
|
-
prefix:
|
|
197
|
-
quote:
|
|
198
|
-
startOffset:
|
|
199
|
-
suffix:
|
|
200
|
-
type:
|
|
215
|
+
prefix: z4.string().max(200).optional(),
|
|
216
|
+
quote: z4.string().min(1).max(1e3),
|
|
217
|
+
startOffset: z4.number().int().nonnegative().max(1e8),
|
|
218
|
+
suffix: z4.string().max(200).optional(),
|
|
219
|
+
type: z4.literal("text")
|
|
201
220
|
});
|
|
202
|
-
var pageAnchorSchema =
|
|
221
|
+
var pageAnchorSchema = z4.object({
|
|
203
222
|
page: anchorPageSchema,
|
|
204
|
-
type:
|
|
223
|
+
type: z4.literal("page")
|
|
205
224
|
});
|
|
206
|
-
var anchorSchema =
|
|
225
|
+
var anchorSchema = z4.discriminatedUnion("type", [
|
|
207
226
|
pointAnchorSchema,
|
|
208
227
|
textAnchorSchema,
|
|
209
228
|
pageAnchorSchema
|
|
210
229
|
]);
|
|
211
|
-
var displayNameSchema =
|
|
212
|
-
var guestSchema =
|
|
230
|
+
var displayNameSchema = z4.string().trim().min(1).max(64);
|
|
231
|
+
var guestSchema = z4.object({
|
|
213
232
|
displayName: displayNameSchema,
|
|
214
|
-
guestId:
|
|
233
|
+
guestId: z4.string().min(16)
|
|
215
234
|
});
|
|
216
|
-
var viaLabelSchema =
|
|
217
|
-
var createCommentThreadSchema =
|
|
235
|
+
var viaLabelSchema = z4.string().trim().min(1).max(64);
|
|
236
|
+
var createCommentThreadSchema = z4.object({
|
|
218
237
|
anchor: anchorSchema,
|
|
219
|
-
body:
|
|
238
|
+
body: z4.string().min(1).max(1e4),
|
|
220
239
|
guest: guestSchema.optional(),
|
|
221
|
-
versionId:
|
|
240
|
+
versionId: z4.string(),
|
|
222
241
|
via: viaLabelSchema.optional()
|
|
223
242
|
});
|
|
224
|
-
var createCommentMessageSchema =
|
|
225
|
-
body:
|
|
243
|
+
var createCommentMessageSchema = z4.object({
|
|
244
|
+
body: z4.string().min(1).max(1e4),
|
|
226
245
|
guest: guestSchema.optional(),
|
|
227
246
|
via: viaLabelSchema.optional()
|
|
228
247
|
});
|
|
229
|
-
var editCommentMessageSchema =
|
|
230
|
-
body:
|
|
248
|
+
var editCommentMessageSchema = z4.object({
|
|
249
|
+
body: z4.string().min(1).max(1e4),
|
|
231
250
|
guest: guestSchema.optional()
|
|
232
251
|
});
|
|
233
|
-
var threadActionSchema =
|
|
252
|
+
var threadActionSchema = z4.object({
|
|
234
253
|
guest: guestSchema.optional()
|
|
235
254
|
});
|
|
236
|
-
var
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
"
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
"\u{1F680}",
|
|
244
|
-
"\u2615"
|
|
245
|
-
];
|
|
246
|
-
var reactionEmojiSchema = z3.enum(REACTION_EMOJI);
|
|
247
|
-
var toggleReactionSchema = z3.object({
|
|
255
|
+
var SINGLE_EMOJI = new RegExp("^\\p{RGI_Emoji}$", "v");
|
|
256
|
+
var REDUNDANT_VS16 = new RegExp("(\\p{Emoji_Presentation})\\uFE0F", "gu");
|
|
257
|
+
function canonicalizeEmoji(s) {
|
|
258
|
+
return s.replace(REDUNDANT_VS16, "$1");
|
|
259
|
+
}
|
|
260
|
+
var reactionEmojiSchema = z4.string().max(64).transform(canonicalizeEmoji).refine((s) => SINGLE_EMOJI.test(s), { message: "Must be a single emoji." }).describe("A single emoji, e.g. \u{1F44D}");
|
|
261
|
+
var toggleReactionSchema = z4.object({
|
|
248
262
|
emoji: reactionEmojiSchema,
|
|
249
263
|
guest: guestSchema.optional()
|
|
250
264
|
});
|
|
251
|
-
var commentAuthorSchema =
|
|
252
|
-
avatarUrl:
|
|
253
|
-
displayName:
|
|
254
|
-
guestId:
|
|
255
|
-
isViewer:
|
|
256
|
-
kind:
|
|
265
|
+
var commentAuthorSchema = z4.object({
|
|
266
|
+
avatarUrl: z4.string().nullable(),
|
|
267
|
+
displayName: z4.string(),
|
|
268
|
+
guestId: z4.string().nullable(),
|
|
269
|
+
isViewer: z4.boolean(),
|
|
270
|
+
kind: z4.enum(["member", "guest"]),
|
|
257
271
|
// Optional "via" attribution (§6.4). Null for plain comments; a bounded
|
|
258
272
|
// label the shell appends after the display name.
|
|
259
|
-
via:
|
|
273
|
+
via: z4.string().nullable()
|
|
260
274
|
});
|
|
261
|
-
var messageReactionSchema =
|
|
262
|
-
emoji:
|
|
263
|
-
reactors:
|
|
275
|
+
var messageReactionSchema = z4.object({
|
|
276
|
+
emoji: z4.string(),
|
|
277
|
+
reactors: z4.array(commentAuthorSchema)
|
|
264
278
|
});
|
|
265
|
-
var commentMessageSchema =
|
|
279
|
+
var commentMessageSchema = z4.object({
|
|
266
280
|
author: commentAuthorSchema,
|
|
267
281
|
// Empty string for a deleted message — the body is stripped server-side
|
|
268
282
|
// (§6.7.1 tombstone), never sent to the client and hidden there.
|
|
269
|
-
body:
|
|
270
|
-
createdAt:
|
|
283
|
+
body: z4.string(),
|
|
284
|
+
createdAt: z4.string(),
|
|
271
285
|
// Soft-deleted (§6.7.1). A tombstone keeps thread structure and replies;
|
|
272
286
|
// the shell renders "Comment deleted" instead of the (absent) body.
|
|
273
|
-
deleted:
|
|
287
|
+
deleted: z4.boolean(),
|
|
274
288
|
// Last edit time (§6.7.1), or null if never edited — drives the "edited"
|
|
275
289
|
// badge. No edit history is kept.
|
|
276
|
-
editedAt:
|
|
277
|
-
id:
|
|
290
|
+
editedAt: z4.string().nullable(),
|
|
291
|
+
id: z4.string(),
|
|
278
292
|
// Defaulted, not required: a new CLI parsing an older server's
|
|
279
293
|
// response must not fail on the missing key.
|
|
280
|
-
reactions:
|
|
281
|
-
});
|
|
282
|
-
var
|
|
294
|
+
reactions: z4.array(messageReactionSchema).default([])
|
|
295
|
+
});
|
|
296
|
+
var threadActorSchema = z4.object({
|
|
297
|
+
displayName: z4.string(),
|
|
298
|
+
kind: z4.enum(["member", "guest", "agent"])
|
|
299
|
+
});
|
|
300
|
+
var commentThreadSchema = z4.object({
|
|
301
|
+
// §6.6.1 — set while open to signal "seen, working on it"; cleared on
|
|
302
|
+
// reopen, kept (but superseded in display) once resolved. Defaulted so
|
|
303
|
+
// clients parsing an older server's response don't fail.
|
|
304
|
+
acknowledgedAt: z4.string().nullable().default(null),
|
|
305
|
+
acknowledgedBy: threadActorSchema.nullable().default(null),
|
|
283
306
|
anchor: anchorSchema,
|
|
284
|
-
artifactId:
|
|
285
|
-
createdAt:
|
|
307
|
+
artifactId: z4.string(),
|
|
308
|
+
createdAt: z4.string(),
|
|
286
309
|
createdBy: commentAuthorSchema,
|
|
287
|
-
id:
|
|
288
|
-
messages:
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
});
|
|
295
|
-
var
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
310
|
+
id: z4.string(),
|
|
311
|
+
messages: z4.array(commentMessageSchema),
|
|
312
|
+
// Null on threads resolved before actor recording existed, and always
|
|
313
|
+
// null while open.
|
|
314
|
+
resolvedBy: threadActorSchema.nullable().default(null),
|
|
315
|
+
status: z4.enum(["open", "resolved"]),
|
|
316
|
+
versionId: z4.string()
|
|
317
|
+
});
|
|
318
|
+
var commentThreadListSchema = z4.object({
|
|
319
|
+
threads: z4.array(commentThreadSchema)
|
|
320
|
+
});
|
|
321
|
+
var commentExportQuerySchema = z4.object({
|
|
322
|
+
status: z4.enum(["open", "resolved", "all"]).default("open"),
|
|
323
|
+
version: z4.enum(["current", "all"]).default("current")
|
|
324
|
+
});
|
|
325
|
+
var exportReactionSchema = z4.object({
|
|
326
|
+
count: z4.number().int().positive(),
|
|
327
|
+
emoji: z4.string()
|
|
328
|
+
});
|
|
329
|
+
var commentExportReplySchema = z4.object({
|
|
330
|
+
author: z4.string(),
|
|
331
|
+
authorKind: z4.enum(["member", "guest"]),
|
|
332
|
+
body: z4.string(),
|
|
333
|
+
createdAt: z4.string(),
|
|
308
334
|
// Soft-delete tombstone (§6.7.1): body is "" when true.
|
|
309
|
-
deleted:
|
|
310
|
-
editedAt:
|
|
335
|
+
deleted: z4.boolean(),
|
|
336
|
+
editedAt: z4.string().nullable(),
|
|
311
337
|
// The message id — what `edit`/`delete` target (§5.1).
|
|
312
|
-
id:
|
|
313
|
-
reactions:
|
|
338
|
+
id: z4.string(),
|
|
339
|
+
reactions: z4.array(exportReactionSchema).optional()
|
|
314
340
|
});
|
|
315
|
-
var commentExportThreadSchema =
|
|
341
|
+
var commentExportThreadSchema = z4.object({
|
|
342
|
+
// §6.6.1 — lets a polling agent skip threads it already acknowledged
|
|
343
|
+
// (acknowledged threads stay in status=open exports on purpose).
|
|
344
|
+
acknowledgedAt: z4.string().nullable().default(null),
|
|
316
345
|
anchor: anchorSchema,
|
|
317
|
-
author:
|
|
318
|
-
authorKind:
|
|
319
|
-
body:
|
|
320
|
-
createdAt:
|
|
321
|
-
deleted:
|
|
322
|
-
editedAt:
|
|
323
|
-
id:
|
|
346
|
+
author: z4.string(),
|
|
347
|
+
authorKind: z4.enum(["member", "guest"]),
|
|
348
|
+
body: z4.string(),
|
|
349
|
+
createdAt: z4.string(),
|
|
350
|
+
deleted: z4.boolean(),
|
|
351
|
+
editedAt: z4.string().nullable(),
|
|
352
|
+
id: z4.string(),
|
|
324
353
|
// The opening message's id (distinct from the thread `id`) — `edit`/
|
|
325
354
|
// `delete` operate on messages, so the CLI needs it to target the first
|
|
326
355
|
// comment, not just the replies.
|
|
327
|
-
messageId:
|
|
328
|
-
reactions:
|
|
329
|
-
replies:
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
356
|
+
messageId: z4.string(),
|
|
357
|
+
reactions: z4.array(exportReactionSchema).optional(),
|
|
358
|
+
replies: z4.array(commentExportReplySchema),
|
|
359
|
+
resolvedBy: threadActorSchema.nullable().default(null),
|
|
360
|
+
status: z4.enum(["open", "resolved"]),
|
|
361
|
+
versionNumber: z4.number().int().positive()
|
|
362
|
+
});
|
|
363
|
+
var commentExportSchema = z4.object({
|
|
364
|
+
artifactId: z4.string(),
|
|
365
|
+
comments: z4.array(commentExportThreadSchema),
|
|
336
366
|
// The artifact's current version (null before the first finalize).
|
|
337
|
-
versionNumber:
|
|
367
|
+
versionNumber: z4.number().int().positive().nullable()
|
|
338
368
|
});
|
|
339
|
-
var commentReadResponseSchema =
|
|
340
|
-
lastSeenAt:
|
|
369
|
+
var commentReadResponseSchema = z4.object({
|
|
370
|
+
lastSeenAt: z4.string()
|
|
341
371
|
});
|
|
342
372
|
function elementLabel(el) {
|
|
343
373
|
if (el.id) {
|
|
@@ -348,163 +378,228 @@ function elementLabel(el) {
|
|
|
348
378
|
}
|
|
349
379
|
|
|
350
380
|
// ../shared/src/errors.ts
|
|
351
|
-
import { z as
|
|
352
|
-
var apiErrorSchema =
|
|
353
|
-
code:
|
|
354
|
-
docsUrl:
|
|
355
|
-
message:
|
|
356
|
-
retryAfter:
|
|
381
|
+
import { z as z5 } from "zod";
|
|
382
|
+
var apiErrorSchema = z5.object({
|
|
383
|
+
code: z5.string(),
|
|
384
|
+
docsUrl: z5.string().url(),
|
|
385
|
+
message: z5.string(),
|
|
386
|
+
retryAfter: z5.number().int().positive().optional()
|
|
357
387
|
});
|
|
358
388
|
|
|
359
389
|
// ../shared/src/feedback.ts
|
|
360
|
-
import { z as
|
|
361
|
-
var feedbackRequestSchema =
|
|
362
|
-
email:
|
|
363
|
-
message:
|
|
390
|
+
import { z as z6 } from "zod";
|
|
391
|
+
var feedbackRequestSchema = z6.object({
|
|
392
|
+
email: z6.string().trim().toLowerCase().email().optional().or(z6.literal("")),
|
|
393
|
+
message: z6.string().trim().min(1).max(4e3)
|
|
364
394
|
});
|
|
365
|
-
var feedbackResponseSchema =
|
|
366
|
-
sent:
|
|
395
|
+
var feedbackResponseSchema = z6.object({
|
|
396
|
+
sent: z6.literal(true)
|
|
367
397
|
});
|
|
368
398
|
|
|
369
|
-
// ../shared/src/
|
|
370
|
-
import { z as
|
|
371
|
-
var
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
// both null for personal artifacts. `folderId` drives the dashboard's
|
|
379
|
-
// move control and folder filter; `folderName` is the display label.
|
|
380
|
-
folderId: z6.string().nullable(),
|
|
381
|
-
folderName: z6.string().nullable(),
|
|
382
|
-
// Whether a publish token is still active — revocable from the
|
|
383
|
-
// dashboard (§6.18); the token itself is never returned.
|
|
384
|
-
hasPublishToken: z6.boolean(),
|
|
385
|
-
id: z6.string(),
|
|
386
|
-
openThreads: z6.number(),
|
|
387
|
-
protected: z6.boolean(),
|
|
388
|
-
slug: z6.string(),
|
|
389
|
-
title: z6.string(),
|
|
390
|
-
totalViews: z6.number(),
|
|
391
|
-
// SPEC §6.20 — messages by others newer than the viewer's last-seen
|
|
392
|
-
// watermark. 0 for signed-out/API-key-less contexts.
|
|
393
|
-
unreadComments: z6.number(),
|
|
394
|
-
updatedAt: z6.string(),
|
|
395
|
-
url: z6.string(),
|
|
396
|
-
versionCount: z6.number()
|
|
399
|
+
// ../shared/src/grants.ts
|
|
400
|
+
import { z as z7 } from "zod";
|
|
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"
|
|
397
408
|
});
|
|
398
|
-
var
|
|
399
|
-
|
|
409
|
+
var grantSchema = z7.object({
|
|
410
|
+
createdAt: z7.string(),
|
|
411
|
+
email: z7.string().email().nullable(),
|
|
412
|
+
expiresAt: z7.string().nullable(),
|
|
413
|
+
id: z7.string(),
|
|
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()
|
|
400
429
|
});
|
|
401
|
-
var
|
|
402
|
-
|
|
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(),
|
|
446
|
+
slug: z7.string(),
|
|
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)
|
|
466
|
+
});
|
|
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()
|
|
474
|
+
});
|
|
475
|
+
var sharedWithMeListResponseSchema = z7.object({
|
|
476
|
+
artifacts: z7.array(sharedWithMeArtifactSchema)
|
|
403
477
|
});
|
|
404
478
|
|
|
405
|
-
// ../shared/src/
|
|
406
|
-
import { z as
|
|
479
|
+
// ../shared/src/me.ts
|
|
480
|
+
import { z as z9 } from "zod";
|
|
407
481
|
|
|
408
482
|
// ../shared/src/workspaces.ts
|
|
409
|
-
import { z as
|
|
483
|
+
import { z as z8 } from "zod";
|
|
410
484
|
var WORKSPACE_HANDLE_PATTERN = /^[a-z0-9](?:[a-z0-9-]{1,30}[a-z0-9])$/;
|
|
411
|
-
var
|
|
412
|
-
|
|
413
|
-
|
|
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
|
+
});
|
|
498
|
+
var workspaceRoleSchema = z8.enum(["owner", "admin", "member"]);
|
|
499
|
+
var workspaceInviteRoleSchema = z8.enum(["admin", "member"]);
|
|
500
|
+
var workspaceHandleSchema = z8.string().min(3).max(32).regex(WORKSPACE_HANDLE_PATTERN, {
|
|
414
501
|
message: "handle must be lowercase letters, digits, and hyphens, with no leading/trailing hyphen"
|
|
415
502
|
});
|
|
416
|
-
var createWorkspaceSchema =
|
|
503
|
+
var createWorkspaceSchema = z8.object({
|
|
417
504
|
handle: workspaceHandleSchema.optional(),
|
|
418
|
-
name:
|
|
505
|
+
name: z8.string().trim().min(1).max(100)
|
|
419
506
|
});
|
|
420
|
-
var updateWorkspaceSchema =
|
|
507
|
+
var updateWorkspaceSchema = z8.object({
|
|
421
508
|
handle: workspaceHandleSchema.optional(),
|
|
422
|
-
name:
|
|
509
|
+
name: z8.string().trim().min(1).max(100).optional()
|
|
423
510
|
}).refine((body) => body.handle !== void 0 || body.name !== void 0, {
|
|
424
511
|
message: "provide at least one of name or handle"
|
|
425
512
|
});
|
|
426
|
-
var workspaceSchema =
|
|
427
|
-
createdAt:
|
|
428
|
-
handle:
|
|
429
|
-
|
|
513
|
+
var workspaceSchema = z8.object({
|
|
514
|
+
createdAt: z8.string(),
|
|
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(),
|
|
520
|
+
id: z8.string(),
|
|
430
521
|
// Auto-provisioned solo workspace, one per user: non-deletable, takes
|
|
431
522
|
// no members, renameable like any workspace.
|
|
432
|
-
isPersonal:
|
|
433
|
-
|
|
523
|
+
isPersonal: z8.boolean(),
|
|
524
|
+
// Uploaded logo URL, or null for the initials fallback. Set through the
|
|
525
|
+
// dedicated /workspaces/:id/avatar route, never the generic update.
|
|
526
|
+
logo: z8.string().nullable(),
|
|
527
|
+
name: z8.string(),
|
|
434
528
|
role: workspaceRoleSchema.nullable(),
|
|
435
|
-
updatedAt:
|
|
529
|
+
updatedAt: z8.string()
|
|
436
530
|
});
|
|
437
|
-
var workspaceListResponseSchema =
|
|
438
|
-
workspaces:
|
|
531
|
+
var workspaceListResponseSchema = z8.object({
|
|
532
|
+
workspaces: z8.array(workspaceSchema)
|
|
439
533
|
});
|
|
440
|
-
var deleteWorkspaceResponseSchema =
|
|
441
|
-
deleted:
|
|
534
|
+
var deleteWorkspaceResponseSchema = z8.object({
|
|
535
|
+
deleted: z8.literal(true)
|
|
442
536
|
});
|
|
443
|
-
var workspaceMemberSchema =
|
|
444
|
-
createdAt:
|
|
445
|
-
email:
|
|
446
|
-
image:
|
|
447
|
-
name:
|
|
537
|
+
var workspaceMemberSchema = z8.object({
|
|
538
|
+
createdAt: z8.string(),
|
|
539
|
+
email: z8.string().email(),
|
|
540
|
+
image: z8.string().nullable(),
|
|
541
|
+
name: z8.string(),
|
|
448
542
|
role: workspaceRoleSchema,
|
|
449
|
-
userId:
|
|
543
|
+
userId: z8.string()
|
|
450
544
|
});
|
|
451
|
-
var workspaceMemberListResponseSchema =
|
|
452
|
-
members:
|
|
545
|
+
var workspaceMemberListResponseSchema = z8.object({
|
|
546
|
+
members: z8.array(workspaceMemberSchema)
|
|
453
547
|
});
|
|
454
|
-
var updateWorkspaceMemberSchema =
|
|
548
|
+
var updateWorkspaceMemberSchema = z8.object({
|
|
455
549
|
role: workspaceRoleSchema
|
|
456
550
|
});
|
|
457
|
-
var removeWorkspaceMemberResponseSchema =
|
|
458
|
-
removed:
|
|
551
|
+
var removeWorkspaceMemberResponseSchema = z8.object({
|
|
552
|
+
removed: z8.literal(true)
|
|
459
553
|
});
|
|
460
|
-
var createWorkspaceInviteSchema =
|
|
461
|
-
email:
|
|
462
|
-
expiresAt:
|
|
463
|
-
maxUses:
|
|
554
|
+
var createWorkspaceInviteSchema = z8.object({
|
|
555
|
+
email: z8.string().trim().toLowerCase().email().optional(),
|
|
556
|
+
expiresAt: z8.string().datetime(),
|
|
557
|
+
maxUses: z8.number().int().positive().optional(),
|
|
464
558
|
role: workspaceInviteRoleSchema
|
|
465
559
|
});
|
|
466
|
-
var workspaceInviteSchema =
|
|
467
|
-
createdAt:
|
|
468
|
-
email:
|
|
469
|
-
expiresAt:
|
|
470
|
-
id:
|
|
471
|
-
maxUses:
|
|
560
|
+
var workspaceInviteSchema = z8.object({
|
|
561
|
+
createdAt: z8.string(),
|
|
562
|
+
email: z8.string().email().nullable(),
|
|
563
|
+
expiresAt: z8.string(),
|
|
564
|
+
id: z8.string(),
|
|
565
|
+
maxUses: z8.number().int().positive().nullable(),
|
|
472
566
|
role: workspaceInviteRoleSchema,
|
|
473
|
-
tokenPrefix:
|
|
474
|
-
useCount:
|
|
567
|
+
tokenPrefix: z8.string(),
|
|
568
|
+
useCount: z8.number().int().nonnegative()
|
|
475
569
|
});
|
|
476
570
|
var createdWorkspaceInviteSchema = workspaceInviteSchema.extend({
|
|
477
|
-
url:
|
|
571
|
+
url: z8.string().url()
|
|
478
572
|
});
|
|
479
|
-
var workspaceInviteListResponseSchema =
|
|
480
|
-
invites:
|
|
573
|
+
var workspaceInviteListResponseSchema = z8.object({
|
|
574
|
+
invites: z8.array(workspaceInviteSchema)
|
|
481
575
|
});
|
|
482
|
-
var revokeWorkspaceInviteResponseSchema =
|
|
483
|
-
revoked:
|
|
576
|
+
var revokeWorkspaceInviteResponseSchema = z8.object({
|
|
577
|
+
revoked: z8.literal(true)
|
|
484
578
|
});
|
|
485
|
-
var acceptWorkspaceInviteSchema =
|
|
486
|
-
token:
|
|
579
|
+
var acceptWorkspaceInviteSchema = z8.object({
|
|
580
|
+
token: z8.string().min(1)
|
|
487
581
|
});
|
|
488
|
-
var acceptWorkspaceInviteResponseSchema =
|
|
582
|
+
var acceptWorkspaceInviteResponseSchema = z8.object({
|
|
489
583
|
role: workspaceRoleSchema,
|
|
490
584
|
workspace: workspaceSchema
|
|
491
585
|
});
|
|
492
|
-
var folderVisibilitySchema =
|
|
493
|
-
var artifactVisibilitySchema =
|
|
586
|
+
var folderVisibilitySchema = z8.enum(["public", "workspace"]);
|
|
587
|
+
var artifactVisibilitySchema = z8.enum([
|
|
494
588
|
"public",
|
|
495
589
|
"unlisted",
|
|
496
|
-
"workspace"
|
|
590
|
+
"workspace",
|
|
591
|
+
"private"
|
|
497
592
|
]);
|
|
498
|
-
var createFolderSchema =
|
|
499
|
-
name:
|
|
593
|
+
var createFolderSchema = z8.object({
|
|
594
|
+
name: z8.string().trim().min(1).max(100),
|
|
500
595
|
visibility: folderVisibilitySchema
|
|
501
596
|
});
|
|
502
|
-
var updateFolderSchema =
|
|
597
|
+
var updateFolderSchema = z8.object({
|
|
503
598
|
// With `visibility`: bulk-update the folder's artifacts to match
|
|
504
599
|
// (SPEC-2 §3.4 "Changing a folder's visibility offers a bulk update").
|
|
505
|
-
cascade:
|
|
506
|
-
name:
|
|
507
|
-
sortOrder:
|
|
600
|
+
cascade: z8.boolean().optional(),
|
|
601
|
+
name: z8.string().trim().min(1).max(100).optional(),
|
|
602
|
+
sortOrder: z8.number().int().min(0).optional(),
|
|
508
603
|
visibility: folderVisibilitySchema.optional()
|
|
509
604
|
}).refine(
|
|
510
605
|
(body) => body.name !== void 0 || body.visibility !== void 0 || body.sortOrder !== void 0,
|
|
@@ -512,175 +607,263 @@ var updateFolderSchema = z7.object({
|
|
|
512
607
|
).refine((body) => !body.cascade || body.visibility !== void 0, {
|
|
513
608
|
message: "cascade requires visibility"
|
|
514
609
|
});
|
|
515
|
-
var folderSchema =
|
|
516
|
-
createdAt:
|
|
517
|
-
id:
|
|
518
|
-
name:
|
|
610
|
+
var folderSchema = z8.object({
|
|
611
|
+
createdAt: z8.string(),
|
|
612
|
+
id: z8.string(),
|
|
613
|
+
name: z8.string(),
|
|
519
614
|
// Permalink segment for the public folder page (/w/{handle}/f/{slug}).
|
|
520
615
|
// Server-derived from the name; renames regenerate it.
|
|
521
|
-
slug:
|
|
522
|
-
sortOrder:
|
|
523
|
-
updatedAt:
|
|
616
|
+
slug: z8.string(),
|
|
617
|
+
sortOrder: z8.number().int(),
|
|
618
|
+
updatedAt: z8.string(),
|
|
524
619
|
visibility: folderVisibilitySchema,
|
|
525
|
-
workspaceId:
|
|
620
|
+
workspaceId: z8.string()
|
|
526
621
|
});
|
|
527
|
-
var folderListResponseSchema =
|
|
528
|
-
folders:
|
|
622
|
+
var folderListResponseSchema = z8.object({
|
|
623
|
+
folders: z8.array(folderSchema)
|
|
529
624
|
});
|
|
530
|
-
var deleteFolderResponseSchema =
|
|
531
|
-
deleted:
|
|
625
|
+
var deleteFolderResponseSchema = z8.object({
|
|
626
|
+
deleted: z8.literal(true)
|
|
532
627
|
});
|
|
533
|
-
var workspaceArtifactSchema =
|
|
534
|
-
createdAt:
|
|
535
|
-
currentVersionNumber:
|
|
536
|
-
folderId:
|
|
537
|
-
id:
|
|
538
|
-
openCommentCount:
|
|
539
|
-
slug:
|
|
540
|
-
title:
|
|
541
|
-
updatedAt:
|
|
542
|
-
url:
|
|
543
|
-
versionCount:
|
|
628
|
+
var workspaceArtifactSchema = z8.object({
|
|
629
|
+
createdAt: z8.string(),
|
|
630
|
+
currentVersionNumber: z8.number().int().nullable(),
|
|
631
|
+
folderId: z8.string().nullable(),
|
|
632
|
+
id: z8.string(),
|
|
633
|
+
openCommentCount: z8.number().int().nonnegative(),
|
|
634
|
+
slug: z8.string(),
|
|
635
|
+
title: z8.string(),
|
|
636
|
+
updatedAt: z8.string(),
|
|
637
|
+
url: z8.string().url(),
|
|
638
|
+
versionCount: z8.number().int().nonnegative(),
|
|
544
639
|
visibility: artifactVisibilitySchema
|
|
545
640
|
});
|
|
546
|
-
var workspaceArtifactListResponseSchema =
|
|
547
|
-
artifacts:
|
|
641
|
+
var workspaceArtifactListResponseSchema = z8.object({
|
|
642
|
+
artifacts: z8.array(workspaceArtifactSchema)
|
|
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
|
+
});
|
|
652
|
+
|
|
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(),
|
|
676
|
+
slug: z9.string(),
|
|
677
|
+
title: z9.string(),
|
|
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()
|
|
548
702
|
});
|
|
549
703
|
|
|
550
704
|
// ../shared/src/owner.ts
|
|
705
|
+
import { z as z10 } from "zod";
|
|
551
706
|
var SLUG_PATTERN = /^[a-z0-9](?:[a-z0-9-]{1,61}[a-z0-9])$/;
|
|
552
|
-
var claimResponseSchema =
|
|
553
|
-
artifactId:
|
|
554
|
-
slug:
|
|
555
|
-
title:
|
|
556
|
-
url:
|
|
707
|
+
var claimResponseSchema = z10.object({
|
|
708
|
+
artifactId: z10.string(),
|
|
709
|
+
slug: z10.string(),
|
|
710
|
+
title: z10.string(),
|
|
711
|
+
url: z10.string().url()
|
|
557
712
|
});
|
|
558
|
-
var updateArtifactSchema =
|
|
713
|
+
var updateArtifactSchema = z10.object({
|
|
559
714
|
// SPEC-2 §6.4 — placement + visibility. `folderId: null` clears the
|
|
560
715
|
// folder; `workspaceId: null` moves the artifact out of its workspace
|
|
561
716
|
// (§5.5 ownership transfer).
|
|
562
|
-
folderId:
|
|
563
|
-
slug:
|
|
717
|
+
folderId: z10.string().min(1).nullable().optional(),
|
|
718
|
+
slug: z10.string().min(3).max(63).regex(SLUG_PATTERN, {
|
|
564
719
|
message: "slug must be lowercase letters, digits, and hyphens, with no leading/trailing hyphen"
|
|
565
720
|
}).optional(),
|
|
566
|
-
title:
|
|
721
|
+
title: z10.string().min(1).max(200).optional(),
|
|
567
722
|
visibility: artifactVisibilitySchema.optional(),
|
|
568
|
-
workspaceId:
|
|
723
|
+
workspaceId: z10.string().min(1).nullable().optional()
|
|
569
724
|
}).refine(
|
|
570
725
|
(body) => body.title !== void 0 || body.slug !== void 0 || body.visibility !== void 0 || body.folderId !== void 0 || body.workspaceId !== void 0,
|
|
571
726
|
{
|
|
572
727
|
message: "provide at least one of title, slug, visibility, folderId, workspaceId"
|
|
573
728
|
}
|
|
574
729
|
);
|
|
575
|
-
var deleteArtifactResponseSchema =
|
|
576
|
-
deleted:
|
|
730
|
+
var deleteArtifactResponseSchema = z10.object({
|
|
731
|
+
deleted: z10.literal(true)
|
|
577
732
|
});
|
|
578
733
|
|
|
579
734
|
// ../shared/src/presence.ts
|
|
580
|
-
import { z as
|
|
735
|
+
import { z as z11 } from "zod";
|
|
736
|
+
var AGENT_STATES = ["listening", "editing", "publishing"];
|
|
737
|
+
var agentStateSchema = z11.enum(AGENT_STATES);
|
|
581
738
|
var AGENT_PRESENCE = {
|
|
739
|
+
editingTtlSeconds: 300,
|
|
582
740
|
heartbeatSeconds: 15,
|
|
583
741
|
shellPollSeconds: 15,
|
|
584
742
|
ttlSeconds: 45
|
|
585
743
|
};
|
|
586
|
-
var
|
|
587
|
-
|
|
588
|
-
|
|
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()
|
|
589
751
|
});
|
|
590
|
-
var agentPresenceSchema =
|
|
591
|
-
listening:
|
|
592
|
-
|
|
752
|
+
var agentPresenceSchema = z11.object({
|
|
753
|
+
listening: z11.boolean(),
|
|
754
|
+
state: agentStateSchema.nullable().optional(),
|
|
755
|
+
versionNumber: z11.number().int().positive().nullable()
|
|
593
756
|
});
|
|
594
757
|
|
|
595
758
|
// ../shared/src/protection.ts
|
|
596
|
-
import { z as
|
|
759
|
+
import { z as z12 } from "zod";
|
|
597
760
|
var PASSWORD_MIN = 6;
|
|
598
761
|
var PASSWORD_MAX = 128;
|
|
599
|
-
var gatePasswordSchema =
|
|
600
|
-
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({
|
|
601
764
|
password: gatePasswordSchema.nullable()
|
|
602
765
|
});
|
|
603
|
-
var protectionResponseSchema =
|
|
604
|
-
protected:
|
|
766
|
+
var protectionResponseSchema = z12.object({
|
|
767
|
+
protected: z12.boolean()
|
|
605
768
|
});
|
|
606
|
-
var unlockSchema =
|
|
607
|
-
password:
|
|
769
|
+
var unlockSchema = z12.object({
|
|
770
|
+
password: z12.string().min(1).max(1024)
|
|
608
771
|
});
|
|
609
|
-
var unlockResponseSchema =
|
|
610
|
-
unlocked:
|
|
772
|
+
var unlockResponseSchema = z12.object({
|
|
773
|
+
unlocked: z12.literal(true)
|
|
611
774
|
});
|
|
612
775
|
|
|
613
776
|
// ../shared/src/report.ts
|
|
614
|
-
import { z as
|
|
615
|
-
var reportRequestSchema =
|
|
616
|
-
reason:
|
|
777
|
+
import { z as z13 } from "zod";
|
|
778
|
+
var reportRequestSchema = z13.object({
|
|
779
|
+
reason: z13.string().max(1e3).optional()
|
|
617
780
|
});
|
|
618
|
-
var reportResponseSchema =
|
|
619
|
-
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)
|
|
620
801
|
});
|
|
621
802
|
|
|
622
803
|
// ../shared/src/stats.ts
|
|
623
|
-
import { z as
|
|
624
|
-
var avgViewSecondsSchema =
|
|
625
|
-
var versionViewStatsSchema =
|
|
804
|
+
import { z as z15 } from "zod";
|
|
805
|
+
var avgViewSecondsSchema = z15.number().int().nonnegative().nullable();
|
|
806
|
+
var versionViewStatsSchema = z15.object({
|
|
626
807
|
avgViewSeconds: avgViewSecondsSchema,
|
|
627
808
|
// Views from inside the review shell's iframe vs. direct visits to
|
|
628
809
|
// the render URL. views = embeddedViews + directViews.
|
|
629
|
-
directViews:
|
|
630
|
-
embeddedViews:
|
|
810
|
+
directViews: z15.number().int().nonnegative(),
|
|
811
|
+
embeddedViews: z15.number().int().nonnegative(),
|
|
631
812
|
// Distinct hashed viewer IPs across the version's lifetime.
|
|
632
|
-
uniqueViewers:
|
|
633
|
-
versionNumber:
|
|
634
|
-
views:
|
|
813
|
+
uniqueViewers: z15.number().int().nonnegative(),
|
|
814
|
+
versionNumber: z15.number().int().positive(),
|
|
815
|
+
views: z15.number().int().nonnegative()
|
|
635
816
|
});
|
|
636
|
-
var dailyViewsSchema =
|
|
817
|
+
var dailyViewsSchema = z15.object({
|
|
637
818
|
avgViewSeconds: avgViewSecondsSchema,
|
|
638
819
|
// UTC day, YYYY-MM-DD.
|
|
639
|
-
day:
|
|
640
|
-
uniqueViewers:
|
|
641
|
-
views:
|
|
820
|
+
day: z15.string(),
|
|
821
|
+
uniqueViewers: z15.number().int().nonnegative(),
|
|
822
|
+
views: z15.number().int().nonnegative()
|
|
642
823
|
});
|
|
643
|
-
var artifactStatsResponseSchema =
|
|
824
|
+
var artifactStatsResponseSchema = z15.object({
|
|
644
825
|
avgViewSeconds: avgViewSecondsSchema,
|
|
645
|
-
daily:
|
|
826
|
+
daily: z15.array(dailyViewsSchema),
|
|
646
827
|
// Distinct hashed viewer IPs across all versions and days.
|
|
647
|
-
totalUniqueViewers:
|
|
648
|
-
totalViews:
|
|
649
|
-
versions:
|
|
828
|
+
totalUniqueViewers: z15.number().int().nonnegative(),
|
|
829
|
+
totalViews: z15.number().int().nonnegative(),
|
|
830
|
+
versions: z15.array(versionViewStatsSchema)
|
|
650
831
|
});
|
|
651
832
|
|
|
652
833
|
// ../shared/src/versions.ts
|
|
653
|
-
import { z as
|
|
654
|
-
var versionSourceSchema =
|
|
655
|
-
agentName:
|
|
656
|
-
type:
|
|
834
|
+
import { z as z16 } from "zod";
|
|
835
|
+
var versionSourceSchema = z16.object({
|
|
836
|
+
agentName: z16.string().nullable(),
|
|
837
|
+
type: z16.string()
|
|
657
838
|
});
|
|
658
|
-
var versionChangesSchema =
|
|
659
|
-
added:
|
|
660
|
-
changed:
|
|
661
|
-
removed:
|
|
839
|
+
var versionChangesSchema = z16.object({
|
|
840
|
+
added: z16.array(z16.string()),
|
|
841
|
+
changed: z16.array(z16.string()),
|
|
842
|
+
removed: z16.array(z16.string())
|
|
662
843
|
});
|
|
663
|
-
var versionSummarySchema =
|
|
844
|
+
var versionSummarySchema = z16.object({
|
|
664
845
|
// Absent for the first version — there is no previous version to diff against.
|
|
665
846
|
changes: versionChangesSchema.nullable(),
|
|
666
|
-
createdAt:
|
|
667
|
-
entryUrl:
|
|
668
|
-
fileCount:
|
|
669
|
-
id:
|
|
670
|
-
isCurrent:
|
|
847
|
+
createdAt: z16.string(),
|
|
848
|
+
entryUrl: z16.string().url(),
|
|
849
|
+
fileCount: z16.number().int().nonnegative(),
|
|
850
|
+
id: z16.string(),
|
|
851
|
+
isCurrent: z16.boolean(),
|
|
852
|
+
// Author-supplied bullet-point changelog; null when the publish omitted it.
|
|
853
|
+
notes: z16.string().nullable(),
|
|
671
854
|
source: versionSourceSchema,
|
|
672
|
-
totalSizeBytes:
|
|
673
|
-
versionNumber:
|
|
855
|
+
totalSizeBytes: z16.number().int().nonnegative(),
|
|
856
|
+
versionNumber: z16.number().int().positive()
|
|
674
857
|
});
|
|
675
|
-
var versionListResponseSchema =
|
|
676
|
-
versions:
|
|
858
|
+
var versionListResponseSchema = z16.object({
|
|
859
|
+
versions: z16.array(versionSummarySchema)
|
|
677
860
|
});
|
|
678
861
|
|
|
679
862
|
// src/api.ts
|
|
680
863
|
var ApiRequestError = class extends Error {
|
|
681
|
-
constructor(
|
|
864
|
+
constructor(status2, code, message, retryAfter) {
|
|
682
865
|
super(message);
|
|
683
|
-
this.status =
|
|
866
|
+
this.status = status2;
|
|
684
867
|
this.code = code;
|
|
685
868
|
this.retryAfter = retryAfter;
|
|
686
869
|
this.name = "ApiRequestError";
|
|
@@ -729,13 +912,38 @@ function createApiClient(apiUrl2, publishToken) {
|
|
|
729
912
|
return {
|
|
730
913
|
// SPEC §6.19 — mark the agent as actively waiting for feedback.
|
|
731
914
|
// Authorized by the publish token this client was created with.
|
|
732
|
-
|
|
915
|
+
// SPEC §6.6.1 — mark an open thread acknowledged ("seen, working on
|
|
916
|
+
// it") without resolving it. Publish token or account key only —
|
|
917
|
+
// the server rejects guests.
|
|
918
|
+
async acknowledgeThread(threadId) {
|
|
919
|
+
return request(
|
|
920
|
+
`${base}/api/v1/comment-threads/${threadId}/acknowledge`,
|
|
921
|
+
{ body: "{}", headers, method: "POST" },
|
|
922
|
+
(d) => commentThreadSchema.parse(d)
|
|
923
|
+
);
|
|
924
|
+
},
|
|
925
|
+
async agentHeartbeat(artifactId, state) {
|
|
733
926
|
return request(
|
|
734
927
|
`${base}/api/v1/artifacts/${artifactId}/agent-presence`,
|
|
735
|
-
{
|
|
928
|
+
{
|
|
929
|
+
...state ? { body: JSON.stringify({ state }) } : {},
|
|
930
|
+
headers,
|
|
931
|
+
method: "POST"
|
|
932
|
+
},
|
|
736
933
|
(d) => agentHeartbeatResponseSchema.parse(d)
|
|
737
934
|
);
|
|
738
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
|
+
},
|
|
739
947
|
async createSession(body) {
|
|
740
948
|
return request(
|
|
741
949
|
`${base}/api/v1/publish`,
|
|
@@ -814,6 +1022,15 @@ function createApiClient(apiUrl2, publishToken) {
|
|
|
814
1022
|
(d) => folderListResponseSchema.parse(d)
|
|
815
1023
|
);
|
|
816
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
|
+
},
|
|
817
1034
|
async listWorkspaces() {
|
|
818
1035
|
return request(
|
|
819
1036
|
`${base}/api/v1/workspaces`,
|
|
@@ -858,6 +1075,14 @@ function createApiClient(apiUrl2, publishToken) {
|
|
|
858
1075
|
(d) => commentThreadSchema.parse(d)
|
|
859
1076
|
);
|
|
860
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
|
+
},
|
|
861
1086
|
// SPEC §6.16 — set a password (string) or clear it (null). Authorized
|
|
862
1087
|
// by the publish token this client was created with.
|
|
863
1088
|
async setProtection(artifactId, password) {
|
|
@@ -894,17 +1119,17 @@ import {
|
|
|
894
1119
|
writeFileSync as writeFileSync2
|
|
895
1120
|
} from "fs";
|
|
896
1121
|
import path2 from "path";
|
|
897
|
-
import { z as
|
|
1122
|
+
import { z as z18 } from "zod";
|
|
898
1123
|
|
|
899
1124
|
// src/credentials.ts
|
|
900
1125
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
901
1126
|
import { homedir } from "os";
|
|
902
1127
|
import path from "path";
|
|
903
|
-
import { z as
|
|
1128
|
+
import { z as z17 } from "zod";
|
|
904
1129
|
var DEFAULT_API_URL = "https://artifact.cafe";
|
|
905
|
-
var credentialsSchema =
|
|
906
|
-
keys:
|
|
907
|
-
version:
|
|
1130
|
+
var credentialsSchema = z17.object({
|
|
1131
|
+
keys: z17.record(z17.string(), z17.string()),
|
|
1132
|
+
version: z17.literal(1)
|
|
908
1133
|
});
|
|
909
1134
|
function credentialsPath() {
|
|
910
1135
|
return path.join(homedir(), ".artifactcafe", "credentials");
|
|
@@ -954,24 +1179,24 @@ function resolveApiKey(apiUrl2, flag) {
|
|
|
954
1179
|
}
|
|
955
1180
|
|
|
956
1181
|
// src/config.ts
|
|
957
|
-
var configSchema =
|
|
958
|
-
apiUrl:
|
|
959
|
-
artifactId:
|
|
960
|
-
folder:
|
|
961
|
-
folderId:
|
|
1182
|
+
var configSchema = z18.object({
|
|
1183
|
+
apiUrl: z18.string(),
|
|
1184
|
+
artifactId: z18.string(),
|
|
1185
|
+
folder: z18.string().optional(),
|
|
1186
|
+
folderId: z18.string().optional(),
|
|
962
1187
|
// Optional: a folder linked by `link` to an artifact you own carries no
|
|
963
1188
|
// token — owner actions authorize via your stored login instead. A first
|
|
964
1189
|
// publish still writes the anonymous-mode token here.
|
|
965
|
-
publishToken:
|
|
966
|
-
slug:
|
|
967
|
-
url:
|
|
968
|
-
workspace:
|
|
969
|
-
workspaceId:
|
|
970
|
-
workspaceKind:
|
|
971
|
-
});
|
|
972
|
-
var projectConfigSchema =
|
|
973
|
-
folder:
|
|
974
|
-
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)
|
|
975
1200
|
}).strict();
|
|
976
1201
|
var CONFIG_DIR = ".artifactcafe";
|
|
977
1202
|
var CONFIG_FILE = "config.json";
|
|
@@ -1007,7 +1232,7 @@ function readProjectConfig(dir) {
|
|
|
1007
1232
|
JSON.parse(readFileSync2(file, "utf8"))
|
|
1008
1233
|
);
|
|
1009
1234
|
} catch (error) {
|
|
1010
|
-
const message = error instanceof
|
|
1235
|
+
const message = error instanceof z18.ZodError ? error.issues[0]?.message ?? "invalid project target" : "invalid JSON";
|
|
1011
1236
|
throw new Error(`Invalid ${file}: ${message}.`);
|
|
1012
1237
|
}
|
|
1013
1238
|
}
|
|
@@ -1194,7 +1419,7 @@ async function comments(opts) {
|
|
|
1194
1419
|
`--version must be one of: ${VERSIONS.join(", ")} (got "${opts.version}").`
|
|
1195
1420
|
);
|
|
1196
1421
|
}
|
|
1197
|
-
const
|
|
1422
|
+
const status2 = opts.status;
|
|
1198
1423
|
const version = opts.version;
|
|
1199
1424
|
const dir = path4.resolve(opts.dir);
|
|
1200
1425
|
const target = resolveArtifactTarget(dir, {
|
|
@@ -1207,21 +1432,21 @@ async function comments(opts) {
|
|
|
1207
1432
|
if (opts.wait) {
|
|
1208
1433
|
await waitForFeedback(client, ref, {
|
|
1209
1434
|
json: opts.json,
|
|
1210
|
-
status,
|
|
1435
|
+
status: status2,
|
|
1211
1436
|
timeoutSeconds: opts.timeout,
|
|
1212
1437
|
version
|
|
1213
1438
|
});
|
|
1214
1439
|
return;
|
|
1215
1440
|
}
|
|
1216
1441
|
const data = await client.exportComments(target.artifactId, {
|
|
1217
|
-
status,
|
|
1442
|
+
status: status2,
|
|
1218
1443
|
version
|
|
1219
1444
|
});
|
|
1220
1445
|
if (opts.json) {
|
|
1221
1446
|
console.log(JSON.stringify(data, null, 2));
|
|
1222
1447
|
return;
|
|
1223
1448
|
}
|
|
1224
|
-
printHuman(data, url,
|
|
1449
|
+
printHuman(data, url, status2, version);
|
|
1225
1450
|
}
|
|
1226
1451
|
async function deriveReviewUrl(client, target) {
|
|
1227
1452
|
const artifact = await client.getArtifact(target.artifactId);
|
|
@@ -1283,6 +1508,10 @@ async function waitForFeedback(client, config, opts) {
|
|
|
1283
1508
|
await sleep(settleSeconds());
|
|
1284
1509
|
const settled = await client.exportComments(config.artifactId, query);
|
|
1285
1510
|
const changed = diffThreads(baseline, settled);
|
|
1511
|
+
try {
|
|
1512
|
+
await client.agentHeartbeat(config.artifactId, "editing");
|
|
1513
|
+
} catch {
|
|
1514
|
+
}
|
|
1286
1515
|
printWaitResult(config, settled, changed, opts.json);
|
|
1287
1516
|
return;
|
|
1288
1517
|
}
|
|
@@ -1333,8 +1562,8 @@ ${changed.length} thread${plural} with new feedback \u2014 ${config.url}
|
|
|
1333
1562
|
printThread(thread);
|
|
1334
1563
|
}
|
|
1335
1564
|
}
|
|
1336
|
-
function printHuman(data, url,
|
|
1337
|
-
const statusLabel =
|
|
1565
|
+
function printHuman(data, url, status2, version) {
|
|
1566
|
+
const statusLabel = status2 === "all" ? "" : `${status2} `;
|
|
1338
1567
|
let scope = "across all versions";
|
|
1339
1568
|
if (version === "current") {
|
|
1340
1569
|
scope = data.versionNumber === null ? "on the current version" : `on v${data.versionNumber}`;
|
|
@@ -1356,8 +1585,14 @@ function printThread(t) {
|
|
|
1356
1585
|
const marker = t.status === "resolved" ? "\u2713" : "\u25CF";
|
|
1357
1586
|
const date = t.createdAt.slice(0, 10);
|
|
1358
1587
|
const edited = t.editedAt && !t.deleted ? " \xB7 edited" : "";
|
|
1588
|
+
let state = "";
|
|
1589
|
+
if (t.status === "resolved" && t.resolvedBy) {
|
|
1590
|
+
state = ` \xB7 resolved by ${t.resolvedBy.displayName}`;
|
|
1591
|
+
} else if (t.status === "open" && t.acknowledgedAt) {
|
|
1592
|
+
state = " \xB7 acknowledged";
|
|
1593
|
+
}
|
|
1359
1594
|
console.log(
|
|
1360
|
-
`${marker} ${t.author} \xB7 v${t.versionNumber} \xB7 ${date} \xB7 ${t.id}${edited}`
|
|
1595
|
+
`${marker} ${t.author} \xB7 v${t.versionNumber} \xB7 ${date} \xB7 ${t.id}${edited}${state}`
|
|
1361
1596
|
);
|
|
1362
1597
|
if (t.anchor.type === "text") {
|
|
1363
1598
|
console.log(` \u21B3 "${t.anchor.quote}"`);
|
|
@@ -1558,6 +1793,9 @@ async function publish(opts) {
|
|
|
1558
1793
|
entryPath,
|
|
1559
1794
|
files: files.map(({ absPath: _absPath, ...manifest }) => manifest),
|
|
1560
1795
|
...placement.folderId ? { folderId: placement.folderId } : {},
|
|
1796
|
+
// Agents often pass a double-quoted string where "\n" is a literal
|
|
1797
|
+
// backslash-n; turn those back into real newlines so bullets survive.
|
|
1798
|
+
...opts.notes?.trim() ? { notes: opts.notes.replace(/\\n/g, "\n").trim() } : {},
|
|
1561
1799
|
source: {
|
|
1562
1800
|
agent: process.env.ARTIFACT_CAFE_AGENT,
|
|
1563
1801
|
runId: process.env.ARTIFACT_CAFE_RUN_ID,
|
|
@@ -1584,17 +1822,26 @@ async function publish(opts) {
|
|
|
1584
1822
|
log(
|
|
1585
1823
|
` uploading ${session.filesToUpload.length} file(s)` + (session.skippedFiles.length ? `, ${session.skippedFiles.length} unchanged` : "")
|
|
1586
1824
|
);
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
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
|
+
}
|
|
1596
1841
|
);
|
|
1597
|
-
}
|
|
1842
|
+
} finally {
|
|
1843
|
+
presence.stop();
|
|
1844
|
+
}
|
|
1598
1845
|
const result = await client.finalize(session.publishSessionId);
|
|
1599
1846
|
const rememberedProjectFile = placement.rememberProjectDefault ? writeProjectConfig(dir, placement.rememberProjectDefault) : null;
|
|
1600
1847
|
const existingToken = config?.artifactId === result.artifactId ? config.publishToken : void 0;
|
|
@@ -1863,6 +2110,16 @@ Publish where? [1-${choices.length}]: `, (answer) => {
|
|
|
1863
2110
|
});
|
|
1864
2111
|
});
|
|
1865
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
|
+
}
|
|
1866
2123
|
async function inBatches(items, concurrency, fn) {
|
|
1867
2124
|
let next = 0;
|
|
1868
2125
|
const workers = Array.from(
|
|
@@ -2442,10 +2699,29 @@ async function changeThreadStatus(opts) {
|
|
|
2442
2699
|
artifact: opts.artifact
|
|
2443
2700
|
});
|
|
2444
2701
|
const client = createApiClient(target.apiUrl, target.credential);
|
|
2445
|
-
const
|
|
2702
|
+
const call = {
|
|
2703
|
+
ack: () => client.acknowledgeThread(threadId),
|
|
2704
|
+
reopen: () => client.reopenThread(threadId),
|
|
2705
|
+
resolve: () => client.resolveThread(threadId)
|
|
2706
|
+
}[opts.action];
|
|
2707
|
+
const thread = await call();
|
|
2446
2708
|
if (opts.json) {
|
|
2447
2709
|
console.log(
|
|
2448
|
-
JSON.stringify(
|
|
2710
|
+
JSON.stringify(
|
|
2711
|
+
{
|
|
2712
|
+
acknowledgedAt: thread.acknowledgedAt,
|
|
2713
|
+
id: thread.id,
|
|
2714
|
+
status: thread.status
|
|
2715
|
+
},
|
|
2716
|
+
null,
|
|
2717
|
+
2
|
|
2718
|
+
)
|
|
2719
|
+
);
|
|
2720
|
+
return;
|
|
2721
|
+
}
|
|
2722
|
+
if (opts.action === "ack") {
|
|
2723
|
+
console.log(
|
|
2724
|
+
`\u2713 Acknowledged ${thread.id} \u2014 reviewers now see it as being handled.`
|
|
2449
2725
|
);
|
|
2450
2726
|
return;
|
|
2451
2727
|
}
|
|
@@ -2453,30 +2729,145 @@ async function changeThreadStatus(opts) {
|
|
|
2453
2729
|
console.log(`\u2713 ${verb} ${thread.id} \u2014 now ${thread.status}.`);
|
|
2454
2730
|
}
|
|
2455
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
|
+
|
|
2456
2847
|
// src/update.ts
|
|
2457
2848
|
import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "fs";
|
|
2458
2849
|
import { createRequire } from "module";
|
|
2459
2850
|
import { homedir as homedir2 } from "os";
|
|
2460
|
-
import
|
|
2461
|
-
import { z as
|
|
2851
|
+
import path16 from "path";
|
|
2852
|
+
import { z as z19 } from "zod";
|
|
2462
2853
|
var REGISTRY_LATEST_URL = "https://registry.npmjs.org/artifact-cafe/latest";
|
|
2463
2854
|
var SKILL_SOURCE_URL = "https://raw.githubusercontent.com/Artifact-Cafe/skill/main/artifact-cafe/SKILL.md";
|
|
2464
2855
|
var SKILL_UPDATE_COMMAND = "npx skills add artifact-cafe/skill --skill artifact-cafe -g";
|
|
2465
2856
|
var CHECK_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
2466
2857
|
var FETCH_TIMEOUT_MS = 2e3;
|
|
2467
2858
|
var SKILL_VERSION_PATTERN = /\*\*Skill version:\s*(\d+\.\d+\.\d+)\*\*/;
|
|
2468
|
-
var cacheSchema =
|
|
2469
|
-
checkedAt:
|
|
2470
|
-
cliLatest:
|
|
2471
|
-
skillLatest:
|
|
2472
|
-
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)
|
|
2473
2864
|
});
|
|
2474
2865
|
function cliVersion() {
|
|
2475
2866
|
const pkg = createRequire(import.meta.url)("../package.json");
|
|
2476
2867
|
return pkg.version;
|
|
2477
2868
|
}
|
|
2478
2869
|
function cachePath() {
|
|
2479
|
-
return
|
|
2870
|
+
return path16.join(homedir2(), ".artifactcafe", "update-check.json");
|
|
2480
2871
|
}
|
|
2481
2872
|
function readCache() {
|
|
2482
2873
|
try {
|
|
@@ -2487,7 +2878,7 @@ function readCache() {
|
|
|
2487
2878
|
}
|
|
2488
2879
|
function writeCache(cache) {
|
|
2489
2880
|
try {
|
|
2490
|
-
mkdirSync3(
|
|
2881
|
+
mkdirSync3(path16.dirname(cachePath()), { mode: 448, recursive: true });
|
|
2491
2882
|
writeFileSync3(cachePath(), `${JSON.stringify(cache, null, 2)}
|
|
2492
2883
|
`);
|
|
2493
2884
|
} catch {
|
|
@@ -2524,7 +2915,7 @@ async function fetchText(url) {
|
|
|
2524
2915
|
}
|
|
2525
2916
|
async function fetchLatestVersions(previous) {
|
|
2526
2917
|
const [cli, skill] = await Promise.all([
|
|
2527
|
-
fetchJson(REGISTRY_LATEST_URL).then((body) =>
|
|
2918
|
+
fetchJson(REGISTRY_LATEST_URL).then((body) => z19.object({ version: z19.string() }).parse(body).version).catch(() => null),
|
|
2528
2919
|
fetchText(SKILL_SOURCE_URL).then((body) => SKILL_VERSION_PATTERN.exec(body)?.[1] ?? null).catch(() => null)
|
|
2529
2920
|
]);
|
|
2530
2921
|
return {
|
|
@@ -2540,7 +2931,7 @@ function installedSkillVersions() {
|
|
|
2540
2931
|
const versions = [];
|
|
2541
2932
|
for (const root of roots) {
|
|
2542
2933
|
for (const dir of dirs) {
|
|
2543
|
-
const file =
|
|
2934
|
+
const file = path16.join(root, dir, "skills", "artifact-cafe", "SKILL.md");
|
|
2544
2935
|
if (!existsSync3(file)) {
|
|
2545
2936
|
continue;
|
|
2546
2937
|
}
|
|
@@ -2637,6 +3028,20 @@ function printWorkspace(workspace) {
|
|
|
2637
3028
|
}
|
|
2638
3029
|
|
|
2639
3030
|
// src/index.ts
|
|
3031
|
+
function readNotesArg(argv) {
|
|
3032
|
+
for (let i = 0; i < argv.length; i++) {
|
|
3033
|
+
const token = argv[i];
|
|
3034
|
+
if (token === void 0) {
|
|
3035
|
+
continue;
|
|
3036
|
+
}
|
|
3037
|
+
if (token === "--notes") {
|
|
3038
|
+
return argv[i + 1];
|
|
3039
|
+
}
|
|
3040
|
+
if (token.startsWith("--notes=")) {
|
|
3041
|
+
return token.slice("--notes=".length);
|
|
3042
|
+
}
|
|
3043
|
+
}
|
|
3044
|
+
}
|
|
2640
3045
|
var publish2 = defineCommand({
|
|
2641
3046
|
args: {
|
|
2642
3047
|
"api-key": {
|
|
@@ -2659,6 +3064,10 @@ var publish2 = defineCommand({
|
|
|
2659
3064
|
},
|
|
2660
3065
|
json: { description: "Machine-readable output", type: "boolean" },
|
|
2661
3066
|
"no-open": { description: "Don't open the review URL", type: "boolean" },
|
|
3067
|
+
notes: {
|
|
3068
|
+
description: "Version notes \u2014 bullet-point changelog of what changed (newline-separated)",
|
|
3069
|
+
type: "string"
|
|
3070
|
+
},
|
|
2662
3071
|
password: {
|
|
2663
3072
|
description: "Password-protect the artifact (min 6 chars)",
|
|
2664
3073
|
type: "string"
|
|
@@ -2679,6 +3088,7 @@ var publish2 = defineCommand({
|
|
|
2679
3088
|
entry: args.entry,
|
|
2680
3089
|
folder: args.folder,
|
|
2681
3090
|
json: Boolean(args.json),
|
|
3091
|
+
notes: readNotesArg(process.argv.slice(2)),
|
|
2682
3092
|
open: !args["no-open"],
|
|
2683
3093
|
password: args.password,
|
|
2684
3094
|
title: args.title,
|
|
@@ -2984,6 +3394,47 @@ var listen = defineCommand({
|
|
|
2984
3394
|
}
|
|
2985
3395
|
}
|
|
2986
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
|
+
});
|
|
2987
3438
|
var protect2 = defineCommand({
|
|
2988
3439
|
args: {
|
|
2989
3440
|
"api-key": {
|
|
@@ -3046,7 +3497,11 @@ var threadStatusCommand = (action) => defineCommand({
|
|
|
3046
3497
|
}
|
|
3047
3498
|
},
|
|
3048
3499
|
meta: {
|
|
3049
|
-
description:
|
|
3500
|
+
description: {
|
|
3501
|
+
ack: "Mark a thread acknowledged (seen, working on it)",
|
|
3502
|
+
reopen: "Reopen a resolved comment thread",
|
|
3503
|
+
resolve: "Mark a comment thread resolved"
|
|
3504
|
+
}[action],
|
|
3050
3505
|
name: action
|
|
3051
3506
|
},
|
|
3052
3507
|
async run({ args }) {
|
|
@@ -3067,6 +3522,7 @@ var threadStatusCommand = (action) => defineCommand({
|
|
|
3067
3522
|
});
|
|
3068
3523
|
var resolve = threadStatusCommand("resolve");
|
|
3069
3524
|
var reopen = threadStatusCommand("reopen");
|
|
3525
|
+
var ack = threadStatusCommand("ack");
|
|
3070
3526
|
var reply = defineCommand({
|
|
3071
3527
|
args: {
|
|
3072
3528
|
"api-key": {
|
|
@@ -3264,6 +3720,89 @@ var del = defineCommand({
|
|
|
3264
3720
|
}
|
|
3265
3721
|
}
|
|
3266
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
|
+
});
|
|
3267
3806
|
var open = defineCommand({
|
|
3268
3807
|
args: {
|
|
3269
3808
|
"api-key": {
|
|
@@ -3333,6 +3872,7 @@ var main = defineCommand({
|
|
|
3333
3872
|
await showUsage(cmd);
|
|
3334
3873
|
},
|
|
3335
3874
|
subCommands: {
|
|
3875
|
+
ack,
|
|
3336
3876
|
comment: comment2,
|
|
3337
3877
|
comments: comments2,
|
|
3338
3878
|
dashboard,
|
|
@@ -3350,6 +3890,9 @@ var main = defineCommand({
|
|
|
3350
3890
|
reopen,
|
|
3351
3891
|
reply,
|
|
3352
3892
|
resolve,
|
|
3893
|
+
share: share2,
|
|
3894
|
+
status: statusCmd,
|
|
3895
|
+
unshare: unshare2,
|
|
3353
3896
|
whoami: whoami2,
|
|
3354
3897
|
workspaces: workspaces2
|
|
3355
3898
|
}
|