@undefineds.co/models 0.2.25 → 0.2.27

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.
Files changed (42) hide show
  1. package/dist/approval.schema.d.ts +4 -0
  2. package/dist/approval.schema.js +6 -1
  3. package/dist/audit.presentation.d.ts +1 -1
  4. package/dist/audit.presentation.js +19 -12
  5. package/dist/audit.schema.d.ts +4 -0
  6. package/dist/audit.schema.js +6 -1
  7. package/dist/bin/udfs.d.ts +2 -0
  8. package/dist/bin/udfs.js +430 -0
  9. package/dist/chat.repository.d.ts +8 -0
  10. package/dist/chat.schema.d.ts +10 -0
  11. package/dist/chat.schema.js +9 -2
  12. package/dist/chat.utils.js +24 -9
  13. package/dist/index.d.ts +9 -3
  14. package/dist/index.js +10 -3
  15. package/dist/issue.repository.d.ts +69 -0
  16. package/dist/issue.repository.js +8 -0
  17. package/dist/issue.schema.d.ts +48 -0
  18. package/dist/issue.schema.js +37 -0
  19. package/dist/message.repository.d.ts +29 -9
  20. package/dist/message.schema.d.ts +29 -6
  21. package/dist/message.schema.js +26 -10
  22. package/dist/namespaces.js +29 -0
  23. package/dist/pod-storage-descriptor.d.ts +189 -0
  24. package/dist/pod-storage-descriptor.js +283 -0
  25. package/dist/repository.d.ts +2 -0
  26. package/dist/repository.js +3 -0
  27. package/dist/resource-id-defaults.d.ts +18 -0
  28. package/dist/resource-id-defaults.js +84 -0
  29. package/dist/run.schema.d.ts +112 -0
  30. package/dist/run.schema.js +89 -0
  31. package/dist/schema.d.ts +176 -8
  32. package/dist/schema.js +11 -0
  33. package/dist/session/session.schema.js +2 -1
  34. package/dist/sidecar/persistence-mapping.d.ts +3 -3
  35. package/dist/sidecar/sidecar-events.d.ts +45 -45
  36. package/dist/sidecar/sidecar-events.js +1 -1
  37. package/dist/task.schema.d.ts +62 -0
  38. package/dist/task.schema.js +49 -0
  39. package/dist/thread.repository.d.ts +15 -3
  40. package/dist/thread.schema.d.ts +14 -2
  41. package/dist/thread.schema.js +13 -5
  42. package/package.json +11 -3
