@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.
- package/dist/approval.schema.d.ts +4 -0
- package/dist/approval.schema.js +6 -1
- package/dist/audit.presentation.d.ts +1 -1
- package/dist/audit.presentation.js +19 -12
- package/dist/audit.schema.d.ts +4 -0
- package/dist/audit.schema.js +6 -1
- package/dist/bin/udfs.d.ts +2 -0
- package/dist/bin/udfs.js +430 -0
- package/dist/chat.repository.d.ts +8 -0
- package/dist/chat.schema.d.ts +10 -0
- package/dist/chat.schema.js +9 -2
- package/dist/chat.utils.js +24 -9
- package/dist/index.d.ts +9 -3
- package/dist/index.js +10 -3
- package/dist/issue.repository.d.ts +69 -0
- package/dist/issue.repository.js +8 -0
- package/dist/issue.schema.d.ts +48 -0
- package/dist/issue.schema.js +37 -0
- package/dist/message.repository.d.ts +29 -9
- package/dist/message.schema.d.ts +29 -6
- package/dist/message.schema.js +26 -10
- package/dist/namespaces.js +29 -0
- package/dist/pod-storage-descriptor.d.ts +189 -0
- package/dist/pod-storage-descriptor.js +283 -0
- package/dist/repository.d.ts +2 -0
- package/dist/repository.js +3 -0
- package/dist/resource-id-defaults.d.ts +18 -0
- package/dist/resource-id-defaults.js +84 -0
- package/dist/run.schema.d.ts +112 -0
- package/dist/run.schema.js +89 -0
- package/dist/schema.d.ts +176 -8
- package/dist/schema.js +11 -0
- package/dist/session/session.schema.js +2 -1
- package/dist/sidecar/persistence-mapping.d.ts +3 -3
- package/dist/sidecar/sidecar-events.d.ts +45 -45
- package/dist/sidecar/sidecar-events.js +1 -1
- package/dist/task.schema.d.ts +62 -0
- package/dist/task.schema.js +49 -0
- package/dist/thread.repository.d.ts +15 -3
- package/dist/thread.schema.d.ts +14 -2
- package/dist/thread.schema.js +13 -5
- package/package.json +11 -3
package/dist/namespaces.js
CHANGED
|
@@ -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
|
+
}
|
package/dist/repository.d.ts
CHANGED
|
@@ -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;
|
package/dist/repository.js
CHANGED
|
@@ -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
|
+
}
|