@nekro-nxt/contracts 0.3.0 → 0.5.0
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/README.md +2 -0
- package/dist/index.mjs +2512 -78
- package/dist/index.mjs.map +1 -1
- package/lib/types/commands.d.ts +408 -0
- package/lib/types/commands.d.ts.map +1 -0
- package/lib/types/community-feedback-host.d.ts +442 -0
- package/lib/types/community-feedback-host.d.ts.map +1 -0
- package/lib/types/community-feedback.d.ts +1072 -0
- package/lib/types/community-feedback.d.ts.map +1 -0
- package/lib/types/community-personas.d.ts +4 -0
- package/lib/types/community-personas.d.ts.map +1 -1
- package/lib/types/community.d.ts +251 -13
- package/lib/types/community.d.ts.map +1 -1
- package/lib/types/domain.d.ts +33 -0
- package/lib/types/domain.d.ts.map +1 -1
- package/lib/types/extension-capabilities.d.ts +105 -3
- package/lib/types/extension-capabilities.d.ts.map +1 -1
- package/lib/types/extension-ui.d.ts +86 -7
- package/lib/types/extension-ui.d.ts.map +1 -1
- package/lib/types/host-api.d.ts +11109 -3874
- package/lib/types/host-api.d.ts.map +1 -1
- package/lib/types/index.d.ts +4 -0
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/logs.d.ts +355 -0
- package/lib/types/logs.d.ts.map +1 -0
- package/package.json +1 -1
- package/src/commands.ts +366 -0
- package/src/community-feedback-host.ts +121 -0
- package/src/community-feedback.ts +289 -0
- package/src/community.ts +56 -1
- package/src/domain.ts +59 -6
- package/src/extension-capabilities.ts +159 -8
- package/src/extension-ui.ts +40 -0
- package/src/host-api.ts +1540 -67
- package/src/index.ts +5 -0
- package/src/logs.ts +138 -0
- package/src/management-api.ts +1 -1
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
|
|
3
|
+
export const COMMUNITY_FEEDBACK_STATUSES = [
|
|
4
|
+
'new',
|
|
5
|
+
'needs_info',
|
|
6
|
+
'triaged',
|
|
7
|
+
'planned',
|
|
8
|
+
'fixed',
|
|
9
|
+
'duplicate',
|
|
10
|
+
'wontfix',
|
|
11
|
+
'withdrawn',
|
|
12
|
+
] as const
|
|
13
|
+
export const CommunityFeedbackStatusSchema = z.enum(COMMUNITY_FEEDBACK_STATUSES)
|
|
14
|
+
export type CommunityFeedbackStatus = z.output<typeof CommunityFeedbackStatusSchema>
|
|
15
|
+
export const COMMUNITY_FEEDBACK_STATUS_LABELS: Readonly<Record<CommunityFeedbackStatus, string>> = {
|
|
16
|
+
new: '新反馈',
|
|
17
|
+
needs_info: '需要补充',
|
|
18
|
+
triaged: '已确认',
|
|
19
|
+
planned: '已计划',
|
|
20
|
+
fixed: '已修复',
|
|
21
|
+
duplicate: '重复',
|
|
22
|
+
wontfix: '不处理',
|
|
23
|
+
withdrawn: '已撤回',
|
|
24
|
+
}
|
|
25
|
+
export const CommunityFeedbackKindSchema = z.enum(['bug', 'suggestion', 'question'])
|
|
26
|
+
export const CommunityFeedbackIdSchema = z
|
|
27
|
+
.string()
|
|
28
|
+
.regex(/^fbk_[0-9a-z]{26}$/u)
|
|
29
|
+
.brand<'CommunityFeedbackId'>()
|
|
30
|
+
export const CommunityFeedbackRefSchema = z.string().regex(/^FB-[1-9][0-9]*$/u)
|
|
31
|
+
export const CommunityFeedbackTargetSchema = z.union([
|
|
32
|
+
z.literal('nxt'),
|
|
33
|
+
z.object({ extensionId: z.string().regex(/^ext_[0-9A-Za-z]+$/u), version: z.string().max(120).optional() }).strict(),
|
|
34
|
+
])
|
|
35
|
+
const version = z.string().trim().min(1).max(120)
|
|
36
|
+
const timestamp = z.number().int().nonnegative()
|
|
37
|
+
|
|
38
|
+
export const CommunityFeedbackExtensionDiagnosticSchema = z
|
|
39
|
+
.object({
|
|
40
|
+
extensionId: z.string().max(100),
|
|
41
|
+
version,
|
|
42
|
+
accessLevel: z.string().max(80).optional(),
|
|
43
|
+
activation: z.enum(['host', 'agent']).optional(),
|
|
44
|
+
})
|
|
45
|
+
.strict()
|
|
46
|
+
export const CommunityFeedbackDiagnosticEntrySchema = z
|
|
47
|
+
.object({
|
|
48
|
+
kind: z.enum(['compatibility', 'extension', 'connection']),
|
|
49
|
+
summary: z.string().max(2000),
|
|
50
|
+
extensionId: z.string().max(100).optional(),
|
|
51
|
+
})
|
|
52
|
+
.strict()
|
|
53
|
+
|
|
54
|
+
/** An explicit allowlist: credentials, account grants and arbitrary host configuration never cross this boundary. */
|
|
55
|
+
export const CommunityFeedbackDiagnosticsSchema = z
|
|
56
|
+
.object({
|
|
57
|
+
nxtVersion: version.optional(),
|
|
58
|
+
releaseChannel: z.enum(['stable', 'preview', 'development']).optional(),
|
|
59
|
+
hostKind: z.enum(['desktop', 'server']).optional(),
|
|
60
|
+
platform: z.string().max(80).optional(),
|
|
61
|
+
arch: z.string().max(40).optional(),
|
|
62
|
+
dshVersion: version.optional(),
|
|
63
|
+
adapters: z.array(z.string().max(100)).max(64).optional(),
|
|
64
|
+
agent: z
|
|
65
|
+
.object({
|
|
66
|
+
accessLevel: z.string().max(80),
|
|
67
|
+
subagents: z.boolean(),
|
|
68
|
+
fileTools: z.boolean(),
|
|
69
|
+
webSearch: z.boolean(),
|
|
70
|
+
dynamicCreation: z.boolean(),
|
|
71
|
+
developmentShell: z.boolean(),
|
|
72
|
+
unrestrictedFileAccess: z.boolean(),
|
|
73
|
+
scheduledTasks: z.boolean(),
|
|
74
|
+
codeRun: z.boolean(),
|
|
75
|
+
commandNetwork: z.boolean(),
|
|
76
|
+
communityFeedbackAuto: z.boolean(),
|
|
77
|
+
})
|
|
78
|
+
.strict()
|
|
79
|
+
.optional(),
|
|
80
|
+
extensions: z.array(CommunityFeedbackExtensionDiagnosticSchema).max(256).optional(),
|
|
81
|
+
entries: z.array(CommunityFeedbackDiagnosticEntrySchema).max(32).optional(),
|
|
82
|
+
instanceId: z.string().min(1).max(100).optional(),
|
|
83
|
+
})
|
|
84
|
+
.strict()
|
|
85
|
+
export type CommunityFeedbackDiagnostics = z.output<typeof CommunityFeedbackDiagnosticsSchema>
|
|
86
|
+
|
|
87
|
+
export const CommunityFeedbackExcerptSchema = z
|
|
88
|
+
.array(
|
|
89
|
+
z
|
|
90
|
+
.object({
|
|
91
|
+
speaker: z.string().max(80),
|
|
92
|
+
text: z.string().max(6000),
|
|
93
|
+
})
|
|
94
|
+
.strict(),
|
|
95
|
+
)
|
|
96
|
+
.max(8)
|
|
97
|
+
export type CommunityFeedbackExcerpt = z.output<typeof CommunityFeedbackExcerptSchema>
|
|
98
|
+
|
|
99
|
+
export const CommunityFeedbackCreateSchema = z
|
|
100
|
+
.object({
|
|
101
|
+
clientRequestId: z.string().min(1).max(160),
|
|
102
|
+
kind: CommunityFeedbackKindSchema,
|
|
103
|
+
target: CommunityFeedbackTargetSchema,
|
|
104
|
+
title: z.string().trim().min(1).max(120),
|
|
105
|
+
body: z.string().trim().min(1).max(8000),
|
|
106
|
+
diagnostics: CommunityFeedbackDiagnosticsSchema.default({}),
|
|
107
|
+
excerpt: CommunityFeedbackExcerptSchema.optional(),
|
|
108
|
+
excerptSharedWithAuthor: z.boolean().default(false),
|
|
109
|
+
source: z.enum(['assistant', 'assistant_auto', 'form', 'web']),
|
|
110
|
+
instanceId: z.string().min(1).max(100).optional(),
|
|
111
|
+
})
|
|
112
|
+
.strict()
|
|
113
|
+
export type CommunityFeedbackCreate = z.output<typeof CommunityFeedbackCreateSchema>
|
|
114
|
+
export const CommunityFeedbackMessageInputSchema = z
|
|
115
|
+
.object({
|
|
116
|
+
body: z.string().trim().min(1).max(4000),
|
|
117
|
+
audience: z.enum(['everyone', 'staff']).default('everyone'),
|
|
118
|
+
})
|
|
119
|
+
.strict()
|
|
120
|
+
export const CommunityFeedbackSupplementSchema = z
|
|
121
|
+
.object({
|
|
122
|
+
diagnostics: CommunityFeedbackDiagnosticsSchema.optional(),
|
|
123
|
+
excerpt: CommunityFeedbackExcerptSchema.optional(),
|
|
124
|
+
excerptSharedWithAuthor: z.boolean().optional(),
|
|
125
|
+
})
|
|
126
|
+
.strict()
|
|
127
|
+
export const CommunityFeedbackWithdrawSchema = z.object({ deleteText: z.boolean().default(false) }).strict()
|
|
128
|
+
export const CommunityFeedbackConfirmSchema = z.object({ clientVersion: version }).strict()
|
|
129
|
+
export const CommunityFeedbackReopenSchema = z.object({ note: z.string().trim().min(1).max(2000) }).strict()
|
|
130
|
+
export const CommunityFeedbackAffectedSchema = z
|
|
131
|
+
.object({
|
|
132
|
+
diagnostics: CommunityFeedbackDiagnosticsSchema.optional(),
|
|
133
|
+
nxtVersion: version.optional(),
|
|
134
|
+
})
|
|
135
|
+
.strict()
|
|
136
|
+
export const CommunityFeedbackTransitionSchema = z
|
|
137
|
+
.object({
|
|
138
|
+
status: CommunityFeedbackStatusSchema,
|
|
139
|
+
fixedIn: version.optional(),
|
|
140
|
+
duplicateOf: CommunityFeedbackRefSchema.optional(),
|
|
141
|
+
note: z.string().trim().max(2000).optional(),
|
|
142
|
+
})
|
|
143
|
+
.strict()
|
|
144
|
+
export type CommunityFeedbackTransition = z.output<typeof CommunityFeedbackTransitionSchema>
|
|
145
|
+
export const CommunityFeedbackLabelsSchema = z
|
|
146
|
+
.object({
|
|
147
|
+
labels: z.array(z.string().trim().min(1).max(40)).max(20),
|
|
148
|
+
priority: z.enum(['low', 'normal', 'high']).nullable(),
|
|
149
|
+
})
|
|
150
|
+
.strict()
|
|
151
|
+
export const CommunityFeedbackLinkSchema = z
|
|
152
|
+
.object({
|
|
153
|
+
githubUrl: z
|
|
154
|
+
.string()
|
|
155
|
+
.url()
|
|
156
|
+
.max(1000)
|
|
157
|
+
.refine((value) => /^https:\/\/github\.com\/[^/]+\/[^/]+\/issues\/[1-9][0-9]*$/u.test(value))
|
|
158
|
+
.nullable(),
|
|
159
|
+
})
|
|
160
|
+
.strict()
|
|
161
|
+
export const CommunityFeedbackVisibilitySchema = z.object({ visibility: z.enum(['private', 'public']) }).strict()
|
|
162
|
+
|
|
163
|
+
export const CommunityFeedbackEventDataSchema = z
|
|
164
|
+
.object({
|
|
165
|
+
from: CommunityFeedbackStatusSchema.optional(),
|
|
166
|
+
to: CommunityFeedbackStatusSchema.optional(),
|
|
167
|
+
fixedIn: version.nullable().optional(),
|
|
168
|
+
duplicateOf: CommunityFeedbackRefSchema.nullable().optional(),
|
|
169
|
+
note: z.string().max(2000).optional(),
|
|
170
|
+
labels: z.array(z.string()).optional(),
|
|
171
|
+
priority: z.enum(['low', 'normal', 'high']).nullable().optional(),
|
|
172
|
+
visibility: z.enum(['private', 'public']).optional(),
|
|
173
|
+
clientVersion: version.optional(),
|
|
174
|
+
messageId: z.string().optional(),
|
|
175
|
+
audience: z.enum(['everyone', 'staff']).optional(),
|
|
176
|
+
deleteText: z.boolean().optional(),
|
|
177
|
+
affected: z.boolean().optional(),
|
|
178
|
+
})
|
|
179
|
+
.strict()
|
|
180
|
+
export const CommunityFeedbackEventSchema = z.object({
|
|
181
|
+
seq: z.number().int().positive(),
|
|
182
|
+
ref: CommunityFeedbackRefSchema,
|
|
183
|
+
type: z.enum([
|
|
184
|
+
'created',
|
|
185
|
+
'message',
|
|
186
|
+
'status_changed',
|
|
187
|
+
'labeled',
|
|
188
|
+
'priority_changed',
|
|
189
|
+
'linked_issue',
|
|
190
|
+
'duplicate_marked',
|
|
191
|
+
'fixed_in_set',
|
|
192
|
+
'visibility_changed',
|
|
193
|
+
'affected_added',
|
|
194
|
+
'withdrawn',
|
|
195
|
+
'reopened',
|
|
196
|
+
'supplemented',
|
|
197
|
+
'fix_confirmed',
|
|
198
|
+
]),
|
|
199
|
+
actorKind: z.enum(['user', 'admin', 'author', 'token', 'system']).optional(),
|
|
200
|
+
actor: z.string().optional(),
|
|
201
|
+
tokenId: z.string().optional(),
|
|
202
|
+
data: CommunityFeedbackEventDataSchema,
|
|
203
|
+
createdAt: timestamp,
|
|
204
|
+
title: z.string().optional(),
|
|
205
|
+
status: CommunityFeedbackStatusSchema.optional(),
|
|
206
|
+
})
|
|
207
|
+
export type CommunityFeedbackEvent = z.output<typeof CommunityFeedbackEventSchema>
|
|
208
|
+
export const CommunityFeedbackMessageSchema = z.object({
|
|
209
|
+
id: z.string(),
|
|
210
|
+
authorKind: z.enum(['user', 'admin', 'author', 'system']),
|
|
211
|
+
author: z.string().nullable(),
|
|
212
|
+
audience: z.enum(['everyone', 'staff']),
|
|
213
|
+
body: z.string(),
|
|
214
|
+
createdAt: timestamp,
|
|
215
|
+
})
|
|
216
|
+
|
|
217
|
+
export const CommunityFeedbackSummarySchema = z.object({
|
|
218
|
+
id: CommunityFeedbackIdSchema,
|
|
219
|
+
ref: CommunityFeedbackRefSchema,
|
|
220
|
+
title: z.string(),
|
|
221
|
+
kind: CommunityFeedbackKindSchema.optional(),
|
|
222
|
+
target: CommunityFeedbackTargetSchema.optional(),
|
|
223
|
+
status: CommunityFeedbackStatusSchema,
|
|
224
|
+
fixedIn: version.nullable(),
|
|
225
|
+
affectedCount: z.number().int().nonnegative(),
|
|
226
|
+
source: CommunityFeedbackCreateSchema.shape.source.optional(),
|
|
227
|
+
confirmedCount: z.number().int().nonnegative().optional(),
|
|
228
|
+
createdAt: timestamp.optional(),
|
|
229
|
+
updatedAt: timestamp.optional(),
|
|
230
|
+
})
|
|
231
|
+
export type CommunityFeedbackSummary = z.output<typeof CommunityFeedbackSummarySchema>
|
|
232
|
+
|
|
233
|
+
/** Optional private fields are emitted only by the server's role-specific projection. */
|
|
234
|
+
export const CommunityFeedbackSchema = CommunityFeedbackSummarySchema.extend({
|
|
235
|
+
access: z.enum(['owner', 'admin', 'author', 'subscriber', 'public']),
|
|
236
|
+
body: z.string().optional(),
|
|
237
|
+
diagnostics: CommunityFeedbackDiagnosticsSchema.optional(),
|
|
238
|
+
excerpt: CommunityFeedbackExcerptSchema.nullable().optional(),
|
|
239
|
+
excerptSharedWithAuthor: z.boolean().optional(),
|
|
240
|
+
messages: z.array(CommunityFeedbackMessageSchema).optional(),
|
|
241
|
+
events: z.array(CommunityFeedbackEventSchema).optional(),
|
|
242
|
+
submitter: z.string().optional(),
|
|
243
|
+
instanceId: z.string().nullable().optional(),
|
|
244
|
+
priority: z.enum(['low', 'normal', 'high']).nullable().optional(),
|
|
245
|
+
labels: z.array(z.string()).optional(),
|
|
246
|
+
visibility: z.enum(['private', 'public']).optional(),
|
|
247
|
+
duplicateOf: CommunityFeedbackRefSchema.nullable().optional(),
|
|
248
|
+
githubUrl: z.string().nullable().optional(),
|
|
249
|
+
closedAt: timestamp.nullable().optional(),
|
|
250
|
+
purgedAt: timestamp.nullable().optional(),
|
|
251
|
+
confirmed: z.boolean().default(false),
|
|
252
|
+
affected: z.boolean().default(false),
|
|
253
|
+
affectedDiagnostics: z
|
|
254
|
+
.array(
|
|
255
|
+
z.object({
|
|
256
|
+
user: z.string(),
|
|
257
|
+
diagnostics: CommunityFeedbackDiagnosticsSchema.nullable(),
|
|
258
|
+
nxtVersion: version.nullable(),
|
|
259
|
+
createdAt: timestamp,
|
|
260
|
+
}),
|
|
261
|
+
)
|
|
262
|
+
.optional(),
|
|
263
|
+
})
|
|
264
|
+
export type CommunityFeedback = z.output<typeof CommunityFeedbackSchema>
|
|
265
|
+
export const CommunityFeedbackListSchema = z.object({
|
|
266
|
+
items: z.array(CommunityFeedbackSummarySchema),
|
|
267
|
+
cursor: z.string().nullable(),
|
|
268
|
+
})
|
|
269
|
+
export const CommunityFeedbackChangesSchema = z.object({
|
|
270
|
+
events: z.array(CommunityFeedbackEventSchema),
|
|
271
|
+
cursor: z.number().int().nonnegative(),
|
|
272
|
+
hasMore: z.boolean(),
|
|
273
|
+
})
|
|
274
|
+
export type CommunityFeedbackChanges = z.output<typeof CommunityFeedbackChangesSchema>
|
|
275
|
+
export const CommunityFeedbackDigestSchema = z.object({
|
|
276
|
+
since: timestamp,
|
|
277
|
+
counts: z.object({
|
|
278
|
+
status: z.record(CommunityFeedbackStatusSchema, z.number().int().nonnegative()),
|
|
279
|
+
kind: z.record(CommunityFeedbackKindSchema, z.number().int().nonnegative()),
|
|
280
|
+
target: z.record(z.enum(['nxt', 'extension']), z.number().int().nonnegative()),
|
|
281
|
+
extensions: z.record(z.string(), z.number().int().nonnegative()),
|
|
282
|
+
}),
|
|
283
|
+
newItems: z.array(CommunityFeedbackSummarySchema),
|
|
284
|
+
awaitingReply: z.array(CommunityFeedbackSummarySchema),
|
|
285
|
+
mostAffected: z.array(CommunityFeedbackSummarySchema),
|
|
286
|
+
unconfirmedFixes: z.array(CommunityFeedbackSummarySchema),
|
|
287
|
+
fixedCount: z.number().int().nonnegative(),
|
|
288
|
+
})
|
|
289
|
+
export type CommunityFeedbackDigest = z.output<typeof CommunityFeedbackDigestSchema>
|
package/src/community.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod'
|
|
2
|
-
import { ExtensionIdSchema } from './domain.js'
|
|
2
|
+
import { ExtensionIdSchema, ExtensionRevisionIdSchema } from './domain.js'
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* NekroNXT 社区在本机的投影。Host 代理社区开放接口并把结果归一到这些结构;社区新增的字段在 Host 处丢弃,
|
|
@@ -90,6 +90,8 @@ export const CommunityExtensionSortSchema = z.enum(['updated', 'score', 'downloa
|
|
|
90
90
|
export const CommunityReleaseIdSchema = z.string().regex(/^rel_[0-9A-Za-z]+$/u)
|
|
91
91
|
|
|
92
92
|
export const CommunityAccountSchema = z.object({
|
|
93
|
+
/** Immutable community identity; absent when connected to a community predating feedback support. */
|
|
94
|
+
id: z.string().min(1).max(100).optional(),
|
|
93
95
|
handle: z.string().min(1).max(80),
|
|
94
96
|
displayName: z.string().max(200),
|
|
95
97
|
avatarUrl: z.string().url().nullable(),
|
|
@@ -100,6 +102,7 @@ export const CommunityEnvironmentSchema = z.enum(['production', 'staging', 'deve
|
|
|
100
102
|
export type CommunityEnvironment = z.output<typeof CommunityEnvironmentSchema>
|
|
101
103
|
|
|
102
104
|
export const CommunityStatusSchema = z.object({
|
|
105
|
+
features: z.array(z.string()).optional(),
|
|
103
106
|
communityUrl: z.string().url(),
|
|
104
107
|
/** 社区自我声明的环境;连不上或旧版社区时为 null。 */
|
|
105
108
|
environment: CommunityEnvironmentSchema.nullable(),
|
|
@@ -131,6 +134,12 @@ export const CommunityReleaseSchema = z.object({
|
|
|
131
134
|
requiresSdk: z.number().int().positive().nullable(),
|
|
132
135
|
notes: z.string().max(2000),
|
|
133
136
|
createdAt: z.number().int(),
|
|
137
|
+
/** Release number on the community line; absent from older communities. */
|
|
138
|
+
number: z.number().int().positive().optional(),
|
|
139
|
+
/** Revision the release contains and its lineage, so NekroNXT can tell fast-forward from divergence. */
|
|
140
|
+
revisionId: ExtensionRevisionIdSchema.optional(),
|
|
141
|
+
parentRevisionId: ExtensionRevisionIdSchema.nullable().optional(),
|
|
142
|
+
ancestry: z.array(ExtensionRevisionIdSchema).max(256).optional(),
|
|
134
143
|
})
|
|
135
144
|
export type CommunityRelease = z.output<typeof CommunityReleaseSchema>
|
|
136
145
|
|
|
@@ -157,6 +166,20 @@ export const CommunityExtensionSummarySchema = z.object({
|
|
|
157
166
|
downloads: z.number().int().nonnegative(),
|
|
158
167
|
updatedAt: z.number().int(),
|
|
159
168
|
pageUrl: z.string().url(),
|
|
169
|
+
/**
|
|
170
|
+
* The extension and version this one is a branch of; null for an original line or an older community. Without a
|
|
171
|
+
* displayName the origin is not public on the community.
|
|
172
|
+
*/
|
|
173
|
+
branchOf: z
|
|
174
|
+
.object({
|
|
175
|
+
extensionId: ExtensionIdSchema,
|
|
176
|
+
revisionId: ExtensionRevisionIdSchema.nullable(),
|
|
177
|
+
displayName: z.string().max(200).nullable(),
|
|
178
|
+
})
|
|
179
|
+
.nullable()
|
|
180
|
+
.optional(),
|
|
181
|
+
/** Public branches made from this extension. */
|
|
182
|
+
branchCount: z.number().int().nonnegative().optional(),
|
|
160
183
|
})
|
|
161
184
|
export type CommunityExtensionSummary = z.output<typeof CommunityExtensionSummarySchema>
|
|
162
185
|
|
|
@@ -220,6 +243,38 @@ export const CommunitySourceSchema = z.object({
|
|
|
220
243
|
})
|
|
221
244
|
export type CommunitySource = z.output<typeof CommunitySourceSchema>
|
|
222
245
|
|
|
246
|
+
/**
|
|
247
|
+
* How this machine's current version of one extension relates to the community's newest public release, with the
|
|
248
|
+
* action that relation calls for. `role` says whether this machine may publish the line or only follows it.
|
|
249
|
+
*/
|
|
250
|
+
export const CommunitySyncItemSchema = z.object({
|
|
251
|
+
extensionId: ExtensionIdSchema,
|
|
252
|
+
displayName: z.string(),
|
|
253
|
+
communityUrl: z.string().url(),
|
|
254
|
+
role: z.enum(['owner', 'subscriber']),
|
|
255
|
+
currentRevisionId: ExtensionRevisionIdSchema,
|
|
256
|
+
currentVersionLabel: z.string(),
|
|
257
|
+
/** Release the current version is, when it is one. */
|
|
258
|
+
currentRelease: z.object({ id: CommunityReleaseIdSchema, number: z.number().int().positive().nullable() }).nullable(),
|
|
259
|
+
/** `remote-ahead`: update; `local-ahead`: publish (owner) or local changes (subscriber); `diverged`: merge first. */
|
|
260
|
+
status: z.enum(['same', 'remote-ahead', 'local-ahead', 'diverged', 'unrelated', 'unknown']),
|
|
261
|
+
found: z.boolean(),
|
|
262
|
+
delisted: z.boolean(),
|
|
263
|
+
delistedReason: z.string().nullable(),
|
|
264
|
+
/** The release the current version came from was withdrawn by its author. */
|
|
265
|
+
releaseWithdrawn: z.boolean(),
|
|
266
|
+
latest: CommunityReleaseSchema.nullable(),
|
|
267
|
+
/** The user chose to keep local changes over `latest`; it is not offered again. */
|
|
268
|
+
dismissed: z.boolean(),
|
|
269
|
+
addedPermissions: z.array(CommunityPermissionItemSchema),
|
|
270
|
+
})
|
|
271
|
+
export type CommunitySyncItem = z.output<typeof CommunitySyncItemSchema>
|
|
272
|
+
|
|
273
|
+
export const CommunitySyncSchema = z.object({
|
|
274
|
+
checkedAt: z.number().int().nullable(),
|
|
275
|
+
items: z.array(CommunitySyncItemSchema),
|
|
276
|
+
})
|
|
277
|
+
|
|
223
278
|
export const CommunityInstalledItemSchema = z.object({
|
|
224
279
|
extensionId: ExtensionIdSchema,
|
|
225
280
|
displayName: z.string(),
|
package/src/domain.ts
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
import { z } from 'zod'
|
|
2
2
|
|
|
3
|
+
/** Rendered send-tool result consumed by both the agent and the product detail view. */
|
|
4
|
+
export const MessageDeliverySummarySchema = z
|
|
5
|
+
.object({
|
|
6
|
+
status: z.enum(['sent', 'partially-sent', 'failed', 'unknown']),
|
|
7
|
+
issues: z
|
|
8
|
+
.array(
|
|
9
|
+
z
|
|
10
|
+
.object({
|
|
11
|
+
status: z.enum(['failed', 'unknown']),
|
|
12
|
+
message: z.string().max(1000),
|
|
13
|
+
kind: z.enum(['transient', 'permanent', 'rate-limited', 'authentication', 'invalid']).optional(),
|
|
14
|
+
action: z.string().max(120).optional(),
|
|
15
|
+
retcode: z.number().int().safe().optional(),
|
|
16
|
+
})
|
|
17
|
+
.strict(),
|
|
18
|
+
)
|
|
19
|
+
.max(20),
|
|
20
|
+
omittedIssues: z.number().int().nonnegative().optional(),
|
|
21
|
+
})
|
|
22
|
+
.strict()
|
|
23
|
+
|
|
3
24
|
const brandedId = <Prefix extends string, Brand extends string>(prefix: Prefix, brand: Brand) =>
|
|
4
25
|
z
|
|
5
26
|
.string()
|
|
@@ -28,8 +49,10 @@ export const DshPluginEntryIdSchema = brandedId('dse', 'DshPluginEntryId')
|
|
|
28
49
|
export const HostUiPageInstanceIdSchema = brandedId('hup', 'HostUiPageInstanceId')
|
|
29
50
|
export const AuthoringTaskIdSchema = brandedId('aut', 'AuthoringTaskId')
|
|
30
51
|
export const AuthoringAttemptIdSchema = brandedId('aua', 'AuthoringAttemptId')
|
|
52
|
+
export const SubConversationIdSchema = brandedId('cnv', 'SubConversationId')
|
|
31
53
|
|
|
32
54
|
export type AgentId = z.infer<typeof AgentIdSchema>
|
|
55
|
+
export type SubConversationId = z.infer<typeof SubConversationIdSchema>
|
|
33
56
|
export type AgentRevisionId = z.infer<typeof AgentRevisionIdSchema>
|
|
34
57
|
export type ConnectionId = z.infer<typeof ConnectionIdSchema>
|
|
35
58
|
export type ConnectionEventId = z.infer<typeof ConnectionEventIdSchema>
|
|
@@ -259,7 +282,18 @@ export const RichTargetUrlSchema = z
|
|
|
259
282
|
export const MessagePartSchema = z.discriminatedUnion('type', [
|
|
260
283
|
z.object({ type: z.literal('text'), text: z.string() }).strict(),
|
|
261
284
|
z.object({ type: z.literal('mention'), memberId: ChannelMemberIdSchema }).strict(),
|
|
262
|
-
z
|
|
285
|
+
z
|
|
286
|
+
.object({
|
|
287
|
+
type: z.literal('image'),
|
|
288
|
+
assetId: AssetIdSchema,
|
|
289
|
+
alt: z.string().optional(),
|
|
290
|
+
/**
|
|
291
|
+
* The platform reported the picture as a sticker. A hint only: a sticker dragged in from a desktop client and
|
|
292
|
+
* pictures from platforms without this signal arrive unmarked.
|
|
293
|
+
*/
|
|
294
|
+
sticker: z.literal(true).optional(),
|
|
295
|
+
})
|
|
296
|
+
.strict(),
|
|
263
297
|
z.object({ type: z.literal('file'), assetId: AssetIdSchema, name: z.string().optional() }).strict(),
|
|
264
298
|
z.object({ type: z.literal('audio'), assetId: AssetIdSchema }).strict(),
|
|
265
299
|
z.object({ type: z.literal('quote'), messageId: LogicalMessageIdSchema }).strict(),
|
|
@@ -287,19 +321,24 @@ export function parseMessageParts(input: unknown): MessagePart[] {
|
|
|
287
321
|
return MessagePartsSchema.parse(input)
|
|
288
322
|
}
|
|
289
323
|
|
|
290
|
-
const collectRichAssetIds = (value: JsonValue | undefined, into: AssetId[]): void => {
|
|
324
|
+
const collectRichAssetIds = (value: JsonValue | undefined, into: AssetId[], imagesOnly = false): void => {
|
|
291
325
|
if (value === null || value === undefined || typeof value === 'boolean' || typeof value === 'number') return
|
|
292
326
|
if (typeof value === 'string') return
|
|
293
327
|
if (Array.isArray(value)) {
|
|
294
|
-
for (const item of value) collectRichAssetIds(item, into)
|
|
328
|
+
for (const item of value) collectRichAssetIds(item, into, imagesOnly)
|
|
295
329
|
return
|
|
296
330
|
}
|
|
297
331
|
for (const [key, child] of Object.entries(value)) {
|
|
298
|
-
if (
|
|
332
|
+
if (
|
|
333
|
+
(key === 'imageAssetId' ||
|
|
334
|
+
key === 'previewAssetId' ||
|
|
335
|
+
(!imagesOnly && (key === 'audioAssetId' || key === 'fileAssetId'))) &&
|
|
336
|
+
typeof child === 'string'
|
|
337
|
+
) {
|
|
299
338
|
const parsed = AssetIdSchema.safeParse(child)
|
|
300
339
|
if (parsed.success) into.push(parsed.data)
|
|
301
340
|
} else {
|
|
302
|
-
collectRichAssetIds(child, into)
|
|
341
|
+
collectRichAssetIds(child, into, imagesOnly)
|
|
303
342
|
}
|
|
304
343
|
}
|
|
305
344
|
}
|
|
@@ -315,6 +354,15 @@ export const messagePartAssetIds = (part: MessagePart): readonly AssetId[] => {
|
|
|
315
354
|
|
|
316
355
|
export const messagePartAssetId = (part: MessagePart): AssetId | undefined => messagePartAssetIds(part)[0]
|
|
317
356
|
|
|
357
|
+
/** Only actual pictures enter visual context; forwarded files and recordings retain their own media kind. */
|
|
358
|
+
export const messagePartImageAssetIds = (part: MessagePart): readonly AssetId[] => {
|
|
359
|
+
if (part.type === 'image') return [part.assetId]
|
|
360
|
+
if (part.type !== 'rich') return []
|
|
361
|
+
const ids: AssetId[] = part.previewAssetId ? [part.previewAssetId] : []
|
|
362
|
+
collectRichAssetIds(part.extension, ids, true)
|
|
363
|
+
return ids
|
|
364
|
+
}
|
|
365
|
+
|
|
318
366
|
const asJsonRecord = (value: JsonValue | undefined): Readonly<Record<string, JsonValue>> | undefined =>
|
|
319
367
|
value !== null && typeof value === 'object' && !Array.isArray(value) ? value : undefined
|
|
320
368
|
|
|
@@ -332,7 +380,12 @@ const richItemLine = (value: JsonValue): string | undefined => {
|
|
|
332
380
|
: undefined
|
|
333
381
|
const imageName = typeof item['imageName'] === 'string' ? item['imageName'] : undefined
|
|
334
382
|
const imageText = typeof item['imageAssetId'] === 'string' ? `[图片${imageName ? ` ${imageName}` : ''}]` : undefined
|
|
335
|
-
const
|
|
383
|
+
const audioText = typeof item['audioAssetId'] === 'string' ? `[语音 ${item['audioAssetId']}]` : undefined
|
|
384
|
+
const fileText =
|
|
385
|
+
typeof item['fileAssetId'] === 'string'
|
|
386
|
+
? `[${typeof item['fileMediaType'] === 'string' && item['fileMediaType'].startsWith('video/') ? '视频' : '文件'} ${item['fileAssetId']}${typeof item['fileName'] === 'string' ? `:${item['fileName']}` : ''}]`
|
|
387
|
+
: undefined
|
|
388
|
+
const body = [text, cardSummary ? `[卡片] ${cardSummary}` : undefined, imageText, audioText, fileText]
|
|
336
389
|
.filter((part): part is string => Boolean(part && part.length > 0))
|
|
337
390
|
.join(' ')
|
|
338
391
|
if (!sender && !body) return undefined
|