@@ -3,6 +3,8 @@ export declare function extractApprovalIdFromApprovalRef(approvalRef: string | n
3
3
  export declare const approvalResource: import("@undefineds.co/drizzle-solid/dist/core/schema").PodTableWithColumns<import("@undefineds.co/drizzle-solid/dist/core/schema").ResolvedColumns<{
4
4
  id: import("@undefineds.co/drizzle-solid/dist/core/schema").PodStringColumn<false, false>;
5
5
  session: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"uri", null, true, false>;
6
+ chat: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"uri", null, false, false>;
7
+ thread: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"uri", null, false, false>;
6
8
  toolCallId: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"string", null, true, false>;
7
9
  toolName: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"string", null, true, false>;
8
10
  target: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"uri", null, true, false>;
@@ -24,6 +26,8 @@ export declare const approvalResource: import("@undefineds.co/drizzle-solid/dist
24
26
  export declare const approvalTable: import("@undefineds.co/drizzle-solid/dist/core/schema").PodTableWithColumns<import("@undefineds.co/drizzle-solid/dist/core/schema").ResolvedColumns<{
25
27
  id: import("@undefineds.co/drizzle-solid/dist/core/schema").PodStringColumn<false, false>;
26
28
  session: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"uri", null, true, false>;
29
+ chat: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"uri", null, false, false>;
30
+ thread: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"uri", null, false, false>;
27
31
  toolCallId: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"string", null, true, false>;
28
32
  toolName: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"string", null, true, false>;
29
33
  target: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"uri", null, true, false>;
@@ -1,5 +1,8 @@
1
1
  import { extractPodResourceTemplateValue, podTable, uri, string, text, timestamp, id } from '@undefineds.co/drizzle-solid';
2
2
  import { ODRL, UDFS, DCTerms } from './namespaces.js';
3
+ import { chatResource } from './chat.schema.js';
4
+ import { threadResource } from './thread.schema.js';
5
+ import { asPodResourceTemplateTarget } from './repository.js';
3
6
  export function buildApprovalSubjectPath(approvalId, createdAt = new Date()) {
4
7
  const date = createdAt instanceof Date ? createdAt : new Date(createdAt);
5
8
  const safeDate = Number.isFinite(date.getTime()) ? date : new Date();
@@ -12,13 +15,15 @@ export function extractApprovalIdFromApprovalRef(approvalRef) {
12
15
  if (approvalRef && !/[/:#]/.test(approvalRef)) {
13
16
  return approvalRef;
14
17
  }
15
- return extractPodResourceTemplateValue(approvalResource, approvalRef);
18
+ return extractPodResourceTemplateValue(asPodResourceTemplateTarget(approvalResource), approvalRef);
16
19
  }
17
20
  // Approval request resource (separate from Solid inbox notifications).
18
21
  export const approvalResource = podTable('approval', {
19
22
  id: id('id'),
20
23
  // Relations
21
24
  session: uri('session').predicate(UDFS.session).notNull(),
25
+ chat: uri('chat').predicate(UDFS.conversation).link(chatResource),
26
+ thread: uri('thread').predicate(UDFS.inThread).link(threadResource),
22
27
  toolCallId: string('toolCallId').predicate(UDFS.toolCallId).notNull(),
23
28
  // Request details
24
29
  toolName: string('toolName').predicate(UDFS.toolName).notNull(),
@@ -14,7 +14,7 @@ export interface AuditPresentation {
14
14
  authMessage: string | null;
15
15
  actorRoleLabel: string;
16
16
  }
17
- type RelatedApproval = Pick<ApprovalRow, 'target' | 'toolName' | 'risk' | 'reason' | 'status' | 'context'> | null | undefined;
17
+ type RelatedApproval = Pick<ApprovalRow, 'chat' | 'thread' | 'target' | 'toolName' | 'risk' | 'reason' | 'status' | 'context'> | null | undefined;
18
18
  export declare function buildAuditDetailRecord(audit: AuditRow, relatedApproval?: RelatedApproval): Record<string, unknown>;
19
19
  export declare function formatInboxStatusLabel(status?: string | null): string | null;
20
20
  export declare function formatAuditActorRole(role?: string | null): string;
@@ -33,6 +33,8 @@ export function buildAuditDetailRecord(audit, relatedApproval) {
33
33
  actorRole: audit.actorRole,
34
34
  onBehalfOf: audit.onBehalfOf || undefined,
35
35
  session: audit.session || undefined,
36
+ chat: audit.chat || undefined,
37
+ thread: audit.thread || undefined,
36
38
  entry: audit.entry || undefined,
37
39
  toolCallId: audit.toolCallId || undefined,
38
40
  toolName: audit.toolName || undefined,
@@ -42,6 +44,8 @@ export function buildAuditDetailRecord(audit, relatedApproval) {
42
44
  createdAt: audit.createdAt,
43
45
  relatedApproval: relatedApproval
44
46
  ? {
47
+ chat: relatedApproval.chat || undefined,
48
+ thread: relatedApproval.thread || undefined,
45
49
  target: relatedApproval.target,
46
50
  toolName: relatedApproval.toolName,
47
51
  risk: relatedApproval.risk,
@@ -102,9 +106,12 @@ export function createResolvedAuthTimestampsIndex(audits) {
102
106
  return resolvedAuthTimestampsByKey;
103
107
  }
104
108
  export function buildAuditPresentation(audit, resolvedAuthTimestampsByKey, relatedApproval) {
105
- const thread = audit.entry || relatedApproval?.target || null;
106
- const about = relatedApproval?.target ?? audit.entry ?? audit.approval ?? null;
109
+ const thread = audit.thread || relatedApproval?.thread || audit.entry || relatedApproval?.target || null;
110
+ const chat = audit.chat || relatedApproval?.chat || null;
111
+ const about = relatedApproval?.target ?? audit.entry ?? audit.approval ?? thread ?? null;
107
112
  const { chatId, threadId } = extractChatThreadRef(thread);
113
+ const chatRef = extractChatThreadRef(chat);
114
+ const resolvedChatId = chatId ?? chatRef.chatId;
108
115
  const actorRoleLabel = formatAuditActorRole(audit.actorRole);
109
116
  if (audit.action === 'runtime.auth_required') {
110
117
  const method = audit.toolName || null;
@@ -117,7 +124,7 @@ export function buildAuditPresentation(audit, resolvedAuthTimestampsByKey, relat
117
124
  description: method ? `运行时需要完成 ${method} 认证后才能继续。` : '运行时需要额外认证后才能继续。',
118
125
  category: 'auth_required',
119
126
  status: isResolved ? 'resolved' : 'pending',
120
- chatId,
127
+ chatId: resolvedChatId,
121
128
  threadId,
122
129
  thread,
123
130
  about,
@@ -134,7 +141,7 @@ export function buildAuditPresentation(audit, resolvedAuthTimestampsByKey, relat
134
141
  description: '运行时认证已完成。',
135
142
  category: 'audit',
136
143
  status: 'resolved',
137
- chatId,
144
+ chatId: resolvedChatId,
138
145
  threadId,
139
146
  thread,
140
147
  about,
@@ -152,7 +159,7 @@ export function buildAuditPresentation(audit, resolvedAuthTimestampsByKey, relat
152
159
  description: [risk, '已进入审批队列'].filter(Boolean).join(' · ') || '工具调用已进入审批队列。',
153
160
  category: 'audit',
154
161
  status: undefined,
155
- chatId,
162
+ chatId: resolvedChatId,
156
163
  threadId,
157
164
  thread,
158
165
  about,
@@ -168,7 +175,7 @@ export function buildAuditPresentation(audit, resolvedAuthTimestampsByKey, relat
168
175
  description: buildApprovalDecisionDescription(audit, relatedApproval, 'approved'),
169
176
  category: 'audit',
170
177
  status: 'approved',
171
- chatId,
178
+ chatId: resolvedChatId,
172
179
  threadId,
173
180
  thread,
174
181
  about,
@@ -184,7 +191,7 @@ export function buildAuditPresentation(audit, resolvedAuthTimestampsByKey, relat
184
191
  description: buildApprovalDecisionDescription(audit, relatedApproval, 'rejected'),
185
192
  category: 'audit',
186
193
  status: 'rejected',
187
- chatId,
194
+ chatId: resolvedChatId,
188
195
  threadId,
189
196
  thread,
190
197
  about,
@@ -200,7 +207,7 @@ export function buildAuditPresentation(audit, resolvedAuthTimestampsByKey, relat
200
207
  description: buildRuntimeSessionDescription(audit, '运行时会话开始执行。'),
201
208
  category: 'audit',
202
209
  status: 'active',
203
- chatId,
210
+ chatId: resolvedChatId,
204
211
  threadId,
205
212
  thread,
206
213
  about,
@@ -216,7 +223,7 @@ export function buildAuditPresentation(audit, resolvedAuthTimestampsByKey, relat
216
223
  description: buildRuntimeSessionDescription(audit, '运行时会话已暂停。'),
217
224
  category: 'audit',
218
225
  status: 'paused',
219
- chatId,
226
+ chatId: resolvedChatId,
220
227
  threadId,
221
228
  thread,
222
229
  about,
@@ -232,7 +239,7 @@ export function buildAuditPresentation(audit, resolvedAuthTimestampsByKey, relat
232
239
  description: buildRuntimeSessionDescription(audit, '运行时会话已完成。'),
233
240
  category: 'audit',
234
241
  status: 'completed',
235
- chatId,
242
+ chatId: resolvedChatId,
236
243
  threadId,
237
244
  thread,
238
245
  about,
@@ -248,7 +255,7 @@ export function buildAuditPresentation(audit, resolvedAuthTimestampsByKey, relat
248
255
  description: buildRuntimeSessionDescription(audit, '运行时会话执行失败。'),
249
256
  category: 'audit',
250
257
  status: 'error',
251
- chatId,
258
+ chatId: resolvedChatId,
252
259
  threadId,
253
260
  thread,
254
261
  about,
@@ -263,7 +270,7 @@ export function buildAuditPresentation(audit, resolvedAuthTimestampsByKey, relat
263
270
  description: actorRoleLabel,
264
271
  category: 'audit',
265
272
  status: undefined,
266
- chatId,
273
+ chatId: resolvedChatId,
267
274
  threadId,
268
275
  thread,
269
276
  about,
@@ -6,6 +6,8 @@ export declare const auditResource: import("@undefineds.co/drizzle-solid/dist/co
6
6
  actorRole: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"string", null, true, false>;
7
7
  onBehalfOf: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"uri", null, false, false>;
8
8
  session: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"uri", null, false, false>;
9
+ chat: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"uri", null, false, false>;
10
+ thread: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"uri", null, false, false>;
9
11
  entry: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"uri", null, false, false>;
10
12
  toolCallId: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"string", null, false, false>;
11
13
  toolName: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"string", null, false, false>;
@@ -22,6 +24,8 @@ export declare const auditTable: import("@undefineds.co/drizzle-solid/dist/core/
22
24
  actorRole: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"string", null, true, false>;
23
25
  onBehalfOf: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"uri", null, false, false>;
24
26
  session: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"uri", null, false, false>;
27
+ chat: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"uri", null, false, false>;
28
+ thread: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"uri", null, false, false>;
25
29
  entry: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"uri", null, false, false>;
26
30
  toolCallId: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"string", null, false, false>;
27
31
  toolName: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"string", null, false, false>;
@@ -1,5 +1,8 @@
1
1
  import { extractPodResourceTemplateValue, podTable, uri, string, timestamp, id } from '@undefineds.co/drizzle-solid';
2
2
  import { UDFS, DCTerms } from './namespaces.js';
3
+ import { chatResource } from './chat.schema.js';
4
+ import { threadResource } from './thread.schema.js';
5
+ import { asPodResourceTemplateTarget } from './repository.js';
3
6
  export function buildAuditSubjectPath(auditId, createdAt = new Date()) {
4
7
  const date = createdAt instanceof Date ? createdAt : new Date(createdAt);
5
8
  const safeDate = Number.isFinite(date.getTime()) ? date : new Date();
@@ -21,6 +24,8 @@ export const auditResource = podTable('audit', {
21
24
  onBehalfOf: uri('onBehalfOf').predicate(UDFS.onBehalfOf),
22
25
  // Relations
23
26
  session: uri('session').predicate(UDFS.session),
27
+ chat: uri('chat').predicate(UDFS.conversation).link(chatResource),
28
+ thread: uri('thread').predicate(UDFS.inThread).link(threadResource),
24
29
  entry: uri('entry').predicate(UDFS.entry),
25
30
  toolCallId: string('toolCallId').predicate(UDFS.toolCallId),
26
31
  toolName: string('toolName').predicate(UDFS.toolName),
@@ -41,7 +46,7 @@ export function extractAuditIdFromAuditRef(auditRef) {
41
46
  if (auditRef && !/[/:#]/.test(auditRef)) {
42
47
  return auditRef;
43
48
  }
44
- return extractPodResourceTemplateValue(auditResource, auditRef);
49
+ return extractPodResourceTemplateValue(asPodResourceTemplateTarget(auditResource), auditRef);
45
50
  }
46
51
  // Compatibility alias. New model code should prefer `auditResource`.
47
52
  export const auditTable = auditResource;
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,430 @@
1
+ #!/usr/bin/env node
2
+ import { createPodStorage, podSchema, XPOD_CREDENTIAL, } from '../index.js';
3
+ async function main(argv) {
4
+ const [area, action, ...rest] = argv;
5
+ if (!area || area === 'help' || area === '--help' || area === '-h') {
6
+ printHelp();
7
+ return;
8
+ }
9
+ if (area === 'schema') {
10
+ handleSchema(action, rest);
11
+ return;
12
+ }
13
+ if (area === 'storage') {
14
+ handleStorage(action, rest);
15
+ return;
16
+ }
17
+ if (area === 'consensus') {
18
+ await handleConsensus(action, rest);
19
+ return;
20
+ }
21
+ throw new Error(`Unknown udfs command: ${area}`);
22
+ }
23
+ function handleSchema(action, args) {
24
+ if (action === 'list') {
25
+ writeJson(podSchema.list());
26
+ return;
27
+ }
28
+ if (action === 'describe') {
29
+ const uri = args[0];
30
+ if (!uri)
31
+ throw new Error('Usage: udfs schema describe <uri>');
32
+ const descriptor = podSchema.describe({ uri });
33
+ if (!descriptor)
34
+ throw new Error(`Descriptor not found: ${uri}`);
35
+ writeJson(descriptor);
36
+ return;
37
+ }
38
+ if (action === 'classes') {
39
+ writeJson(podSchema.classes({
40
+ uri: readOption(args, '--uri'),
41
+ }));
42
+ return;
43
+ }
44
+ if (action === 'search') {
45
+ const query = readOption(args, '--query') ?? args[0];
46
+ if (!query)
47
+ throw new Error('Usage: udfs schema search --query <text>');
48
+ writeJson(podSchema.search({
49
+ query,
50
+ source: readOption(args, '--source'),
51
+ resourceKind: readOption(args, '--resource-kind'),
52
+ limit: readNumberOption(args, '--limit'),
53
+ }));
54
+ return;
55
+ }
56
+ if (action === 'predicates') {
57
+ writeJson(podSchema.predicates({
58
+ uri: readOption(args, '--uri'),
59
+ field: readOption(args, '--field'),
60
+ }));
61
+ return;
62
+ }
63
+ throw new Error(`Unknown schema command: ${action ?? '(missing)'}`);
64
+ }
65
+ function handleStorage(action, args) {
66
+ if (action === 'validate') {
67
+ const input = readInputPayload(args, 'udfs storage validate --input \'<mutation-json>\'');
68
+ writeJson(createPodStorage().validate(input));
69
+ return;
70
+ }
71
+ throw new Error(`Unknown storage command: ${action ?? '(missing)'}`);
72
+ }
73
+ async function handleConsensus(action, args) {
74
+ if (!action || action === '--help' || action === '-h') {
75
+ printConsensusHelp();
76
+ return;
77
+ }
78
+ const allArgs = [action, ...args];
79
+ const input = readConsensusInput(allArgs);
80
+ const result = await resolveConsensusRequest({
81
+ sessionId: input.session_id,
82
+ request: input.request,
83
+ tokenType: input.answers?.token_type ?? 'tunnel-token',
84
+ conversation: input.conversation_id ?? process.env.UDFS_CONSENSUS_CONVERSATION_ID,
85
+ });
86
+ if (allArgs.includes('--json')) {
87
+ writeJson(result);
88
+ return;
89
+ }
90
+ process.stdout.write(`Consensus: ${input.request}\n`);
91
+ if (result.session_id) {
92
+ process.stdout.write(`Session: ${result.session_id}\n`);
93
+ }
94
+ process.stdout.write(`Consensus runtime: ${result.consensusRuntime.mode}${result.consensusRuntime.mode === 'remote' ? ` (${result.consensusRuntime.baseUrl})` : ''}\n`);
95
+ if (result.consensusResponse?.conversationId) {
96
+ process.stdout.write(`Conversation: ${result.consensusResponse.conversationId}\n`);
97
+ }
98
+ process.stdout.write(`Clarification: ${result.first.questions[0].question}\n`);
99
+ process.stdout.write(`Answer: ${input.answers?.token_type ?? 'tunnel-token'}\n`);
100
+ process.stdout.write(`Schema: ${result.resolved.schemaUri}\n`);
101
+ process.stdout.write(`Descriptor storage: ${result.descriptor.storage.base}${result.descriptor.storage.resourceIdPattern}\n`);
102
+ }
103
+ function resolveConsensusRuntime() {
104
+ const baseUrl = process.env.UDFS_CONSENSUS_BASE_URL;
105
+ const token = process.env.UDFS_CONSENSUS_TOKEN;
106
+ if (baseUrl && token) {
107
+ return {
108
+ mode: 'remote',
109
+ baseUrl,
110
+ auth: 'runtime-token',
111
+ };
112
+ }
113
+ return {
114
+ mode: 'local-fallback',
115
+ auth: 'none',
116
+ };
117
+ }
118
+ async function resolveConsensusRequest(input) {
119
+ const runtime = resolveConsensusRuntime();
120
+ if (runtime.mode === 'remote') {
121
+ const remote = await callRemoteConsensus({
122
+ runtime,
123
+ sessionId: input.sessionId,
124
+ request: input.request,
125
+ conversation: input.conversation,
126
+ });
127
+ const parsed = parseRemoteConsensusPayload(remote.body);
128
+ const resolved = coerceResolvedConsensusPayload(parsed);
129
+ if (!resolved) {
130
+ throw new Error('Remote Consensus response did not contain a resolved schema payload');
131
+ }
132
+ return buildConsensusResult({
133
+ runtime,
134
+ sessionId: input.sessionId,
135
+ tokenType: input.tokenType,
136
+ fieldMapping: resolved.fieldMapping,
137
+ confidence: resolved.confidence,
138
+ response: {
139
+ id: remote.id,
140
+ conversationId: remote.conversationId,
141
+ parsed,
142
+ },
143
+ });
144
+ }
145
+ return buildConsensusResult({
146
+ runtime,
147
+ sessionId: input.sessionId,
148
+ tokenType: input.tokenType,
149
+ });
150
+ }
151
+ async function callRemoteConsensus(input) {
152
+ const token = process.env.UDFS_CONSENSUS_TOKEN;
153
+ if (!token) {
154
+ throw new Error('Remote Consensus requires injected UDFS_CONSENSUS_TOKEN');
155
+ }
156
+ const body = {
157
+ model: process.env.UDFS_CONSENSUS_MODEL ?? 'consensus-modeling',
158
+ input: [
159
+ {
160
+ role: 'user',
161
+ content: [
162
+ {
163
+ type: 'input_text',
164
+ text: input.request,
165
+ },
166
+ ],
167
+ },
168
+ ],
169
+ metadata: {
170
+ product: 'linx',
171
+ purpose: 'pod-storage',
172
+ ...(input.sessionId ? { session_id: input.sessionId } : {}),
173
+ },
174
+ };
175
+ if (input.conversation) {
176
+ body.conversation = input.conversation;
177
+ }
178
+ const response = await fetch(`${input.runtime.baseUrl.replace(/\/+$/u, '')}/responses`, {
179
+ method: 'POST',
180
+ headers: {
181
+ authorization: `Bearer ${token}`,
182
+ 'content-type': 'application/json',
183
+ },
184
+ body: JSON.stringify(body),
185
+ });
186
+ const text = await response.text();
187
+ const parsedBody = text ? JSON.parse(text) : {};
188
+ if (!response.ok) {
189
+ throw new Error(`Remote Consensus request failed: ${response.status} ${text}`);
190
+ }
191
+ return {
192
+ id: typeof parsedBody.id === 'string' ? parsedBody.id : undefined,
193
+ conversationId: extractConversationId(parsedBody),
194
+ body: parsedBody,
195
+ };
196
+ }
197
+ function extractConversationId(body) {
198
+ if (typeof body.conversation === 'string')
199
+ return body.conversation;
200
+ if (body.conversation
201
+ && typeof body.conversation === 'object'
202
+ && 'id' in body.conversation
203
+ && typeof body.conversation.id === 'string') {
204
+ return body.conversation.id;
205
+ }
206
+ return undefined;
207
+ }
208
+ function parseRemoteConsensusPayload(body) {
209
+ if (isRecord(body) && typeof body.status === 'string') {
210
+ return body;
211
+ }
212
+ if (isRecord(body) && typeof body.output_text === 'string') {
213
+ return parseJsonMaybe(body.output_text);
214
+ }
215
+ if (isRecord(body) && Array.isArray(body.output)) {
216
+ for (const item of body.output) {
217
+ if (!isRecord(item) || !Array.isArray(item.content))
218
+ continue;
219
+ for (const content of item.content) {
220
+ if (!isRecord(content))
221
+ continue;
222
+ const text = typeof content.text === 'string'
223
+ ? content.text
224
+ : typeof content.output_text === 'string'
225
+ ? content.output_text
226
+ : undefined;
227
+ if (!text)
228
+ continue;
229
+ const parsed = parseJsonMaybe(text);
230
+ if (parsed)
231
+ return parsed;
232
+ }
233
+ }
234
+ }
235
+ if (isRecord(body) && Array.isArray(body.choices)) {
236
+ for (const choice of body.choices) {
237
+ if (!isRecord(choice) || !isRecord(choice.message))
238
+ continue;
239
+ if (typeof choice.message.content !== 'string')
240
+ continue;
241
+ const parsed = parseJsonMaybe(choice.message.content);
242
+ if (parsed)
243
+ return parsed;
244
+ }
245
+ }
246
+ return undefined;
247
+ }
248
+ function coerceResolvedConsensusPayload(payload) {
249
+ if (!isRecord(payload) || payload.status !== 'resolved')
250
+ return null;
251
+ const schemaUri = stringField(payload, 'schemaUri') ?? stringField(payload, 'uri');
252
+ if (schemaUri !== XPOD_CREDENTIAL.Credential)
253
+ return null;
254
+ if (!isRecord(payload.fieldMapping))
255
+ return null;
256
+ const service = stringField(payload.fieldMapping, 'service');
257
+ const providerId = stringField(payload.fieldMapping, 'providerId');
258
+ const secretType = stringField(payload.fieldMapping, 'secretType');
259
+ if (!service || !providerId || !secretType)
260
+ return null;
261
+ return {
262
+ fieldMapping: {
263
+ service,
264
+ providerId,
265
+ secretType,
266
+ label: stringField(payload.fieldMapping, 'label'),
267
+ status: stringField(payload.fieldMapping, 'status'),
268
+ },
269
+ confidence: typeof payload.confidence === 'number' ? payload.confidence : undefined,
270
+ };
271
+ }
272
+ function parseJsonMaybe(text) {
273
+ try {
274
+ return JSON.parse(text);
275
+ }
276
+ catch {
277
+ return undefined;
278
+ }
279
+ }
280
+ function isRecord(value) {
281
+ return typeof value === 'object' && value !== null;
282
+ }
283
+ function stringField(record, field) {
284
+ const value = record[field];
285
+ return typeof value === 'string' && value.trim() ? value : undefined;
286
+ }
287
+ function buildConsensusResult(input) {
288
+ const first = {
289
+ status: 'needs_clarification',
290
+ questions: [
291
+ {
292
+ id: 'token_type',
293
+ question: '这是 Cloudflare API Token 还是 Tunnel Token?',
294
+ options: ['tunnel-token', 'api-token'],
295
+ },
296
+ ],
297
+ };
298
+ const resolved = {
299
+ status: 'resolved',
300
+ schemaUri: XPOD_CREDENTIAL.Credential,
301
+ fieldMapping: {
302
+ service: input.fieldMapping?.service ?? 'infra',
303
+ providerId: input.fieldMapping?.providerId ?? 'cloudflare',
304
+ secretType: input.fieldMapping?.secretType ?? input.tokenType,
305
+ label: input.fieldMapping?.label
306
+ ?? defaultCredentialLabel(input.fieldMapping?.providerId ?? 'cloudflare', input.fieldMapping?.secretType ?? input.tokenType),
307
+ status: input.fieldMapping?.status ?? 'active',
308
+ },
309
+ confidence: input.confidence ?? (input.tokenType === 'tunnel-token' ? 0.96 : 0.94),
310
+ };
311
+ const descriptor = podSchema.describe({ uri: resolved.schemaUri });
312
+ if (!descriptor) {
313
+ throw new Error(`Descriptor not found: ${resolved.schemaUri}`);
314
+ }
315
+ return {
316
+ session_id: input.sessionId,
317
+ consensusRuntime: input.runtime,
318
+ consensusResponse: input.response,
319
+ first,
320
+ resolved,
321
+ descriptor: {
322
+ uri: descriptor.uri,
323
+ storage: descriptor.storage,
324
+ },
325
+ };
326
+ }
327
+ function readOption(args, name) {
328
+ const index = args.indexOf(name);
329
+ if (index === -1)
330
+ return undefined;
331
+ const value = args[index + 1];
332
+ return value && !value.startsWith('--') ? value : undefined;
333
+ }
334
+ function readNumberOption(args, name) {
335
+ const value = readOption(args, name);
336
+ if (!value)
337
+ return undefined;
338
+ const parsed = Number(value);
339
+ if (!Number.isFinite(parsed) || parsed <= 0) {
340
+ throw new Error(`${name} must be a positive number`);
341
+ }
342
+ return Math.floor(parsed);
343
+ }
344
+ function readConsensusInput(args) {
345
+ if (args[0] === 'model') {
346
+ throw new Error('Use: udfs consensus --input \'<json>\'');
347
+ }
348
+ const parsed = readInputPayload(args, 'udfs consensus --input \'<json>\' --json');
349
+ if (!isRecord(parsed)) {
350
+ throw new Error('Consensus input must be a JSON object');
351
+ }
352
+ const request = stringField(parsed, 'request')
353
+ ?? stringField(parsed, 'message')
354
+ ?? stringField(parsed, 'text');
355
+ if (!request) {
356
+ throw new Error('Consensus input requires a non-empty request field');
357
+ }
358
+ const answers = isRecord(parsed.answers) ? parsed.answers : {};
359
+ const tokenTypeText = stringField(answers, 'token_type') ?? stringField(parsed, 'token_type');
360
+ const tokenType = coerceTokenType(tokenTypeText);
361
+ if (tokenTypeText && !tokenType) {
362
+ throw new Error(`Unsupported token type: ${tokenTypeText}`);
363
+ }
364
+ return {
365
+ session_id: stringField(parsed, 'session_id'),
366
+ request,
367
+ answers: tokenType ? { token_type: tokenType } : undefined,
368
+ conversation_id: stringField(parsed, 'conversation_id') ?? stringField(parsed, 'conversation'),
369
+ };
370
+ }
371
+ function coerceTokenType(value) {
372
+ if (value === 'tunnel-token' || value === 'api-token') {
373
+ return value;
374
+ }
375
+ return undefined;
376
+ }
377
+ function defaultCredentialLabel(providerId, secretType) {
378
+ const providerLabel = providerId
379
+ .split(/[-_.]/g)
380
+ .filter(Boolean)
381
+ .map((part) => `${part.slice(0, 1).toUpperCase()}${part.slice(1)}`)
382
+ .join(' ');
383
+ const secretLabel = secretType
384
+ .split(/[-_.]/g)
385
+ .filter(Boolean)
386
+ .map((part) => part.toLowerCase() === 'api' ? 'API' : `${part.slice(0, 1).toUpperCase()}${part.slice(1)}`)
387
+ .join(' ');
388
+ return `${providerLabel} ${secretLabel}`;
389
+ }
390
+ function readInputPayload(args, usage) {
391
+ const raw = readOption(args, '--input');
392
+ if (!raw) {
393
+ throw new Error(`Usage: ${usage}`);
394
+ }
395
+ return JSON.parse(raw);
396
+ }
397
+ function writeJson(value) {
398
+ process.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
399
+ }
400
+ function printHelp() {
401
+ process.stdout.write(`udfs - Undefineds Pod data semantics tool
402
+
403
+ Usage:
404
+ udfs schema list
405
+ udfs schema search --query <text>
406
+ udfs schema describe <uri>
407
+ udfs schema classes [--uri <uri>]
408
+ udfs schema predicates [--uri <uri>] [--field <field>]
409
+ udfs consensus --input '{"session_id":"sess_123","request":"我要保存这个 Cloudflare token","answers":{"token_type":"tunnel-token"}}' --json
410
+ udfs storage validate --input '<mutation-json>'
411
+
412
+ Runtime:
413
+ Remote Consensus uses UDFS_CONSENSUS_BASE_URL plus UDFS_CONSENSUS_TOKEN when injected by LinX/linx-lite.
414
+ Do not pass user API keys on the command line.
415
+ `);
416
+ }
417
+ function printConsensusHelp() {
418
+ process.stdout.write(`udfs consensus - Ask Consensus how a storage request should be represented
419
+
420
+ Usage:
421
+ udfs consensus --input '{"session_id":"sess_123","request":"我要保存这个 Cloudflare token","answers":{"token_type":"tunnel-token"}}' --json
422
+
423
+ Runtime:
424
+ Remote Consensus uses UDFS_CONSENSUS_BASE_URL plus UDFS_CONSENSUS_TOKEN when injected by LinX/linx-lite.
425
+ `);
426
+ }
427
+ main(process.argv.slice(2)).catch((error) => {
428
+ process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
429
+ process.exitCode = 1;
430
+ });