artifact-cafe 0.0.12 → 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 +998 -510
- 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,260 +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:
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
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(),
|
|
267
|
+
// SPEC-2 §5.2 — who can open the review URL. A publish into a folder
|
|
268
|
+
// inherits that folder's visibility, so this is the only place the CLI
|
|
269
|
+
// learns that a link it just printed is members-only. Optional so a new
|
|
270
|
+
// CLI against an older API degrades to "unknown" instead of failing the
|
|
271
|
+
// publish over a field that only shapes the closing message.
|
|
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()
|
|
191
280
|
}).nullable(),
|
|
281
|
+
// Custom icon, or null to render the default document glyph.
|
|
282
|
+
emoji: z5.string().nullable(),
|
|
192
283
|
// SPEC-2 §6.4 — placement + visibility surface on the artifact.
|
|
193
|
-
folderId:
|
|
194
|
-
id:
|
|
284
|
+
folderId: z5.string().nullable(),
|
|
285
|
+
id: z5.string(),
|
|
195
286
|
// SPEC-2 §5.8 — what a viewer may do once in (open / readonly / off).
|
|
196
287
|
reviewMode: reviewModeSchema,
|
|
197
|
-
slug:
|
|
198
|
-
title:
|
|
199
|
-
visibility:
|
|
200
|
-
workspaceId:
|
|
288
|
+
slug: z5.string(),
|
|
289
|
+
title: z5.string(),
|
|
290
|
+
visibility: z5.enum(["public", "unlisted", "workspace", "private"]),
|
|
291
|
+
workspaceId: z5.string().nullable()
|
|
201
292
|
});
|
|
202
293
|
|
|
203
294
|
// ../shared/src/comments.ts
|
|
204
|
-
var anchorPageSchema =
|
|
295
|
+
var anchorPageSchema = z6.string().max(1024).refine(isSafeArtifactPath, {
|
|
205
296
|
message: "page must be a safe relative path"
|
|
206
297
|
}).optional();
|
|
207
|
-
var elementSnapshotSchema =
|
|
208
|
-
classes:
|
|
209
|
-
id:
|
|
210
|
-
tag:
|
|
211
|
-
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()
|
|
212
303
|
});
|
|
213
|
-
var pointAnchorSchema =
|
|
304
|
+
var pointAnchorSchema = z6.object({
|
|
214
305
|
element: elementSnapshotSchema.optional(),
|
|
215
306
|
// elementPath is the primary anchor; x/y are offsets within the
|
|
216
307
|
// element's box, normalized 0..1 (SPEC.md §8.1).
|
|
217
|
-
elementPath:
|
|
308
|
+
elementPath: z6.string().max(2048),
|
|
218
309
|
page: anchorPageSchema,
|
|
219
|
-
type:
|
|
220
|
-
viewportHeight:
|
|
221
|
-
viewportWidth:
|
|
222
|
-
x:
|
|
223
|
-
y:
|
|
224
|
-
});
|
|
225
|
-
var textAnchorSchema =
|
|
226
|
-
elementPath:
|
|
227
|
-
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),
|
|
228
319
|
page: anchorPageSchema,
|
|
229
|
-
prefix:
|
|
230
|
-
quote:
|
|
231
|
-
startOffset:
|
|
232
|
-
suffix:
|
|
233
|
-
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")
|
|
234
325
|
});
|
|
235
|
-
var pageAnchorSchema =
|
|
326
|
+
var pageAnchorSchema = z6.object({
|
|
236
327
|
page: anchorPageSchema,
|
|
237
|
-
type:
|
|
328
|
+
type: z6.literal("page")
|
|
238
329
|
});
|
|
239
|
-
var anchorSchema =
|
|
330
|
+
var anchorSchema = z6.discriminatedUnion("type", [
|
|
240
331
|
pointAnchorSchema,
|
|
241
332
|
textAnchorSchema,
|
|
242
333
|
pageAnchorSchema
|
|
243
334
|
]);
|
|
244
|
-
var displayNameSchema =
|
|
245
|
-
var guestSchema =
|
|
335
|
+
var displayNameSchema = z6.string().trim().min(1).max(64);
|
|
336
|
+
var guestSchema = z6.object({
|
|
246
337
|
displayName: displayNameSchema,
|
|
247
|
-
guestId:
|
|
338
|
+
guestId: z6.string().min(16)
|
|
248
339
|
});
|
|
249
|
-
var viaLabelSchema =
|
|
250
|
-
var createCommentThreadSchema =
|
|
340
|
+
var viaLabelSchema = z6.string().trim().min(1).max(64);
|
|
341
|
+
var createCommentThreadSchema = z6.object({
|
|
251
342
|
anchor: anchorSchema,
|
|
252
|
-
body:
|
|
343
|
+
body: z6.string().min(1).max(1e4),
|
|
253
344
|
guest: guestSchema.optional(),
|
|
254
|
-
versionId:
|
|
345
|
+
versionId: z6.string(),
|
|
255
346
|
via: viaLabelSchema.optional()
|
|
256
347
|
});
|
|
257
|
-
var createCommentMessageSchema =
|
|
258
|
-
body:
|
|
348
|
+
var createCommentMessageSchema = z6.object({
|
|
349
|
+
body: z6.string().min(1).max(1e4),
|
|
259
350
|
guest: guestSchema.optional(),
|
|
260
351
|
via: viaLabelSchema.optional()
|
|
261
352
|
});
|
|
262
|
-
var editCommentMessageSchema =
|
|
263
|
-
body:
|
|
353
|
+
var editCommentMessageSchema = z6.object({
|
|
354
|
+
body: z6.string().min(1).max(1e4),
|
|
264
355
|
guest: guestSchema.optional()
|
|
265
356
|
});
|
|
266
|
-
var threadActionSchema =
|
|
357
|
+
var threadActionSchema = z6.object({
|
|
267
358
|
guest: guestSchema.optional()
|
|
268
359
|
});
|
|
269
|
-
var
|
|
270
|
-
var
|
|
271
|
-
function canonicalizeEmoji(s) {
|
|
272
|
-
return s.replace(REDUNDANT_VS16, "$1");
|
|
273
|
-
}
|
|
274
|
-
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}");
|
|
275
|
-
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({
|
|
276
362
|
emoji: reactionEmojiSchema,
|
|
277
363
|
guest: guestSchema.optional()
|
|
278
364
|
});
|
|
279
|
-
var
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
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"]),
|
|
285
376
|
// Optional "via" attribution (§6.4). Null for plain comments; a bounded
|
|
286
|
-
// label the shell appends after the display name.
|
|
287
|
-
|
|
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)
|
|
288
380
|
});
|
|
289
|
-
var messageReactionSchema =
|
|
290
|
-
emoji:
|
|
291
|
-
reactors:
|
|
381
|
+
var messageReactionSchema = z6.object({
|
|
382
|
+
emoji: z6.string(),
|
|
383
|
+
reactors: z6.array(commentAuthorSchema)
|
|
292
384
|
});
|
|
293
|
-
var commentMessageSchema =
|
|
385
|
+
var commentMessageSchema = z6.object({
|
|
294
386
|
author: commentAuthorSchema,
|
|
295
387
|
// Empty string for a deleted message — the body is stripped server-side
|
|
296
388
|
// (§6.7.1 tombstone), never sent to the client and hidden there.
|
|
297
|
-
body:
|
|
298
|
-
createdAt:
|
|
389
|
+
body: z6.string(),
|
|
390
|
+
createdAt: z6.string(),
|
|
299
391
|
// Soft-deleted (§6.7.1). A tombstone keeps thread structure and replies;
|
|
300
392
|
// the shell renders "Comment deleted" instead of the (absent) body.
|
|
301
|
-
deleted:
|
|
393
|
+
deleted: z6.boolean(),
|
|
302
394
|
// Last edit time (§6.7.1), or null if never edited — drives the "edited"
|
|
303
395
|
// badge. No edit history is kept.
|
|
304
|
-
editedAt:
|
|
305
|
-
id:
|
|
396
|
+
editedAt: z6.string().nullable(),
|
|
397
|
+
id: z6.string(),
|
|
306
398
|
// Defaulted, not required: a new CLI parsing an older server's
|
|
307
399
|
// response must not fail on the missing key.
|
|
308
|
-
reactions:
|
|
400
|
+
reactions: z6.array(messageReactionSchema).default([])
|
|
309
401
|
});
|
|
310
|
-
var threadActorSchema =
|
|
311
|
-
displayName:
|
|
312
|
-
kind:
|
|
402
|
+
var threadActorSchema = z6.object({
|
|
403
|
+
displayName: z6.string(),
|
|
404
|
+
kind: z6.enum(["member", "guest", "agent"])
|
|
313
405
|
});
|
|
314
|
-
var commentThreadSchema =
|
|
406
|
+
var commentThreadSchema = z6.object({
|
|
315
407
|
// §6.6.1 — set while open to signal "seen, working on it"; cleared on
|
|
316
408
|
// reopen, kept (but superseded in display) once resolved. Defaulted so
|
|
317
409
|
// clients parsing an older server's response don't fail.
|
|
318
|
-
acknowledgedAt:
|
|
410
|
+
acknowledgedAt: z6.string().nullable().default(null),
|
|
319
411
|
acknowledgedBy: threadActorSchema.nullable().default(null),
|
|
320
412
|
anchor: anchorSchema,
|
|
321
|
-
artifactId:
|
|
322
|
-
createdAt:
|
|
413
|
+
artifactId: z6.string(),
|
|
414
|
+
createdAt: z6.string(),
|
|
323
415
|
createdBy: commentAuthorSchema,
|
|
324
|
-
id:
|
|
325
|
-
messages:
|
|
416
|
+
id: z6.string(),
|
|
417
|
+
messages: z6.array(commentMessageSchema),
|
|
326
418
|
// Null on threads resolved before actor recording existed, and always
|
|
327
419
|
// null while open.
|
|
328
420
|
resolvedBy: threadActorSchema.nullable().default(null),
|
|
329
|
-
status:
|
|
330
|
-
versionId:
|
|
421
|
+
status: z6.enum(["open", "resolved"]),
|
|
422
|
+
versionId: z6.string()
|
|
331
423
|
});
|
|
332
|
-
var commentThreadListSchema =
|
|
333
|
-
threads:
|
|
424
|
+
var commentThreadListSchema = z6.object({
|
|
425
|
+
threads: z6.array(commentThreadSchema)
|
|
334
426
|
});
|
|
335
|
-
var commentExportQuerySchema =
|
|
336
|
-
status:
|
|
337
|
-
version:
|
|
427
|
+
var commentExportQuerySchema = z6.object({
|
|
428
|
+
status: z6.enum(["open", "resolved", "all"]).default("open"),
|
|
429
|
+
version: z6.enum(["current", "all"]).default("current")
|
|
338
430
|
});
|
|
339
|
-
var exportReactionSchema =
|
|
340
|
-
count:
|
|
341
|
-
emoji:
|
|
431
|
+
var exportReactionSchema = z6.object({
|
|
432
|
+
count: z6.number().int().positive(),
|
|
433
|
+
emoji: z6.string()
|
|
342
434
|
});
|
|
343
|
-
var commentExportReplySchema =
|
|
344
|
-
author:
|
|
345
|
-
authorKind:
|
|
346
|
-
body:
|
|
347
|
-
createdAt:
|
|
435
|
+
var commentExportReplySchema = z6.object({
|
|
436
|
+
author: z6.string(),
|
|
437
|
+
authorKind: z6.enum(["member", "guest"]),
|
|
438
|
+
body: z6.string(),
|
|
439
|
+
createdAt: z6.string(),
|
|
348
440
|
// Soft-delete tombstone (§6.7.1): body is "" when true.
|
|
349
|
-
deleted:
|
|
350
|
-
editedAt:
|
|
441
|
+
deleted: z6.boolean(),
|
|
442
|
+
editedAt: z6.string().nullable(),
|
|
351
443
|
// The message id — what `edit`/`delete` target (§5.1).
|
|
352
|
-
id:
|
|
353
|
-
reactions:
|
|
444
|
+
id: z6.string(),
|
|
445
|
+
reactions: z6.array(exportReactionSchema).optional()
|
|
354
446
|
});
|
|
355
|
-
var commentExportThreadSchema =
|
|
447
|
+
var commentExportThreadSchema = z6.object({
|
|
356
448
|
// §6.6.1 — lets a polling agent skip threads it already acknowledged
|
|
357
449
|
// (acknowledged threads stay in status=open exports on purpose).
|
|
358
|
-
acknowledgedAt:
|
|
450
|
+
acknowledgedAt: z6.string().nullable().default(null),
|
|
359
451
|
anchor: anchorSchema,
|
|
360
|
-
author:
|
|
361
|
-
authorKind:
|
|
362
|
-
body:
|
|
363
|
-
createdAt:
|
|
364
|
-
deleted:
|
|
365
|
-
editedAt:
|
|
366
|
-
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(),
|
|
367
459
|
// The opening message's id (distinct from the thread `id`) — `edit`/
|
|
368
460
|
// `delete` operate on messages, so the CLI needs it to target the first
|
|
369
461
|
// comment, not just the replies.
|
|
370
|
-
messageId:
|
|
371
|
-
reactions:
|
|
372
|
-
replies:
|
|
462
|
+
messageId: z6.string(),
|
|
463
|
+
reactions: z6.array(exportReactionSchema).optional(),
|
|
464
|
+
replies: z6.array(commentExportReplySchema),
|
|
373
465
|
resolvedBy: threadActorSchema.nullable().default(null),
|
|
374
|
-
status:
|
|
375
|
-
versionNumber:
|
|
466
|
+
status: z6.enum(["open", "resolved"]),
|
|
467
|
+
versionNumber: z6.number().int().positive()
|
|
376
468
|
});
|
|
377
|
-
var commentExportSchema =
|
|
378
|
-
artifactId:
|
|
379
|
-
comments:
|
|
469
|
+
var commentExportSchema = z6.object({
|
|
470
|
+
artifactId: z6.string(),
|
|
471
|
+
comments: z6.array(commentExportThreadSchema),
|
|
380
472
|
// The artifact's current version (null before the first finalize).
|
|
381
|
-
versionNumber:
|
|
473
|
+
versionNumber: z6.number().int().positive().nullable()
|
|
382
474
|
});
|
|
383
|
-
var commentReadResponseSchema =
|
|
384
|
-
lastSeenAt:
|
|
475
|
+
var commentReadResponseSchema = z6.object({
|
|
476
|
+
lastSeenAt: z6.string()
|
|
385
477
|
});
|
|
386
478
|
function elementLabel(el) {
|
|
387
479
|
if (el.id) {
|
|
@@ -392,491 +484,528 @@ function elementLabel(el) {
|
|
|
392
484
|
}
|
|
393
485
|
|
|
394
486
|
// ../shared/src/errors.ts
|
|
395
|
-
import { z as
|
|
396
|
-
var apiErrorSchema =
|
|
397
|
-
code:
|
|
398
|
-
docsUrl:
|
|
399
|
-
message:
|
|
400
|
-
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()
|
|
401
493
|
});
|
|
402
494
|
|
|
403
495
|
// ../shared/src/feedback.ts
|
|
404
|
-
import { z as
|
|
405
|
-
var feedbackRequestSchema =
|
|
406
|
-
email:
|
|
407
|
-
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)
|
|
408
500
|
});
|
|
409
|
-
var feedbackResponseSchema =
|
|
410
|
-
sent:
|
|
501
|
+
var feedbackResponseSchema = z8.object({
|
|
502
|
+
sent: z8.literal(true)
|
|
411
503
|
});
|
|
412
504
|
|
|
413
505
|
// ../shared/src/grants.ts
|
|
414
|
-
import { z as
|
|
415
|
-
var grantRoleSchema =
|
|
416
|
-
var createGrantSchema =
|
|
417
|
-
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(),
|
|
418
510
|
role: grantRoleSchema.default("viewer"),
|
|
419
|
-
userId:
|
|
511
|
+
userId: z9.string().min(1).optional()
|
|
420
512
|
}).refine((body) => Boolean(body.email) !== Boolean(body.userId), {
|
|
421
513
|
message: "provide exactly one of email or userId"
|
|
422
514
|
});
|
|
423
|
-
var grantSchema =
|
|
424
|
-
createdAt:
|
|
425
|
-
email:
|
|
426
|
-
expiresAt:
|
|
427
|
-
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(),
|
|
428
520
|
// The subject's avatar once they have an account; null otherwise.
|
|
429
|
-
image:
|
|
521
|
+
image: z9.string().nullable(),
|
|
430
522
|
// Present on the invited account after redemption / when granting an
|
|
431
523
|
// existing user; null for a still-pending email invite.
|
|
432
|
-
name:
|
|
433
|
-
redeemedAt:
|
|
524
|
+
name: z9.string().nullable(),
|
|
525
|
+
redeemedAt: z9.string().nullable(),
|
|
434
526
|
role: grantRoleSchema,
|
|
435
527
|
// Shown as "· pending" beside the role until the link is redeemed.
|
|
436
|
-
status:
|
|
528
|
+
status: z9.enum(["pending", "active"]),
|
|
437
529
|
// Display fragment of the live invitation token, or null once redeemed.
|
|
438
|
-
tokenPrefix:
|
|
439
|
-
userId:
|
|
530
|
+
tokenPrefix: z9.string().nullable(),
|
|
531
|
+
userId: z9.string().nullable()
|
|
440
532
|
});
|
|
441
533
|
var createdGrantSchema = grantSchema.extend({
|
|
442
|
-
url:
|
|
534
|
+
url: z9.string().url()
|
|
443
535
|
});
|
|
444
|
-
var grantListResponseSchema =
|
|
445
|
-
grants:
|
|
536
|
+
var grantListResponseSchema = z9.object({
|
|
537
|
+
grants: z9.array(grantSchema),
|
|
446
538
|
// The artifact's current general-access value, so the share surface can
|
|
447
539
|
// render the "General access" line without a second read.
|
|
448
|
-
visibility:
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
540
|
+
visibility: z9.enum(["public", "unlisted", "workspace", "private"]),
|
|
541
|
+
// The owning workspace's logo, so the share modal can draw the workspace
|
|
542
|
+
// itself rather than a generic glyph. Null when none was uploaded.
|
|
543
|
+
workspaceLogo: z9.string().nullable().optional(),
|
|
544
|
+
// The owning workspace's display name, so "People with access" can name the
|
|
545
|
+
// audience `workspace` visibility actually admits ("All Acme members") rather
|
|
546
|
+
// than leaving an empty list to imply nobody. Null for a workspace-less
|
|
547
|
+
// artifact; optional so an older server still parses.
|
|
548
|
+
workspaceName: z9.string().nullable().optional()
|
|
549
|
+
});
|
|
550
|
+
var revokeGrantResponseSchema = z9.object({
|
|
551
|
+
revoked: z9.literal(true)
|
|
452
552
|
});
|
|
453
|
-
var acceptGrantSchema =
|
|
454
|
-
token:
|
|
553
|
+
var acceptGrantSchema = z9.object({
|
|
554
|
+
token: z9.string().min(1)
|
|
455
555
|
});
|
|
456
|
-
var acceptGrantResponseSchema =
|
|
457
|
-
artifactId:
|
|
556
|
+
var acceptGrantResponseSchema = z9.object({
|
|
557
|
+
artifactId: z9.string(),
|
|
458
558
|
// The review shell URL to land on, carrying ?invited=1 for the banner.
|
|
459
|
-
artifactUrl:
|
|
460
|
-
slug:
|
|
461
|
-
title:
|
|
462
|
-
});
|
|
463
|
-
var workspaceGuestSchema =
|
|
464
|
-
artifacts:
|
|
465
|
-
|
|
466
|
-
artifactId:
|
|
467
|
-
grantId:
|
|
468
|
-
slug:
|
|
469
|
-
status:
|
|
470
|
-
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()
|
|
471
571
|
})
|
|
472
572
|
),
|
|
473
|
-
email:
|
|
474
|
-
image:
|
|
475
|
-
name:
|
|
476
|
-
userId:
|
|
477
|
-
});
|
|
478
|
-
var workspaceGuestListResponseSchema =
|
|
479
|
-
guests:
|
|
480
|
-
});
|
|
481
|
-
var sharedWithMeArtifactSchema =
|
|
482
|
-
artifactId:
|
|
483
|
-
slug:
|
|
484
|
-
title:
|
|
485
|
-
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(),
|
|
486
586
|
// Who shared it, for the "Shared with me" list.
|
|
487
|
-
workspaceName:
|
|
587
|
+
workspaceName: z9.string()
|
|
488
588
|
});
|
|
489
|
-
var sharedWithMeListResponseSchema =
|
|
490
|
-
artifacts:
|
|
589
|
+
var sharedWithMeListResponseSchema = z9.object({
|
|
590
|
+
artifacts: z9.array(sharedWithMeArtifactSchema)
|
|
491
591
|
});
|
|
492
592
|
|
|
593
|
+
// ../shared/src/html-meta.ts
|
|
594
|
+
var HEAD_SCAN_CHARS = 64 * 1024;
|
|
595
|
+
|
|
493
596
|
// ../shared/src/me.ts
|
|
494
|
-
import { z as
|
|
597
|
+
import { z as z11 } from "zod";
|
|
495
598
|
|
|
496
599
|
// ../shared/src/workspaces.ts
|
|
497
|
-
import { z as
|
|
600
|
+
import { z as z10 } from "zod";
|
|
498
601
|
var WORKSPACE_HANDLE_PATTERN = /^[a-z0-9](?:[a-z0-9-]{1,30}[a-z0-9])$/;
|
|
499
|
-
var workspaceHandleUnavailableReasonSchema =
|
|
602
|
+
var workspaceHandleUnavailableReasonSchema = z10.enum([
|
|
500
603
|
"held",
|
|
501
604
|
"invalid",
|
|
502
605
|
"reserved",
|
|
503
606
|
"taken"
|
|
504
607
|
]);
|
|
505
|
-
var workspaceHandleAvailabilitySchema =
|
|
506
|
-
available:
|
|
507
|
-
handle:
|
|
608
|
+
var workspaceHandleAvailabilitySchema = z10.object({
|
|
609
|
+
available: z10.boolean(),
|
|
610
|
+
handle: z10.string(),
|
|
508
611
|
// Human-readable sentence for the field hint; null when available.
|
|
509
|
-
message:
|
|
612
|
+
message: z10.string().nullable(),
|
|
510
613
|
reason: workspaceHandleUnavailableReasonSchema.nullable()
|
|
511
614
|
});
|
|
512
|
-
var workspaceRoleSchema =
|
|
513
|
-
var workspaceInviteRoleSchema =
|
|
514
|
-
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, {
|
|
515
618
|
message: "handle must be lowercase letters, digits, and hyphens, with no leading/trailing hyphen"
|
|
516
619
|
});
|
|
517
|
-
var createWorkspaceSchema =
|
|
620
|
+
var createWorkspaceSchema = z10.object({
|
|
518
621
|
handle: workspaceHandleSchema.optional(),
|
|
519
|
-
name:
|
|
622
|
+
name: z10.string().trim().min(1).max(100)
|
|
520
623
|
});
|
|
521
|
-
var updateWorkspaceSchema =
|
|
624
|
+
var updateWorkspaceSchema = z10.object({
|
|
522
625
|
handle: workspaceHandleSchema.optional(),
|
|
523
|
-
name:
|
|
626
|
+
name: z10.string().trim().min(1).max(100).optional()
|
|
524
627
|
}).refine((body) => body.handle !== void 0 || body.name !== void 0, {
|
|
525
628
|
message: "provide at least one of name or handle"
|
|
526
629
|
});
|
|
527
|
-
var workspaceSchema =
|
|
528
|
-
createdAt:
|
|
529
|
-
handle:
|
|
630
|
+
var workspaceSchema = z10.object({
|
|
631
|
+
createdAt: z10.string(),
|
|
632
|
+
handle: z10.string(),
|
|
530
633
|
// ISO timestamp when `{handle}.artifact.cafe` was provisioned, or null.
|
|
531
634
|
// Set by the one-time, self-serve enable flow (§4.4); never auto at
|
|
532
635
|
// create, and always null for personal workspaces.
|
|
533
|
-
hostnameProvisionedAt:
|
|
534
|
-
id:
|
|
636
|
+
hostnameProvisionedAt: z10.string().nullable(),
|
|
637
|
+
id: z10.string(),
|
|
535
638
|
// Auto-provisioned solo workspace, one per user: non-deletable, takes
|
|
536
639
|
// no members, renameable like any workspace.
|
|
537
|
-
isPersonal:
|
|
640
|
+
isPersonal: z10.boolean(),
|
|
538
641
|
// Uploaded logo URL, or null for the initials fallback. Set through the
|
|
539
642
|
// dedicated /workspaces/:id/avatar route, never the generic update.
|
|
540
|
-
logo:
|
|
541
|
-
name:
|
|
643
|
+
logo: z10.string().nullable(),
|
|
644
|
+
name: z10.string(),
|
|
542
645
|
role: workspaceRoleSchema.nullable(),
|
|
543
|
-
updatedAt:
|
|
646
|
+
updatedAt: z10.string()
|
|
544
647
|
});
|
|
545
|
-
var workspaceListResponseSchema =
|
|
546
|
-
workspaces:
|
|
648
|
+
var workspaceListResponseSchema = z10.object({
|
|
649
|
+
workspaces: z10.array(workspaceSchema)
|
|
547
650
|
});
|
|
548
|
-
var deleteWorkspaceResponseSchema =
|
|
549
|
-
deleted:
|
|
651
|
+
var deleteWorkspaceResponseSchema = z10.object({
|
|
652
|
+
deleted: z10.literal(true)
|
|
550
653
|
});
|
|
551
|
-
var workspaceMemberSchema =
|
|
552
|
-
createdAt:
|
|
553
|
-
email:
|
|
554
|
-
image:
|
|
555
|
-
name:
|
|
654
|
+
var workspaceMemberSchema = z10.object({
|
|
655
|
+
createdAt: z10.string(),
|
|
656
|
+
email: z10.string().email(),
|
|
657
|
+
image: z10.string().nullable(),
|
|
658
|
+
name: z10.string(),
|
|
556
659
|
role: workspaceRoleSchema,
|
|
557
|
-
userId:
|
|
660
|
+
userId: z10.string()
|
|
558
661
|
});
|
|
559
|
-
var workspaceMemberListResponseSchema =
|
|
560
|
-
members:
|
|
662
|
+
var workspaceMemberListResponseSchema = z10.object({
|
|
663
|
+
members: z10.array(workspaceMemberSchema)
|
|
561
664
|
});
|
|
562
|
-
var updateWorkspaceMemberSchema =
|
|
665
|
+
var updateWorkspaceMemberSchema = z10.object({
|
|
563
666
|
role: workspaceRoleSchema
|
|
564
667
|
});
|
|
565
|
-
var removeWorkspaceMemberResponseSchema =
|
|
566
|
-
removed:
|
|
668
|
+
var removeWorkspaceMemberResponseSchema = z10.object({
|
|
669
|
+
removed: z10.literal(true)
|
|
567
670
|
});
|
|
568
|
-
var createWorkspaceInviteSchema =
|
|
569
|
-
email:
|
|
570
|
-
expiresAt:
|
|
571
|
-
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(),
|
|
572
675
|
role: workspaceInviteRoleSchema
|
|
573
676
|
});
|
|
574
|
-
var workspaceInviteSchema =
|
|
575
|
-
createdAt:
|
|
576
|
-
email:
|
|
577
|
-
expiresAt:
|
|
578
|
-
id:
|
|
579
|
-
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(),
|
|
580
683
|
role: workspaceInviteRoleSchema,
|
|
581
|
-
tokenPrefix:
|
|
582
|
-
useCount:
|
|
684
|
+
tokenPrefix: z10.string(),
|
|
685
|
+
useCount: z10.number().int().nonnegative()
|
|
583
686
|
});
|
|
584
687
|
var createdWorkspaceInviteSchema = workspaceInviteSchema.extend({
|
|
585
|
-
url:
|
|
688
|
+
url: z10.string().url()
|
|
586
689
|
});
|
|
587
|
-
var workspaceInviteListResponseSchema =
|
|
588
|
-
invites:
|
|
690
|
+
var workspaceInviteListResponseSchema = z10.object({
|
|
691
|
+
invites: z10.array(workspaceInviteSchema)
|
|
589
692
|
});
|
|
590
|
-
var revokeWorkspaceInviteResponseSchema =
|
|
591
|
-
revoked:
|
|
693
|
+
var revokeWorkspaceInviteResponseSchema = z10.object({
|
|
694
|
+
revoked: z10.literal(true)
|
|
592
695
|
});
|
|
593
|
-
var acceptWorkspaceInviteSchema =
|
|
594
|
-
token:
|
|
696
|
+
var acceptWorkspaceInviteSchema = z10.object({
|
|
697
|
+
token: z10.string().min(1)
|
|
595
698
|
});
|
|
596
|
-
var acceptWorkspaceInviteResponseSchema =
|
|
699
|
+
var acceptWorkspaceInviteResponseSchema = z10.object({
|
|
597
700
|
role: workspaceRoleSchema,
|
|
598
701
|
workspace: workspaceSchema
|
|
599
702
|
});
|
|
600
|
-
var folderVisibilitySchema =
|
|
601
|
-
var artifactVisibilitySchema =
|
|
703
|
+
var folderVisibilitySchema = z10.enum(["public", "workspace"]);
|
|
704
|
+
var artifactVisibilitySchema = z10.enum([
|
|
602
705
|
"public",
|
|
603
706
|
"unlisted",
|
|
604
707
|
"workspace",
|
|
605
708
|
"private"
|
|
606
709
|
]);
|
|
607
|
-
var createFolderSchema =
|
|
608
|
-
|
|
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),
|
|
609
714
|
visibility: folderVisibilitySchema
|
|
610
715
|
});
|
|
611
|
-
var updateFolderSchema =
|
|
716
|
+
var updateFolderSchema = z10.object({
|
|
612
717
|
// With `visibility`: bulk-update the folder's artifacts to match
|
|
613
718
|
// (SPEC-2 §3.4 "Changing a folder's visibility offers a bulk update").
|
|
614
|
-
cascade:
|
|
615
|
-
|
|
616
|
-
|
|
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(),
|
|
617
725
|
visibility: folderVisibilitySchema.optional()
|
|
618
726
|
}).refine(
|
|
619
|
-
(body) => body.name !== void 0 || body.visibility !== void 0 || body.sortOrder !== void 0,
|
|
620
|
-
{ 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" }
|
|
621
729
|
).refine((body) => !body.cascade || body.visibility !== void 0, {
|
|
622
730
|
message: "cascade requires visibility"
|
|
623
731
|
});
|
|
624
|
-
var folderSchema =
|
|
625
|
-
createdAt:
|
|
626
|
-
|
|
627
|
-
|
|
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(),
|
|
628
738
|
// Permalink segment for the public folder page (/w/{handle}/f/{slug}).
|
|
629
739
|
// Server-derived from the name; renames regenerate it.
|
|
630
|
-
slug:
|
|
631
|
-
sortOrder:
|
|
632
|
-
updatedAt:
|
|
740
|
+
slug: z10.string(),
|
|
741
|
+
sortOrder: z10.number().int(),
|
|
742
|
+
updatedAt: z10.string(),
|
|
633
743
|
visibility: folderVisibilitySchema,
|
|
634
|
-
workspaceId:
|
|
744
|
+
workspaceId: z10.string()
|
|
635
745
|
});
|
|
636
|
-
var folderListResponseSchema =
|
|
637
|
-
folders:
|
|
746
|
+
var folderListResponseSchema = z10.object({
|
|
747
|
+
folders: z10.array(folderSchema)
|
|
638
748
|
});
|
|
639
|
-
var deleteFolderResponseSchema =
|
|
640
|
-
deleted:
|
|
749
|
+
var deleteFolderResponseSchema = z10.object({
|
|
750
|
+
deleted: z10.literal(true)
|
|
641
751
|
});
|
|
642
|
-
var workspaceArtifactSchema =
|
|
643
|
-
createdAt:
|
|
644
|
-
currentVersionNumber:
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
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(),
|
|
648
760
|
reviewMode: reviewModeSchema,
|
|
649
|
-
slug:
|
|
650
|
-
title:
|
|
651
|
-
updatedAt:
|
|
652
|
-
url:
|
|
653
|
-
versionCount:
|
|
761
|
+
slug: z10.string(),
|
|
762
|
+
title: z10.string(),
|
|
763
|
+
updatedAt: z10.string(),
|
|
764
|
+
url: z10.string().url(),
|
|
765
|
+
versionCount: z10.number().int().nonnegative(),
|
|
654
766
|
visibility: artifactVisibilitySchema
|
|
655
767
|
});
|
|
656
|
-
var workspaceArtifactListResponseSchema =
|
|
657
|
-
artifacts:
|
|
768
|
+
var workspaceArtifactListResponseSchema = z10.object({
|
|
769
|
+
artifacts: z10.array(workspaceArtifactSchema)
|
|
658
770
|
});
|
|
659
|
-
var workspaceArtifactSearchResultSchema =
|
|
660
|
-
id:
|
|
661
|
-
slug:
|
|
662
|
-
title:
|
|
771
|
+
var workspaceArtifactSearchResultSchema = z10.object({
|
|
772
|
+
id: z10.string(),
|
|
773
|
+
slug: z10.string(),
|
|
774
|
+
title: z10.string()
|
|
663
775
|
});
|
|
664
|
-
var workspaceArtifactSearchResponseSchema =
|
|
665
|
-
results:
|
|
776
|
+
var workspaceArtifactSearchResponseSchema = z10.object({
|
|
777
|
+
results: z10.array(workspaceArtifactSearchResultSchema)
|
|
666
778
|
});
|
|
667
779
|
|
|
668
780
|
// ../shared/src/me.ts
|
|
669
|
-
var ownArtifactSchema =
|
|
670
|
-
createdAt:
|
|
671
|
-
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(),
|
|
672
786
|
// Owned artifacts normally never expire; non-null only while an
|
|
673
787
|
// expiry is still set (e.g. an unclaimed publish surfaced here later).
|
|
674
|
-
expiresAt:
|
|
788
|
+
expiresAt: z11.string().nullable(),
|
|
675
789
|
// SPEC-2 §8.4 — the containing folder for workspace-owned artifacts;
|
|
676
790
|
// both null for personal artifacts. `folderId` drives the dashboard's
|
|
677
|
-
// move control and folder filter; `folderName` is the display label
|
|
678
|
-
|
|
679
|
-
|
|
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(),
|
|
680
796
|
// Whether a publish token is still active — revocable from the
|
|
681
797
|
// dashboard (§6.18); the token itself is never returned.
|
|
682
|
-
hasPublishToken:
|
|
683
|
-
id:
|
|
684
|
-
openThreads:
|
|
685
|
-
protected:
|
|
798
|
+
hasPublishToken: z11.boolean(),
|
|
799
|
+
id: z11.string(),
|
|
800
|
+
openThreads: z11.number(),
|
|
801
|
+
protected: z11.boolean(),
|
|
686
802
|
// Who published the current version (falling back to the claiming
|
|
687
803
|
// owner) — the dashboard shows a name and avatar per artifact so a
|
|
688
804
|
// shared workspace reads as people's work, not anonymous rows. Null
|
|
689
805
|
// when the publish was token-only and the artifact is unclaimed.
|
|
690
|
-
publishedBy:
|
|
806
|
+
publishedBy: z11.object({ image: z11.string().nullable(), name: z11.string() }).nullable(),
|
|
691
807
|
// SPEC-2 §5.8 — the review dial, so the dashboard's settings dialog can
|
|
692
808
|
// render current state without a second fetch.
|
|
693
809
|
reviewMode: reviewModeSchema,
|
|
694
|
-
slug:
|
|
695
|
-
title:
|
|
696
|
-
totalViews:
|
|
810
|
+
slug: z11.string(),
|
|
811
|
+
title: z11.string(),
|
|
812
|
+
totalViews: z11.number(),
|
|
697
813
|
// SPEC §6.20 — messages by others newer than the viewer's last-seen
|
|
698
814
|
// watermark. 0 for signed-out/API-key-less contexts.
|
|
699
|
-
unreadComments:
|
|
700
|
-
updatedAt:
|
|
701
|
-
url:
|
|
702
|
-
versionCount:
|
|
815
|
+
unreadComments: z11.number(),
|
|
816
|
+
updatedAt: z11.string(),
|
|
817
|
+
url: z11.string(),
|
|
818
|
+
versionCount: z11.number(),
|
|
703
819
|
// SPEC-2 §5.1 — whether the caller clears the manage bar for this
|
|
704
820
|
// artifact (workspace admin, or the person who first published it).
|
|
705
821
|
// Only a manager's folder move inherits the folder's visibility, so the
|
|
706
822
|
// dashboard warns exactly the people the change can actually affect, and
|
|
707
823
|
// only a manager is offered the Share entry (§5.7).
|
|
708
|
-
viewerCanManage:
|
|
824
|
+
viewerCanManage: z11.boolean(),
|
|
709
825
|
// SPEC-2 §5.2 — the artifact's own visibility, the single enforcement
|
|
710
826
|
// source. The dashboard needs it to tell whether a folder move would
|
|
711
|
-
// widen exposure before it sends the PATCH (§3.4), and to render the
|
|
712
|
-
// 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).
|
|
713
829
|
visibility: artifactVisibilitySchema
|
|
714
830
|
});
|
|
715
|
-
var ownArtifactsResponseSchema =
|
|
716
|
-
artifacts:
|
|
831
|
+
var ownArtifactsResponseSchema = z11.object({
|
|
832
|
+
artifacts: z11.array(ownArtifactSchema)
|
|
717
833
|
});
|
|
718
|
-
var revokePublishTokenResponseSchema =
|
|
719
|
-
revoked:
|
|
834
|
+
var revokePublishTokenResponseSchema = z11.object({
|
|
835
|
+
revoked: z11.boolean()
|
|
720
836
|
});
|
|
721
837
|
|
|
722
838
|
// ../shared/src/owner.ts
|
|
723
|
-
import { z as
|
|
839
|
+
import { z as z12 } from "zod";
|
|
724
840
|
var SLUG_PATTERN = /^[a-z0-9](?:[a-z0-9-]{1,61}[a-z0-9])$/;
|
|
725
|
-
var claimResponseSchema =
|
|
726
|
-
artifactId:
|
|
727
|
-
slug:
|
|
728
|
-
title:
|
|
729
|
-
url:
|
|
730
|
-
});
|
|
731
|
-
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(),
|
|
732
852
|
// SPEC-2 §6.4 — placement + visibility. `folderId: null` clears the
|
|
733
853
|
// folder; `workspaceId: null` moves the artifact out of its workspace
|
|
734
854
|
// (§5.5 ownership transfer).
|
|
735
|
-
folderId:
|
|
736
|
-
slug:
|
|
855
|
+
folderId: z12.string().min(1).nullable().optional(),
|
|
856
|
+
slug: z12.string().min(3).max(63).regex(SLUG_PATTERN, {
|
|
737
857
|
message: "slug must be lowercase letters, digits, and hyphens, with no leading/trailing hyphen"
|
|
738
858
|
}).optional(),
|
|
739
|
-
title:
|
|
859
|
+
title: z12.string().min(1).max(200).optional(),
|
|
740
860
|
visibility: artifactVisibilitySchema.optional(),
|
|
741
|
-
workspaceId:
|
|
861
|
+
workspaceId: z12.string().min(1).nullable().optional()
|
|
742
862
|
}).refine(
|
|
743
|
-
(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,
|
|
744
864
|
{
|
|
745
|
-
message: "provide at least one of title, slug, visibility, folderId, workspaceId"
|
|
865
|
+
message: "provide at least one of title, slug, visibility, folderId, workspaceId, emoji"
|
|
746
866
|
}
|
|
747
867
|
);
|
|
748
|
-
var deleteArtifactResponseSchema =
|
|
749
|
-
deleted:
|
|
868
|
+
var deleteArtifactResponseSchema = z12.object({
|
|
869
|
+
deleted: z12.literal(true)
|
|
750
870
|
});
|
|
751
871
|
|
|
752
872
|
// ../shared/src/presence.ts
|
|
753
|
-
import { z as
|
|
873
|
+
import { z as z13 } from "zod";
|
|
754
874
|
var AGENT_STATES = ["listening", "editing", "publishing"];
|
|
755
|
-
var agentStateSchema =
|
|
875
|
+
var agentStateSchema = z13.enum(AGENT_STATES);
|
|
756
876
|
var AGENT_PRESENCE = {
|
|
757
877
|
editingTtlSeconds: 300,
|
|
758
878
|
heartbeatSeconds: 15,
|
|
759
879
|
shellPollSeconds: 15,
|
|
760
880
|
ttlSeconds: 45
|
|
761
881
|
};
|
|
762
|
-
var agentHeartbeatBodySchema =
|
|
882
|
+
var agentHeartbeatBodySchema = z13.object({
|
|
763
883
|
state: agentStateSchema.optional()
|
|
764
884
|
});
|
|
765
|
-
var agentHeartbeatResponseSchema =
|
|
766
|
-
listening:
|
|
885
|
+
var agentHeartbeatResponseSchema = z13.object({
|
|
886
|
+
listening: z13.literal(true),
|
|
767
887
|
state: agentStateSchema.optional(),
|
|
768
|
-
ttlSeconds:
|
|
888
|
+
ttlSeconds: z13.number().int().positive()
|
|
769
889
|
});
|
|
770
|
-
var agentPresenceSchema =
|
|
771
|
-
|
|
890
|
+
var agentPresenceSchema = z13.object({
|
|
891
|
+
agent: z13.object({ id: z13.string().nullable(), label: z13.string() }).nullable().default(null),
|
|
892
|
+
listening: z13.boolean(),
|
|
772
893
|
state: agentStateSchema.nullable().optional(),
|
|
773
|
-
versionNumber:
|
|
894
|
+
versionNumber: z13.number().int().positive().nullable()
|
|
774
895
|
});
|
|
775
896
|
|
|
776
897
|
// ../shared/src/protection.ts
|
|
777
|
-
import { z as
|
|
898
|
+
import { z as z14 } from "zod";
|
|
778
899
|
var PASSWORD_MIN = 6;
|
|
779
900
|
var PASSWORD_MAX = 128;
|
|
780
|
-
var gatePasswordSchema =
|
|
781
|
-
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({
|
|
782
903
|
password: gatePasswordSchema.nullable()
|
|
783
904
|
});
|
|
784
|
-
var protectionResponseSchema =
|
|
785
|
-
protected:
|
|
905
|
+
var protectionResponseSchema = z14.object({
|
|
906
|
+
protected: z14.boolean()
|
|
786
907
|
});
|
|
787
|
-
var unlockSchema =
|
|
788
|
-
password:
|
|
908
|
+
var unlockSchema = z14.object({
|
|
909
|
+
password: z14.string().min(1).max(1024)
|
|
789
910
|
});
|
|
790
|
-
var unlockResponseSchema =
|
|
791
|
-
unlocked:
|
|
911
|
+
var unlockResponseSchema = z14.object({
|
|
912
|
+
unlocked: z14.literal(true)
|
|
792
913
|
});
|
|
793
914
|
|
|
794
915
|
// ../shared/src/report.ts
|
|
795
|
-
import { z as
|
|
796
|
-
var reportRequestSchema =
|
|
797
|
-
reason:
|
|
916
|
+
import { z as z15 } from "zod";
|
|
917
|
+
var reportRequestSchema = z15.object({
|
|
918
|
+
reason: z15.string().max(1e3).optional()
|
|
798
919
|
});
|
|
799
|
-
var reportResponseSchema =
|
|
800
|
-
reported:
|
|
920
|
+
var reportResponseSchema = z15.object({
|
|
921
|
+
reported: z15.literal(true)
|
|
801
922
|
});
|
|
802
923
|
|
|
803
924
|
// ../shared/src/reviewers.ts
|
|
804
|
-
import { z as
|
|
805
|
-
var artifactReviewerSchema =
|
|
806
|
-
avatarUrl:
|
|
807
|
-
displayName:
|
|
925
|
+
import { z as z16 } from "zod";
|
|
926
|
+
var artifactReviewerSchema = z16.object({
|
|
927
|
+
avatarUrl: z16.string().nullable(),
|
|
928
|
+
displayName: z16.string(),
|
|
808
929
|
// Exactly one of userId/guestId is set, per `kind`.
|
|
809
|
-
guestId:
|
|
930
|
+
guestId: z16.string().nullable(),
|
|
810
931
|
// "account", not commentAuthorSchema's "member" — the whole point here is
|
|
811
932
|
// that these people need not be workspace members. A guest can be named in
|
|
812
933
|
// a comment but never notified: guest_identities carries a display name and
|
|
813
934
|
// no email, so there is nowhere to send anything.
|
|
814
|
-
kind:
|
|
815
|
-
userId:
|
|
935
|
+
kind: z16.enum(["account", "guest"]),
|
|
936
|
+
userId: z16.string().nullable()
|
|
816
937
|
});
|
|
817
|
-
var artifactReviewerListResponseSchema =
|
|
818
|
-
reviewers:
|
|
938
|
+
var artifactReviewerListResponseSchema = z16.object({
|
|
939
|
+
reviewers: z16.array(artifactReviewerSchema)
|
|
819
940
|
});
|
|
820
941
|
|
|
821
942
|
// ../shared/src/stats.ts
|
|
822
|
-
import { z as
|
|
823
|
-
var avgViewSecondsSchema =
|
|
824
|
-
var versionViewStatsSchema =
|
|
943
|
+
import { z as z17 } from "zod";
|
|
944
|
+
var avgViewSecondsSchema = z17.number().int().nonnegative().nullable();
|
|
945
|
+
var versionViewStatsSchema = z17.object({
|
|
825
946
|
avgViewSeconds: avgViewSecondsSchema,
|
|
826
947
|
// Views from inside the review shell's iframe vs. direct visits to
|
|
827
948
|
// the render URL. views = embeddedViews + directViews.
|
|
828
|
-
directViews:
|
|
829
|
-
embeddedViews:
|
|
949
|
+
directViews: z17.number().int().nonnegative(),
|
|
950
|
+
embeddedViews: z17.number().int().nonnegative(),
|
|
830
951
|
// Distinct hashed viewer IPs across the version's lifetime.
|
|
831
|
-
uniqueViewers:
|
|
832
|
-
versionNumber:
|
|
833
|
-
views:
|
|
952
|
+
uniqueViewers: z17.number().int().nonnegative(),
|
|
953
|
+
versionNumber: z17.number().int().positive(),
|
|
954
|
+
views: z17.number().int().nonnegative()
|
|
834
955
|
});
|
|
835
|
-
var dailyViewsSchema =
|
|
956
|
+
var dailyViewsSchema = z17.object({
|
|
836
957
|
avgViewSeconds: avgViewSecondsSchema,
|
|
837
958
|
// UTC day, YYYY-MM-DD.
|
|
838
|
-
day:
|
|
839
|
-
uniqueViewers:
|
|
840
|
-
views:
|
|
959
|
+
day: z17.string(),
|
|
960
|
+
uniqueViewers: z17.number().int().nonnegative(),
|
|
961
|
+
views: z17.number().int().nonnegative()
|
|
841
962
|
});
|
|
842
|
-
var artifactStatsResponseSchema =
|
|
963
|
+
var artifactStatsResponseSchema = z17.object({
|
|
843
964
|
avgViewSeconds: avgViewSecondsSchema,
|
|
844
|
-
daily:
|
|
965
|
+
daily: z17.array(dailyViewsSchema),
|
|
845
966
|
// Distinct hashed viewer IPs across all versions and days.
|
|
846
|
-
totalUniqueViewers:
|
|
847
|
-
totalViews:
|
|
848
|
-
versions:
|
|
967
|
+
totalUniqueViewers: z17.number().int().nonnegative(),
|
|
968
|
+
totalViews: z17.number().int().nonnegative(),
|
|
969
|
+
versions: z17.array(versionViewStatsSchema)
|
|
849
970
|
});
|
|
850
971
|
|
|
851
972
|
// ../shared/src/versions.ts
|
|
852
|
-
import { z as
|
|
853
|
-
var versionSourceSchema =
|
|
854
|
-
agentName:
|
|
855
|
-
type:
|
|
973
|
+
import { z as z18 } from "zod";
|
|
974
|
+
var versionSourceSchema = z18.object({
|
|
975
|
+
agentName: z18.string().nullable(),
|
|
976
|
+
type: z18.string()
|
|
856
977
|
});
|
|
857
|
-
var versionChangesSchema =
|
|
858
|
-
added:
|
|
859
|
-
changed:
|
|
860
|
-
removed:
|
|
978
|
+
var versionChangesSchema = z18.object({
|
|
979
|
+
added: z18.array(z18.string()),
|
|
980
|
+
changed: z18.array(z18.string()),
|
|
981
|
+
removed: z18.array(z18.string())
|
|
861
982
|
});
|
|
862
|
-
var versionSummarySchema =
|
|
983
|
+
var versionSummarySchema = z18.object({
|
|
863
984
|
// Absent for the first version — there is no previous version to diff against.
|
|
864
985
|
changes: versionChangesSchema.nullable(),
|
|
865
|
-
createdAt:
|
|
866
|
-
entryUrl:
|
|
867
|
-
fileCount:
|
|
868
|
-
id:
|
|
869
|
-
isCurrent:
|
|
986
|
+
createdAt: z18.string(),
|
|
987
|
+
entryUrl: z18.string().url(),
|
|
988
|
+
fileCount: z18.number().int().nonnegative(),
|
|
989
|
+
id: z18.string(),
|
|
990
|
+
isCurrent: z18.boolean(),
|
|
870
991
|
// Author-supplied bullet-point changelog; null when the publish omitted it.
|
|
871
|
-
notes:
|
|
992
|
+
notes: z18.string().nullable(),
|
|
872
993
|
source: versionSourceSchema,
|
|
873
|
-
totalSizeBytes:
|
|
874
|
-
versionNumber:
|
|
994
|
+
totalSizeBytes: z18.number().int().nonnegative(),
|
|
995
|
+
versionNumber: z18.number().int().positive()
|
|
875
996
|
});
|
|
876
|
-
var versionListResponseSchema =
|
|
877
|
-
versions:
|
|
997
|
+
var versionListResponseSchema = z18.object({
|
|
998
|
+
versions: z18.array(versionSummarySchema)
|
|
878
999
|
});
|
|
879
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
|
+
|
|
880
1009
|
// src/api.ts
|
|
881
1010
|
var ApiRequestError = class extends Error {
|
|
882
1011
|
constructor(status2, code, message, retryAfter) {
|
|
@@ -951,6 +1080,15 @@ function createApiClient(apiUrl2, publishToken) {
|
|
|
951
1080
|
(d) => agentHeartbeatResponseSchema.parse(d)
|
|
952
1081
|
);
|
|
953
1082
|
},
|
|
1083
|
+
// SPEC-2 §6.3 — create a folder in a workspace. Account key required
|
|
1084
|
+
// (owner/admin; in a personal workspace that's always the user).
|
|
1085
|
+
async createFolder(workspaceId, body) {
|
|
1086
|
+
return request(
|
|
1087
|
+
`${base}/api/v1/workspaces/${workspaceId}/folders`,
|
|
1088
|
+
{ body: JSON.stringify(body), headers, method: "POST" },
|
|
1089
|
+
(d) => folderSchema.parse(d)
|
|
1090
|
+
);
|
|
1091
|
+
},
|
|
954
1092
|
// SPEC-2 §6.6 — share an artifact with a person (email or user id).
|
|
955
1093
|
// Authorized by this client's credential: the publish token (an agent
|
|
956
1094
|
// sharing a private draft) or an account key/session. The invitation
|
|
@@ -1049,6 +1187,15 @@ function createApiClient(apiUrl2, publishToken) {
|
|
|
1049
1187
|
(d) => grantListResponseSchema.parse(d)
|
|
1050
1188
|
);
|
|
1051
1189
|
},
|
|
1190
|
+
// SPEC-2 §6.4 — every artifact in a workspace (members see all, with
|
|
1191
|
+
// each artifact's folderId). The only folder-aware artifact listing.
|
|
1192
|
+
async listWorkspaceArtifacts(workspaceId) {
|
|
1193
|
+
return request(
|
|
1194
|
+
`${base}/api/v1/workspaces/${workspaceId}/artifacts`,
|
|
1195
|
+
{ headers, method: "GET" },
|
|
1196
|
+
(d) => workspaceArtifactListResponseSchema.parse(d)
|
|
1197
|
+
);
|
|
1198
|
+
},
|
|
1052
1199
|
async listWorkspaces() {
|
|
1053
1200
|
return request(
|
|
1054
1201
|
`${base}/api/v1/workspaces`,
|
|
@@ -1076,11 +1223,13 @@ function createApiClient(apiUrl2, publishToken) {
|
|
|
1076
1223
|
// SPEC §6.5 — post a reply into a thread. Authorized by this client's
|
|
1077
1224
|
// credential: the artifact's publish token (the reply renders as the
|
|
1078
1225
|
// agent) or the owner's account key (renders as the owner). No guest
|
|
1079
|
-
// payload — the credential is the identity.
|
|
1080
|
-
|
|
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) {
|
|
1081
1230
|
return request(
|
|
1082
1231
|
`${base}/api/v1/comment-threads/${threadId}/messages`,
|
|
1083
|
-
{ body: JSON.stringify({ body }), headers, method: "POST" },
|
|
1232
|
+
{ body: JSON.stringify({ body, via }), headers, method: "POST" },
|
|
1084
1233
|
(d) => commentThreadSchema.parse(d)
|
|
1085
1234
|
);
|
|
1086
1235
|
},
|
|
@@ -1119,6 +1268,16 @@ function createApiClient(apiUrl2, publishToken) {
|
|
|
1119
1268
|
{ body: JSON.stringify({ mode }), headers, method: "PUT" },
|
|
1120
1269
|
(d) => reviewModeResponseSchema.parse(d)
|
|
1121
1270
|
);
|
|
1271
|
+
},
|
|
1272
|
+
// SPEC.md §6.11 / SPEC-2 §6.4 — update an artifact (folder placement,
|
|
1273
|
+
// title, slug, visibility). Workspace-member action: account key only,
|
|
1274
|
+
// a publish token can't re-file.
|
|
1275
|
+
async updateArtifact(artifactId, body) {
|
|
1276
|
+
return request(
|
|
1277
|
+
`${base}/api/v1/artifacts/${artifactId}`,
|
|
1278
|
+
{ body: JSON.stringify(body), headers, method: "PATCH" },
|
|
1279
|
+
(d) => artifactResponseSchema.parse(d)
|
|
1280
|
+
);
|
|
1122
1281
|
}
|
|
1123
1282
|
};
|
|
1124
1283
|
}
|
|
@@ -1147,17 +1306,17 @@ import {
|
|
|
1147
1306
|
writeFileSync as writeFileSync2
|
|
1148
1307
|
} from "fs";
|
|
1149
1308
|
import path2 from "path";
|
|
1150
|
-
import { z as
|
|
1309
|
+
import { z as z20 } from "zod";
|
|
1151
1310
|
|
|
1152
1311
|
// src/credentials.ts
|
|
1153
1312
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
1154
1313
|
import { homedir } from "os";
|
|
1155
1314
|
import path from "path";
|
|
1156
|
-
import { z as
|
|
1315
|
+
import { z as z19 } from "zod";
|
|
1157
1316
|
var DEFAULT_API_URL = "https://artifact.cafe";
|
|
1158
|
-
var credentialsSchema =
|
|
1159
|
-
keys:
|
|
1160
|
-
version:
|
|
1317
|
+
var credentialsSchema = z19.object({
|
|
1318
|
+
keys: z19.record(z19.string(), z19.string()),
|
|
1319
|
+
version: z19.literal(1)
|
|
1161
1320
|
});
|
|
1162
1321
|
function credentialsPath() {
|
|
1163
1322
|
return path.join(homedir(), ".artifactcafe", "credentials");
|
|
@@ -1207,24 +1366,24 @@ function resolveApiKey(apiUrl2, flag) {
|
|
|
1207
1366
|
}
|
|
1208
1367
|
|
|
1209
1368
|
// src/config.ts
|
|
1210
|
-
var configSchema =
|
|
1211
|
-
apiUrl:
|
|
1212
|
-
artifactId:
|
|
1213
|
-
folder:
|
|
1214
|
-
folderId:
|
|
1369
|
+
var configSchema = z20.object({
|
|
1370
|
+
apiUrl: z20.string(),
|
|
1371
|
+
artifactId: z20.string(),
|
|
1372
|
+
folder: z20.string().optional(),
|
|
1373
|
+
folderId: z20.string().optional(),
|
|
1215
1374
|
// Optional: a folder linked by `link` to an artifact you own carries no
|
|
1216
1375
|
// token — owner actions authorize via your stored login instead. A first
|
|
1217
1376
|
// publish still writes the anonymous-mode token here.
|
|
1218
|
-
publishToken:
|
|
1219
|
-
slug:
|
|
1220
|
-
url:
|
|
1221
|
-
workspace:
|
|
1222
|
-
workspaceId:
|
|
1223
|
-
workspaceKind:
|
|
1224
|
-
});
|
|
1225
|
-
var projectConfigSchema =
|
|
1226
|
-
folder:
|
|
1227
|
-
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)
|
|
1228
1387
|
}).strict();
|
|
1229
1388
|
var CONFIG_DIR = ".artifactcafe";
|
|
1230
1389
|
var CONFIG_FILE = "config.json";
|
|
@@ -1260,7 +1419,7 @@ function readProjectConfig(dir) {
|
|
|
1260
1419
|
JSON.parse(readFileSync2(file, "utf8"))
|
|
1261
1420
|
);
|
|
1262
1421
|
} catch (error) {
|
|
1263
|
-
const message = error instanceof
|
|
1422
|
+
const message = error instanceof z20.ZodError ? error.issues[0]?.message ?? "invalid project target" : "invalid JSON";
|
|
1264
1423
|
throw new Error(`Invalid ${file}: ${message}.`);
|
|
1265
1424
|
}
|
|
1266
1425
|
}
|
|
@@ -1399,7 +1558,10 @@ async function comment(opts) {
|
|
|
1399
1558
|
anchor,
|
|
1400
1559
|
body,
|
|
1401
1560
|
versionId: artifact.currentVersion.id,
|
|
1402
|
-
|
|
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)
|
|
1403
1565
|
});
|
|
1404
1566
|
} catch (err) {
|
|
1405
1567
|
if (err instanceof ApiRequestError && err.status === 401) {
|
|
@@ -1831,6 +1993,9 @@ async function publish(opts) {
|
|
|
1831
1993
|
}
|
|
1832
1994
|
const sessionBody = {
|
|
1833
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() } : {},
|
|
1834
1999
|
entryPath,
|
|
1835
2000
|
files: files.map(({ absPath: _absPath, ...manifest }) => manifest),
|
|
1836
2001
|
...placement.folderId ? { folderId: placement.folderId } : {},
|
|
@@ -1838,7 +2003,10 @@ async function publish(opts) {
|
|
|
1838
2003
|
// backslash-n; turn those back into real newlines so bullets survive.
|
|
1839
2004
|
...opts.notes?.trim() ? { notes: opts.notes.replace(/\\n/g, "\n").trim() } : {},
|
|
1840
2005
|
source: {
|
|
1841
|
-
|
|
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(),
|
|
1842
2010
|
runId: process.env.ARTIFACT_CAFE_RUN_ID,
|
|
1843
2011
|
type: "cli"
|
|
1844
2012
|
},
|
|
@@ -1927,6 +2095,7 @@ async function publish(opts) {
|
|
|
1927
2095
|
folderId: placement.folderId ?? null,
|
|
1928
2096
|
url: result.url,
|
|
1929
2097
|
versionNumber: result.versionNumber,
|
|
2098
|
+
visibility: result.visibility ?? null,
|
|
1930
2099
|
workspace: placement.workspace ?? null,
|
|
1931
2100
|
workspaceId: placement.workspaceId ?? null,
|
|
1932
2101
|
...result.claimUrl ? { claimUrl: result.claimUrl } : {},
|
|
@@ -1951,6 +2120,11 @@ async function publish(opts) {
|
|
|
1951
2120
|
console.log(`Review URL:
|
|
1952
2121
|
${result.url}
|
|
1953
2122
|
`);
|
|
2123
|
+
const access = accessNote(result.visibility);
|
|
2124
|
+
if (access) {
|
|
2125
|
+
console.log(`${access}
|
|
2126
|
+
`);
|
|
2127
|
+
}
|
|
1954
2128
|
if (result.claimUrl) {
|
|
1955
2129
|
console.log(
|
|
1956
2130
|
`Claim URL (shown once \u2014 claim to keep this artifact):
|
|
@@ -1979,6 +2153,11 @@ ${result.claimUrl}
|
|
|
1979
2153
|
}
|
|
1980
2154
|
console.log(`${result.url}
|
|
1981
2155
|
`);
|
|
2156
|
+
const access = accessNote(result.visibility);
|
|
2157
|
+
if (access) {
|
|
2158
|
+
console.log(`${access}
|
|
2159
|
+
`);
|
|
2160
|
+
}
|
|
1982
2161
|
if (opts.password !== void 0) {
|
|
1983
2162
|
console.log("Password protection: on\n");
|
|
1984
2163
|
}
|
|
@@ -1991,6 +2170,15 @@ ${result.claimUrl}
|
|
|
1991
2170
|
openInBrowser(result.url);
|
|
1992
2171
|
}
|
|
1993
2172
|
}
|
|
2173
|
+
function accessNote(visibility) {
|
|
2174
|
+
if (visibility === "workspace") {
|
|
2175
|
+
return "Access: workspace members only \u2014 anyone else needs `artifact-cafe share <email>` to open it.";
|
|
2176
|
+
}
|
|
2177
|
+
if (visibility === "private") {
|
|
2178
|
+
return "Access: private \u2014 you, the workspace's admins, and anyone you `artifact-cafe share` it with.";
|
|
2179
|
+
}
|
|
2180
|
+
return null;
|
|
2181
|
+
}
|
|
1994
2182
|
async function resolvePlacement(params) {
|
|
1995
2183
|
const { apiKey, apiUrl: apiUrl2, config, isNewArtifact, opts } = params;
|
|
1996
2184
|
const hasPlacementFlag = opts.workspace !== void 0 || opts.folder !== void 0;
|
|
@@ -2257,6 +2445,24 @@ function printCliError(err, json) {
|
|
|
2257
2445
|
|
|
2258
2446
|
// src/folders.ts
|
|
2259
2447
|
async function folders(opts) {
|
|
2448
|
+
if (opts.action !== void 0 && opts.action !== "create") {
|
|
2449
|
+
throw new Error(
|
|
2450
|
+
`Unknown folders action "${opts.action}" \u2014 run \`folders\` to list, or \`folders create <name>\` to create one.`
|
|
2451
|
+
);
|
|
2452
|
+
}
|
|
2453
|
+
if (opts.action === "create") {
|
|
2454
|
+
if (!opts.name?.trim()) {
|
|
2455
|
+
throw new Error(
|
|
2456
|
+
`Pass the folder name \u2014 e.g. \`artifact-cafe folders create "Design specs" --workspace ${opts.workspace}\`.`
|
|
2457
|
+
);
|
|
2458
|
+
}
|
|
2459
|
+
const visibility = opts.visibility ?? "workspace";
|
|
2460
|
+
if (visibility !== "workspace" && visibility !== "public") {
|
|
2461
|
+
throw new Error(
|
|
2462
|
+
`--visibility must be "workspace" or "public" (got "${opts.visibility}").`
|
|
2463
|
+
);
|
|
2464
|
+
}
|
|
2465
|
+
}
|
|
2260
2466
|
const apiUrl2 = (process.env.ARTIFACT_CAFE_URL ?? DEFAULT_API_URL).replace(
|
|
2261
2467
|
/\/$/,
|
|
2262
2468
|
""
|
|
@@ -2264,7 +2470,7 @@ async function folders(opts) {
|
|
|
2264
2470
|
const key = resolveApiKey(apiUrl2, opts.apiKey);
|
|
2265
2471
|
if (!key) {
|
|
2266
2472
|
throw new Error(
|
|
2267
|
-
`
|
|
2473
|
+
`Folder commands need an account \u2014 run \`artifact-cafe login\` first (no API key for ${apiOrigin(apiUrl2)}).`
|
|
2268
2474
|
);
|
|
2269
2475
|
}
|
|
2270
2476
|
const client = createApiClient(apiUrl2, key);
|
|
@@ -2277,6 +2483,10 @@ async function folders(opts) {
|
|
|
2277
2483
|
`No workspace with handle "${opts.workspace}" belongs to this account.`
|
|
2278
2484
|
);
|
|
2279
2485
|
}
|
|
2486
|
+
if (opts.action === "create") {
|
|
2487
|
+
await createFolder(client, workspace, opts);
|
|
2488
|
+
return;
|
|
2489
|
+
}
|
|
2280
2490
|
const data = await client.listFolders(workspace.id);
|
|
2281
2491
|
if (opts.json) {
|
|
2282
2492
|
console.log(JSON.stringify(data, null, 2));
|
|
@@ -2295,6 +2505,33 @@ async function folders(opts) {
|
|
|
2295
2505
|
printFolder(folder);
|
|
2296
2506
|
}
|
|
2297
2507
|
}
|
|
2508
|
+
async function createFolder(client, workspace, opts) {
|
|
2509
|
+
const name = opts.name.trim();
|
|
2510
|
+
const visibility = opts.visibility ?? "workspace";
|
|
2511
|
+
const existing = await client.listFolders(workspace.id);
|
|
2512
|
+
const duplicate = existing.folders.find(
|
|
2513
|
+
(candidate) => candidate.name.toLowerCase() === name.toLowerCase()
|
|
2514
|
+
);
|
|
2515
|
+
if (duplicate) {
|
|
2516
|
+
throw new Error(
|
|
2517
|
+
`A folder named "${duplicate.name}" already exists in ${workspace.handle} (${duplicate.id}) \u2014 publish into it with --folder, or pick a different name.`
|
|
2518
|
+
);
|
|
2519
|
+
}
|
|
2520
|
+
const folder = await client.createFolder(workspace.id, { name, visibility });
|
|
2521
|
+
if (opts.json) {
|
|
2522
|
+
console.log(JSON.stringify(folder, null, 2));
|
|
2523
|
+
return;
|
|
2524
|
+
}
|
|
2525
|
+
console.log(
|
|
2526
|
+
`\u2713 Created folder "${folder.name}" (${folder.visibility}) in ${workspace.handle}`
|
|
2527
|
+
);
|
|
2528
|
+
console.log(` ${folder.id}`);
|
|
2529
|
+
if (folder.visibility === "public") {
|
|
2530
|
+
console.log(
|
|
2531
|
+
" Artifacts placed in it default to public \u2014 visible to anyone."
|
|
2532
|
+
);
|
|
2533
|
+
}
|
|
2534
|
+
}
|
|
2298
2535
|
function printFolder(folder) {
|
|
2299
2536
|
console.log(`${folder.name} (${folder.visibility})`);
|
|
2300
2537
|
console.log(` ${folder.id}
|
|
@@ -2409,7 +2646,12 @@ async function list(opts) {
|
|
|
2409
2646
|
`Listing your artifacts needs an account \u2014 run \`artifact-cafe login\` first (no API key for ${apiOrigin(apiUrl2)}).`
|
|
2410
2647
|
);
|
|
2411
2648
|
}
|
|
2412
|
-
const
|
|
2649
|
+
const client = createApiClient(apiUrl2, key);
|
|
2650
|
+
if (opts.workspace !== void 0) {
|
|
2651
|
+
await listWorkspace(client, opts);
|
|
2652
|
+
return;
|
|
2653
|
+
}
|
|
2654
|
+
const data = await client.listArtifacts();
|
|
2413
2655
|
if (opts.json) {
|
|
2414
2656
|
console.log(JSON.stringify(data, null, 2));
|
|
2415
2657
|
return;
|
|
@@ -2427,6 +2669,70 @@ async function list(opts) {
|
|
|
2427
2669
|
printArtifact(artifact);
|
|
2428
2670
|
}
|
|
2429
2671
|
}
|
|
2672
|
+
async function listWorkspace(client, opts) {
|
|
2673
|
+
const workspaceData = await client.listWorkspaces();
|
|
2674
|
+
const workspace = workspaceData.workspaces.find(
|
|
2675
|
+
(candidate) => candidate.handle === opts.workspace
|
|
2676
|
+
);
|
|
2677
|
+
if (!workspace) {
|
|
2678
|
+
throw new Error(
|
|
2679
|
+
`No workspace with handle "${opts.workspace}" belongs to this account.`
|
|
2680
|
+
);
|
|
2681
|
+
}
|
|
2682
|
+
const [artifactData, folderData] = await Promise.all([
|
|
2683
|
+
client.listWorkspaceArtifacts(workspace.id),
|
|
2684
|
+
client.listFolders(workspace.id)
|
|
2685
|
+
]);
|
|
2686
|
+
if (opts.json) {
|
|
2687
|
+
console.log(
|
|
2688
|
+
JSON.stringify(
|
|
2689
|
+
{ artifacts: artifactData.artifacts, folders: folderData.folders },
|
|
2690
|
+
null,
|
|
2691
|
+
2
|
|
2692
|
+
)
|
|
2693
|
+
);
|
|
2694
|
+
return;
|
|
2695
|
+
}
|
|
2696
|
+
if (artifactData.artifacts.length === 0) {
|
|
2697
|
+
console.log(`No artifacts in workspace ${workspace.handle}.`);
|
|
2698
|
+
return;
|
|
2699
|
+
}
|
|
2700
|
+
const plural = artifactData.artifacts.length === 1 ? "" : "s";
|
|
2701
|
+
console.log(
|
|
2702
|
+
`${artifactData.artifacts.length} artifact${plural} in ${workspace.handle}
|
|
2703
|
+
`
|
|
2704
|
+
);
|
|
2705
|
+
for (const folder of folderData.folders) {
|
|
2706
|
+
const inFolder = artifactData.artifacts.filter(
|
|
2707
|
+
(artifact) => artifact.folderId === folder.id
|
|
2708
|
+
);
|
|
2709
|
+
if (inFolder.length === 0) {
|
|
2710
|
+
continue;
|
|
2711
|
+
}
|
|
2712
|
+
console.log(`${folder.name} (${folder.visibility})`);
|
|
2713
|
+
for (const artifact of inFolder) {
|
|
2714
|
+
printWorkspaceArtifact(artifact);
|
|
2715
|
+
}
|
|
2716
|
+
}
|
|
2717
|
+
const unfiled = artifactData.artifacts.filter(
|
|
2718
|
+
(artifact) => artifact.folderId === null
|
|
2719
|
+
);
|
|
2720
|
+
if (unfiled.length > 0) {
|
|
2721
|
+
console.log("Unfiled");
|
|
2722
|
+
for (const artifact of unfiled) {
|
|
2723
|
+
printWorkspaceArtifact(artifact);
|
|
2724
|
+
}
|
|
2725
|
+
}
|
|
2726
|
+
}
|
|
2727
|
+
function printWorkspaceArtifact(a) {
|
|
2728
|
+
const version = a.currentVersionNumber === null ? "no version" : `v${a.currentVersionNumber}`;
|
|
2729
|
+
const open2 = a.openCommentCount === 0 ? "no open comments" : `${a.openCommentCount} open comment${a.openCommentCount === 1 ? "" : "s"}`;
|
|
2730
|
+
const marker = a.openCommentCount > 0 ? "\u25CF" : "\u25CB";
|
|
2731
|
+
console.log(
|
|
2732
|
+
` ${marker} ${a.title} \u2014 ${version} \xB7 ${open2} \xB7 ${a.visibility}`
|
|
2733
|
+
);
|
|
2734
|
+
console.log(` ${a.url}`);
|
|
2735
|
+
}
|
|
2430
2736
|
function printArtifact(a) {
|
|
2431
2737
|
const version = a.currentVersionNumber === null ? "no version" : `v${a.currentVersionNumber}`;
|
|
2432
2738
|
const open2 = a.openCommentCount === 0 ? "no open comments" : `${a.openCommentCount} open comment${a.openCommentCount === 1 ? "" : "s"}`;
|
|
@@ -2626,14 +2932,109 @@ async function deleteMessage(opts) {
|
|
|
2626
2932
|
console.log(`\u2713 Deleted ${messageId}.`);
|
|
2627
2933
|
}
|
|
2628
2934
|
|
|
2629
|
-
// src/
|
|
2935
|
+
// src/move.ts
|
|
2630
2936
|
import path10 from "path";
|
|
2631
|
-
async function
|
|
2937
|
+
async function move(opts) {
|
|
2938
|
+
if (Boolean(opts.folder) === Boolean(opts.unfiled)) {
|
|
2939
|
+
throw new Error("Pass exactly one of --folder <name-or-id> or --unfiled.");
|
|
2940
|
+
}
|
|
2632
2941
|
const dir = path10.resolve(opts.dir);
|
|
2633
2942
|
const target = resolveArtifactTarget(dir, {
|
|
2634
2943
|
apiKey: opts.apiKey,
|
|
2635
2944
|
artifact: opts.artifact
|
|
2636
2945
|
});
|
|
2946
|
+
const key = resolveApiKey(target.apiUrl, opts.apiKey);
|
|
2947
|
+
if (!key) {
|
|
2948
|
+
throw new Error(
|
|
2949
|
+
`Moving an artifact needs an account \u2014 run \`artifact-cafe login\` first (no API key for ${apiOrigin(target.apiUrl)}).`
|
|
2950
|
+
);
|
|
2951
|
+
}
|
|
2952
|
+
const client = createApiClient(target.apiUrl, key);
|
|
2953
|
+
const artifact = await client.getArtifact(target.artifactId);
|
|
2954
|
+
if (!artifact.workspaceId) {
|
|
2955
|
+
throw new Error(
|
|
2956
|
+
"This artifact isn't in a workspace \u2014 folders live in workspaces. Claim it (or publish it while logged in) first."
|
|
2957
|
+
);
|
|
2958
|
+
}
|
|
2959
|
+
let folderId = null;
|
|
2960
|
+
let folderName = null;
|
|
2961
|
+
if (opts.folder) {
|
|
2962
|
+
const data = await client.listFolders(artifact.workspaceId);
|
|
2963
|
+
const matches = data.folders.filter(
|
|
2964
|
+
(candidate) => candidate.name === opts.folder || candidate.id === opts.folder
|
|
2965
|
+
);
|
|
2966
|
+
if (matches.length === 0) {
|
|
2967
|
+
throw new Error(
|
|
2968
|
+
`No folder named "${opts.folder}" exists in this workspace \u2014 list them with \`artifact-cafe folders --workspace <handle>\`, or create it with \`folders create\`.`
|
|
2969
|
+
);
|
|
2970
|
+
}
|
|
2971
|
+
if (matches.length > 1) {
|
|
2972
|
+
throw new Error(
|
|
2973
|
+
`More than one folder is named "${opts.folder}"; pass the folder id instead.`
|
|
2974
|
+
);
|
|
2975
|
+
}
|
|
2976
|
+
folderId = matches[0].id;
|
|
2977
|
+
folderName = matches[0].name;
|
|
2978
|
+
}
|
|
2979
|
+
if (artifact.folderId === folderId) {
|
|
2980
|
+
const where = folderName ? `folder "${folderName}"` : "no folder";
|
|
2981
|
+
if (opts.json) {
|
|
2982
|
+
console.log(
|
|
2983
|
+
JSON.stringify(
|
|
2984
|
+
{
|
|
2985
|
+
artifactId: artifact.id,
|
|
2986
|
+
folder: folderName ? { id: folderId, name: folderName } : null,
|
|
2987
|
+
moved: false,
|
|
2988
|
+
title: artifact.title,
|
|
2989
|
+
visibility: artifact.visibility
|
|
2990
|
+
},
|
|
2991
|
+
null,
|
|
2992
|
+
2
|
|
2993
|
+
)
|
|
2994
|
+
);
|
|
2995
|
+
return;
|
|
2996
|
+
}
|
|
2997
|
+
console.log(`"${artifact.title}" is already in ${where} \u2014 nothing to do.`);
|
|
2998
|
+
return;
|
|
2999
|
+
}
|
|
3000
|
+
const updated = await client.updateArtifact(artifact.id, { folderId });
|
|
3001
|
+
if (opts.json) {
|
|
3002
|
+
console.log(
|
|
3003
|
+
JSON.stringify(
|
|
3004
|
+
{
|
|
3005
|
+
artifactId: updated.id,
|
|
3006
|
+
folder: folderName ? { id: folderId, name: folderName } : null,
|
|
3007
|
+
moved: true,
|
|
3008
|
+
previousVisibility: artifact.visibility,
|
|
3009
|
+
title: updated.title,
|
|
3010
|
+
visibility: updated.visibility
|
|
3011
|
+
},
|
|
3012
|
+
null,
|
|
3013
|
+
2
|
|
3014
|
+
)
|
|
3015
|
+
);
|
|
3016
|
+
return;
|
|
3017
|
+
}
|
|
3018
|
+
const destination = folderName ? `"${folderName}"` : "Unfiled";
|
|
3019
|
+
console.log(`\u2713 Moved "${updated.title}" \u2192 ${destination}`);
|
|
3020
|
+
if (updated.visibility !== artifact.visibility) {
|
|
3021
|
+
console.log(
|
|
3022
|
+
` Visibility: ${artifact.visibility} \u2192 ${updated.visibility} (folder default)`
|
|
3023
|
+
);
|
|
3024
|
+
if (updated.visibility === "public") {
|
|
3025
|
+
console.log(" Now public \u2014 visible to anyone.");
|
|
3026
|
+
}
|
|
3027
|
+
}
|
|
3028
|
+
}
|
|
3029
|
+
|
|
3030
|
+
// src/open.ts
|
|
3031
|
+
import path11 from "path";
|
|
3032
|
+
async function openArtifact(opts) {
|
|
3033
|
+
const dir = path11.resolve(opts.dir);
|
|
3034
|
+
const target = resolveArtifactTarget(dir, {
|
|
3035
|
+
apiKey: opts.apiKey,
|
|
3036
|
+
artifact: opts.artifact
|
|
3037
|
+
});
|
|
2637
3038
|
const url = target.url ?? reviewUrl(
|
|
2638
3039
|
target.apiUrl,
|
|
2639
3040
|
(await createApiClient(target.apiUrl, target.credential).getArtifact(
|
|
@@ -2647,7 +3048,7 @@ async function openArtifact(opts) {
|
|
|
2647
3048
|
}
|
|
2648
3049
|
|
|
2649
3050
|
// src/protect.ts
|
|
2650
|
-
import
|
|
3051
|
+
import path12 from "path";
|
|
2651
3052
|
async function protect(opts) {
|
|
2652
3053
|
if (opts.off && opts.password !== void 0) {
|
|
2653
3054
|
throw new Error("Pass either --password or --off, not both.");
|
|
@@ -2664,7 +3065,7 @@ async function protect(opts) {
|
|
|
2664
3065
|
throw new Error(parsed.error.issues[0]?.message ?? "Invalid password.");
|
|
2665
3066
|
}
|
|
2666
3067
|
}
|
|
2667
|
-
const dir =
|
|
3068
|
+
const dir = path12.resolve(opts.dir);
|
|
2668
3069
|
const target = resolveArtifactTarget(dir, {
|
|
2669
3070
|
apiKey: opts.apiKey,
|
|
2670
3071
|
artifact: opts.artifact
|
|
@@ -2689,7 +3090,7 @@ async function protect(opts) {
|
|
|
2689
3090
|
}
|
|
2690
3091
|
|
|
2691
3092
|
// src/reply.ts
|
|
2692
|
-
import
|
|
3093
|
+
import path13 from "path";
|
|
2693
3094
|
async function readStdin3() {
|
|
2694
3095
|
if (process.stdin.isTTY) {
|
|
2695
3096
|
return "";
|
|
@@ -2713,13 +3114,13 @@ async function replyToThread(opts) {
|
|
|
2713
3114
|
'Nothing to post. Pass the reply with --body "\u2026", or pipe it on stdin.'
|
|
2714
3115
|
);
|
|
2715
3116
|
}
|
|
2716
|
-
const dir =
|
|
3117
|
+
const dir = path13.resolve(opts.dir);
|
|
2717
3118
|
const target = resolveArtifactTarget(dir, {
|
|
2718
3119
|
apiKey: opts.apiKey,
|
|
2719
3120
|
artifact: opts.artifact
|
|
2720
3121
|
});
|
|
2721
3122
|
const client = createApiClient(target.apiUrl, target.credential);
|
|
2722
|
-
let thread = await client.replyThread(threadId, body);
|
|
3123
|
+
let thread = await client.replyThread(threadId, body, agentLabel(opts.as));
|
|
2723
3124
|
if (opts.resolve) {
|
|
2724
3125
|
thread = await client.resolveThread(threadId);
|
|
2725
3126
|
}
|
|
@@ -2742,7 +3143,7 @@ async function replyToThread(opts) {
|
|
|
2742
3143
|
}
|
|
2743
3144
|
|
|
2744
3145
|
// src/resolve.ts
|
|
2745
|
-
import
|
|
3146
|
+
import path14 from "path";
|
|
2746
3147
|
async function changeThreadStatus(opts) {
|
|
2747
3148
|
const threadId = opts.thread?.trim();
|
|
2748
3149
|
if (!threadId) {
|
|
@@ -2750,7 +3151,7 @@ async function changeThreadStatus(opts) {
|
|
|
2750
3151
|
`Pass the thread id to ${opts.action} \u2014 get it from \`artifact-cafe comments --json\`.`
|
|
2751
3152
|
);
|
|
2752
3153
|
}
|
|
2753
|
-
const dir =
|
|
3154
|
+
const dir = path14.resolve(opts.dir);
|
|
2754
3155
|
const target = resolveArtifactTarget(dir, {
|
|
2755
3156
|
apiKey: opts.apiKey,
|
|
2756
3157
|
artifact: opts.artifact
|
|
@@ -2787,7 +3188,7 @@ async function changeThreadStatus(opts) {
|
|
|
2787
3188
|
}
|
|
2788
3189
|
|
|
2789
3190
|
// src/review.ts
|
|
2790
|
-
import
|
|
3191
|
+
import path15 from "path";
|
|
2791
3192
|
var OUTCOME = {
|
|
2792
3193
|
off: "Plain artifact \u2014 the review tools are hidden entirely",
|
|
2793
3194
|
open: "Open for review \u2014 anyone who can open it can comment",
|
|
@@ -2801,7 +3202,7 @@ async function review(opts) {
|
|
|
2801
3202
|
);
|
|
2802
3203
|
}
|
|
2803
3204
|
const mode = parsed.data;
|
|
2804
|
-
const dir =
|
|
3205
|
+
const dir = path15.resolve(opts.dir);
|
|
2805
3206
|
const target = resolveArtifactTarget(dir, {
|
|
2806
3207
|
apiKey: opts.apiKey,
|
|
2807
3208
|
artifact: opts.artifact
|
|
@@ -2823,10 +3224,10 @@ async function review(opts) {
|
|
|
2823
3224
|
}
|
|
2824
3225
|
|
|
2825
3226
|
// src/share.ts
|
|
2826
|
-
import
|
|
3227
|
+
import path16 from "path";
|
|
2827
3228
|
var EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
2828
3229
|
async function share(opts) {
|
|
2829
|
-
const dir =
|
|
3230
|
+
const dir = path16.resolve(opts.dir);
|
|
2830
3231
|
const target = resolveArtifactTarget(dir, {
|
|
2831
3232
|
apiKey: opts.apiKey,
|
|
2832
3233
|
artifact: opts.artifact
|
|
@@ -2881,7 +3282,7 @@ General access: ${visibility}`);
|
|
|
2881
3282
|
console.log("");
|
|
2882
3283
|
}
|
|
2883
3284
|
async function unshare(opts) {
|
|
2884
|
-
const dir =
|
|
3285
|
+
const dir = path16.resolve(opts.dir);
|
|
2885
3286
|
const target = resolveArtifactTarget(dir, {
|
|
2886
3287
|
apiKey: opts.apiKey,
|
|
2887
3288
|
artifact: opts.artifact
|
|
@@ -2904,7 +3305,7 @@ async function unshare(opts) {
|
|
|
2904
3305
|
}
|
|
2905
3306
|
|
|
2906
3307
|
// src/status.ts
|
|
2907
|
-
import
|
|
3308
|
+
import path17 from "path";
|
|
2908
3309
|
async function status(opts) {
|
|
2909
3310
|
if (!AGENT_STATES.includes(opts.state)) {
|
|
2910
3311
|
throw new Error(
|
|
@@ -2912,7 +3313,7 @@ async function status(opts) {
|
|
|
2912
3313
|
);
|
|
2913
3314
|
}
|
|
2914
3315
|
const state = opts.state;
|
|
2915
|
-
const dir =
|
|
3316
|
+
const dir = path17.resolve(opts.dir);
|
|
2916
3317
|
const target = resolveArtifactTarget(dir, {
|
|
2917
3318
|
apiKey: opts.apiKey,
|
|
2918
3319
|
artifact: opts.artifact
|
|
@@ -2941,26 +3342,26 @@ async function status(opts) {
|
|
|
2941
3342
|
import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "fs";
|
|
2942
3343
|
import { createRequire } from "module";
|
|
2943
3344
|
import { homedir as homedir2 } from "os";
|
|
2944
|
-
import
|
|
2945
|
-
import { z as
|
|
3345
|
+
import path18 from "path";
|
|
3346
|
+
import { z as z21 } from "zod";
|
|
2946
3347
|
var REGISTRY_LATEST_URL = "https://registry.npmjs.org/artifact-cafe/latest";
|
|
2947
3348
|
var SKILL_SOURCE_URL = "https://raw.githubusercontent.com/Artifact-Cafe/skill/main/artifact-cafe/SKILL.md";
|
|
2948
3349
|
var SKILL_UPDATE_COMMAND = "npx skills add artifact-cafe/skill --skill artifact-cafe -g";
|
|
2949
3350
|
var CHECK_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
2950
3351
|
var FETCH_TIMEOUT_MS = 2e3;
|
|
2951
3352
|
var SKILL_VERSION_PATTERN = /\*\*Skill version:\s*(\d+\.\d+\.\d+)\*\*/;
|
|
2952
|
-
var cacheSchema =
|
|
2953
|
-
checkedAt:
|
|
2954
|
-
cliLatest:
|
|
2955
|
-
skillLatest:
|
|
2956
|
-
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)
|
|
2957
3358
|
});
|
|
2958
3359
|
function cliVersion() {
|
|
2959
3360
|
const pkg = createRequire(import.meta.url)("../package.json");
|
|
2960
3361
|
return pkg.version;
|
|
2961
3362
|
}
|
|
2962
3363
|
function cachePath() {
|
|
2963
|
-
return
|
|
3364
|
+
return path18.join(homedir2(), ".artifactcafe", "update-check.json");
|
|
2964
3365
|
}
|
|
2965
3366
|
function readCache() {
|
|
2966
3367
|
try {
|
|
@@ -2971,7 +3372,7 @@ function readCache() {
|
|
|
2971
3372
|
}
|
|
2972
3373
|
function writeCache(cache) {
|
|
2973
3374
|
try {
|
|
2974
|
-
mkdirSync3(
|
|
3375
|
+
mkdirSync3(path18.dirname(cachePath()), { mode: 448, recursive: true });
|
|
2975
3376
|
writeFileSync3(cachePath(), `${JSON.stringify(cache, null, 2)}
|
|
2976
3377
|
`);
|
|
2977
3378
|
} catch {
|
|
@@ -3008,7 +3409,7 @@ async function fetchText(url) {
|
|
|
3008
3409
|
}
|
|
3009
3410
|
async function fetchLatestVersions(previous) {
|
|
3010
3411
|
const [cli, skill] = await Promise.all([
|
|
3011
|
-
fetchJson(REGISTRY_LATEST_URL).then((body) =>
|
|
3412
|
+
fetchJson(REGISTRY_LATEST_URL).then((body) => z21.object({ version: z21.string() }).parse(body).version).catch(() => null),
|
|
3012
3413
|
fetchText(SKILL_SOURCE_URL).then((body) => SKILL_VERSION_PATTERN.exec(body)?.[1] ?? null).catch(() => null)
|
|
3013
3414
|
]);
|
|
3014
3415
|
return {
|
|
@@ -3024,7 +3425,7 @@ function installedSkillVersions() {
|
|
|
3024
3425
|
const versions = [];
|
|
3025
3426
|
for (const root of roots) {
|
|
3026
3427
|
for (const dir of dirs) {
|
|
3027
|
-
const file =
|
|
3428
|
+
const file = path18.join(root, dir, "skills", "artifact-cafe", "SKILL.md");
|
|
3028
3429
|
if (!existsSync3(file)) {
|
|
3029
3430
|
continue;
|
|
3030
3431
|
}
|
|
@@ -3121,17 +3522,18 @@ function printWorkspace(workspace) {
|
|
|
3121
3522
|
}
|
|
3122
3523
|
|
|
3123
3524
|
// src/index.ts
|
|
3124
|
-
function
|
|
3525
|
+
function readStringArg(argv, flag) {
|
|
3526
|
+
const prefix = `${flag}=`;
|
|
3125
3527
|
for (let i = 0; i < argv.length; i++) {
|
|
3126
3528
|
const token = argv[i];
|
|
3127
3529
|
if (token === void 0) {
|
|
3128
3530
|
continue;
|
|
3129
3531
|
}
|
|
3130
|
-
if (token ===
|
|
3532
|
+
if (token === flag) {
|
|
3131
3533
|
return argv[i + 1];
|
|
3132
3534
|
}
|
|
3133
|
-
if (token.startsWith(
|
|
3134
|
-
return token.slice(
|
|
3535
|
+
if (token.startsWith(prefix)) {
|
|
3536
|
+
return token.slice(prefix.length);
|
|
3135
3537
|
}
|
|
3136
3538
|
}
|
|
3137
3539
|
}
|
|
@@ -3145,6 +3547,10 @@ var publish2 = defineCommand({
|
|
|
3145
3547
|
description: "Publish to an existing artifact ID",
|
|
3146
3548
|
type: "string"
|
|
3147
3549
|
},
|
|
3550
|
+
description: {
|
|
3551
|
+
description: "One-line share-card summary (default: the entry HTML's own meta description)",
|
|
3552
|
+
type: "string"
|
|
3553
|
+
},
|
|
3148
3554
|
dir: {
|
|
3149
3555
|
default: ".",
|
|
3150
3556
|
description: "Directory to publish",
|
|
@@ -3181,11 +3587,12 @@ var publish2 = defineCommand({
|
|
|
3181
3587
|
await publish({
|
|
3182
3588
|
apiKey: args["api-key"],
|
|
3183
3589
|
artifact: args.artifact,
|
|
3590
|
+
description: readStringArg(process.argv.slice(2), "--description"),
|
|
3184
3591
|
dir: args.dir,
|
|
3185
3592
|
entry: args.entry,
|
|
3186
3593
|
folder: args.folder,
|
|
3187
3594
|
json: Boolean(args.json),
|
|
3188
|
-
notes:
|
|
3595
|
+
notes: readStringArg(process.argv.slice(2), "--notes"),
|
|
3189
3596
|
open: !args["no-open"],
|
|
3190
3597
|
password: args.password,
|
|
3191
3598
|
review: args.review,
|
|
@@ -3259,7 +3666,11 @@ var list2 = defineCommand({
|
|
|
3259
3666
|
description: "List with this API key (default: stored login)",
|
|
3260
3667
|
type: "string"
|
|
3261
3668
|
},
|
|
3262
|
-
json: { description: "Machine-readable output", type: "boolean" }
|
|
3669
|
+
json: { description: "Machine-readable output", type: "boolean" },
|
|
3670
|
+
workspace: {
|
|
3671
|
+
description: "List this workspace's artifacts, grouped by folder",
|
|
3672
|
+
type: "string"
|
|
3673
|
+
}
|
|
3263
3674
|
},
|
|
3264
3675
|
meta: {
|
|
3265
3676
|
description: "List the artifacts your account owns",
|
|
@@ -3267,7 +3678,11 @@ var list2 = defineCommand({
|
|
|
3267
3678
|
},
|
|
3268
3679
|
async run({ args }) {
|
|
3269
3680
|
try {
|
|
3270
|
-
await list({
|
|
3681
|
+
await list({
|
|
3682
|
+
apiKey: args["api-key"],
|
|
3683
|
+
json: Boolean(args.json),
|
|
3684
|
+
workspace: args.workspace
|
|
3685
|
+
});
|
|
3271
3686
|
} catch (err) {
|
|
3272
3687
|
printCliError(err, Boolean(args.json));
|
|
3273
3688
|
process.exit(1);
|
|
@@ -3276,26 +3691,43 @@ var list2 = defineCommand({
|
|
|
3276
3691
|
});
|
|
3277
3692
|
var folders2 = defineCommand({
|
|
3278
3693
|
args: {
|
|
3694
|
+
action: {
|
|
3695
|
+
description: 'Optional action: "create"',
|
|
3696
|
+
required: false,
|
|
3697
|
+
type: "positional"
|
|
3698
|
+
},
|
|
3279
3699
|
"api-key": {
|
|
3280
|
-
description: "
|
|
3700
|
+
description: "Authorize with an account API key (default: stored login)",
|
|
3281
3701
|
type: "string"
|
|
3282
3702
|
},
|
|
3283
3703
|
json: { description: "Machine-readable output", type: "boolean" },
|
|
3704
|
+
name: {
|
|
3705
|
+
description: "Folder name (with create)",
|
|
3706
|
+
required: false,
|
|
3707
|
+
type: "positional"
|
|
3708
|
+
},
|
|
3709
|
+
visibility: {
|
|
3710
|
+
description: "With create: workspace (default) | public",
|
|
3711
|
+
type: "string"
|
|
3712
|
+
},
|
|
3284
3713
|
workspace: {
|
|
3285
|
-
description: "Workspace handle
|
|
3714
|
+
description: "Workspace handle to list or create in",
|
|
3286
3715
|
required: true,
|
|
3287
3716
|
type: "string"
|
|
3288
3717
|
}
|
|
3289
3718
|
},
|
|
3290
3719
|
meta: {
|
|
3291
|
-
description: "List folders
|
|
3720
|
+
description: "List a workspace's folders, or create one (folders create)",
|
|
3292
3721
|
name: "folders"
|
|
3293
3722
|
},
|
|
3294
3723
|
async run({ args }) {
|
|
3295
3724
|
try {
|
|
3296
3725
|
await folders({
|
|
3726
|
+
action: args.action,
|
|
3297
3727
|
apiKey: args["api-key"],
|
|
3298
3728
|
json: Boolean(args.json),
|
|
3729
|
+
name: args.name,
|
|
3730
|
+
visibility: args.visibility,
|
|
3299
3731
|
workspace: args.workspace
|
|
3300
3732
|
});
|
|
3301
3733
|
} catch (err) {
|
|
@@ -3304,6 +3736,51 @@ var folders2 = defineCommand({
|
|
|
3304
3736
|
}
|
|
3305
3737
|
}
|
|
3306
3738
|
});
|
|
3739
|
+
var move2 = defineCommand({
|
|
3740
|
+
args: {
|
|
3741
|
+
"api-key": {
|
|
3742
|
+
description: "Authorize with an account API key (default: stored login)",
|
|
3743
|
+
type: "string"
|
|
3744
|
+
},
|
|
3745
|
+
artifact: {
|
|
3746
|
+
description: "Move this artifact ID instead of the linked folder",
|
|
3747
|
+
type: "string"
|
|
3748
|
+
},
|
|
3749
|
+
dir: {
|
|
3750
|
+
default: ".",
|
|
3751
|
+
description: "Linked directory to resolve the artifact from (default: .)",
|
|
3752
|
+
type: "string"
|
|
3753
|
+
},
|
|
3754
|
+
folder: {
|
|
3755
|
+
description: "Target folder name (or id) in the artifact's workspace",
|
|
3756
|
+
type: "string"
|
|
3757
|
+
},
|
|
3758
|
+
json: { description: "Machine-readable output", type: "boolean" },
|
|
3759
|
+
unfiled: {
|
|
3760
|
+
description: "Move out of its folder (workspace root)",
|
|
3761
|
+
type: "boolean"
|
|
3762
|
+
}
|
|
3763
|
+
},
|
|
3764
|
+
meta: {
|
|
3765
|
+
description: "Move an artifact into a workspace folder (or --unfiled)",
|
|
3766
|
+
name: "move"
|
|
3767
|
+
},
|
|
3768
|
+
async run({ args }) {
|
|
3769
|
+
try {
|
|
3770
|
+
await move({
|
|
3771
|
+
apiKey: args["api-key"],
|
|
3772
|
+
artifact: args.artifact,
|
|
3773
|
+
dir: args.dir,
|
|
3774
|
+
folder: args.folder,
|
|
3775
|
+
json: Boolean(args.json),
|
|
3776
|
+
unfiled: Boolean(args.unfiled)
|
|
3777
|
+
});
|
|
3778
|
+
} catch (err) {
|
|
3779
|
+
printCliError(err, Boolean(args.json));
|
|
3780
|
+
process.exit(1);
|
|
3781
|
+
}
|
|
3782
|
+
}
|
|
3783
|
+
});
|
|
3307
3784
|
var workspaces2 = defineCommand({
|
|
3308
3785
|
args: {
|
|
3309
3786
|
"api-key": {
|
|
@@ -3672,6 +4149,10 @@ var reply = defineCommand({
|
|
|
3672
4149
|
description: "Act on an artifact ID instead of the linked folder",
|
|
3673
4150
|
type: "string"
|
|
3674
4151
|
},
|
|
4152
|
+
as: {
|
|
4153
|
+
description: 'Who is replying, e.g. "Claude Code" (default: detected; "" to opt out)',
|
|
4154
|
+
type: "string"
|
|
4155
|
+
},
|
|
3675
4156
|
body: {
|
|
3676
4157
|
description: "Reply text (omit to read from stdin)",
|
|
3677
4158
|
type: "string"
|
|
@@ -3701,6 +4182,7 @@ var reply = defineCommand({
|
|
|
3701
4182
|
await replyToThread({
|
|
3702
4183
|
apiKey: args["api-key"],
|
|
3703
4184
|
artifact: args.artifact,
|
|
4185
|
+
as: args.as,
|
|
3704
4186
|
body: args.body,
|
|
3705
4187
|
dir: args.dir,
|
|
3706
4188
|
json: Boolean(args.json),
|
|
@@ -3723,6 +4205,10 @@ var comment2 = defineCommand({
|
|
|
3723
4205
|
description: "Act on an artifact ID instead of the linked folder",
|
|
3724
4206
|
type: "string"
|
|
3725
4207
|
},
|
|
4208
|
+
as: {
|
|
4209
|
+
description: 'Tool posting on your behalf, e.g. "Claude Code" (default: detected)',
|
|
4210
|
+
type: "string"
|
|
4211
|
+
},
|
|
3726
4212
|
body: {
|
|
3727
4213
|
description: "Comment text (omit to read from stdin)",
|
|
3728
4214
|
type: "string"
|
|
@@ -3750,7 +4236,7 @@ var comment2 = defineCommand({
|
|
|
3750
4236
|
type: "string"
|
|
3751
4237
|
},
|
|
3752
4238
|
via: {
|
|
3753
|
-
description:
|
|
4239
|
+
description: "Older name for --as",
|
|
3754
4240
|
type: "string"
|
|
3755
4241
|
}
|
|
3756
4242
|
},
|
|
@@ -3763,6 +4249,7 @@ var comment2 = defineCommand({
|
|
|
3763
4249
|
await comment({
|
|
3764
4250
|
apiKey: args["api-key"],
|
|
3765
4251
|
artifact: args.artifact,
|
|
4252
|
+
as: args.as,
|
|
3766
4253
|
body: args.body,
|
|
3767
4254
|
dir: args.dir,
|
|
3768
4255
|
json: Boolean(args.json),
|
|
@@ -4023,6 +4510,7 @@ var main = defineCommand({
|
|
|
4023
4510
|
listen,
|
|
4024
4511
|
login: login2,
|
|
4025
4512
|
logout: logout2,
|
|
4513
|
+
move: move2,
|
|
4026
4514
|
open,
|
|
4027
4515
|
protect: protect2,
|
|
4028
4516
|
publish: publish2,
|