@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
@@ -95,6 +95,10 @@ export const UDFS = createNamespace('udfs', 'https://undefineds.co/ns#', {
95
95
  ApprovalRequest: 'ApprovalRequest',
96
96
  AuditEntry: 'AuditEntry',
97
97
  AutonomyGrant: 'AutonomyGrant',
98
+ Issue: 'Issue',
99
+ Task: 'Task',
100
+ Run: 'Run',
101
+ RunStep: 'RunStep',
98
102
  favorite: 'favorite',
99
103
  favoriteType: 'favoriteType',
100
104
  favoriteTarget: 'favoriteTarget',
@@ -113,6 +117,8 @@ export const UDFS = createNamespace('udfs', 'https://undefineds.co/ns#', {
113
117
  messageResource: 'messageResource',
114
118
  messageType: 'messageType',
115
119
  messageStatus: 'messageStatus',
120
+ commandKind: 'commandKind',
121
+ surfaceId: 'surfaceId',
116
122
  readBy: 'readBy',
117
123
  Contact: 'Contact',
118
124
  PersonContact: 'PersonContact',
@@ -153,12 +159,23 @@ export const UDFS = createNamespace('udfs', 'https://undefineds.co/ns#', {
153
159
  apiKey: 'apiKey',
154
160
  baseUrl: 'baseUrl',
155
161
  inbox: 'inbox',
162
+ issue: 'issue',
163
+ task: 'task',
164
+ triggerKind: 'triggerKind',
165
+ cron: 'cron',
166
+ intervalSeconds: 'intervalSeconds',
167
+ eventName: 'eventName',
168
+ nextRunAt: 'nextRunAt',
169
+ lastRunAt: 'lastRunAt',
170
+ priority: 'priority',
171
+ parentIssue: 'parentIssue',
156
172
  session: 'session',
157
173
  status: 'status',
158
174
  risk: 'risk',
159
175
  assignedTo: 'assignedTo',
160
176
  reason: 'reason',
161
177
  resolvedAt: 'resolvedAt',
178
+ closedAt: 'closedAt',
162
179
  action: 'action',
163
180
  actor: 'actor',
164
181
  actorRole: 'actorRole',
@@ -196,6 +213,18 @@ export const UDFS = createNamespace('udfs', 'https://undefineds.co/ns#', {
196
213
  policyVersion: 'policyVersion',
197
214
  parentThreadId: 'parentThreadId',
198
215
  sessionStatus: 'sessionStatus',
216
+ runner: 'runner',
217
+ prompt: 'prompt',
218
+ externalRunId: 'externalRunId',
219
+ leaseOwner: 'leaseOwner',
220
+ leaseExpiresAt: 'leaseExpiresAt',
221
+ heartbeatAt: 'heartbeatAt',
222
+ cancelRequestedAt: 'cancelRequestedAt',
223
+ startedAt: 'startedAt',
224
+ completedAt: 'completedAt',
225
+ error: 'error',
226
+ runId: 'runId',
227
+ run: 'run',
199
228
  sessionTool: 'sessionTool',
200
229
  tokenUsage: 'tokenUsage',
201
230
  groupOwner: 'groupOwner',
@@ -0,0 +1,189 @@
1
+ export type PodModelDescriptorSource = 'official' | 'verified-community' | 'developer' | 'user';
2
+ export type PodModelDescriptorTrustLevel = 'high' | 'medium' | 'low';
3
+ export type PodModelFieldType = 'string' | 'text' | 'number' | 'boolean' | 'timestamp' | 'uri' | 'json';
4
+ export type PodModelMergePolicy = 'create-only' | 'upsert' | 'patch' | 'append';
5
+ export interface PodModelFieldDescriptor {
6
+ type: PodModelFieldType;
7
+ predicate: string;
8
+ required?: boolean;
9
+ secret?: boolean;
10
+ array?: boolean;
11
+ description?: string;
12
+ }
13
+ export interface PodModelDescriptor {
14
+ uri: string;
15
+ version: string;
16
+ source: PodModelDescriptorSource;
17
+ trustLevel: PodModelDescriptorTrustLevel;
18
+ namespace: string;
19
+ class: string;
20
+ resourceKind: string;
21
+ description: string;
22
+ storage: {
23
+ base: string;
24
+ resourceIdPattern: string;
25
+ /**
26
+ * @deprecated subjectTemplate exists only for legacy fragment layouts.
27
+ * New descriptors should express exact base-relative ids through
28
+ * resourceIdPattern and store those ids directly.
29
+ */
30
+ subjectTemplate?: string;
31
+ };
32
+ fields: Record<string, PodModelFieldDescriptor>;
33
+ uniqueBy: string[];
34
+ writableFields: string[];
35
+ mergePolicy: PodModelMergePolicy;
36
+ examples: Array<{
37
+ request: string;
38
+ match: Record<string, unknown>;
39
+ }>;
40
+ }
41
+ export interface PodStorageMutationPlan {
42
+ id: string;
43
+ schemaUri: string;
44
+ operation: 'upsert';
45
+ resourceId: string;
46
+ resourceUri: string;
47
+ match: Record<string, unknown>;
48
+ set: Record<string, unknown>;
49
+ summary: string;
50
+ }
51
+ export type PodStorageValidationResult = {
52
+ ok: true;
53
+ plan: PodStorageMutationPlan;
54
+ } | {
55
+ ok: false;
56
+ error: {
57
+ code: string;
58
+ message: string;
59
+ };
60
+ };
61
+ export type PodStorageCommitResult = {
62
+ ok: true;
63
+ resource: Record<string, unknown>;
64
+ } | {
65
+ ok: false;
66
+ error: {
67
+ code: string;
68
+ message: string;
69
+ };
70
+ };
71
+ export interface PodSchemaClassEntry {
72
+ schemaUri: string;
73
+ resourceKind: string;
74
+ class: string;
75
+ namespace: string;
76
+ source: PodModelDescriptorSource;
77
+ trustLevel: PodModelDescriptorTrustLevel;
78
+ description: string;
79
+ }
80
+ export interface PodSchemaPredicateEntry {
81
+ schemaUri: string;
82
+ field: string;
83
+ predicate: string;
84
+ type: PodModelFieldType;
85
+ required: boolean;
86
+ secret: boolean;
87
+ array: boolean;
88
+ description?: string;
89
+ }
90
+ export interface PodSchemaSearchEntry {
91
+ uri: string;
92
+ resourceKind: string;
93
+ class: string;
94
+ namespace: string;
95
+ source: PodModelDescriptorSource;
96
+ trustLevel: PodModelDescriptorTrustLevel;
97
+ description: string;
98
+ score: number;
99
+ matchedFields: string[];
100
+ }
101
+ export declare const credentialDescriptor: PodModelDescriptor;
102
+ export declare const officialPodModelDescriptors: readonly [PodModelDescriptor];
103
+ export declare function createPodModelDescriptorRegistry(descriptors?: readonly PodModelDescriptor[]): {
104
+ list(filter?: {
105
+ source?: PodModelDescriptorSource;
106
+ resourceKind?: string;
107
+ }): PodModelDescriptor[];
108
+ describe(uri: string): PodModelDescriptor | null;
109
+ };
110
+ export declare const podSchema: {
111
+ list: (filter?: {
112
+ source?: PodModelDescriptorSource;
113
+ resourceKind?: string;
114
+ }) => PodModelDescriptor[];
115
+ describe(uriOrInput: string | {
116
+ uri: string;
117
+ } | {
118
+ schemaUri: string;
119
+ }): PodModelDescriptor | null;
120
+ classes(input?: {
121
+ uri?: string;
122
+ schemaUri?: string;
123
+ }): PodSchemaClassEntry[];
124
+ search(input: {
125
+ query: string;
126
+ source?: PodModelDescriptorSource;
127
+ resourceKind?: string;
128
+ limit?: number;
129
+ }): PodSchemaSearchEntry[];
130
+ predicates(input?: {
131
+ uri?: string;
132
+ schemaUri?: string;
133
+ field?: string;
134
+ }): PodSchemaPredicateEntry[];
135
+ };
136
+ export declare function createPodSchema(registry?: {
137
+ list(filter?: {
138
+ source?: PodModelDescriptorSource;
139
+ resourceKind?: string;
140
+ }): PodModelDescriptor[];
141
+ describe(uri: string): PodModelDescriptor | null;
142
+ }): {
143
+ list: (filter?: {
144
+ source?: PodModelDescriptorSource;
145
+ resourceKind?: string;
146
+ }) => PodModelDescriptor[];
147
+ describe(uriOrInput: string | {
148
+ uri: string;
149
+ } | {
150
+ schemaUri: string;
151
+ }): PodModelDescriptor | null;
152
+ classes(input?: {
153
+ uri?: string;
154
+ schemaUri?: string;
155
+ }): PodSchemaClassEntry[];
156
+ search(input: {
157
+ query: string;
158
+ source?: PodModelDescriptorSource;
159
+ resourceKind?: string;
160
+ limit?: number;
161
+ }): PodSchemaSearchEntry[];
162
+ predicates(input?: {
163
+ uri?: string;
164
+ schemaUri?: string;
165
+ field?: string;
166
+ }): PodSchemaPredicateEntry[];
167
+ };
168
+ export declare function createPodStorage(registry?: {
169
+ list(filter?: {
170
+ source?: PodModelDescriptorSource;
171
+ resourceKind?: string;
172
+ }): PodModelDescriptor[];
173
+ describe(uri: string): PodModelDescriptor | null;
174
+ }, store?: Map<string, Record<string, unknown>>): {
175
+ validate(input: {
176
+ schemaUri?: string;
177
+ operation: "upsert";
178
+ match: Record<string, unknown>;
179
+ set?: Record<string, unknown>;
180
+ }): PodStorageValidationResult;
181
+ commit(input: {
182
+ planId: string;
183
+ }): PodStorageCommitResult;
184
+ read(input: {
185
+ resourceUri: string;
186
+ }): PodStorageCommitResult;
187
+ store: Map<string, Record<string, unknown>>;
188
+ plans: Map<string, PodStorageMutationPlan>;
189
+ };
@@ -0,0 +1,283 @@
1
+ import { XPOD_CREDENTIAL } from './namespaces.js';
2
+ export const credentialDescriptor = {
3
+ uri: XPOD_CREDENTIAL.Credential,
4
+ version: '1.0.0',
5
+ source: 'official',
6
+ trustLevel: 'high',
7
+ namespace: XPOD_CREDENTIAL.NAMESPACE,
8
+ class: XPOD_CREDENTIAL.Credential,
9
+ resourceKind: 'credential',
10
+ description: 'Generic credential material required by runtimes, tools, MCP servers, and providers.',
11
+ storage: {
12
+ base: '/settings/credentials.ttl',
13
+ resourceIdPattern: '#{id}',
14
+ subjectTemplate: '#{id}',
15
+ },
16
+ fields: {
17
+ id: {
18
+ type: 'string',
19
+ predicate: XPOD_CREDENTIAL.term('id'),
20
+ required: true,
21
+ description: 'Local credential id.',
22
+ },
23
+ service: {
24
+ type: 'string',
25
+ predicate: XPOD_CREDENTIAL.service,
26
+ required: true,
27
+ description: 'Credential service grouping, for example ai or infra.',
28
+ },
29
+ providerId: {
30
+ type: 'string',
31
+ predicate: XPOD_CREDENTIAL.provider,
32
+ required: true,
33
+ description: 'Provider identifier such as openai or cloudflare.',
34
+ },
35
+ secretType: {
36
+ type: 'string',
37
+ predicate: XPOD_CREDENTIAL.term('secretType'),
38
+ required: true,
39
+ description: 'Provider-specific secret kind such as api-key or tunnel-token.',
40
+ },
41
+ label: {
42
+ type: 'string',
43
+ predicate: XPOD_CREDENTIAL.label,
44
+ description: 'User-facing credential label.',
45
+ },
46
+ apiKey: {
47
+ type: 'string',
48
+ predicate: XPOD_CREDENTIAL.apiKey,
49
+ secret: true,
50
+ description: 'Secret token or API key material.',
51
+ },
52
+ status: {
53
+ type: 'string',
54
+ predicate: XPOD_CREDENTIAL.status,
55
+ description: 'Credential health status.',
56
+ },
57
+ },
58
+ uniqueBy: ['service', 'providerId', 'secretType'],
59
+ writableFields: ['label', 'apiKey', 'status'],
60
+ mergePolicy: 'upsert',
61
+ examples: [
62
+ {
63
+ request: '保存 Cloudflare tunnel token',
64
+ match: {
65
+ service: 'infra',
66
+ providerId: 'cloudflare',
67
+ secretType: 'tunnel-token',
68
+ },
69
+ },
70
+ {
71
+ request: '保存 OpenAI API key',
72
+ match: {
73
+ service: 'ai',
74
+ providerId: 'openai',
75
+ secretType: 'api-key',
76
+ },
77
+ },
78
+ ],
79
+ };
80
+ export const officialPodModelDescriptors = [credentialDescriptor];
81
+ export function createPodModelDescriptorRegistry(descriptors = officialPodModelDescriptors) {
82
+ const byUri = new Map(descriptors.map((descriptor) => [descriptor.uri, descriptor]));
83
+ return {
84
+ list(filter = {}) {
85
+ return descriptors.filter((descriptor) => {
86
+ if (filter.source && descriptor.source !== filter.source)
87
+ return false;
88
+ if (filter.resourceKind && descriptor.resourceKind !== filter.resourceKind)
89
+ return false;
90
+ return true;
91
+ });
92
+ },
93
+ describe(uri) {
94
+ return byUri.get(uri) ?? null;
95
+ },
96
+ };
97
+ }
98
+ export const podSchema = createPodSchema();
99
+ export function createPodSchema(registry = createPodModelDescriptorRegistry()) {
100
+ const resolveDescriptors = (input = {}) => {
101
+ const uri = input.uri ?? input.schemaUri;
102
+ if (!uri)
103
+ return registry.list();
104
+ const descriptor = registry.describe(uri);
105
+ return descriptor ? [descriptor] : [];
106
+ };
107
+ return {
108
+ list: registry.list,
109
+ describe(uriOrInput) {
110
+ const uri = typeof uriOrInput === 'string'
111
+ ? uriOrInput
112
+ : 'uri' in uriOrInput
113
+ ? uriOrInput.uri
114
+ : uriOrInput.schemaUri;
115
+ return registry.describe(uri);
116
+ },
117
+ classes(input = {}) {
118
+ return resolveDescriptors(input).map((descriptor) => ({
119
+ schemaUri: descriptor.uri,
120
+ resourceKind: descriptor.resourceKind,
121
+ class: descriptor.class,
122
+ namespace: descriptor.namespace,
123
+ source: descriptor.source,
124
+ trustLevel: descriptor.trustLevel,
125
+ description: descriptor.description,
126
+ }));
127
+ },
128
+ search(input) {
129
+ const terms = normalizeSearchTerms(input.query);
130
+ if (terms.length === 0)
131
+ return [];
132
+ return registry.list({
133
+ source: input.source,
134
+ resourceKind: input.resourceKind,
135
+ })
136
+ .map((descriptor) => scoreDescriptorSearch(descriptor, terms))
137
+ .filter((entry) => entry !== null)
138
+ .sort((a, b) => b.score - a.score || a.uri.localeCompare(b.uri))
139
+ .slice(0, Math.max(1, input.limit ?? 10));
140
+ },
141
+ predicates(input = {}) {
142
+ return resolveDescriptors(input).flatMap((descriptor) => (Object.entries(descriptor.fields)
143
+ .filter(([field]) => !input.field || field === input.field)
144
+ .map(([field, descriptorField]) => ({
145
+ schemaUri: descriptor.uri,
146
+ field,
147
+ predicate: descriptorField.predicate,
148
+ type: descriptorField.type,
149
+ required: Boolean(descriptorField.required),
150
+ secret: Boolean(descriptorField.secret),
151
+ array: Boolean(descriptorField.array),
152
+ description: descriptorField.description,
153
+ }))));
154
+ },
155
+ };
156
+ }
157
+ export function createPodStorage(registry = createPodModelDescriptorRegistry(), store = new Map()) {
158
+ const plans = new Map();
159
+ return {
160
+ validate(input) {
161
+ const schemaUri = input.schemaUri;
162
+ if (!schemaUri)
163
+ return invalid('schema_uri_required', 'Missing schemaUri');
164
+ const descriptor = registry.describe(schemaUri);
165
+ if (!descriptor)
166
+ return invalid('descriptor_not_found', `Descriptor not found: ${schemaUri}`);
167
+ if (input.operation !== 'upsert')
168
+ return invalid('unsupported_operation', `Unsupported operation: ${input.operation}`);
169
+ const missingKeys = descriptor.uniqueBy.filter((field) => !input.match[field]);
170
+ if (missingKeys.length > 0) {
171
+ return invalid('missing_match_fields', `Missing match fields: ${missingKeys.join(', ')}`);
172
+ }
173
+ const set = input.set ?? {};
174
+ const invalidSetFields = Object.keys(set).filter((field) => !descriptor.writableFields.includes(field));
175
+ if (invalidSetFields.length > 0) {
176
+ return invalid('invalid_set_fields', `Fields are not writable: ${invalidSetFields.join(', ')}`);
177
+ }
178
+ const resourceId = buildResourceId(descriptor, input.match);
179
+ const plan = {
180
+ id: `plan_${resourceId.replace(/[^a-zA-Z0-9_.-]+/g, '-')}`,
181
+ schemaUri: descriptor.uri,
182
+ operation: input.operation,
183
+ resourceId,
184
+ resourceUri: buildResourceUri(descriptor, resourceId),
185
+ match: input.match,
186
+ set,
187
+ summary: `Upsert ${descriptor.resourceKind} for ${descriptor.uniqueBy.map((field) => input.match[field]).join('/')}`,
188
+ };
189
+ plans.set(plan.id, plan);
190
+ return { ok: true, plan };
191
+ },
192
+ commit(input) {
193
+ const plan = plans.get(input.planId);
194
+ if (!plan)
195
+ return invalid('plan_not_found', `Plan not found: ${input.planId}`);
196
+ const existing = store.get(plan.resourceUri) ?? {};
197
+ const resource = {
198
+ ...existing,
199
+ ...plan.match,
200
+ ...plan.set,
201
+ schemaUri: plan.schemaUri,
202
+ resourceId: plan.resourceId,
203
+ resourceUri: plan.resourceUri,
204
+ };
205
+ store.set(plan.resourceUri, resource);
206
+ return { ok: true, resource };
207
+ },
208
+ read(input) {
209
+ const resource = store.get(input.resourceUri);
210
+ if (!resource)
211
+ return invalid('resource_not_found', `Resource not found: ${input.resourceUri}`);
212
+ return { ok: true, resource };
213
+ },
214
+ store,
215
+ plans,
216
+ };
217
+ }
218
+ function invalid(code, message) {
219
+ return {
220
+ ok: false,
221
+ error: { code, message },
222
+ };
223
+ }
224
+ function buildResourceId(descriptor, match) {
225
+ const raw = descriptor.uniqueBy.map((field) => String(match[field])).join('-');
226
+ const localId = raw.replace(/[^a-zA-Z0-9_.-]+/g, '-');
227
+ return descriptor.storage.resourceIdPattern.replace('{id}', localId);
228
+ }
229
+ function buildResourceUri(descriptor, resourceId) {
230
+ return `${descriptor.storage.base}${resourceId}`;
231
+ }
232
+ function normalizeSearchTerms(query) {
233
+ return query
234
+ .toLowerCase()
235
+ .split(/[\s,;:/#._-]+/u)
236
+ .map((term) => term.trim())
237
+ .filter(Boolean);
238
+ }
239
+ function scoreDescriptorSearch(descriptor, terms) {
240
+ const matchedFields = new Set();
241
+ let score = 0;
242
+ const match = (field, value, weight) => {
243
+ if (!value)
244
+ return;
245
+ const normalized = value.toLowerCase();
246
+ for (const term of terms) {
247
+ if (!normalized.includes(term))
248
+ continue;
249
+ matchedFields.add(field);
250
+ score += weight;
251
+ }
252
+ };
253
+ match('uri', descriptor.uri, 10);
254
+ match('class', descriptor.class, 10);
255
+ match('namespace', descriptor.namespace, 4);
256
+ match('resourceKind', descriptor.resourceKind, 8);
257
+ match('description', descriptor.description, 4);
258
+ match('storage', `${descriptor.storage.base}${descriptor.storage.resourceIdPattern}`, 3);
259
+ for (const [fieldName, field] of Object.entries(descriptor.fields)) {
260
+ match(`field:${fieldName}`, fieldName, 6);
261
+ match(`predicate:${fieldName}`, field.predicate, 6);
262
+ match(`description:${fieldName}`, field.description, 3);
263
+ }
264
+ for (const example of descriptor.examples) {
265
+ match('example', example.request, 3);
266
+ for (const [fieldName, value] of Object.entries(example.match)) {
267
+ match(`example:${fieldName}`, String(value), 3);
268
+ }
269
+ }
270
+ if (score <= 0)
271
+ return null;
272
+ return {
273
+ uri: descriptor.uri,
274
+ resourceKind: descriptor.resourceKind,
275
+ class: descriptor.class,
276
+ namespace: descriptor.namespace,
277
+ source: descriptor.source,
278
+ trustLevel: descriptor.trustLevel,
279
+ description: descriptor.description,
280
+ score,
281
+ matchedFields: [...matchedFields].sort(),
282
+ };
283
+ }
@@ -4,3 +4,5 @@ export { initSolidTables };
4
4
  export type { AnyPodTable };
5
5
  export declare const initSolidResources: typeof initSolidTables;
6
6
  export type AnyPodResource = AnyPodTable;
7
+ type PodResourceTemplateTarget = Parameters<typeof import('@undefineds.co/drizzle-solid').extractPodResourceTemplateValue>[0];
8
+ export declare function asPodResourceTemplateTarget(resource: AnyPodResource): PodResourceTemplateTarget;
@@ -4,3 +4,6 @@ export { initSolidTables };
4
4
  // Resource-first aliases for shared Solid model call sites. The underlying
5
5
  // drizzle-solid API still uses table-shaped arguments for compatibility.
6
6
  export const initSolidResources = initSolidTables;
7
+ export function asPodResourceTemplateTarget(resource) {
8
+ return resource;
9
+ }
@@ -0,0 +1,18 @@
1
+ export type CommandKind = 'chat' | 'task';
2
+ export type DateInput = Date | string | number | null | undefined;
3
+ export interface DateParts {
4
+ yyyy: string;
5
+ MM: string;
6
+ dd: string;
7
+ }
8
+ export declare function dateParts(value?: DateInput): DateParts;
9
+ export declare function resourceKey(key: string | undefined, prefix: string): string;
10
+ export declare function parentDir(id: string | null | undefined): string | null;
11
+ export declare function surfaceIdFromCommandResourceId(id: string | null | undefined): string | null;
12
+ export declare function commandKindFromResourceId(id: string | null | undefined): CommandKind | null;
13
+ export declare function chatResourceId(key?: string): string;
14
+ export declare function taskResourceId(key?: string): string;
15
+ export declare function threadResourceId(key: string | undefined, row?: Record<string, unknown>): string;
16
+ export declare function messageResourceId(key: string | undefined, row?: Record<string, unknown>): string;
17
+ export declare function runResourceId(key: string | undefined, row?: Record<string, unknown>): string;
18
+ export declare function runStepResourceId(key: string | undefined, row?: Record<string, unknown>): string;
@@ -0,0 +1,84 @@
1
+ export function dateParts(value) {
2
+ const date = value instanceof Date
3
+ ? value
4
+ : typeof value === 'string' || typeof value === 'number'
5
+ ? new Date(typeof value === 'number' && Math.abs(value) < 100000000000 ? value * 1000 : value)
6
+ : new Date();
7
+ const safeDate = Number.isFinite(date.getTime()) ? date : new Date();
8
+ return {
9
+ yyyy: String(safeDate.getUTCFullYear()),
10
+ MM: String(safeDate.getUTCMonth() + 1).padStart(2, '0'),
11
+ dd: String(safeDate.getUTCDate()).padStart(2, '0'),
12
+ };
13
+ }
14
+ export function resourceKey(key, prefix) {
15
+ return key && key.length > 0
16
+ ? key
17
+ : `${prefix}_${Math.random().toString(36).slice(2, 12)}`;
18
+ }
19
+ export function parentDir(id) {
20
+ if (!id)
21
+ return null;
22
+ const hashless = id.split('#')[0] ?? id;
23
+ const parts = hashless.split('/').filter(Boolean);
24
+ if (parts.length <= 1)
25
+ return null;
26
+ return parts.slice(0, -1).join('/');
27
+ }
28
+ export function surfaceIdFromCommandResourceId(id) {
29
+ if (!id)
30
+ return null;
31
+ const match = id.match(/^(chat|task)\/([^/]+)\//);
32
+ return match ? decodeURIComponent(match[2]) : null;
33
+ }
34
+ export function commandKindFromResourceId(id) {
35
+ if (!id)
36
+ return null;
37
+ const match = id.match(/^(chat|task)\//);
38
+ return match?.[1] === 'task' ? 'task' : match?.[1] === 'chat' ? 'chat' : null;
39
+ }
40
+ export function chatResourceId(key) {
41
+ return `${resourceKey(key, 'chat')}/index.ttl#this`;
42
+ }
43
+ export function taskResourceId(key) {
44
+ return `index.ttl#${resourceKey(key, 'task')}`;
45
+ }
46
+ export function threadResourceId(key, row) {
47
+ const localKey = resourceKey(key, 'thread');
48
+ const commandKind = row?.commandKind === 'task' ? 'task' : 'chat';
49
+ const surfaceId = typeof row?.surfaceId === 'string' && row.surfaceId.length > 0
50
+ ? row.surfaceId
51
+ : surfaceIdFromCommandResourceId(typeof row?.id === 'string' ? row.id : undefined) ?? 'default';
52
+ return `${commandKind}/${surfaceId}/index.ttl#${localKey}`;
53
+ }
54
+ export function messageResourceId(key, row) {
55
+ const localKey = resourceKey(key, 'msg');
56
+ const commandKind = row?.commandKind === 'task' ? 'task' : 'chat';
57
+ const surfaceId = typeof row?.surfaceId === 'string' && row.surfaceId.length > 0
58
+ ? row.surfaceId
59
+ : surfaceIdFromCommandResourceId(typeof row?.thread === 'string' ? row.thread : undefined) ?? 'default';
60
+ const { yyyy, MM, dd } = dateParts(row?.createdAt);
61
+ return `${commandKind}/${surfaceId}/${yyyy}/${MM}/${dd}/messages.ttl#${localKey}`;
62
+ }
63
+ export function runResourceId(key, row) {
64
+ const localKey = resourceKey(key, 'run');
65
+ const commandKind = row?.commandKind === 'task' ? 'task' : 'chat';
66
+ const surfaceId = typeof row?.surfaceId === 'string' && row.surfaceId.length > 0
67
+ ? row.surfaceId
68
+ : surfaceIdFromCommandResourceId(typeof row?.thread === 'string' ? row.thread : undefined) ?? 'default';
69
+ const { yyyy, MM, dd } = dateParts(row?.createdAt);
70
+ return `${commandKind}/${surfaceId}/${yyyy}/${MM}/${dd}/runs.ttl#${localKey}`;
71
+ }
72
+ export function runStepResourceId(key, row) {
73
+ const localKey = resourceKey(key, 'run-step');
74
+ const runId = typeof row?.runId === 'string' ? row.runId : undefined;
75
+ if (runId && /^(chat|task)\/[^/]+\/\d{4}\/\d{2}\/\d{2}\/runs\.ttl#[^#/]+$/.test(runId)) {
76
+ return `${runId.slice(0, runId.lastIndexOf('#') + 1)}${localKey}`;
77
+ }
78
+ const commandKind = row?.commandKind === 'task' ? 'task' : 'chat';
79
+ const surfaceId = typeof row?.surfaceId === 'string' && row.surfaceId.length > 0
80
+ ? row.surfaceId
81
+ : 'default';
82
+ const { yyyy, MM, dd } = dateParts(row?.createdAt);
83
+ return `${commandKind}/${surfaceId}/${yyyy}/${MM}/${dd}/runs.ttl#${localKey}`;
84
+ }