@undefineds.co/models 0.2.26 → 0.2.28

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 CHANGED
@@ -31,6 +31,18 @@ import {
31
31
  } from '@undefineds.co/models'
32
32
  ```
33
33
 
34
+ ## Pi Package
35
+
36
+ `@undefineds.co/models` is also a Pi package. It exposes the shared
37
+ `solid-modeling` skill through the package manifest, so Pi users can install it
38
+ from npm or git:
39
+
40
+ ```bash
41
+ pi install npm:@undefineds.co/models
42
+ ```
43
+
44
+ After installation, Pi can load the skill from `skills/solid-modeling/SKILL.md`.
45
+
34
46
  ## Namespaces
35
47
 
36
48
  LinX-owned predicates and classes use the company namespace:
@@ -2,6 +2,7 @@ import { extractPodResourceTemplateValue, podTable, uri, string, text, timestamp
2
2
  import { ODRL, UDFS, DCTerms } from './namespaces.js';
3
3
  import { chatResource } from './chat.schema.js';
4
4
  import { threadResource } from './thread.schema.js';
5
+ import { asPodResourceTemplateTarget } from './repository.js';
5
6
  export function buildApprovalSubjectPath(approvalId, createdAt = new Date()) {
6
7
  const date = createdAt instanceof Date ? createdAt : new Date(createdAt);
7
8
  const safeDate = Number.isFinite(date.getTime()) ? date : new Date();
@@ -14,7 +15,7 @@ export function extractApprovalIdFromApprovalRef(approvalRef) {
14
15
  if (approvalRef && !/[/:#]/.test(approvalRef)) {
15
16
  return approvalRef;
16
17
  }
17
- return extractPodResourceTemplateValue(approvalResource, approvalRef);
18
+ return extractPodResourceTemplateValue(asPodResourceTemplateTarget(approvalResource), approvalRef);
18
19
  }
19
20
  // Approval request resource (separate from Solid inbox notifications).
20
21
  export const approvalResource = podTable('approval', {
@@ -2,6 +2,7 @@ import { extractPodResourceTemplateValue, podTable, uri, string, timestamp, id }
2
2
  import { UDFS, DCTerms } from './namespaces.js';
3
3
  import { chatResource } from './chat.schema.js';
4
4
  import { threadResource } from './thread.schema.js';
5
+ import { asPodResourceTemplateTarget } from './repository.js';
5
6
  export function buildAuditSubjectPath(auditId, createdAt = new Date()) {
6
7
  const date = createdAt instanceof Date ? createdAt : new Date(createdAt);
7
8
  const safeDate = Number.isFinite(date.getTime()) ? date : new Date();
@@ -45,7 +46,7 @@ export function extractAuditIdFromAuditRef(auditRef) {
45
46
  if (auditRef && !/[/:#]/.test(auditRef)) {
46
47
  return auditRef;
47
48
  }
48
- return extractPodResourceTemplateValue(auditResource, auditRef);
49
+ return extractPodResourceTemplateValue(asPodResourceTemplateTarget(auditResource), auditRef);
49
50
  }
50
51
  // Compatibility alias. New model code should prefer `auditResource`.
51
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
+ });
@@ -3,6 +3,8 @@ export declare const chatRepository: import("@undefineds.co/drizzle-solid/dist/c
3
3
  title: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"string", null, true, false>;
4
4
  description: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"string", null, false, false>;
5
5
  avatarUrl: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"uri", null, false, false>;
6
+ author: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"uri", null, false, false>;
7
+ status: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"string", null, true, true>;
6
8
  starred: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"boolean", null, false, true>;
7
9
  muted: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"boolean", null, false, true>;
8
10
  unreadCount: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"integer", null, false, true>;
@@ -19,6 +21,8 @@ export declare const chatRepository: import("@undefineds.co/drizzle-solid/dist/c
19
21
  title: string;
20
22
  description: string;
21
23
  avatarUrl: string;
24
+ author: string;
25
+ status: string;
22
26
  starred: boolean;
23
27
  muted: boolean;
24
28
  unreadCount: number;
@@ -35,6 +39,8 @@ export declare const chatRepository: import("@undefineds.co/drizzle-solid/dist/c
35
39
  id?: string | undefined;
36
40
  description?: string | undefined;
37
41
  avatarUrl?: string | undefined;
42
+ author?: string | undefined;
43
+ status?: string | undefined;
38
44
  starred?: boolean | undefined;
39
45
  muted?: boolean | undefined;
40
46
  unreadCount?: number | undefined;
@@ -51,6 +57,8 @@ export declare const chatRepository: import("@undefineds.co/drizzle-solid/dist/c
51
57
  title?: string | undefined;
52
58
  description?: string | null | undefined;
53
59
  avatarUrl?: string | null | undefined;
60
+ author?: string | null | undefined;
61
+ status?: string | undefined;
54
62
  starred?: boolean | null | undefined;
55
63
  muted?: boolean | null | undefined;
56
64
  unreadCount?: number | null | undefined;
@@ -1,4 +1,10 @@
1
1
  export type ChatMemberRole = 'owner' | 'admin' | 'member';
2
+ export type ChatStatusType = 'active' | 'archived' | 'deleted';
3
+ export declare const ChatStatus: {
4
+ readonly ACTIVE: "active";
5
+ readonly ARCHIVED: "archived";
6
+ readonly DELETED: "deleted";
7
+ };
2
8
  export interface ChatMetadata {
3
9
  memberRoles?: Record<string, ChatMemberRole>;
4
10
  }
@@ -24,6 +30,8 @@ export declare const chatResource: import("@undefineds.co/drizzle-solid/dist/cor
24
30
  title: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"string", null, true, false>;
25
31
  description: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"string", null, false, false>;
26
32
  avatarUrl: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"uri", null, false, false>;
33
+ author: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"uri", null, false, false>;
34
+ status: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"string", null, true, true>;
27
35
  starred: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"boolean", null, false, true>;
28
36
  muted: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"boolean", null, false, true>;
29
37
  unreadCount: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"integer", null, false, true>;
@@ -41,6 +49,8 @@ export declare const chatTable: import("@undefineds.co/drizzle-solid/dist/core/s
41
49
  title: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"string", null, true, false>;
42
50
  description: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"string", null, false, false>;
43
51
  avatarUrl: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"uri", null, false, false>;
52
+ author: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"uri", null, false, false>;
53
+ status: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"string", null, true, true>;
44
54
  starred: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"boolean", null, false, true>;
45
55
  muted: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"boolean", null, false, true>;
46
56
  unreadCount: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"integer", null, false, true>;
@@ -1,5 +1,11 @@
1
1
  import { boolean, object, podTable, string, text, timestamp, uri, id, integer } from '@undefineds.co/drizzle-solid';
2
2
  import { UDFS, DCTerms, SCHEMA, MEETING, WF } from './namespaces.js';
3
+ import { chatResourceId } from './resource-id-defaults.js';
4
+ export const ChatStatus = {
5
+ ACTIVE: 'active',
6
+ ARCHIVED: 'archived',
7
+ DELETED: 'deleted',
8
+ };
3
9
  /**
4
10
  * Chat resource.
5
11
  *
@@ -18,12 +24,14 @@ import { UDFS, DCTerms, SCHEMA, MEETING, WF } from './namespaces.js';
18
24
  * - Threads stored as fragments in same file: /.data/chat/{id}/index.ttl#{threadId}
19
25
  */
20
26
  export const chatResource = podTable('chats', {
21
- id: id('id'),
27
+ id: id('id').default(chatResourceId),
22
28
  // Display
23
29
  title: string('title').predicate(DCTerms.title).notNull(),
24
30
  description: string('description').predicate(DCTerms.description),
25
31
  avatarUrl: uri('avatarUrl').predicate(SCHEMA.image),
26
32
  // Chat state
33
+ author: uri('author').predicate(DCTerms.creator),
34
+ status: string('status').predicate(UDFS.status).notNull().default(ChatStatus.ACTIVE),
27
35
  starred: boolean('starred').predicate(UDFS.favorite).default(false),
28
36
  muted: boolean('muted').predicate(UDFS.muted).default(false),
29
37
  unreadCount: integer('unreadCount').predicate(UDFS.unreadCount).default(0),
@@ -49,7 +57,6 @@ export const chatResource = podTable('chats', {
49
57
  sparqlEndpoint: '/.data/chat/-/sparql',
50
58
  type: MEETING.LongChat,
51
59
  namespace: UDFS,
52
- subjectTemplate: '{id}/index.ttl#this',
53
60
  });
54
61
  // Compatibility alias. New model code should prefer `chatResource`.
55
62
  export const chatTable = chatResource;
@@ -1,6 +1,5 @@
1
- import { extractPodResourceTemplateValue, parsePodResourceRef } from '@undefineds.co/drizzle-solid';
2
- import { chatResource } from './chat.schema.js';
3
- import { threadResource } from './thread.schema.js';
1
+ import { parsePodResourceRef } from '@undefineds.co/drizzle-solid';
2
+ import { commandKindFromResourceId, surfaceIdFromCommandResourceId, } from './resource-id-defaults.js';
4
3
  export const toTimestamp = (value, fallback = 0) => {
5
4
  if (value instanceof Date)
6
5
  return value.getTime();
@@ -13,19 +12,35 @@ export const toTimestamp = (value, fallback = 0) => {
13
12
  return fallback;
14
13
  };
15
14
  export function extractChatIdFromChatRef(chatRef) {
16
- return extractPodResourceTemplateValue(threadResource, chatRef, 'chat')
17
- ?? extractPodResourceTemplateValue(chatResource, chatRef);
15
+ if (!chatRef)
16
+ return null;
17
+ const parsed = parsePodResourceRef({ config: { base: '/.data/chat/' } }, chatRef);
18
+ const resourceId = parsed?.resourceId ?? chatRef;
19
+ const direct = resourceId.match(/^([^/]+)\/index\.ttl#this$/);
20
+ if (direct)
21
+ return decodeURIComponent(direct[1]);
22
+ return surfaceIdFromCommandResourceId(resourceId);
18
23
  }
19
24
  export function extractThreadIdFromThreadRef(threadRef) {
20
- return extractPodResourceTemplateValue(threadResource, threadRef);
25
+ if (!threadRef)
26
+ return null;
27
+ const parsed = parsePodResourceRef({ config: { base: '/.data/' } }, threadRef);
28
+ const resourceId = parsed?.resourceId ?? threadRef;
29
+ const hashIndex = resourceId.lastIndexOf('#');
30
+ return hashIndex >= 0 && hashIndex < resourceId.length - 1
31
+ ? resourceId.slice(hashIndex + 1)
32
+ : resourceId;
21
33
  }
22
34
  export function extractChatThreadRef(uri) {
23
35
  if (!uri)
24
36
  return { chatId: null, threadId: null };
25
- const parsed = parsePodResourceRef(threadResource, uri);
37
+ const parsed = parsePodResourceRef({ config: { base: '/.data/' } }, uri);
38
+ const resourceId = parsed?.resourceId ?? uri;
26
39
  return {
27
- chatId: parsed?.templateValues.chat ?? null,
28
- threadId: parsed?.templateValues.id ?? null,
40
+ chatId: commandKindFromResourceId(resourceId) === 'chat'
41
+ ? surfaceIdFromCommandResourceId(resourceId)
42
+ : null,
43
+ threadId: extractThreadIdFromThreadRef(resourceId),
29
44
  };
30
45
  }
31
46
  export function resolveThreadChatId(thread) {
package/dist/index.d.ts CHANGED
@@ -5,13 +5,16 @@ export * from './profile.repository';
5
5
  export * from './profile.schema';
6
6
  export { ContactGender, contactResource, contactTable, ContactClass, ContactType, isAgentContact, isGroupContact, normalizeContactGender, type ContactRow, type ContactInsert, type ContactUpdate, type ContactClassValue, type ContactGenderValue, type ContactTypeValue, } from './contact.schema';
7
7
  export { contactRepository } from './contact.repository';
8
- export { chatResource, chatTable, type ChatMetadata, type ChatMemberRole, type ChatRow, type ChatInsert, type ChatUpdate, } from './chat.schema';
8
+ export { ChatStatus, chatResource, chatTable, type ChatMetadata, type ChatMemberRole, type ChatStatusType, type ChatRow, type ChatInsert, type ChatUpdate, } from './chat.schema';
9
9
  export { chatRepository } from './chat.repository';
10
10
  export { extractChatIdFromChatRef, extractChatThreadRef, extractThreadIdFromThreadRef, resolveThreadChatId, toTimestamp, type ChatThreadRef, } from './chat.utils';
11
- export { threadResource, threadTable, type ThreadRow, type ThreadInsert, type ThreadUpdate, } from './thread.schema';
11
+ export { ThreadStatus, threadResource, threadTable, type ThreadStatusType, type ThreadRow, type ThreadInsert, type ThreadUpdate, } from './thread.schema';
12
12
  export { threadRepository } from './thread.repository';
13
- export { messageResource, messageTable, type MessageRow, type MessageInsert, type MessageUpdate, } from './message.schema';
13
+ export { MessageRole, MessageStatus, messageResource, messageTable, type MessageRoleType, type MessageStatusType, type MessageRow, type MessageInsert, type MessageUpdate, } from './message.schema';
14
14
  export { messageRepository } from './message.repository';
15
+ export { TaskStatus, TaskTriggerKind, taskResource, taskTable, type TaskStatusType, type TaskTriggerKindType, type TaskRow, type TaskInsert, type TaskUpdate, } from './task.schema';
16
+ export { RunStatus, RunStepType, runResource, runStepResource, runTable, runStepTable, type RunStatusType, type RunStepTypeValue, type RunRow, type RunInsert, type RunUpdate, type RunStepRow, type RunStepInsert, type RunStepUpdate, } from './run.schema';
17
+ export { chatResourceId, commandKindFromResourceId, dateParts, messageResourceId, parentDir, resourceKey, runResourceId, runStepResourceId, surfaceIdFromCommandResourceId, taskResourceId, threadResourceId, type CommandKind, type DateInput, type DateParts, } from './resource-id-defaults';
15
18
  export { issueResource, issueTable, type IssueStatus, type IssuePriority, type IssueRow, type IssueInsert, type IssueUpdate, } from './issue.schema';
16
19
  export { issueRepository } from './issue.repository';
17
20
  export { MessageBlockType, MessageBlockStatus, type BaseMessageBlock, type PlaceholderMessageBlock, type MainTextMessageBlock, type ThinkingMessageBlock, type ImageMessageBlock, type CodeMessageBlock, type ToolMessageBlock, type FileMessageBlock, type ErrorMessageBlock, type CitationMessageBlock, type MessageBlock, type MessageRichContent, createMessageBlock, isBlockType, parseMessageBlocks, serializeMessageBlocks, } from './types/message-block';
@@ -41,6 +44,7 @@ export { aiModelResource, aiModelTable, type AIModelRow, type AIModelInsert, typ
41
44
  export { agentStatusResource, agentStatusTable, aiConfigResource, aiConfigTable, indexedFileResource, indexedFileTable, vectorStoreResource, vectorStoreTable, type AgentStatusRow, type AgentStatusInsert, type AgentStatusUpdate, type AIConfigRow, type AIConfigInsert, type AIConfigUpdate as AIConfigResourceUpdate, type IndexedFileRow, type IndexedFileInsert, type IndexedFileUpdate, type VectorStoreRow, type VectorStoreInsert, type VectorStoreUpdate, } from './ai-runtime.schema';
42
45
  export { aiConfigModelRef, aiConfigModelUri, aiConfigProviderRef, aiConfigProviderUri, buildAIConfigDisconnectPlan, buildAIConfigMutationPlan, buildAIConfigProviderStateMap, getAIConfigDefaultBaseUrl, getAIConfigProviderCatalog, getAIConfigProviderFamilyIds, getAIConfigProviderMetadata, getDefaultAIConfigCredentialId, normalizeAIConfigProviderId, normalizeAIConfigModelId, normalizeAIConfigResourceId, sameAIConfigProviderFamily, selectAIConfigCredential, type AIConfigModel, type AIConfigCredentialSelection, type AIConfigDisconnectPlan, type AIConfigMutationPlan, type AIConfigProviderCatalogEntry, type AIConfigProviderState, type AIConfigUpdate, type BuildAIConfigProviderStateMapOptions, } from './ai-config';
43
46
  export { applySolidComunicaPatches, } from './comunica-patches';
47
+ export { credentialDescriptor, createPodModelDescriptorRegistry, createPodSchema, createPodStorage, officialPodModelDescriptors, podSchema, type PodModelDescriptor, type PodModelDescriptorSource, type PodModelDescriptorTrustLevel, type PodModelFieldDescriptor, type PodModelFieldType, type PodModelMergePolicy, type PodSchemaClassEntry, type PodSchemaPredicateEntry, type PodSchemaSearchEntry, type PodStorageCommitResult, type PodStorageMutationPlan, type PodStorageValidationResult, } from './pod-storage-descriptor';
44
48
  export { createRepositoryDescriptor, definePodRepository, initSolidResources, initSolidTables, type AnyPodResource, type AnyPodTable, type PodRepositoryDescriptor, type RepositoryCacheOptions, type RepositoryInvalidations, type RepositoryScope, type SolidDatabase, } from './repository';
45
49
  export { importJobSchema } from './import';
46
50
  export { eq, ne, and, or, drizzle } from '@undefineds.co/drizzle-solid';