artifact-cafe 0.0.13 → 0.0.14
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 +628 -486
- package/package.json +12 -1
package/dist/index.js
CHANGED
|
@@ -83,6 +83,74 @@ var artifactListResponseSchema = z.object({
|
|
|
83
83
|
artifacts: z.array(artifactListItemSchema)
|
|
84
84
|
});
|
|
85
85
|
|
|
86
|
+
// ../shared/src/agents.ts
|
|
87
|
+
var AGENT_BRANDS = [
|
|
88
|
+
{
|
|
89
|
+
id: "claude-code",
|
|
90
|
+
label: "Claude Code",
|
|
91
|
+
match: ["claude"],
|
|
92
|
+
short: "Claude"
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
id: "codex",
|
|
96
|
+
label: "OpenAI Codex",
|
|
97
|
+
match: ["codex"],
|
|
98
|
+
short: "Codex"
|
|
99
|
+
},
|
|
100
|
+
{ id: "cursor", label: "Cursor", match: ["cursor"], short: "Cursor" },
|
|
101
|
+
{
|
|
102
|
+
id: "copilot",
|
|
103
|
+
label: "GitHub Copilot",
|
|
104
|
+
match: ["copilot"],
|
|
105
|
+
short: "Copilot"
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
id: "gemini-cli",
|
|
109
|
+
label: "Gemini CLI",
|
|
110
|
+
match: ["gemini"],
|
|
111
|
+
short: "Gemini"
|
|
112
|
+
},
|
|
113
|
+
{ id: "opencode", label: "opencode", match: ["opencode"], short: "opencode" },
|
|
114
|
+
{
|
|
115
|
+
id: "openclaw",
|
|
116
|
+
label: "OpenClaw",
|
|
117
|
+
match: ["openclaw"],
|
|
118
|
+
short: "OpenClaw"
|
|
119
|
+
},
|
|
120
|
+
{ id: "hermes", label: "Hermes", match: ["hermes"], short: "Hermes" }
|
|
121
|
+
];
|
|
122
|
+
function normalizeAgent(raw) {
|
|
123
|
+
const value = raw?.trim().toLowerCase();
|
|
124
|
+
if (!value) {
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
return AGENT_BRANDS.find((brand) => brand.id === value) ?? AGENT_BRANDS.find((brand) => brand.match.some((m) => value.includes(m))) ?? null;
|
|
128
|
+
}
|
|
129
|
+
var ENV_FINGERPRINTS = [
|
|
130
|
+
{ id: "claude-code", prefixes: ["CLAUDECODE", "CLAUDE_CODE_"] },
|
|
131
|
+
{ id: "codex", prefixes: ["CODEX_"] },
|
|
132
|
+
{ id: "cursor", prefixes: ["CURSOR_"] },
|
|
133
|
+
{ id: "copilot", prefixes: ["COPILOT_", "GITHUB_COPILOT_"] },
|
|
134
|
+
{ id: "gemini-cli", prefixes: ["GEMINI_CLI", "GEMINI_SANDBOX"] },
|
|
135
|
+
{ id: "opencode", prefixes: ["OPENCODE"] }
|
|
136
|
+
];
|
|
137
|
+
function detectAgentFromEnv(env) {
|
|
138
|
+
const explicit = env.ARTIFACT_CAFE_AGENT?.trim();
|
|
139
|
+
if (explicit) {
|
|
140
|
+
return explicit;
|
|
141
|
+
}
|
|
142
|
+
const keys = Object.keys(env).filter((key) => env[key]);
|
|
143
|
+
for (const { id, prefixes } of ENV_FINGERPRINTS) {
|
|
144
|
+
const hit = keys.some(
|
|
145
|
+
(key) => prefixes.some((prefix) => key.startsWith(prefix))
|
|
146
|
+
);
|
|
147
|
+
if (hit) {
|
|
148
|
+
return AGENT_BRANDS.find((brand) => brand.id === id)?.label;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return normalizeAgent(env.AI_AGENT)?.label;
|
|
152
|
+
}
|
|
153
|
+
|
|
86
154
|
// ../shared/src/avatars.ts
|
|
87
155
|
import { z as z2 } from "zod";
|
|
88
156
|
var AVATAR_CONTENT_TYPES = [
|
|
@@ -100,18 +168,27 @@ var workspaceAvatarResponseSchema = z2.object({
|
|
|
100
168
|
});
|
|
101
169
|
|
|
102
170
|
// ../shared/src/comments.ts
|
|
103
|
-
import { z as
|
|
171
|
+
import { z as z6 } from "zod";
|
|
172
|
+
|
|
173
|
+
// ../shared/src/emoji.ts
|
|
174
|
+
import { z as z3 } from "zod";
|
|
175
|
+
var SINGLE_EMOJI = new RegExp("^\\p{RGI_Emoji}$", "v");
|
|
176
|
+
var REDUNDANT_VS16 = new RegExp("(\\p{Emoji_Presentation})\\uFE0F", "gu");
|
|
177
|
+
function canonicalizeEmoji(s) {
|
|
178
|
+
return s.replace(REDUNDANT_VS16, "$1");
|
|
179
|
+
}
|
|
180
|
+
var iconEmojiSchema = z3.string().max(64).transform(canonicalizeEmoji).refine((s) => SINGLE_EMOJI.test(s), { message: "Must be a single emoji." }).nullable().describe("A single emoji shown as the icon, or null for the default.");
|
|
104
181
|
|
|
105
182
|
// ../shared/src/publish.ts
|
|
106
|
-
import { z as
|
|
183
|
+
import { z as z5 } from "zod";
|
|
107
184
|
|
|
108
185
|
// ../shared/src/review-mode.ts
|
|
109
|
-
import { z as
|
|
110
|
-
var reviewModeSchema =
|
|
111
|
-
var setReviewModeSchema =
|
|
186
|
+
import { z as z4 } from "zod";
|
|
187
|
+
var reviewModeSchema = z4.enum(["open", "readonly", "off"]);
|
|
188
|
+
var setReviewModeSchema = z4.object({
|
|
112
189
|
mode: reviewModeSchema
|
|
113
190
|
});
|
|
114
|
-
var reviewModeResponseSchema =
|
|
191
|
+
var reviewModeResponseSchema = z4.object({
|
|
115
192
|
mode: reviewModeSchema
|
|
116
193
|
});
|
|
117
194
|
|
|
@@ -128,266 +205,275 @@ function isSafeArtifactPath(p) {
|
|
|
128
205
|
}
|
|
129
206
|
return p.split("/").every((seg) => seg.length > 0 && seg !== "." && seg !== "..");
|
|
130
207
|
}
|
|
131
|
-
var
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
208
|
+
var CARD_DESCRIPTION_MAX = 300;
|
|
209
|
+
var CARD_IMAGE_MAX_BYTES = 5 * 1024 * 1024;
|
|
210
|
+
var manifestFileSchema = z5.object({
|
|
211
|
+
hash: z5.string().regex(/^sha256_[a-f0-9]{64}$/),
|
|
212
|
+
mimeType: z5.string().regex(/^[-\w.+]+\/[-\w.+]+$/, { message: "invalid MIME type" }),
|
|
213
|
+
path: z5.string().min(1).max(1024).refine(isSafeArtifactPath, {
|
|
135
214
|
message: "path must be a safe relative path"
|
|
136
215
|
}),
|
|
137
|
-
size:
|
|
138
|
-
});
|
|
139
|
-
var publishSourceSchema =
|
|
140
|
-
agent:
|
|
141
|
-
runId:
|
|
142
|
-
type:
|
|
143
|
-
});
|
|
144
|
-
var createPublishSessionSchema =
|
|
145
|
-
artifactId:
|
|
146
|
-
|
|
147
|
-
|
|
216
|
+
size: z5.number().int().positive()
|
|
217
|
+
});
|
|
218
|
+
var publishSourceSchema = z5.object({
|
|
219
|
+
agent: z5.string().optional(),
|
|
220
|
+
runId: z5.string().optional(),
|
|
221
|
+
type: z5.literal("cli")
|
|
222
|
+
});
|
|
223
|
+
var createPublishSessionSchema = z5.object({
|
|
224
|
+
artifactId: z5.string().nullable(),
|
|
225
|
+
// One-line share-card summary (`--description`). Overrides whatever the
|
|
226
|
+
// entry HTML declares; leave it off and the API reads the document's own
|
|
227
|
+
// `og:description`/`description` at finalize.
|
|
228
|
+
description: z5.string().max(CARD_DESCRIPTION_MAX).optional(),
|
|
229
|
+
entryPath: z5.string().optional(),
|
|
230
|
+
files: z5.array(manifestFileSchema).min(1).max(1e3),
|
|
148
231
|
// SPEC-2 §6.4 — workspace placement is available only to authenticated
|
|
149
232
|
// members; the API enforces membership and folder ownership. folderId
|
|
150
233
|
// without workspaceId resolves against the account's personal workspace.
|
|
151
|
-
folderId:
|
|
234
|
+
folderId: z5.string().min(1).optional(),
|
|
152
235
|
// Bullet-point changelog for this version, authored by the publisher.
|
|
153
236
|
// Optional on every publish (incl. v1); stored immutably on the version.
|
|
154
|
-
notes:
|
|
237
|
+
notes: z5.string().max(4e3).optional(),
|
|
155
238
|
source: publishSourceSchema,
|
|
156
|
-
title:
|
|
157
|
-
workspaceId:
|
|
158
|
-
});
|
|
159
|
-
var publishSessionResponseSchema =
|
|
160
|
-
artifactId:
|
|
161
|
-
expiresAt:
|
|
162
|
-
filesToUpload:
|
|
163
|
-
|
|
164
|
-
method:
|
|
165
|
-
path:
|
|
166
|
-
uploadUrl:
|
|
239
|
+
title: z5.string().max(200).optional(),
|
|
240
|
+
workspaceId: z5.string().min(1).optional()
|
|
241
|
+
});
|
|
242
|
+
var publishSessionResponseSchema = z5.object({
|
|
243
|
+
artifactId: z5.string(),
|
|
244
|
+
expiresAt: z5.string(),
|
|
245
|
+
filesToUpload: z5.array(
|
|
246
|
+
z5.object({
|
|
247
|
+
method: z5.literal("PUT"),
|
|
248
|
+
path: z5.string(),
|
|
249
|
+
uploadUrl: z5.string().url()
|
|
167
250
|
})
|
|
168
251
|
),
|
|
169
|
-
publishSessionId:
|
|
170
|
-
skippedFiles:
|
|
171
|
-
versionId:
|
|
252
|
+
publishSessionId: z5.string(),
|
|
253
|
+
skippedFiles: z5.array(z5.string()),
|
|
254
|
+
versionId: z5.string()
|
|
172
255
|
});
|
|
173
|
-
var finalizeResponseSchema =
|
|
174
|
-
artifactId:
|
|
256
|
+
var finalizeResponseSchema = z5.object({
|
|
257
|
+
artifactId: z5.string(),
|
|
175
258
|
// API-key publishes create the artifact already claimed (SPEC §5.4) —
|
|
176
259
|
// the CLI uses this to tell "claim URL pending" from "already yours".
|
|
177
|
-
claimed:
|
|
260
|
+
claimed: z5.boolean(),
|
|
178
261
|
// Returned only on first publish of a new artifact (one-time).
|
|
179
|
-
claimUrl:
|
|
180
|
-
publishToken:
|
|
181
|
-
url:
|
|
182
|
-
versionId:
|
|
183
|
-
versionNumber:
|
|
262
|
+
claimUrl: z5.string().url().optional(),
|
|
263
|
+
publishToken: z5.string().optional(),
|
|
264
|
+
url: z5.string().url(),
|
|
265
|
+
versionId: z5.string(),
|
|
266
|
+
versionNumber: z5.number().int().positive(),
|
|
184
267
|
// SPEC-2 §5.2 — who can open the review URL. A publish into a folder
|
|
185
268
|
// inherits that folder's visibility, so this is the only place the CLI
|
|
186
269
|
// learns that a link it just printed is members-only. Optional so a new
|
|
187
270
|
// CLI against an older API degrades to "unknown" instead of failing the
|
|
188
271
|
// publish over a field that only shapes the closing message.
|
|
189
|
-
visibility:
|
|
190
|
-
});
|
|
191
|
-
var artifactResponseSchema =
|
|
192
|
-
claimed:
|
|
193
|
-
currentVersion:
|
|
194
|
-
entryUrl:
|
|
195
|
-
id:
|
|
196
|
-
versionNumber:
|
|
272
|
+
visibility: z5.enum(["public", "unlisted", "workspace", "private"]).optional()
|
|
273
|
+
});
|
|
274
|
+
var artifactResponseSchema = z5.object({
|
|
275
|
+
claimed: z5.boolean(),
|
|
276
|
+
currentVersion: z5.object({
|
|
277
|
+
entryUrl: z5.string().url(),
|
|
278
|
+
id: z5.string(),
|
|
279
|
+
versionNumber: z5.number().int().positive()
|
|
197
280
|
}).nullable(),
|
|
281
|
+
// Custom icon, or null to render the default document glyph.
|
|
282
|
+
emoji: z5.string().nullable(),
|
|
198
283
|
// SPEC-2 §6.4 — placement + visibility surface on the artifact.
|
|
199
|
-
folderId:
|
|
200
|
-
id:
|
|
284
|
+
folderId: z5.string().nullable(),
|
|
285
|
+
id: z5.string(),
|
|
201
286
|
// SPEC-2 §5.8 — what a viewer may do once in (open / readonly / off).
|
|
202
287
|
reviewMode: reviewModeSchema,
|
|
203
|
-
slug:
|
|
204
|
-
title:
|
|
205
|
-
visibility:
|
|
206
|
-
workspaceId:
|
|
288
|
+
slug: z5.string(),
|
|
289
|
+
title: z5.string(),
|
|
290
|
+
visibility: z5.enum(["public", "unlisted", "workspace", "private"]),
|
|
291
|
+
workspaceId: z5.string().nullable()
|
|
207
292
|
});
|
|
208
293
|
|
|
209
294
|
// ../shared/src/comments.ts
|
|
210
|
-
var anchorPageSchema =
|
|
295
|
+
var anchorPageSchema = z6.string().max(1024).refine(isSafeArtifactPath, {
|
|
211
296
|
message: "page must be a safe relative path"
|
|
212
297
|
}).optional();
|
|
213
|
-
var elementSnapshotSchema =
|
|
214
|
-
classes:
|
|
215
|
-
id:
|
|
216
|
-
tag:
|
|
217
|
-
text:
|
|
298
|
+
var elementSnapshotSchema = z6.object({
|
|
299
|
+
classes: z6.string().max(256).optional(),
|
|
300
|
+
id: z6.string().max(256).optional(),
|
|
301
|
+
tag: z6.string().min(1).max(128),
|
|
302
|
+
text: z6.string().max(200).optional()
|
|
218
303
|
});
|
|
219
|
-
var pointAnchorSchema =
|
|
304
|
+
var pointAnchorSchema = z6.object({
|
|
220
305
|
element: elementSnapshotSchema.optional(),
|
|
221
306
|
// elementPath is the primary anchor; x/y are offsets within the
|
|
222
307
|
// element's box, normalized 0..1 (SPEC.md §8.1).
|
|
223
|
-
elementPath:
|
|
308
|
+
elementPath: z6.string().max(2048),
|
|
224
309
|
page: anchorPageSchema,
|
|
225
|
-
type:
|
|
226
|
-
viewportHeight:
|
|
227
|
-
viewportWidth:
|
|
228
|
-
x:
|
|
229
|
-
y:
|
|
230
|
-
});
|
|
231
|
-
var textAnchorSchema =
|
|
232
|
-
elementPath:
|
|
233
|
-
endOffset:
|
|
310
|
+
type: z6.literal("point"),
|
|
311
|
+
viewportHeight: z6.number().int().positive().max(1e5),
|
|
312
|
+
viewportWidth: z6.number().int().positive().max(1e5),
|
|
313
|
+
x: z6.number().min(0).max(1),
|
|
314
|
+
y: z6.number().min(0).max(1)
|
|
315
|
+
});
|
|
316
|
+
var textAnchorSchema = z6.object({
|
|
317
|
+
elementPath: z6.string().max(2048),
|
|
318
|
+
endOffset: z6.number().int().nonnegative().max(1e8),
|
|
234
319
|
page: anchorPageSchema,
|
|
235
|
-
prefix:
|
|
236
|
-
quote:
|
|
237
|
-
startOffset:
|
|
238
|
-
suffix:
|
|
239
|
-
type:
|
|
320
|
+
prefix: z6.string().max(200).optional(),
|
|
321
|
+
quote: z6.string().min(1).max(1e3),
|
|
322
|
+
startOffset: z6.number().int().nonnegative().max(1e8),
|
|
323
|
+
suffix: z6.string().max(200).optional(),
|
|
324
|
+
type: z6.literal("text")
|
|
240
325
|
});
|
|
241
|
-
var pageAnchorSchema =
|
|
326
|
+
var pageAnchorSchema = z6.object({
|
|
242
327
|
page: anchorPageSchema,
|
|
243
|
-
type:
|
|
328
|
+
type: z6.literal("page")
|
|
244
329
|
});
|
|
245
|
-
var anchorSchema =
|
|
330
|
+
var anchorSchema = z6.discriminatedUnion("type", [
|
|
246
331
|
pointAnchorSchema,
|
|
247
332
|
textAnchorSchema,
|
|
248
333
|
pageAnchorSchema
|
|
249
334
|
]);
|
|
250
|
-
var displayNameSchema =
|
|
251
|
-
var guestSchema =
|
|
335
|
+
var displayNameSchema = z6.string().trim().min(1).max(64);
|
|
336
|
+
var guestSchema = z6.object({
|
|
252
337
|
displayName: displayNameSchema,
|
|
253
|
-
guestId:
|
|
338
|
+
guestId: z6.string().min(16)
|
|
254
339
|
});
|
|
255
|
-
var viaLabelSchema =
|
|
256
|
-
var createCommentThreadSchema =
|
|
340
|
+
var viaLabelSchema = z6.string().trim().min(1).max(64);
|
|
341
|
+
var createCommentThreadSchema = z6.object({
|
|
257
342
|
anchor: anchorSchema,
|
|
258
|
-
body:
|
|
343
|
+
body: z6.string().min(1).max(1e4),
|
|
259
344
|
guest: guestSchema.optional(),
|
|
260
|
-
versionId:
|
|
345
|
+
versionId: z6.string(),
|
|
261
346
|
via: viaLabelSchema.optional()
|
|
262
347
|
});
|
|
263
|
-
var createCommentMessageSchema =
|
|
264
|
-
body:
|
|
348
|
+
var createCommentMessageSchema = z6.object({
|
|
349
|
+
body: z6.string().min(1).max(1e4),
|
|
265
350
|
guest: guestSchema.optional(),
|
|
266
351
|
via: viaLabelSchema.optional()
|
|
267
352
|
});
|
|
268
|
-
var editCommentMessageSchema =
|
|
269
|
-
body:
|
|
353
|
+
var editCommentMessageSchema = z6.object({
|
|
354
|
+
body: z6.string().min(1).max(1e4),
|
|
270
355
|
guest: guestSchema.optional()
|
|
271
356
|
});
|
|
272
|
-
var threadActionSchema =
|
|
357
|
+
var threadActionSchema = z6.object({
|
|
273
358
|
guest: guestSchema.optional()
|
|
274
359
|
});
|
|
275
|
-
var
|
|
276
|
-
var
|
|
277
|
-
function canonicalizeEmoji(s) {
|
|
278
|
-
return s.replace(REDUNDANT_VS16, "$1");
|
|
279
|
-
}
|
|
280
|
-
var reactionEmojiSchema = z5.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}");
|
|
281
|
-
var toggleReactionSchema = z5.object({
|
|
360
|
+
var reactionEmojiSchema = z6.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}");
|
|
361
|
+
var toggleReactionSchema = z6.object({
|
|
282
362
|
emoji: reactionEmojiSchema,
|
|
283
363
|
guest: guestSchema.optional()
|
|
284
364
|
});
|
|
285
|
-
var
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
365
|
+
var commentAgentSchema = z6.object({
|
|
366
|
+
id: z6.string().nullable(),
|
|
367
|
+
label: z6.string()
|
|
368
|
+
});
|
|
369
|
+
var commentAuthorSchema = z6.object({
|
|
370
|
+
agent: commentAgentSchema.nullable().default(null),
|
|
371
|
+
avatarUrl: z6.string().nullable(),
|
|
372
|
+
displayName: z6.string(),
|
|
373
|
+
guestId: z6.string().nullable(),
|
|
374
|
+
isViewer: z6.boolean(),
|
|
375
|
+
kind: z6.enum(["member", "guest"]),
|
|
291
376
|
// Optional "via" attribution (§6.4). Null for plain comments; a bounded
|
|
292
|
-
// label the shell appends after the display name.
|
|
293
|
-
|
|
377
|
+
// label the shell appends after the display name. Defaulted for the same
|
|
378
|
+
// reason as `agent`: a server predating §6.4 omits the key entirely.
|
|
379
|
+
via: z6.string().nullable().default(null)
|
|
294
380
|
});
|
|
295
|
-
var messageReactionSchema =
|
|
296
|
-
emoji:
|
|
297
|
-
reactors:
|
|
381
|
+
var messageReactionSchema = z6.object({
|
|
382
|
+
emoji: z6.string(),
|
|
383
|
+
reactors: z6.array(commentAuthorSchema)
|
|
298
384
|
});
|
|
299
|
-
var commentMessageSchema =
|
|
385
|
+
var commentMessageSchema = z6.object({
|
|
300
386
|
author: commentAuthorSchema,
|
|
301
387
|
// Empty string for a deleted message — the body is stripped server-side
|
|
302
388
|
// (§6.7.1 tombstone), never sent to the client and hidden there.
|
|
303
|
-
body:
|
|
304
|
-
createdAt:
|
|
389
|
+
body: z6.string(),
|
|
390
|
+
createdAt: z6.string(),
|
|
305
391
|
// Soft-deleted (§6.7.1). A tombstone keeps thread structure and replies;
|
|
306
392
|
// the shell renders "Comment deleted" instead of the (absent) body.
|
|
307
|
-
deleted:
|
|
393
|
+
deleted: z6.boolean(),
|
|
308
394
|
// Last edit time (§6.7.1), or null if never edited — drives the "edited"
|
|
309
395
|
// badge. No edit history is kept.
|
|
310
|
-
editedAt:
|
|
311
|
-
id:
|
|
396
|
+
editedAt: z6.string().nullable(),
|
|
397
|
+
id: z6.string(),
|
|
312
398
|
// Defaulted, not required: a new CLI parsing an older server's
|
|
313
399
|
// response must not fail on the missing key.
|
|
314
|
-
reactions:
|
|
400
|
+
reactions: z6.array(messageReactionSchema).default([])
|
|
315
401
|
});
|
|
316
|
-
var threadActorSchema =
|
|
317
|
-
displayName:
|
|
318
|
-
kind:
|
|
402
|
+
var threadActorSchema = z6.object({
|
|
403
|
+
displayName: z6.string(),
|
|
404
|
+
kind: z6.enum(["member", "guest", "agent"])
|
|
319
405
|
});
|
|
320
|
-
var commentThreadSchema =
|
|
406
|
+
var commentThreadSchema = z6.object({
|
|
321
407
|
// §6.6.1 — set while open to signal "seen, working on it"; cleared on
|
|
322
408
|
// reopen, kept (but superseded in display) once resolved. Defaulted so
|
|
323
409
|
// clients parsing an older server's response don't fail.
|
|
324
|
-
acknowledgedAt:
|
|
410
|
+
acknowledgedAt: z6.string().nullable().default(null),
|
|
325
411
|
acknowledgedBy: threadActorSchema.nullable().default(null),
|
|
326
412
|
anchor: anchorSchema,
|
|
327
|
-
artifactId:
|
|
328
|
-
createdAt:
|
|
413
|
+
artifactId: z6.string(),
|
|
414
|
+
createdAt: z6.string(),
|
|
329
415
|
createdBy: commentAuthorSchema,
|
|
330
|
-
id:
|
|
331
|
-
messages:
|
|
416
|
+
id: z6.string(),
|
|
417
|
+
messages: z6.array(commentMessageSchema),
|
|
332
418
|
// Null on threads resolved before actor recording existed, and always
|
|
333
419
|
// null while open.
|
|
334
420
|
resolvedBy: threadActorSchema.nullable().default(null),
|
|
335
|
-
status:
|
|
336
|
-
versionId:
|
|
421
|
+
status: z6.enum(["open", "resolved"]),
|
|
422
|
+
versionId: z6.string()
|
|
337
423
|
});
|
|
338
|
-
var commentThreadListSchema =
|
|
339
|
-
threads:
|
|
424
|
+
var commentThreadListSchema = z6.object({
|
|
425
|
+
threads: z6.array(commentThreadSchema)
|
|
340
426
|
});
|
|
341
|
-
var commentExportQuerySchema =
|
|
342
|
-
status:
|
|
343
|
-
version:
|
|
427
|
+
var commentExportQuerySchema = z6.object({
|
|
428
|
+
status: z6.enum(["open", "resolved", "all"]).default("open"),
|
|
429
|
+
version: z6.enum(["current", "all"]).default("current")
|
|
344
430
|
});
|
|
345
|
-
var exportReactionSchema =
|
|
346
|
-
count:
|
|
347
|
-
emoji:
|
|
431
|
+
var exportReactionSchema = z6.object({
|
|
432
|
+
count: z6.number().int().positive(),
|
|
433
|
+
emoji: z6.string()
|
|
348
434
|
});
|
|
349
|
-
var commentExportReplySchema =
|
|
350
|
-
author:
|
|
351
|
-
authorKind:
|
|
352
|
-
body:
|
|
353
|
-
createdAt:
|
|
435
|
+
var commentExportReplySchema = z6.object({
|
|
436
|
+
author: z6.string(),
|
|
437
|
+
authorKind: z6.enum(["member", "guest"]),
|
|
438
|
+
body: z6.string(),
|
|
439
|
+
createdAt: z6.string(),
|
|
354
440
|
// Soft-delete tombstone (§6.7.1): body is "" when true.
|
|
355
|
-
deleted:
|
|
356
|
-
editedAt:
|
|
441
|
+
deleted: z6.boolean(),
|
|
442
|
+
editedAt: z6.string().nullable(),
|
|
357
443
|
// The message id — what `edit`/`delete` target (§5.1).
|
|
358
|
-
id:
|
|
359
|
-
reactions:
|
|
444
|
+
id: z6.string(),
|
|
445
|
+
reactions: z6.array(exportReactionSchema).optional()
|
|
360
446
|
});
|
|
361
|
-
var commentExportThreadSchema =
|
|
447
|
+
var commentExportThreadSchema = z6.object({
|
|
362
448
|
// §6.6.1 — lets a polling agent skip threads it already acknowledged
|
|
363
449
|
// (acknowledged threads stay in status=open exports on purpose).
|
|
364
|
-
acknowledgedAt:
|
|
450
|
+
acknowledgedAt: z6.string().nullable().default(null),
|
|
365
451
|
anchor: anchorSchema,
|
|
366
|
-
author:
|
|
367
|
-
authorKind:
|
|
368
|
-
body:
|
|
369
|
-
createdAt:
|
|
370
|
-
deleted:
|
|
371
|
-
editedAt:
|
|
372
|
-
id:
|
|
452
|
+
author: z6.string(),
|
|
453
|
+
authorKind: z6.enum(["member", "guest"]),
|
|
454
|
+
body: z6.string(),
|
|
455
|
+
createdAt: z6.string(),
|
|
456
|
+
deleted: z6.boolean(),
|
|
457
|
+
editedAt: z6.string().nullable(),
|
|
458
|
+
id: z6.string(),
|
|
373
459
|
// The opening message's id (distinct from the thread `id`) — `edit`/
|
|
374
460
|
// `delete` operate on messages, so the CLI needs it to target the first
|
|
375
461
|
// comment, not just the replies.
|
|
376
|
-
messageId:
|
|
377
|
-
reactions:
|
|
378
|
-
replies:
|
|
462
|
+
messageId: z6.string(),
|
|
463
|
+
reactions: z6.array(exportReactionSchema).optional(),
|
|
464
|
+
replies: z6.array(commentExportReplySchema),
|
|
379
465
|
resolvedBy: threadActorSchema.nullable().default(null),
|
|
380
|
-
status:
|
|
381
|
-
versionNumber:
|
|
466
|
+
status: z6.enum(["open", "resolved"]),
|
|
467
|
+
versionNumber: z6.number().int().positive()
|
|
382
468
|
});
|
|
383
|
-
var commentExportSchema =
|
|
384
|
-
artifactId:
|
|
385
|
-
comments:
|
|
469
|
+
var commentExportSchema = z6.object({
|
|
470
|
+
artifactId: z6.string(),
|
|
471
|
+
comments: z6.array(commentExportThreadSchema),
|
|
386
472
|
// The artifact's current version (null before the first finalize).
|
|
387
|
-
versionNumber:
|
|
473
|
+
versionNumber: z6.number().int().positive().nullable()
|
|
388
474
|
});
|
|
389
|
-
var commentReadResponseSchema =
|
|
390
|
-
lastSeenAt:
|
|
475
|
+
var commentReadResponseSchema = z6.object({
|
|
476
|
+
lastSeenAt: z6.string()
|
|
391
477
|
});
|
|
392
478
|
function elementLabel(el) {
|
|
393
479
|
if (el.id) {
|
|
@@ -398,499 +484,528 @@ function elementLabel(el) {
|
|
|
398
484
|
}
|
|
399
485
|
|
|
400
486
|
// ../shared/src/errors.ts
|
|
401
|
-
import { z as
|
|
402
|
-
var apiErrorSchema =
|
|
403
|
-
code:
|
|
404
|
-
docsUrl:
|
|
405
|
-
message:
|
|
406
|
-
retryAfter:
|
|
487
|
+
import { z as z7 } from "zod";
|
|
488
|
+
var apiErrorSchema = z7.object({
|
|
489
|
+
code: z7.string(),
|
|
490
|
+
docsUrl: z7.string().url(),
|
|
491
|
+
message: z7.string(),
|
|
492
|
+
retryAfter: z7.number().int().positive().optional()
|
|
407
493
|
});
|
|
408
494
|
|
|
409
495
|
// ../shared/src/feedback.ts
|
|
410
|
-
import { z as
|
|
411
|
-
var feedbackRequestSchema =
|
|
412
|
-
email:
|
|
413
|
-
message:
|
|
496
|
+
import { z as z8 } from "zod";
|
|
497
|
+
var feedbackRequestSchema = z8.object({
|
|
498
|
+
email: z8.string().trim().toLowerCase().email().optional().or(z8.literal("")),
|
|
499
|
+
message: z8.string().trim().min(1).max(4e3)
|
|
414
500
|
});
|
|
415
|
-
var feedbackResponseSchema =
|
|
416
|
-
sent:
|
|
501
|
+
var feedbackResponseSchema = z8.object({
|
|
502
|
+
sent: z8.literal(true)
|
|
417
503
|
});
|
|
418
504
|
|
|
419
505
|
// ../shared/src/grants.ts
|
|
420
|
-
import { z as
|
|
421
|
-
var grantRoleSchema =
|
|
422
|
-
var createGrantSchema =
|
|
423
|
-
email:
|
|
506
|
+
import { z as z9 } from "zod";
|
|
507
|
+
var grantRoleSchema = z9.enum(["viewer"]);
|
|
508
|
+
var createGrantSchema = z9.object({
|
|
509
|
+
email: z9.string().trim().toLowerCase().email().optional(),
|
|
424
510
|
role: grantRoleSchema.default("viewer"),
|
|
425
|
-
userId:
|
|
511
|
+
userId: z9.string().min(1).optional()
|
|
426
512
|
}).refine((body) => Boolean(body.email) !== Boolean(body.userId), {
|
|
427
513
|
message: "provide exactly one of email or userId"
|
|
428
514
|
});
|
|
429
|
-
var grantSchema =
|
|
430
|
-
createdAt:
|
|
431
|
-
email:
|
|
432
|
-
expiresAt:
|
|
433
|
-
id:
|
|
515
|
+
var grantSchema = z9.object({
|
|
516
|
+
createdAt: z9.string(),
|
|
517
|
+
email: z9.string().email().nullable(),
|
|
518
|
+
expiresAt: z9.string().nullable(),
|
|
519
|
+
id: z9.string(),
|
|
434
520
|
// The subject's avatar once they have an account; null otherwise.
|
|
435
|
-
image:
|
|
521
|
+
image: z9.string().nullable(),
|
|
436
522
|
// Present on the invited account after redemption / when granting an
|
|
437
523
|
// existing user; null for a still-pending email invite.
|
|
438
|
-
name:
|
|
439
|
-
redeemedAt:
|
|
524
|
+
name: z9.string().nullable(),
|
|
525
|
+
redeemedAt: z9.string().nullable(),
|
|
440
526
|
role: grantRoleSchema,
|
|
441
527
|
// Shown as "· pending" beside the role until the link is redeemed.
|
|
442
|
-
status:
|
|
528
|
+
status: z9.enum(["pending", "active"]),
|
|
443
529
|
// Display fragment of the live invitation token, or null once redeemed.
|
|
444
|
-
tokenPrefix:
|
|
445
|
-
userId:
|
|
530
|
+
tokenPrefix: z9.string().nullable(),
|
|
531
|
+
userId: z9.string().nullable()
|
|
446
532
|
});
|
|
447
533
|
var createdGrantSchema = grantSchema.extend({
|
|
448
|
-
url:
|
|
534
|
+
url: z9.string().url()
|
|
449
535
|
});
|
|
450
|
-
var grantListResponseSchema =
|
|
451
|
-
grants:
|
|
536
|
+
var grantListResponseSchema = z9.object({
|
|
537
|
+
grants: z9.array(grantSchema),
|
|
452
538
|
// The artifact's current general-access value, so the share surface can
|
|
453
539
|
// render the "General access" line without a second read.
|
|
454
|
-
visibility:
|
|
540
|
+
visibility: z9.enum(["public", "unlisted", "workspace", "private"]),
|
|
455
541
|
// The owning workspace's logo, so the share modal can draw the workspace
|
|
456
542
|
// itself rather than a generic glyph. Null when none was uploaded.
|
|
457
|
-
workspaceLogo:
|
|
543
|
+
workspaceLogo: z9.string().nullable().optional(),
|
|
458
544
|
// The owning workspace's display name, so "People with access" can name the
|
|
459
545
|
// audience `workspace` visibility actually admits ("All Acme members") rather
|
|
460
546
|
// than leaving an empty list to imply nobody. Null for a workspace-less
|
|
461
547
|
// artifact; optional so an older server still parses.
|
|
462
|
-
workspaceName:
|
|
548
|
+
workspaceName: z9.string().nullable().optional()
|
|
463
549
|
});
|
|
464
|
-
var revokeGrantResponseSchema =
|
|
465
|
-
revoked:
|
|
550
|
+
var revokeGrantResponseSchema = z9.object({
|
|
551
|
+
revoked: z9.literal(true)
|
|
466
552
|
});
|
|
467
|
-
var acceptGrantSchema =
|
|
468
|
-
token:
|
|
553
|
+
var acceptGrantSchema = z9.object({
|
|
554
|
+
token: z9.string().min(1)
|
|
469
555
|
});
|
|
470
|
-
var acceptGrantResponseSchema =
|
|
471
|
-
artifactId:
|
|
556
|
+
var acceptGrantResponseSchema = z9.object({
|
|
557
|
+
artifactId: z9.string(),
|
|
472
558
|
// The review shell URL to land on, carrying ?invited=1 for the banner.
|
|
473
|
-
artifactUrl:
|
|
474
|
-
slug:
|
|
475
|
-
title:
|
|
476
|
-
});
|
|
477
|
-
var workspaceGuestSchema =
|
|
478
|
-
artifacts:
|
|
479
|
-
|
|
480
|
-
artifactId:
|
|
481
|
-
grantId:
|
|
482
|
-
slug:
|
|
483
|
-
status:
|
|
484
|
-
title:
|
|
559
|
+
artifactUrl: z9.string().url(),
|
|
560
|
+
slug: z9.string(),
|
|
561
|
+
title: z9.string()
|
|
562
|
+
});
|
|
563
|
+
var workspaceGuestSchema = z9.object({
|
|
564
|
+
artifacts: z9.array(
|
|
565
|
+
z9.object({
|
|
566
|
+
artifactId: z9.string(),
|
|
567
|
+
grantId: z9.string(),
|
|
568
|
+
slug: z9.string(),
|
|
569
|
+
status: z9.enum(["pending", "active"]),
|
|
570
|
+
title: z9.string()
|
|
485
571
|
})
|
|
486
572
|
),
|
|
487
|
-
email:
|
|
488
|
-
image:
|
|
489
|
-
name:
|
|
490
|
-
userId:
|
|
491
|
-
});
|
|
492
|
-
var workspaceGuestListResponseSchema =
|
|
493
|
-
guests:
|
|
494
|
-
});
|
|
495
|
-
var sharedWithMeArtifactSchema =
|
|
496
|
-
artifactId:
|
|
497
|
-
slug:
|
|
498
|
-
title:
|
|
499
|
-
url:
|
|
573
|
+
email: z9.string().nullable(),
|
|
574
|
+
image: z9.string().nullable(),
|
|
575
|
+
name: z9.string().nullable(),
|
|
576
|
+
userId: z9.string().nullable()
|
|
577
|
+
});
|
|
578
|
+
var workspaceGuestListResponseSchema = z9.object({
|
|
579
|
+
guests: z9.array(workspaceGuestSchema)
|
|
580
|
+
});
|
|
581
|
+
var sharedWithMeArtifactSchema = z9.object({
|
|
582
|
+
artifactId: z9.string(),
|
|
583
|
+
slug: z9.string(),
|
|
584
|
+
title: z9.string(),
|
|
585
|
+
url: z9.string().url(),
|
|
500
586
|
// Who shared it, for the "Shared with me" list.
|
|
501
|
-
workspaceName:
|
|
587
|
+
workspaceName: z9.string()
|
|
502
588
|
});
|
|
503
|
-
var sharedWithMeListResponseSchema =
|
|
504
|
-
artifacts:
|
|
589
|
+
var sharedWithMeListResponseSchema = z9.object({
|
|
590
|
+
artifacts: z9.array(sharedWithMeArtifactSchema)
|
|
505
591
|
});
|
|
506
592
|
|
|
593
|
+
// ../shared/src/html-meta.ts
|
|
594
|
+
var HEAD_SCAN_CHARS = 64 * 1024;
|
|
595
|
+
|
|
507
596
|
// ../shared/src/me.ts
|
|
508
|
-
import { z as
|
|
597
|
+
import { z as z11 } from "zod";
|
|
509
598
|
|
|
510
599
|
// ../shared/src/workspaces.ts
|
|
511
|
-
import { z as
|
|
600
|
+
import { z as z10 } from "zod";
|
|
512
601
|
var WORKSPACE_HANDLE_PATTERN = /^[a-z0-9](?:[a-z0-9-]{1,30}[a-z0-9])$/;
|
|
513
|
-
var workspaceHandleUnavailableReasonSchema =
|
|
602
|
+
var workspaceHandleUnavailableReasonSchema = z10.enum([
|
|
514
603
|
"held",
|
|
515
604
|
"invalid",
|
|
516
605
|
"reserved",
|
|
517
606
|
"taken"
|
|
518
607
|
]);
|
|
519
|
-
var workspaceHandleAvailabilitySchema =
|
|
520
|
-
available:
|
|
521
|
-
handle:
|
|
608
|
+
var workspaceHandleAvailabilitySchema = z10.object({
|
|
609
|
+
available: z10.boolean(),
|
|
610
|
+
handle: z10.string(),
|
|
522
611
|
// Human-readable sentence for the field hint; null when available.
|
|
523
|
-
message:
|
|
612
|
+
message: z10.string().nullable(),
|
|
524
613
|
reason: workspaceHandleUnavailableReasonSchema.nullable()
|
|
525
614
|
});
|
|
526
|
-
var workspaceRoleSchema =
|
|
527
|
-
var workspaceInviteRoleSchema =
|
|
528
|
-
var workspaceHandleSchema =
|
|
615
|
+
var workspaceRoleSchema = z10.enum(["owner", "admin", "member"]);
|
|
616
|
+
var workspaceInviteRoleSchema = z10.enum(["admin", "member"]);
|
|
617
|
+
var workspaceHandleSchema = z10.string().min(3).max(32).regex(WORKSPACE_HANDLE_PATTERN, {
|
|
529
618
|
message: "handle must be lowercase letters, digits, and hyphens, with no leading/trailing hyphen"
|
|
530
619
|
});
|
|
531
|
-
var createWorkspaceSchema =
|
|
620
|
+
var createWorkspaceSchema = z10.object({
|
|
532
621
|
handle: workspaceHandleSchema.optional(),
|
|
533
|
-
name:
|
|
622
|
+
name: z10.string().trim().min(1).max(100)
|
|
534
623
|
});
|
|
535
|
-
var updateWorkspaceSchema =
|
|
624
|
+
var updateWorkspaceSchema = z10.object({
|
|
536
625
|
handle: workspaceHandleSchema.optional(),
|
|
537
|
-
name:
|
|
626
|
+
name: z10.string().trim().min(1).max(100).optional()
|
|
538
627
|
}).refine((body) => body.handle !== void 0 || body.name !== void 0, {
|
|
539
628
|
message: "provide at least one of name or handle"
|
|
540
629
|
});
|
|
541
|
-
var workspaceSchema =
|
|
542
|
-
createdAt:
|
|
543
|
-
handle:
|
|
630
|
+
var workspaceSchema = z10.object({
|
|
631
|
+
createdAt: z10.string(),
|
|
632
|
+
handle: z10.string(),
|
|
544
633
|
// ISO timestamp when `{handle}.artifact.cafe` was provisioned, or null.
|
|
545
634
|
// Set by the one-time, self-serve enable flow (§4.4); never auto at
|
|
546
635
|
// create, and always null for personal workspaces.
|
|
547
|
-
hostnameProvisionedAt:
|
|
548
|
-
id:
|
|
636
|
+
hostnameProvisionedAt: z10.string().nullable(),
|
|
637
|
+
id: z10.string(),
|
|
549
638
|
// Auto-provisioned solo workspace, one per user: non-deletable, takes
|
|
550
639
|
// no members, renameable like any workspace.
|
|
551
|
-
isPersonal:
|
|
640
|
+
isPersonal: z10.boolean(),
|
|
552
641
|
// Uploaded logo URL, or null for the initials fallback. Set through the
|
|
553
642
|
// dedicated /workspaces/:id/avatar route, never the generic update.
|
|
554
|
-
logo:
|
|
555
|
-
name:
|
|
643
|
+
logo: z10.string().nullable(),
|
|
644
|
+
name: z10.string(),
|
|
556
645
|
role: workspaceRoleSchema.nullable(),
|
|
557
|
-
updatedAt:
|
|
646
|
+
updatedAt: z10.string()
|
|
558
647
|
});
|
|
559
|
-
var workspaceListResponseSchema =
|
|
560
|
-
workspaces:
|
|
648
|
+
var workspaceListResponseSchema = z10.object({
|
|
649
|
+
workspaces: z10.array(workspaceSchema)
|
|
561
650
|
});
|
|
562
|
-
var deleteWorkspaceResponseSchema =
|
|
563
|
-
deleted:
|
|
651
|
+
var deleteWorkspaceResponseSchema = z10.object({
|
|
652
|
+
deleted: z10.literal(true)
|
|
564
653
|
});
|
|
565
|
-
var workspaceMemberSchema =
|
|
566
|
-
createdAt:
|
|
567
|
-
email:
|
|
568
|
-
image:
|
|
569
|
-
name:
|
|
654
|
+
var workspaceMemberSchema = z10.object({
|
|
655
|
+
createdAt: z10.string(),
|
|
656
|
+
email: z10.string().email(),
|
|
657
|
+
image: z10.string().nullable(),
|
|
658
|
+
name: z10.string(),
|
|
570
659
|
role: workspaceRoleSchema,
|
|
571
|
-
userId:
|
|
660
|
+
userId: z10.string()
|
|
572
661
|
});
|
|
573
|
-
var workspaceMemberListResponseSchema =
|
|
574
|
-
members:
|
|
662
|
+
var workspaceMemberListResponseSchema = z10.object({
|
|
663
|
+
members: z10.array(workspaceMemberSchema)
|
|
575
664
|
});
|
|
576
|
-
var updateWorkspaceMemberSchema =
|
|
665
|
+
var updateWorkspaceMemberSchema = z10.object({
|
|
577
666
|
role: workspaceRoleSchema
|
|
578
667
|
});
|
|
579
|
-
var removeWorkspaceMemberResponseSchema =
|
|
580
|
-
removed:
|
|
668
|
+
var removeWorkspaceMemberResponseSchema = z10.object({
|
|
669
|
+
removed: z10.literal(true)
|
|
581
670
|
});
|
|
582
|
-
var createWorkspaceInviteSchema =
|
|
583
|
-
email:
|
|
584
|
-
expiresAt:
|
|
585
|
-
maxUses:
|
|
671
|
+
var createWorkspaceInviteSchema = z10.object({
|
|
672
|
+
email: z10.string().trim().toLowerCase().email().optional(),
|
|
673
|
+
expiresAt: z10.string().datetime(),
|
|
674
|
+
maxUses: z10.number().int().positive().optional(),
|
|
586
675
|
role: workspaceInviteRoleSchema
|
|
587
676
|
});
|
|
588
|
-
var workspaceInviteSchema =
|
|
589
|
-
createdAt:
|
|
590
|
-
email:
|
|
591
|
-
expiresAt:
|
|
592
|
-
id:
|
|
593
|
-
maxUses:
|
|
677
|
+
var workspaceInviteSchema = z10.object({
|
|
678
|
+
createdAt: z10.string(),
|
|
679
|
+
email: z10.string().email().nullable(),
|
|
680
|
+
expiresAt: z10.string(),
|
|
681
|
+
id: z10.string(),
|
|
682
|
+
maxUses: z10.number().int().positive().nullable(),
|
|
594
683
|
role: workspaceInviteRoleSchema,
|
|
595
|
-
tokenPrefix:
|
|
596
|
-
useCount:
|
|
684
|
+
tokenPrefix: z10.string(),
|
|
685
|
+
useCount: z10.number().int().nonnegative()
|
|
597
686
|
});
|
|
598
687
|
var createdWorkspaceInviteSchema = workspaceInviteSchema.extend({
|
|
599
|
-
url:
|
|
688
|
+
url: z10.string().url()
|
|
600
689
|
});
|
|
601
|
-
var workspaceInviteListResponseSchema =
|
|
602
|
-
invites:
|
|
690
|
+
var workspaceInviteListResponseSchema = z10.object({
|
|
691
|
+
invites: z10.array(workspaceInviteSchema)
|
|
603
692
|
});
|
|
604
|
-
var revokeWorkspaceInviteResponseSchema =
|
|
605
|
-
revoked:
|
|
693
|
+
var revokeWorkspaceInviteResponseSchema = z10.object({
|
|
694
|
+
revoked: z10.literal(true)
|
|
606
695
|
});
|
|
607
|
-
var acceptWorkspaceInviteSchema =
|
|
608
|
-
token:
|
|
696
|
+
var acceptWorkspaceInviteSchema = z10.object({
|
|
697
|
+
token: z10.string().min(1)
|
|
609
698
|
});
|
|
610
|
-
var acceptWorkspaceInviteResponseSchema =
|
|
699
|
+
var acceptWorkspaceInviteResponseSchema = z10.object({
|
|
611
700
|
role: workspaceRoleSchema,
|
|
612
701
|
workspace: workspaceSchema
|
|
613
702
|
});
|
|
614
|
-
var folderVisibilitySchema =
|
|
615
|
-
var artifactVisibilitySchema =
|
|
703
|
+
var folderVisibilitySchema = z10.enum(["public", "workspace"]);
|
|
704
|
+
var artifactVisibilitySchema = z10.enum([
|
|
616
705
|
"public",
|
|
617
706
|
"unlisted",
|
|
618
707
|
"workspace",
|
|
619
708
|
"private"
|
|
620
709
|
]);
|
|
621
|
-
var createFolderSchema =
|
|
622
|
-
|
|
710
|
+
var createFolderSchema = z10.object({
|
|
711
|
+
// Optional custom icon; omitted (or null) leaves the default glyph.
|
|
712
|
+
emoji: iconEmojiSchema.optional(),
|
|
713
|
+
name: z10.string().trim().min(1).max(100),
|
|
623
714
|
visibility: folderVisibilitySchema
|
|
624
715
|
});
|
|
625
|
-
var updateFolderSchema =
|
|
716
|
+
var updateFolderSchema = z10.object({
|
|
626
717
|
// With `visibility`: bulk-update the folder's artifacts to match
|
|
627
718
|
// (SPEC-2 §3.4 "Changing a folder's visibility offers a bulk update").
|
|
628
|
-
cascade:
|
|
629
|
-
|
|
630
|
-
|
|
719
|
+
cascade: z10.boolean().optional(),
|
|
720
|
+
// Explicit null clears the icon back to the default glyph, so this is
|
|
721
|
+
// a field where "sent as null" and "omitted" mean different things.
|
|
722
|
+
emoji: iconEmojiSchema.optional(),
|
|
723
|
+
name: z10.string().trim().min(1).max(100).optional(),
|
|
724
|
+
sortOrder: z10.number().int().min(0).optional(),
|
|
631
725
|
visibility: folderVisibilitySchema.optional()
|
|
632
726
|
}).refine(
|
|
633
|
-
(body) => body.name !== void 0 || body.visibility !== void 0 || body.sortOrder !== void 0,
|
|
634
|
-
{ message: "provide at least one of name, visibility, sortOrder" }
|
|
727
|
+
(body) => body.name !== void 0 || body.visibility !== void 0 || body.sortOrder !== void 0 || body.emoji !== void 0,
|
|
728
|
+
{ message: "provide at least one of name, visibility, sortOrder, emoji" }
|
|
635
729
|
).refine((body) => !body.cascade || body.visibility !== void 0, {
|
|
636
730
|
message: "cascade requires visibility"
|
|
637
731
|
});
|
|
638
|
-
var folderSchema =
|
|
639
|
-
createdAt:
|
|
640
|
-
|
|
641
|
-
|
|
732
|
+
var folderSchema = z10.object({
|
|
733
|
+
createdAt: z10.string(),
|
|
734
|
+
// Custom icon, or null to render the default folder glyph.
|
|
735
|
+
emoji: z10.string().nullable(),
|
|
736
|
+
id: z10.string(),
|
|
737
|
+
name: z10.string(),
|
|
642
738
|
// Permalink segment for the public folder page (/w/{handle}/f/{slug}).
|
|
643
739
|
// Server-derived from the name; renames regenerate it.
|
|
644
|
-
slug:
|
|
645
|
-
sortOrder:
|
|
646
|
-
updatedAt:
|
|
740
|
+
slug: z10.string(),
|
|
741
|
+
sortOrder: z10.number().int(),
|
|
742
|
+
updatedAt: z10.string(),
|
|
647
743
|
visibility: folderVisibilitySchema,
|
|
648
|
-
workspaceId:
|
|
744
|
+
workspaceId: z10.string()
|
|
649
745
|
});
|
|
650
|
-
var folderListResponseSchema =
|
|
651
|
-
folders:
|
|
746
|
+
var folderListResponseSchema = z10.object({
|
|
747
|
+
folders: z10.array(folderSchema)
|
|
652
748
|
});
|
|
653
|
-
var deleteFolderResponseSchema =
|
|
654
|
-
deleted:
|
|
749
|
+
var deleteFolderResponseSchema = z10.object({
|
|
750
|
+
deleted: z10.literal(true)
|
|
655
751
|
});
|
|
656
|
-
var workspaceArtifactSchema =
|
|
657
|
-
createdAt:
|
|
658
|
-
currentVersionNumber:
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
752
|
+
var workspaceArtifactSchema = z10.object({
|
|
753
|
+
createdAt: z10.string(),
|
|
754
|
+
currentVersionNumber: z10.number().int().nullable(),
|
|
755
|
+
// Custom icon, or null to render the default document glyph.
|
|
756
|
+
emoji: z10.string().nullable(),
|
|
757
|
+
folderId: z10.string().nullable(),
|
|
758
|
+
id: z10.string(),
|
|
759
|
+
openCommentCount: z10.number().int().nonnegative(),
|
|
662
760
|
reviewMode: reviewModeSchema,
|
|
663
|
-
slug:
|
|
664
|
-
title:
|
|
665
|
-
updatedAt:
|
|
666
|
-
url:
|
|
667
|
-
versionCount:
|
|
761
|
+
slug: z10.string(),
|
|
762
|
+
title: z10.string(),
|
|
763
|
+
updatedAt: z10.string(),
|
|
764
|
+
url: z10.string().url(),
|
|
765
|
+
versionCount: z10.number().int().nonnegative(),
|
|
668
766
|
visibility: artifactVisibilitySchema
|
|
669
767
|
});
|
|
670
|
-
var workspaceArtifactListResponseSchema =
|
|
671
|
-
artifacts:
|
|
768
|
+
var workspaceArtifactListResponseSchema = z10.object({
|
|
769
|
+
artifacts: z10.array(workspaceArtifactSchema)
|
|
672
770
|
});
|
|
673
|
-
var workspaceArtifactSearchResultSchema =
|
|
674
|
-
id:
|
|
675
|
-
slug:
|
|
676
|
-
title:
|
|
771
|
+
var workspaceArtifactSearchResultSchema = z10.object({
|
|
772
|
+
id: z10.string(),
|
|
773
|
+
slug: z10.string(),
|
|
774
|
+
title: z10.string()
|
|
677
775
|
});
|
|
678
|
-
var workspaceArtifactSearchResponseSchema =
|
|
679
|
-
results:
|
|
776
|
+
var workspaceArtifactSearchResponseSchema = z10.object({
|
|
777
|
+
results: z10.array(workspaceArtifactSearchResultSchema)
|
|
680
778
|
});
|
|
681
779
|
|
|
682
780
|
// ../shared/src/me.ts
|
|
683
|
-
var ownArtifactSchema =
|
|
684
|
-
createdAt:
|
|
685
|
-
currentVersionNumber:
|
|
781
|
+
var ownArtifactSchema = z11.object({
|
|
782
|
+
createdAt: z11.string(),
|
|
783
|
+
currentVersionNumber: z11.number().nullable(),
|
|
784
|
+
// Custom icon, or null to render the default document glyph.
|
|
785
|
+
emoji: z11.string().nullable(),
|
|
686
786
|
// Owned artifacts normally never expire; non-null only while an
|
|
687
787
|
// expiry is still set (e.g. an unclaimed publish surfaced here later).
|
|
688
|
-
expiresAt:
|
|
788
|
+
expiresAt: z11.string().nullable(),
|
|
689
789
|
// SPEC-2 §8.4 — the containing folder for workspace-owned artifacts;
|
|
690
790
|
// both null for personal artifacts. `folderId` drives the dashboard's
|
|
691
|
-
// move control and folder filter; `folderName` is the display label
|
|
692
|
-
|
|
693
|
-
|
|
791
|
+
// move control and folder filter; `folderName` is the display label,
|
|
792
|
+
// `folderEmoji` its icon (null = the default folder glyph).
|
|
793
|
+
folderEmoji: z11.string().nullable(),
|
|
794
|
+
folderId: z11.string().nullable(),
|
|
795
|
+
folderName: z11.string().nullable(),
|
|
694
796
|
// Whether a publish token is still active — revocable from the
|
|
695
797
|
// dashboard (§6.18); the token itself is never returned.
|
|
696
|
-
hasPublishToken:
|
|
697
|
-
id:
|
|
698
|
-
openThreads:
|
|
699
|
-
protected:
|
|
798
|
+
hasPublishToken: z11.boolean(),
|
|
799
|
+
id: z11.string(),
|
|
800
|
+
openThreads: z11.number(),
|
|
801
|
+
protected: z11.boolean(),
|
|
700
802
|
// Who published the current version (falling back to the claiming
|
|
701
803
|
// owner) — the dashboard shows a name and avatar per artifact so a
|
|
702
804
|
// shared workspace reads as people's work, not anonymous rows. Null
|
|
703
805
|
// when the publish was token-only and the artifact is unclaimed.
|
|
704
|
-
publishedBy:
|
|
806
|
+
publishedBy: z11.object({ image: z11.string().nullable(), name: z11.string() }).nullable(),
|
|
705
807
|
// SPEC-2 §5.8 — the review dial, so the dashboard's settings dialog can
|
|
706
808
|
// render current state without a second fetch.
|
|
707
809
|
reviewMode: reviewModeSchema,
|
|
708
|
-
slug:
|
|
709
|
-
title:
|
|
710
|
-
totalViews:
|
|
810
|
+
slug: z11.string(),
|
|
811
|
+
title: z11.string(),
|
|
812
|
+
totalViews: z11.number(),
|
|
711
813
|
// SPEC §6.20 — messages by others newer than the viewer's last-seen
|
|
712
814
|
// watermark. 0 for signed-out/API-key-less contexts.
|
|
713
|
-
unreadComments:
|
|
714
|
-
updatedAt:
|
|
715
|
-
url:
|
|
716
|
-
versionCount:
|
|
815
|
+
unreadComments: z11.number(),
|
|
816
|
+
updatedAt: z11.string(),
|
|
817
|
+
url: z11.string(),
|
|
818
|
+
versionCount: z11.number(),
|
|
717
819
|
// SPEC-2 §5.1 — whether the caller clears the manage bar for this
|
|
718
820
|
// artifact (workspace admin, or the person who first published it).
|
|
719
821
|
// Only a manager's folder move inherits the folder's visibility, so the
|
|
720
822
|
// dashboard warns exactly the people the change can actually affect, and
|
|
721
823
|
// only a manager is offered the Share entry (§5.7).
|
|
722
|
-
viewerCanManage:
|
|
824
|
+
viewerCanManage: z11.boolean(),
|
|
723
825
|
// SPEC-2 §5.2 — the artifact's own visibility, the single enforcement
|
|
724
826
|
// source. The dashboard needs it to tell whether a folder move would
|
|
725
|
-
// widen exposure before it sends the PATCH (§3.4), and to render the
|
|
726
|
-
// glyph on
|
|
827
|
+
// widen exposure before it sends the PATCH (§3.4), and to render the
|
|
828
|
+
// audience glyph — one per level — on rows and cards (§5.7).
|
|
727
829
|
visibility: artifactVisibilitySchema
|
|
728
830
|
});
|
|
729
|
-
var ownArtifactsResponseSchema =
|
|
730
|
-
artifacts:
|
|
831
|
+
var ownArtifactsResponseSchema = z11.object({
|
|
832
|
+
artifacts: z11.array(ownArtifactSchema)
|
|
731
833
|
});
|
|
732
|
-
var revokePublishTokenResponseSchema =
|
|
733
|
-
revoked:
|
|
834
|
+
var revokePublishTokenResponseSchema = z11.object({
|
|
835
|
+
revoked: z11.boolean()
|
|
734
836
|
});
|
|
735
837
|
|
|
736
838
|
// ../shared/src/owner.ts
|
|
737
|
-
import { z as
|
|
839
|
+
import { z as z12 } from "zod";
|
|
738
840
|
var SLUG_PATTERN = /^[a-z0-9](?:[a-z0-9-]{1,61}[a-z0-9])$/;
|
|
739
|
-
var claimResponseSchema =
|
|
740
|
-
artifactId:
|
|
741
|
-
slug:
|
|
742
|
-
title:
|
|
743
|
-
url:
|
|
744
|
-
});
|
|
745
|
-
var updateArtifactSchema =
|
|
841
|
+
var claimResponseSchema = z12.object({
|
|
842
|
+
artifactId: z12.string(),
|
|
843
|
+
slug: z12.string(),
|
|
844
|
+
title: z12.string(),
|
|
845
|
+
url: z12.string().url()
|
|
846
|
+
});
|
|
847
|
+
var updateArtifactSchema = z12.object({
|
|
848
|
+
// Custom icon; explicit null clears it back to the default glyph.
|
|
849
|
+
// Part of what the artifact *is* (like the title), so it takes the
|
|
850
|
+
// same manage rights as title/slug — not the member-level folder move.
|
|
851
|
+
emoji: iconEmojiSchema.optional(),
|
|
746
852
|
// SPEC-2 §6.4 — placement + visibility. `folderId: null` clears the
|
|
747
853
|
// folder; `workspaceId: null` moves the artifact out of its workspace
|
|
748
854
|
// (§5.5 ownership transfer).
|
|
749
|
-
folderId:
|
|
750
|
-
slug:
|
|
855
|
+
folderId: z12.string().min(1).nullable().optional(),
|
|
856
|
+
slug: z12.string().min(3).max(63).regex(SLUG_PATTERN, {
|
|
751
857
|
message: "slug must be lowercase letters, digits, and hyphens, with no leading/trailing hyphen"
|
|
752
858
|
}).optional(),
|
|
753
|
-
title:
|
|
859
|
+
title: z12.string().min(1).max(200).optional(),
|
|
754
860
|
visibility: artifactVisibilitySchema.optional(),
|
|
755
|
-
workspaceId:
|
|
861
|
+
workspaceId: z12.string().min(1).nullable().optional()
|
|
756
862
|
}).refine(
|
|
757
|
-
(body) => body.title !== void 0 || body.slug !== void 0 || body.visibility !== void 0 || body.folderId !== void 0 || body.workspaceId !== void 0,
|
|
863
|
+
(body) => body.title !== void 0 || body.slug !== void 0 || body.visibility !== void 0 || body.folderId !== void 0 || body.workspaceId !== void 0 || body.emoji !== void 0,
|
|
758
864
|
{
|
|
759
|
-
message: "provide at least one of title, slug, visibility, folderId, workspaceId"
|
|
865
|
+
message: "provide at least one of title, slug, visibility, folderId, workspaceId, emoji"
|
|
760
866
|
}
|
|
761
867
|
);
|
|
762
|
-
var deleteArtifactResponseSchema =
|
|
763
|
-
deleted:
|
|
868
|
+
var deleteArtifactResponseSchema = z12.object({
|
|
869
|
+
deleted: z12.literal(true)
|
|
764
870
|
});
|
|
765
871
|
|
|
766
872
|
// ../shared/src/presence.ts
|
|
767
|
-
import { z as
|
|
873
|
+
import { z as z13 } from "zod";
|
|
768
874
|
var AGENT_STATES = ["listening", "editing", "publishing"];
|
|
769
|
-
var agentStateSchema =
|
|
875
|
+
var agentStateSchema = z13.enum(AGENT_STATES);
|
|
770
876
|
var AGENT_PRESENCE = {
|
|
771
877
|
editingTtlSeconds: 300,
|
|
772
878
|
heartbeatSeconds: 15,
|
|
773
879
|
shellPollSeconds: 15,
|
|
774
880
|
ttlSeconds: 45
|
|
775
881
|
};
|
|
776
|
-
var agentHeartbeatBodySchema =
|
|
882
|
+
var agentHeartbeatBodySchema = z13.object({
|
|
777
883
|
state: agentStateSchema.optional()
|
|
778
884
|
});
|
|
779
|
-
var agentHeartbeatResponseSchema =
|
|
780
|
-
listening:
|
|
885
|
+
var agentHeartbeatResponseSchema = z13.object({
|
|
886
|
+
listening: z13.literal(true),
|
|
781
887
|
state: agentStateSchema.optional(),
|
|
782
|
-
ttlSeconds:
|
|
888
|
+
ttlSeconds: z13.number().int().positive()
|
|
783
889
|
});
|
|
784
|
-
var agentPresenceSchema =
|
|
785
|
-
|
|
890
|
+
var agentPresenceSchema = z13.object({
|
|
891
|
+
agent: z13.object({ id: z13.string().nullable(), label: z13.string() }).nullable().default(null),
|
|
892
|
+
listening: z13.boolean(),
|
|
786
893
|
state: agentStateSchema.nullable().optional(),
|
|
787
|
-
versionNumber:
|
|
894
|
+
versionNumber: z13.number().int().positive().nullable()
|
|
788
895
|
});
|
|
789
896
|
|
|
790
897
|
// ../shared/src/protection.ts
|
|
791
|
-
import { z as
|
|
898
|
+
import { z as z14 } from "zod";
|
|
792
899
|
var PASSWORD_MIN = 6;
|
|
793
900
|
var PASSWORD_MAX = 128;
|
|
794
|
-
var gatePasswordSchema =
|
|
795
|
-
var setProtectionSchema =
|
|
901
|
+
var gatePasswordSchema = z14.string().min(PASSWORD_MIN, `Password must be at least ${PASSWORD_MIN} characters.`).max(PASSWORD_MAX, `Password must be at most ${PASSWORD_MAX} characters.`);
|
|
902
|
+
var setProtectionSchema = z14.object({
|
|
796
903
|
password: gatePasswordSchema.nullable()
|
|
797
904
|
});
|
|
798
|
-
var protectionResponseSchema =
|
|
799
|
-
protected:
|
|
905
|
+
var protectionResponseSchema = z14.object({
|
|
906
|
+
protected: z14.boolean()
|
|
800
907
|
});
|
|
801
|
-
var unlockSchema =
|
|
802
|
-
password:
|
|
908
|
+
var unlockSchema = z14.object({
|
|
909
|
+
password: z14.string().min(1).max(1024)
|
|
803
910
|
});
|
|
804
|
-
var unlockResponseSchema =
|
|
805
|
-
unlocked:
|
|
911
|
+
var unlockResponseSchema = z14.object({
|
|
912
|
+
unlocked: z14.literal(true)
|
|
806
913
|
});
|
|
807
914
|
|
|
808
915
|
// ../shared/src/report.ts
|
|
809
|
-
import { z as
|
|
810
|
-
var reportRequestSchema =
|
|
811
|
-
reason:
|
|
916
|
+
import { z as z15 } from "zod";
|
|
917
|
+
var reportRequestSchema = z15.object({
|
|
918
|
+
reason: z15.string().max(1e3).optional()
|
|
812
919
|
});
|
|
813
|
-
var reportResponseSchema =
|
|
814
|
-
reported:
|
|
920
|
+
var reportResponseSchema = z15.object({
|
|
921
|
+
reported: z15.literal(true)
|
|
815
922
|
});
|
|
816
923
|
|
|
817
924
|
// ../shared/src/reviewers.ts
|
|
818
|
-
import { z as
|
|
819
|
-
var artifactReviewerSchema =
|
|
820
|
-
avatarUrl:
|
|
821
|
-
displayName:
|
|
925
|
+
import { z as z16 } from "zod";
|
|
926
|
+
var artifactReviewerSchema = z16.object({
|
|
927
|
+
avatarUrl: z16.string().nullable(),
|
|
928
|
+
displayName: z16.string(),
|
|
822
929
|
// Exactly one of userId/guestId is set, per `kind`.
|
|
823
|
-
guestId:
|
|
930
|
+
guestId: z16.string().nullable(),
|
|
824
931
|
// "account", not commentAuthorSchema's "member" — the whole point here is
|
|
825
932
|
// that these people need not be workspace members. A guest can be named in
|
|
826
933
|
// a comment but never notified: guest_identities carries a display name and
|
|
827
934
|
// no email, so there is nowhere to send anything.
|
|
828
|
-
kind:
|
|
829
|
-
userId:
|
|
935
|
+
kind: z16.enum(["account", "guest"]),
|
|
936
|
+
userId: z16.string().nullable()
|
|
830
937
|
});
|
|
831
|
-
var artifactReviewerListResponseSchema =
|
|
832
|
-
reviewers:
|
|
938
|
+
var artifactReviewerListResponseSchema = z16.object({
|
|
939
|
+
reviewers: z16.array(artifactReviewerSchema)
|
|
833
940
|
});
|
|
834
941
|
|
|
835
942
|
// ../shared/src/stats.ts
|
|
836
|
-
import { z as
|
|
837
|
-
var avgViewSecondsSchema =
|
|
838
|
-
var versionViewStatsSchema =
|
|
943
|
+
import { z as z17 } from "zod";
|
|
944
|
+
var avgViewSecondsSchema = z17.number().int().nonnegative().nullable();
|
|
945
|
+
var versionViewStatsSchema = z17.object({
|
|
839
946
|
avgViewSeconds: avgViewSecondsSchema,
|
|
840
947
|
// Views from inside the review shell's iframe vs. direct visits to
|
|
841
948
|
// the render URL. views = embeddedViews + directViews.
|
|
842
|
-
directViews:
|
|
843
|
-
embeddedViews:
|
|
949
|
+
directViews: z17.number().int().nonnegative(),
|
|
950
|
+
embeddedViews: z17.number().int().nonnegative(),
|
|
844
951
|
// Distinct hashed viewer IPs across the version's lifetime.
|
|
845
|
-
uniqueViewers:
|
|
846
|
-
versionNumber:
|
|
847
|
-
views:
|
|
952
|
+
uniqueViewers: z17.number().int().nonnegative(),
|
|
953
|
+
versionNumber: z17.number().int().positive(),
|
|
954
|
+
views: z17.number().int().nonnegative()
|
|
848
955
|
});
|
|
849
|
-
var dailyViewsSchema =
|
|
956
|
+
var dailyViewsSchema = z17.object({
|
|
850
957
|
avgViewSeconds: avgViewSecondsSchema,
|
|
851
958
|
// UTC day, YYYY-MM-DD.
|
|
852
|
-
day:
|
|
853
|
-
uniqueViewers:
|
|
854
|
-
views:
|
|
959
|
+
day: z17.string(),
|
|
960
|
+
uniqueViewers: z17.number().int().nonnegative(),
|
|
961
|
+
views: z17.number().int().nonnegative()
|
|
855
962
|
});
|
|
856
|
-
var artifactStatsResponseSchema =
|
|
963
|
+
var artifactStatsResponseSchema = z17.object({
|
|
857
964
|
avgViewSeconds: avgViewSecondsSchema,
|
|
858
|
-
daily:
|
|
965
|
+
daily: z17.array(dailyViewsSchema),
|
|
859
966
|
// Distinct hashed viewer IPs across all versions and days.
|
|
860
|
-
totalUniqueViewers:
|
|
861
|
-
totalViews:
|
|
862
|
-
versions:
|
|
967
|
+
totalUniqueViewers: z17.number().int().nonnegative(),
|
|
968
|
+
totalViews: z17.number().int().nonnegative(),
|
|
969
|
+
versions: z17.array(versionViewStatsSchema)
|
|
863
970
|
});
|
|
864
971
|
|
|
865
972
|
// ../shared/src/versions.ts
|
|
866
|
-
import { z as
|
|
867
|
-
var versionSourceSchema =
|
|
868
|
-
agentName:
|
|
869
|
-
type:
|
|
973
|
+
import { z as z18 } from "zod";
|
|
974
|
+
var versionSourceSchema = z18.object({
|
|
975
|
+
agentName: z18.string().nullable(),
|
|
976
|
+
type: z18.string()
|
|
870
977
|
});
|
|
871
|
-
var versionChangesSchema =
|
|
872
|
-
added:
|
|
873
|
-
changed:
|
|
874
|
-
removed:
|
|
978
|
+
var versionChangesSchema = z18.object({
|
|
979
|
+
added: z18.array(z18.string()),
|
|
980
|
+
changed: z18.array(z18.string()),
|
|
981
|
+
removed: z18.array(z18.string())
|
|
875
982
|
});
|
|
876
|
-
var versionSummarySchema =
|
|
983
|
+
var versionSummarySchema = z18.object({
|
|
877
984
|
// Absent for the first version — there is no previous version to diff against.
|
|
878
985
|
changes: versionChangesSchema.nullable(),
|
|
879
|
-
createdAt:
|
|
880
|
-
entryUrl:
|
|
881
|
-
fileCount:
|
|
882
|
-
id:
|
|
883
|
-
isCurrent:
|
|
986
|
+
createdAt: z18.string(),
|
|
987
|
+
entryUrl: z18.string().url(),
|
|
988
|
+
fileCount: z18.number().int().nonnegative(),
|
|
989
|
+
id: z18.string(),
|
|
990
|
+
isCurrent: z18.boolean(),
|
|
884
991
|
// Author-supplied bullet-point changelog; null when the publish omitted it.
|
|
885
|
-
notes:
|
|
992
|
+
notes: z18.string().nullable(),
|
|
886
993
|
source: versionSourceSchema,
|
|
887
|
-
totalSizeBytes:
|
|
888
|
-
versionNumber:
|
|
994
|
+
totalSizeBytes: z18.number().int().nonnegative(),
|
|
995
|
+
versionNumber: z18.number().int().positive()
|
|
889
996
|
});
|
|
890
|
-
var versionListResponseSchema =
|
|
891
|
-
versions:
|
|
997
|
+
var versionListResponseSchema = z18.object({
|
|
998
|
+
versions: z18.array(versionSummarySchema)
|
|
892
999
|
});
|
|
893
1000
|
|
|
1001
|
+
// src/agent-identity.ts
|
|
1002
|
+
function agentLabel(explicit) {
|
|
1003
|
+
if (explicit !== void 0) {
|
|
1004
|
+
return explicit.trim() || void 0;
|
|
1005
|
+
}
|
|
1006
|
+
return detectAgentFromEnv(process.env);
|
|
1007
|
+
}
|
|
1008
|
+
|
|
894
1009
|
// src/api.ts
|
|
895
1010
|
var ApiRequestError = class extends Error {
|
|
896
1011
|
constructor(status2, code, message, retryAfter) {
|
|
@@ -1108,11 +1223,13 @@ function createApiClient(apiUrl2, publishToken) {
|
|
|
1108
1223
|
// SPEC §6.5 — post a reply into a thread. Authorized by this client's
|
|
1109
1224
|
// credential: the artifact's publish token (the reply renders as the
|
|
1110
1225
|
// agent) or the owner's account key (renders as the owner). No guest
|
|
1111
|
-
// payload — the credential is the identity.
|
|
1112
|
-
|
|
1226
|
+
// payload — the credential is the identity. `via` names the tool: it
|
|
1227
|
+
// becomes the agent's byline on a token reply, a "via" label on an
|
|
1228
|
+
// account one.
|
|
1229
|
+
async replyThread(threadId, body, via) {
|
|
1113
1230
|
return request(
|
|
1114
1231
|
`${base}/api/v1/comment-threads/${threadId}/messages`,
|
|
1115
|
-
{ body: JSON.stringify({ body }), headers, method: "POST" },
|
|
1232
|
+
{ body: JSON.stringify({ body, via }), headers, method: "POST" },
|
|
1116
1233
|
(d) => commentThreadSchema.parse(d)
|
|
1117
1234
|
);
|
|
1118
1235
|
},
|
|
@@ -1189,17 +1306,17 @@ import {
|
|
|
1189
1306
|
writeFileSync as writeFileSync2
|
|
1190
1307
|
} from "fs";
|
|
1191
1308
|
import path2 from "path";
|
|
1192
|
-
import { z as
|
|
1309
|
+
import { z as z20 } from "zod";
|
|
1193
1310
|
|
|
1194
1311
|
// src/credentials.ts
|
|
1195
1312
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
1196
1313
|
import { homedir } from "os";
|
|
1197
1314
|
import path from "path";
|
|
1198
|
-
import { z as
|
|
1315
|
+
import { z as z19 } from "zod";
|
|
1199
1316
|
var DEFAULT_API_URL = "https://artifact.cafe";
|
|
1200
|
-
var credentialsSchema =
|
|
1201
|
-
keys:
|
|
1202
|
-
version:
|
|
1317
|
+
var credentialsSchema = z19.object({
|
|
1318
|
+
keys: z19.record(z19.string(), z19.string()),
|
|
1319
|
+
version: z19.literal(1)
|
|
1203
1320
|
});
|
|
1204
1321
|
function credentialsPath() {
|
|
1205
1322
|
return path.join(homedir(), ".artifactcafe", "credentials");
|
|
@@ -1249,24 +1366,24 @@ function resolveApiKey(apiUrl2, flag) {
|
|
|
1249
1366
|
}
|
|
1250
1367
|
|
|
1251
1368
|
// src/config.ts
|
|
1252
|
-
var configSchema =
|
|
1253
|
-
apiUrl:
|
|
1254
|
-
artifactId:
|
|
1255
|
-
folder:
|
|
1256
|
-
folderId:
|
|
1369
|
+
var configSchema = z20.object({
|
|
1370
|
+
apiUrl: z20.string(),
|
|
1371
|
+
artifactId: z20.string(),
|
|
1372
|
+
folder: z20.string().optional(),
|
|
1373
|
+
folderId: z20.string().optional(),
|
|
1257
1374
|
// Optional: a folder linked by `link` to an artifact you own carries no
|
|
1258
1375
|
// token — owner actions authorize via your stored login instead. A first
|
|
1259
1376
|
// publish still writes the anonymous-mode token here.
|
|
1260
|
-
publishToken:
|
|
1261
|
-
slug:
|
|
1262
|
-
url:
|
|
1263
|
-
workspace:
|
|
1264
|
-
workspaceId:
|
|
1265
|
-
workspaceKind:
|
|
1266
|
-
});
|
|
1267
|
-
var projectConfigSchema =
|
|
1268
|
-
folder:
|
|
1269
|
-
workspace:
|
|
1377
|
+
publishToken: z20.string().optional(),
|
|
1378
|
+
slug: z20.string(),
|
|
1379
|
+
url: z20.string(),
|
|
1380
|
+
workspace: z20.string().optional(),
|
|
1381
|
+
workspaceId: z20.string().optional(),
|
|
1382
|
+
workspaceKind: z20.enum(["personal", "workspace"]).optional()
|
|
1383
|
+
});
|
|
1384
|
+
var projectConfigSchema = z20.object({
|
|
1385
|
+
folder: z20.string().trim().min(1).optional(),
|
|
1386
|
+
workspace: z20.string().trim().min(1)
|
|
1270
1387
|
}).strict();
|
|
1271
1388
|
var CONFIG_DIR = ".artifactcafe";
|
|
1272
1389
|
var CONFIG_FILE = "config.json";
|
|
@@ -1302,7 +1419,7 @@ function readProjectConfig(dir) {
|
|
|
1302
1419
|
JSON.parse(readFileSync2(file, "utf8"))
|
|
1303
1420
|
);
|
|
1304
1421
|
} catch (error) {
|
|
1305
|
-
const message = error instanceof
|
|
1422
|
+
const message = error instanceof z20.ZodError ? error.issues[0]?.message ?? "invalid project target" : "invalid JSON";
|
|
1306
1423
|
throw new Error(`Invalid ${file}: ${message}.`);
|
|
1307
1424
|
}
|
|
1308
1425
|
}
|
|
@@ -1441,7 +1558,10 @@ async function comment(opts) {
|
|
|
1441
1558
|
anchor,
|
|
1442
1559
|
body,
|
|
1443
1560
|
versionId: artifact.currentVersion.id,
|
|
1444
|
-
|
|
1561
|
+
// An account comment keeps its own name and takes the tool as a "via"
|
|
1562
|
+
// label (§6.4) — detected when neither flag is given, so an agent
|
|
1563
|
+
// commenting with your key still says which tool typed it.
|
|
1564
|
+
via: agentLabel(opts.as ?? opts.via)
|
|
1445
1565
|
});
|
|
1446
1566
|
} catch (err) {
|
|
1447
1567
|
if (err instanceof ApiRequestError && err.status === 401) {
|
|
@@ -1873,6 +1993,9 @@ async function publish(opts) {
|
|
|
1873
1993
|
}
|
|
1874
1994
|
const sessionBody = {
|
|
1875
1995
|
artifactId,
|
|
1996
|
+
// Overrides the entry HTML's own meta description on the share card.
|
|
1997
|
+
// Omitted entirely when absent, so the document keeps speaking for itself.
|
|
1998
|
+
...opts.description?.trim() ? { description: opts.description.trim() } : {},
|
|
1876
1999
|
entryPath,
|
|
1877
2000
|
files: files.map(({ absPath: _absPath, ...manifest }) => manifest),
|
|
1878
2001
|
...placement.folderId ? { folderId: placement.folderId } : {},
|
|
@@ -1880,7 +2003,10 @@ async function publish(opts) {
|
|
|
1880
2003
|
// backslash-n; turn those back into real newlines so bullets survive.
|
|
1881
2004
|
...opts.notes?.trim() ? { notes: opts.notes.replace(/\\n/g, "\n").trim() } : {},
|
|
1882
2005
|
source: {
|
|
1883
|
-
|
|
2006
|
+
// ARTIFACT_CAFE_AGENT if it's set, else whichever agent's environment
|
|
2007
|
+
// we recognize — this is what names the agent on every reply to a
|
|
2008
|
+
// thread opened against this version (§6.5).
|
|
2009
|
+
agent: agentLabel(),
|
|
1884
2010
|
runId: process.env.ARTIFACT_CAFE_RUN_ID,
|
|
1885
2011
|
type: "cli"
|
|
1886
2012
|
},
|
|
@@ -2994,7 +3120,7 @@ async function replyToThread(opts) {
|
|
|
2994
3120
|
artifact: opts.artifact
|
|
2995
3121
|
});
|
|
2996
3122
|
const client = createApiClient(target.apiUrl, target.credential);
|
|
2997
|
-
let thread = await client.replyThread(threadId, body);
|
|
3123
|
+
let thread = await client.replyThread(threadId, body, agentLabel(opts.as));
|
|
2998
3124
|
if (opts.resolve) {
|
|
2999
3125
|
thread = await client.resolveThread(threadId);
|
|
3000
3126
|
}
|
|
@@ -3217,18 +3343,18 @@ import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as rea
|
|
|
3217
3343
|
import { createRequire } from "module";
|
|
3218
3344
|
import { homedir as homedir2 } from "os";
|
|
3219
3345
|
import path18 from "path";
|
|
3220
|
-
import { z as
|
|
3346
|
+
import { z as z21 } from "zod";
|
|
3221
3347
|
var REGISTRY_LATEST_URL = "https://registry.npmjs.org/artifact-cafe/latest";
|
|
3222
3348
|
var SKILL_SOURCE_URL = "https://raw.githubusercontent.com/Artifact-Cafe/skill/main/artifact-cafe/SKILL.md";
|
|
3223
3349
|
var SKILL_UPDATE_COMMAND = "npx skills add artifact-cafe/skill --skill artifact-cafe -g";
|
|
3224
3350
|
var CHECK_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
3225
3351
|
var FETCH_TIMEOUT_MS = 2e3;
|
|
3226
3352
|
var SKILL_VERSION_PATTERN = /\*\*Skill version:\s*(\d+\.\d+\.\d+)\*\*/;
|
|
3227
|
-
var cacheSchema =
|
|
3228
|
-
checkedAt:
|
|
3229
|
-
cliLatest:
|
|
3230
|
-
skillLatest:
|
|
3231
|
-
version:
|
|
3353
|
+
var cacheSchema = z21.object({
|
|
3354
|
+
checkedAt: z21.number(),
|
|
3355
|
+
cliLatest: z21.string().nullable(),
|
|
3356
|
+
skillLatest: z21.string().nullable(),
|
|
3357
|
+
version: z21.literal(1)
|
|
3232
3358
|
});
|
|
3233
3359
|
function cliVersion() {
|
|
3234
3360
|
const pkg = createRequire(import.meta.url)("../package.json");
|
|
@@ -3283,7 +3409,7 @@ async function fetchText(url) {
|
|
|
3283
3409
|
}
|
|
3284
3410
|
async function fetchLatestVersions(previous) {
|
|
3285
3411
|
const [cli, skill] = await Promise.all([
|
|
3286
|
-
fetchJson(REGISTRY_LATEST_URL).then((body) =>
|
|
3412
|
+
fetchJson(REGISTRY_LATEST_URL).then((body) => z21.object({ version: z21.string() }).parse(body).version).catch(() => null),
|
|
3287
3413
|
fetchText(SKILL_SOURCE_URL).then((body) => SKILL_VERSION_PATTERN.exec(body)?.[1] ?? null).catch(() => null)
|
|
3288
3414
|
]);
|
|
3289
3415
|
return {
|
|
@@ -3396,17 +3522,18 @@ function printWorkspace(workspace) {
|
|
|
3396
3522
|
}
|
|
3397
3523
|
|
|
3398
3524
|
// src/index.ts
|
|
3399
|
-
function
|
|
3525
|
+
function readStringArg(argv, flag) {
|
|
3526
|
+
const prefix = `${flag}=`;
|
|
3400
3527
|
for (let i = 0; i < argv.length; i++) {
|
|
3401
3528
|
const token = argv[i];
|
|
3402
3529
|
if (token === void 0) {
|
|
3403
3530
|
continue;
|
|
3404
3531
|
}
|
|
3405
|
-
if (token ===
|
|
3532
|
+
if (token === flag) {
|
|
3406
3533
|
return argv[i + 1];
|
|
3407
3534
|
}
|
|
3408
|
-
if (token.startsWith(
|
|
3409
|
-
return token.slice(
|
|
3535
|
+
if (token.startsWith(prefix)) {
|
|
3536
|
+
return token.slice(prefix.length);
|
|
3410
3537
|
}
|
|
3411
3538
|
}
|
|
3412
3539
|
}
|
|
@@ -3420,6 +3547,10 @@ var publish2 = defineCommand({
|
|
|
3420
3547
|
description: "Publish to an existing artifact ID",
|
|
3421
3548
|
type: "string"
|
|
3422
3549
|
},
|
|
3550
|
+
description: {
|
|
3551
|
+
description: "One-line share-card summary (default: the entry HTML's own meta description)",
|
|
3552
|
+
type: "string"
|
|
3553
|
+
},
|
|
3423
3554
|
dir: {
|
|
3424
3555
|
default: ".",
|
|
3425
3556
|
description: "Directory to publish",
|
|
@@ -3456,11 +3587,12 @@ var publish2 = defineCommand({
|
|
|
3456
3587
|
await publish({
|
|
3457
3588
|
apiKey: args["api-key"],
|
|
3458
3589
|
artifact: args.artifact,
|
|
3590
|
+
description: readStringArg(process.argv.slice(2), "--description"),
|
|
3459
3591
|
dir: args.dir,
|
|
3460
3592
|
entry: args.entry,
|
|
3461
3593
|
folder: args.folder,
|
|
3462
3594
|
json: Boolean(args.json),
|
|
3463
|
-
notes:
|
|
3595
|
+
notes: readStringArg(process.argv.slice(2), "--notes"),
|
|
3464
3596
|
open: !args["no-open"],
|
|
3465
3597
|
password: args.password,
|
|
3466
3598
|
review: args.review,
|
|
@@ -4017,6 +4149,10 @@ var reply = defineCommand({
|
|
|
4017
4149
|
description: "Act on an artifact ID instead of the linked folder",
|
|
4018
4150
|
type: "string"
|
|
4019
4151
|
},
|
|
4152
|
+
as: {
|
|
4153
|
+
description: 'Who is replying, e.g. "Claude Code" (default: detected; "" to opt out)',
|
|
4154
|
+
type: "string"
|
|
4155
|
+
},
|
|
4020
4156
|
body: {
|
|
4021
4157
|
description: "Reply text (omit to read from stdin)",
|
|
4022
4158
|
type: "string"
|
|
@@ -4046,6 +4182,7 @@ var reply = defineCommand({
|
|
|
4046
4182
|
await replyToThread({
|
|
4047
4183
|
apiKey: args["api-key"],
|
|
4048
4184
|
artifact: args.artifact,
|
|
4185
|
+
as: args.as,
|
|
4049
4186
|
body: args.body,
|
|
4050
4187
|
dir: args.dir,
|
|
4051
4188
|
json: Boolean(args.json),
|
|
@@ -4068,6 +4205,10 @@ var comment2 = defineCommand({
|
|
|
4068
4205
|
description: "Act on an artifact ID instead of the linked folder",
|
|
4069
4206
|
type: "string"
|
|
4070
4207
|
},
|
|
4208
|
+
as: {
|
|
4209
|
+
description: 'Tool posting on your behalf, e.g. "Claude Code" (default: detected)',
|
|
4210
|
+
type: "string"
|
|
4211
|
+
},
|
|
4071
4212
|
body: {
|
|
4072
4213
|
description: "Comment text (omit to read from stdin)",
|
|
4073
4214
|
type: "string"
|
|
@@ -4095,7 +4236,7 @@ var comment2 = defineCommand({
|
|
|
4095
4236
|
type: "string"
|
|
4096
4237
|
},
|
|
4097
4238
|
via: {
|
|
4098
|
-
description:
|
|
4239
|
+
description: "Older name for --as",
|
|
4099
4240
|
type: "string"
|
|
4100
4241
|
}
|
|
4101
4242
|
},
|
|
@@ -4108,6 +4249,7 @@ var comment2 = defineCommand({
|
|
|
4108
4249
|
await comment({
|
|
4109
4250
|
apiKey: args["api-key"],
|
|
4110
4251
|
artifact: args.artifact,
|
|
4252
|
+
as: args.as,
|
|
4111
4253
|
body: args.body,
|
|
4112
4254
|
dir: args.dir,
|
|
4113
4255
|
json: Boolean(args.json),
|