@lucern/sdk 0.2.0-alpha.4 → 0.2.0-alpha.5
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 +31 -0
- package/dist/.generated +2 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -8894
- package/dist/lib/platform/auth/credentials.d.ts +5 -0
- package/dist/lib/platform/auth/credentials.js +40 -0
- package/dist/lib/platform/sdk/adminClient.d.ts +404 -0
- package/dist/lib/platform/sdk/adminClient.js +384 -0
- package/dist/lib/platform/sdk/answersClient.d.ts +16 -0
- package/dist/lib/platform/sdk/answersClient.js +21 -0
- package/dist/{packages/sdk/src → lib/platform/sdk}/audiencesClient.d.ts +6 -0
- package/dist/lib/platform/sdk/audiencesClient.js +111 -0
- package/dist/{packages/sdk/src → lib/platform/sdk}/auditClient.d.ts +3 -0
- package/dist/lib/platform/sdk/auditClient.js +21 -0
- package/dist/lib/platform/sdk/beliefsClient.d.ts +157 -0
- package/dist/lib/platform/sdk/beliefsClient.js +124 -0
- package/dist/{packages/sdk/src → lib/platform/sdk}/client.d.ts +957 -146
- package/dist/lib/platform/sdk/client.js +1831 -0
- package/dist/lib/platform/sdk/contextClient.d.ts +21 -0
- package/dist/lib/platform/sdk/contextClient.js +86 -0
- package/dist/{lucern/packages/domain-context/src/context-pack-compiler.d.ts → lib/platform/sdk/contextPackCompiler.d.ts} +2 -3
- package/dist/lib/platform/sdk/contextPackCompiler.js +534 -0
- package/dist/lib/platform/sdk/contextTypes.d.ts +133 -0
- package/dist/lib/platform/sdk/contextTypes.js +1 -0
- package/dist/{packages/sdk/src → lib/platform/sdk}/controlObjectOwnership.d.ts +15 -0
- package/dist/lib/platform/sdk/controlObjectOwnership.js +220 -0
- package/dist/{packages/sdk/src → lib/platform/sdk}/coreClient.d.ts +19 -0
- package/dist/lib/platform/sdk/coreClient.js +366 -0
- package/dist/{packages/sdk/src → lib/platform/sdk}/customTools.d.ts +21 -3
- package/dist/lib/platform/sdk/customTools.js +247 -0
- package/dist/{packages/sdk/src → lib/platform/sdk}/decisionsClient.d.ts +9 -0
- package/dist/lib/platform/sdk/decisionsClient.js +129 -0
- package/dist/lib/platform/sdk/domainContext.d.ts +1 -0
- package/dist/lib/platform/sdk/domainContext.js +1 -0
- package/dist/{lucern/packages/events/src/types.d.ts → lib/platform/sdk/events.d.ts} +25 -0
- package/dist/lib/platform/sdk/events.js +261 -0
- package/dist/lib/platform/sdk/gatewayFacades.d.ts +586 -0
- package/dist/lib/platform/sdk/gatewayFacades.js +845 -0
- package/dist/{packages/sdk/src → lib/platform/sdk}/graphClient.d.ts +75 -0
- package/dist/lib/platform/sdk/graphClient.js +235 -0
- package/dist/{packages/sdk/src → lib/platform/sdk}/harnessClient.d.ts +90 -1
- package/dist/lib/platform/sdk/harnessClient.js +219 -0
- package/dist/{packages/sdk/src → lib/platform/sdk}/identityClient.d.ts +45 -15
- package/dist/lib/platform/sdk/identityClient.js +131 -0
- package/dist/{packages/sdk/src → lib/platform/sdk}/index.d.ts +21 -3
- package/dist/lib/platform/sdk/index.js +46 -0
- package/dist/{packages/sdk/src → lib/platform/sdk}/learningClient.d.ts +3 -0
- package/dist/lib/platform/sdk/learningClient.js +53 -0
- package/dist/{packages/sdk/src → lib/platform/sdk}/mcpParityClient.d.ts +1 -0
- package/dist/lib/platform/sdk/mcpParityClient.js +196 -0
- package/dist/{packages/sdk/src → lib/platform/sdk}/mcpParitySurface.d.ts +2 -0
- package/dist/lib/platform/sdk/mcpParitySurface.js +57 -0
- package/dist/{packages/sdk/src → lib/platform/sdk}/ontologyClient.d.ts +16 -0
- package/dist/lib/platform/sdk/ontologyClient.js +161 -0
- package/dist/lib/platform/sdk/packRuntime.d.ts +1 -0
- package/dist/lib/platform/sdk/packRuntime.js +1 -0
- package/dist/{packages/sdk/src → lib/platform/sdk}/packsClient.d.ts +25 -0
- package/dist/lib/platform/sdk/packsClient.js +157 -0
- package/dist/{packages/sdk/src → lib/platform/sdk}/policyClient.d.ts +90 -1
- package/dist/lib/platform/sdk/policyClient.js +277 -0
- package/dist/lib/platform/sdk/promptCatalog.d.ts +1 -0
- package/dist/lib/platform/sdk/promptCatalog.js +1 -0
- package/dist/{packages/sdk/src → lib/platform/sdk}/reportsClient.d.ts +3 -0
- package/dist/lib/platform/sdk/reportsClient.js +64 -0
- package/dist/{packages/sdk/src → lib/platform/sdk}/schemaClient.d.ts +5 -0
- package/dist/lib/platform/sdk/schemaClient.js +71 -0
- package/dist/{packages/sdk/src → lib/platform/sdk}/sdkSurface.d.ts +1 -0
- package/dist/lib/platform/sdk/sdkSurface.js +140 -0
- package/dist/{packages/sdk/src → lib/platform/sdk}/topicsClient.d.ts +33 -0
- package/dist/lib/platform/sdk/topicsClient.js +118 -0
- package/dist/{packages/sdk/src → lib/platform/sdk}/types.d.ts +224 -2
- package/dist/lib/platform/sdk/types.js +1 -0
- package/dist/lib/platform/sdk/version.js +2 -0
- package/dist/{packages/sdk/src → lib/platform/sdk}/workflowClient.d.ts +63 -2
- package/dist/lib/platform/sdk/workflowClient.js +366 -0
- package/dist/lucern/contracts/src/api-enums.contract.d.ts +58 -0
- package/dist/lucern/contracts/src/api-enums.contract.js +147 -0
- package/dist/lucern/contracts/src/lens-filter.contract.js +95 -0
- package/dist/lucern/contracts/src/lens-workflow.contract.js +54 -0
- package/dist/lucern/contracts/src/mcp-tools.contract.js +3281 -0
- package/package.json +17 -3
- package/dist/index.js.map +0 -1
- package/dist/lucern/contracts/src/auth-session.contract.d.ts +0 -53
- package/dist/lucern/contracts/src/context-pack.contract.d.ts +0 -494
- package/dist/lucern/contracts/src/workflow-runtime.contract.d.ts +0 -161
- package/dist/lucern/mcp-server/src/context-pack-policy.d.ts +0 -119
- package/dist/lucern/mcp-server/src/context-pack-schema.d.ts +0 -18
- package/dist/lucern/modules/graph-primitives/src/ontology-matching.d.ts +0 -78
- package/dist/lucern/modules/graph-primitives/src/text-matching.d.ts +0 -53
- package/dist/lucern/packages/client-core/src/beliefs.d.ts +0 -30
- package/dist/lucern/packages/client-core/src/context.d.ts +0 -29
- package/dist/lucern/packages/client-core/src/contradictions.d.ts +0 -11
- package/dist/lucern/packages/client-core/src/edges.d.ts +0 -11
- package/dist/lucern/packages/client-core/src/events.d.ts +0 -9
- package/dist/lucern/packages/client-core/src/evidence.d.ts +0 -21
- package/dist/lucern/packages/client-core/src/graph.d.ts +0 -17
- package/dist/lucern/packages/client-core/src/identity.d.ts +0 -7
- package/dist/lucern/packages/client-core/src/ids.d.ts +0 -7
- package/dist/lucern/packages/client-core/src/ontologies.d.ts +0 -13
- package/dist/lucern/packages/client-core/src/questions.d.ts +0 -39
- package/dist/lucern/packages/client-core/src/search.d.ts +0 -7
- package/dist/lucern/packages/client-core/src/tasks.d.ts +0 -13
- package/dist/lucern/packages/client-core/src/topics.d.ts +0 -17
- package/dist/lucern/packages/client-core/src/webhooks.d.ts +0 -35
- package/dist/lucern/packages/client-core/src/worktrees.d.ts +0 -17
- package/dist/lucern/packages/domain-beliefs/src/beliefs.d.ts +0 -283
- package/dist/lucern/packages/domain-beliefs/src/index.d.ts +0 -1
- package/dist/lucern/packages/domain-context/src/compile.d.ts +0 -11
- package/dist/lucern/packages/domain-context/src/index.d.ts +0 -4
- package/dist/lucern/packages/domain-context/src/ports.d.ts +0 -58
- package/dist/lucern/packages/domain-context/src/public-types.d.ts +0 -1
- package/dist/lucern/packages/domain-edges/src/contradictions.d.ts +0 -59
- package/dist/lucern/packages/domain-edges/src/edges.d.ts +0 -91
- package/dist/lucern/packages/domain-edges/src/index.d.ts +0 -2
- package/dist/lucern/packages/domain-evidence/src/evidence.d.ts +0 -115
- package/dist/lucern/packages/domain-evidence/src/index.d.ts +0 -1
- package/dist/lucern/packages/domain-graph/src/graph.d.ts +0 -150
- package/dist/lucern/packages/domain-identity/src/index.d.ts +0 -1
- package/dist/lucern/packages/domain-identity/src/whoami.d.ts +0 -13
- package/dist/lucern/packages/domain-ontologies/src/ontologies.d.ts +0 -123
- package/dist/lucern/packages/domain-questions/src/index.d.ts +0 -1
- package/dist/lucern/packages/domain-questions/src/questions.d.ts +0 -147
- package/dist/lucern/packages/domain-search/src/search.d.ts +0 -97
- package/dist/lucern/packages/domain-tasks/src/index.d.ts +0 -1
- package/dist/lucern/packages/domain-tasks/src/tasks.d.ts +0 -102
- package/dist/lucern/packages/domain-topics/src/index.d.ts +0 -1
- package/dist/lucern/packages/domain-topics/src/topics.d.ts +0 -147
- package/dist/lucern/packages/domain-worktrees/src/index.d.ts +0 -1
- package/dist/lucern/packages/domain-worktrees/src/worktrees.d.ts +0 -185
- package/dist/lucern/packages/events/src/index.d.ts +0 -4
- package/dist/lucern/packages/events/src/matching.d.ts +0 -3
- package/dist/lucern/packages/events/src/outbox.d.ts +0 -15
- package/dist/lucern/packages/events/src/webhooks.d.ts +0 -9
- package/dist/lucern/packages/sdk-typescript/src/facade/beliefs.d.ts +0 -15
- package/dist/lucern/packages/sdk-typescript/src/facade/context.d.ts +0 -12
- package/dist/lucern/packages/sdk-typescript/src/facade/contradictions.d.ts +0 -7
- package/dist/lucern/packages/sdk-typescript/src/facade/edges.d.ts +0 -7
- package/dist/lucern/packages/sdk-typescript/src/facade/events.d.ts +0 -6
- package/dist/lucern/packages/sdk-typescript/src/facade/evidence.d.ts +0 -21
- package/dist/lucern/packages/sdk-typescript/src/facade/graph.d.ts +0 -10
- package/dist/lucern/packages/sdk-typescript/src/facade/identity.d.ts +0 -5
- package/dist/lucern/packages/sdk-typescript/src/facade/ontologies.d.ts +0 -8
- package/dist/lucern/packages/sdk-typescript/src/facade/questions.d.ts +0 -39
- package/dist/lucern/packages/sdk-typescript/src/facade/search.d.ts +0 -5
- package/dist/lucern/packages/sdk-typescript/src/facade/tasks.d.ts +0 -8
- package/dist/lucern/packages/sdk-typescript/src/facade/topics.d.ts +0 -10
- package/dist/lucern/packages/sdk-typescript/src/facade/webhooks.d.ts +0 -16
- package/dist/lucern/packages/sdk-typescript/src/facade/worktrees.d.ts +0 -10
- package/dist/lucern/packages/sdk-typescript/src/index.d.ts +0 -28
- package/dist/packages/sdk/src/adminClient.d.ts +0 -89
- package/dist/packages/sdk/src/answersClient.d.ts +0 -5
- package/dist/packages/sdk/src/beliefsClient.d.ts +0 -52
- package/dist/packages/sdk/src/contextClient.d.ts +0 -9
- package/dist/packages/sdk/src/contracts/api-enums.contract.d.ts +0 -79
- /package/dist/{packages/sdk/src → lib/platform/sdk}/version.d.ts +0 -0
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
import { createGatewayRequestClient, LucernApiError, randomIdempotencyKey, toQueryString, } from "./coreClient.js";
|
|
2
|
+
import { asListItems, createListResult, mapAliasedList, mapGatewayData, normalizeTopicQuery, resolveTopicId, withTopicAlias, } from "./sdkSurface.js";
|
|
3
|
+
export { LucernApiError };
|
|
4
|
+
function normalizeLensQuery(value) {
|
|
5
|
+
const topicId = resolveTopicId(value);
|
|
6
|
+
return {
|
|
7
|
+
...value,
|
|
8
|
+
...(topicId ? { topicId } : {}),
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Create the workflow client for lenses, legacy branches, worktrees, context,
|
|
13
|
+
* and tasks.
|
|
14
|
+
* @param config - Gateway transport configuration.
|
|
15
|
+
* @returns An object with methods to manage branches, lenses, worktrees, topics, and tasks.
|
|
16
|
+
*/
|
|
17
|
+
export function createWorkflowClient(config = {}) {
|
|
18
|
+
const gateway = createGatewayRequestClient(config);
|
|
19
|
+
const client = {
|
|
20
|
+
/**
|
|
21
|
+
* List workflow branches for a topic scope.
|
|
22
|
+
*/
|
|
23
|
+
async listBranches(query) {
|
|
24
|
+
return gateway.request({
|
|
25
|
+
path: `/api/platform/v1/workflow/branches${toQueryString(normalizeTopicQuery(query))}`,
|
|
26
|
+
}).then((response) => mapGatewayData(response, (data) => mapAliasedList(data, "branches")));
|
|
27
|
+
},
|
|
28
|
+
/**
|
|
29
|
+
* Create a workflow branch.
|
|
30
|
+
*/
|
|
31
|
+
async createBranch(input, idempotencyKey) {
|
|
32
|
+
return gateway.request({
|
|
33
|
+
path: "/api/platform/v1/workflow/branches",
|
|
34
|
+
method: "POST",
|
|
35
|
+
body: normalizeTopicQuery(input),
|
|
36
|
+
idempotencyKey: idempotencyKey ?? randomIdempotencyKey(),
|
|
37
|
+
}).then((response) => mapGatewayData(response, (data) => withTopicAlias(data)));
|
|
38
|
+
},
|
|
39
|
+
/**
|
|
40
|
+
* List reusable lenses for a workspace or topic scope.
|
|
41
|
+
*/
|
|
42
|
+
async listLenses(query) {
|
|
43
|
+
return gateway.request({
|
|
44
|
+
path: `/api/platform/v1/workflow/lenses${toQueryString(normalizeLensQuery(query))}`,
|
|
45
|
+
}).then((response) => mapGatewayData(response, (data) => mapAliasedList(data, "lenses")));
|
|
46
|
+
},
|
|
47
|
+
/**
|
|
48
|
+
* Create a reusable workflow lens.
|
|
49
|
+
*/
|
|
50
|
+
async createLens(input, idempotencyKey) {
|
|
51
|
+
const payload = normalizeLensQuery(input);
|
|
52
|
+
return gateway.request({
|
|
53
|
+
path: "/api/platform/v1/workflow/lenses",
|
|
54
|
+
method: "POST",
|
|
55
|
+
body: payload,
|
|
56
|
+
idempotencyKey: idempotencyKey ?? randomIdempotencyKey(),
|
|
57
|
+
}).then((response) => mapGatewayData(response, (data) => withTopicAlias(data)));
|
|
58
|
+
},
|
|
59
|
+
/**
|
|
60
|
+
* Apply an existing lens to a topic.
|
|
61
|
+
*/
|
|
62
|
+
async applyLensToTopic(input, idempotencyKey) {
|
|
63
|
+
const payload = normalizeLensQuery(input);
|
|
64
|
+
return gateway.request({
|
|
65
|
+
path: "/api/platform/v1/workflow/lens-bindings",
|
|
66
|
+
method: "POST",
|
|
67
|
+
body: payload,
|
|
68
|
+
idempotencyKey: idempotencyKey ?? randomIdempotencyKey(),
|
|
69
|
+
}).then((response) => mapGatewayData(response, (data) => withTopicAlias(data)));
|
|
70
|
+
},
|
|
71
|
+
/**
|
|
72
|
+
* Remove an applied lens from a topic.
|
|
73
|
+
*/
|
|
74
|
+
async removeLensFromTopic(input, idempotencyKey) {
|
|
75
|
+
const topicId = resolveTopicId(input);
|
|
76
|
+
if (!topicId) {
|
|
77
|
+
throw new LucernApiError({
|
|
78
|
+
code: "INVALID_REQUEST",
|
|
79
|
+
message: "topicId is required",
|
|
80
|
+
status: 400,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
return gateway.request({
|
|
84
|
+
path: `/api/platform/v1/workflow/lens-bindings${toQueryString({
|
|
85
|
+
lensId: input.lensId,
|
|
86
|
+
topicId,
|
|
87
|
+
})}`,
|
|
88
|
+
method: "DELETE",
|
|
89
|
+
idempotencyKey: idempotencyKey ?? randomIdempotencyKey(),
|
|
90
|
+
}).then((response) => mapGatewayData(response, (data) => withTopicAlias(data)));
|
|
91
|
+
},
|
|
92
|
+
/**
|
|
93
|
+
* List worktrees for a topic scope.
|
|
94
|
+
*/
|
|
95
|
+
async listWorktrees(query) {
|
|
96
|
+
const normalized = normalizeTopicQuery(query);
|
|
97
|
+
return gateway.request({
|
|
98
|
+
path: `/api/platform/v1/worktrees${toQueryString({
|
|
99
|
+
...normalized,
|
|
100
|
+
track: query.track,
|
|
101
|
+
executionBand: query.executionBand,
|
|
102
|
+
})}`,
|
|
103
|
+
}).then((response) => mapGatewayData(response, (data) => mapAliasedList(data, "worktrees")));
|
|
104
|
+
},
|
|
105
|
+
/**
|
|
106
|
+
* List all worktrees across accessible topics.
|
|
107
|
+
*/
|
|
108
|
+
async listAllWorktrees(query = {}) {
|
|
109
|
+
return gateway.request({
|
|
110
|
+
path: `/api/platform/v1/worktrees${toQueryString({
|
|
111
|
+
status: query.status,
|
|
112
|
+
track: query.track,
|
|
113
|
+
executionBand: query.executionBand,
|
|
114
|
+
limit: query.limit,
|
|
115
|
+
})}`,
|
|
116
|
+
}).then((response) => mapGatewayData(response, (data) => {
|
|
117
|
+
const record = data && typeof data === "object" && !Array.isArray(data)
|
|
118
|
+
? data
|
|
119
|
+
: {};
|
|
120
|
+
const list = mapAliasedList(data, "worktrees");
|
|
121
|
+
return {
|
|
122
|
+
...list,
|
|
123
|
+
...(record.tracks &&
|
|
124
|
+
typeof record.tracks === "object" &&
|
|
125
|
+
!Array.isArray(record.tracks)
|
|
126
|
+
? { tracks: record.tracks }
|
|
127
|
+
: {}),
|
|
128
|
+
...(record.bands &&
|
|
129
|
+
typeof record.bands === "object" &&
|
|
130
|
+
!Array.isArray(record.bands)
|
|
131
|
+
? { bands: record.bands }
|
|
132
|
+
: {}),
|
|
133
|
+
};
|
|
134
|
+
}));
|
|
135
|
+
},
|
|
136
|
+
/**
|
|
137
|
+
* Create a workflow worktree.
|
|
138
|
+
*/
|
|
139
|
+
async createWorktree(input, idempotencyKey) {
|
|
140
|
+
return gateway.request({
|
|
141
|
+
path: "/api/platform/v1/worktrees",
|
|
142
|
+
method: "POST",
|
|
143
|
+
body: normalizeTopicQuery(input),
|
|
144
|
+
idempotencyKey: idempotencyKey ?? randomIdempotencyKey(),
|
|
145
|
+
}).then((response) => mapGatewayData(response, (data) => withTopicAlias(data)));
|
|
146
|
+
},
|
|
147
|
+
/**
|
|
148
|
+
* @deprecated Use createWorktree.
|
|
149
|
+
*/
|
|
150
|
+
async addWorktree(input, idempotencyKey) {
|
|
151
|
+
return client.createWorktree(input, idempotencyKey);
|
|
152
|
+
},
|
|
153
|
+
/**
|
|
154
|
+
* Merge a worktree into the main belief line.
|
|
155
|
+
*/
|
|
156
|
+
async merge(worktreeId, input, idempotencyKey) {
|
|
157
|
+
return gateway.request({
|
|
158
|
+
path: `/api/platform/v1/worktrees/${encodeURIComponent(worktreeId)}/merge`,
|
|
159
|
+
method: "POST",
|
|
160
|
+
body: input,
|
|
161
|
+
idempotencyKey: idempotencyKey ?? randomIdempotencyKey(),
|
|
162
|
+
});
|
|
163
|
+
},
|
|
164
|
+
/**
|
|
165
|
+
* Activate a planning worktree.
|
|
166
|
+
*/
|
|
167
|
+
async activateWorktree(worktreeId, idempotencyKey) {
|
|
168
|
+
return gateway.request({
|
|
169
|
+
path: `/api/platform/v1/worktrees/${encodeURIComponent(worktreeId)}/activate`,
|
|
170
|
+
method: "POST",
|
|
171
|
+
idempotencyKey: idempotencyKey ?? randomIdempotencyKey(),
|
|
172
|
+
}).then((response) => mapGatewayData(response, (data) => withTopicAlias(data)));
|
|
173
|
+
},
|
|
174
|
+
/**
|
|
175
|
+
* Update targeted beliefs/questions for a worktree.
|
|
176
|
+
*/
|
|
177
|
+
async updateWorktreeTargets(input, idempotencyKey) {
|
|
178
|
+
const { worktreeId, ...body } = input;
|
|
179
|
+
return gateway.request({
|
|
180
|
+
path: `/api/platform/v1/worktrees/${encodeURIComponent(worktreeId)}/targets`,
|
|
181
|
+
method: "POST",
|
|
182
|
+
body,
|
|
183
|
+
idempotencyKey: idempotencyKey ?? randomIdempotencyKey(),
|
|
184
|
+
}).then((response) => mapGatewayData(response, (data) => withTopicAlias(data)));
|
|
185
|
+
},
|
|
186
|
+
/**
|
|
187
|
+
* Mark a worktree record complete.
|
|
188
|
+
*/
|
|
189
|
+
async completeWorktree(input, idempotencyKey) {
|
|
190
|
+
return gateway.request({
|
|
191
|
+
path: "/api/platform/v1/worktrees/complete",
|
|
192
|
+
method: "POST",
|
|
193
|
+
body: input,
|
|
194
|
+
idempotencyKey: idempotencyKey ?? randomIdempotencyKey(),
|
|
195
|
+
});
|
|
196
|
+
},
|
|
197
|
+
/**
|
|
198
|
+
* Advance a worktree to its next lifecycle phase.
|
|
199
|
+
*/
|
|
200
|
+
async advanceWorktreePhase(input, idempotencyKey) {
|
|
201
|
+
return gateway.request({
|
|
202
|
+
path: "/api/platform/v1/worktrees/advance-phase",
|
|
203
|
+
method: "POST",
|
|
204
|
+
body: input,
|
|
205
|
+
idempotencyKey: idempotencyKey ?? randomIdempotencyKey(),
|
|
206
|
+
});
|
|
207
|
+
},
|
|
208
|
+
/**
|
|
209
|
+
* Force a worktree into a specific lifecycle phase.
|
|
210
|
+
*/
|
|
211
|
+
async setWorktreePhase(input, idempotencyKey) {
|
|
212
|
+
return gateway.request({
|
|
213
|
+
path: "/api/platform/v1/worktrees/set-phase",
|
|
214
|
+
method: "POST",
|
|
215
|
+
body: input,
|
|
216
|
+
idempotencyKey: idempotencyKey ?? randomIdempotencyKey(),
|
|
217
|
+
});
|
|
218
|
+
},
|
|
219
|
+
/**
|
|
220
|
+
* Patch opaque worktree state for orchestration flows.
|
|
221
|
+
*/
|
|
222
|
+
async patchWorktreeState(input, idempotencyKey) {
|
|
223
|
+
return gateway.request({
|
|
224
|
+
path: "/api/platform/v1/worktrees/patch-state",
|
|
225
|
+
method: "POST",
|
|
226
|
+
body: input,
|
|
227
|
+
idempotencyKey: idempotencyKey ?? randomIdempotencyKey(),
|
|
228
|
+
});
|
|
229
|
+
},
|
|
230
|
+
/**
|
|
231
|
+
* Batch create worktree records.
|
|
232
|
+
*/
|
|
233
|
+
async bulkCreateWorktrees(input, idempotencyKey) {
|
|
234
|
+
return gateway.request({
|
|
235
|
+
path: "/api/platform/v1/worktrees/bulk",
|
|
236
|
+
method: "POST",
|
|
237
|
+
body: input,
|
|
238
|
+
idempotencyKey: idempotencyKey ?? randomIdempotencyKey(),
|
|
239
|
+
});
|
|
240
|
+
},
|
|
241
|
+
/**
|
|
242
|
+
* Open a pull request for a worktree.
|
|
243
|
+
*/
|
|
244
|
+
async openPullRequest(worktreeId, input, idempotencyKey) {
|
|
245
|
+
return gateway.request({
|
|
246
|
+
path: `/api/platform/v1/workflow/worktrees/${encodeURIComponent(worktreeId)}/pull-request`,
|
|
247
|
+
method: "POST",
|
|
248
|
+
body: input,
|
|
249
|
+
idempotencyKey: idempotencyKey ?? randomIdempotencyKey(),
|
|
250
|
+
});
|
|
251
|
+
},
|
|
252
|
+
/**
|
|
253
|
+
* Push scored worktree findings into another context.
|
|
254
|
+
*/
|
|
255
|
+
async push(worktreeId, input, idempotencyKey) {
|
|
256
|
+
return gateway.request({
|
|
257
|
+
path: `/api/platform/v1/workflow/worktrees/${encodeURIComponent(worktreeId)}/push`,
|
|
258
|
+
method: "POST",
|
|
259
|
+
body: input,
|
|
260
|
+
idempotencyKey: idempotencyKey ?? randomIdempotencyKey(),
|
|
261
|
+
});
|
|
262
|
+
},
|
|
263
|
+
/**
|
|
264
|
+
* List accessible topic contexts.
|
|
265
|
+
*/
|
|
266
|
+
async listTopics(query = {}) {
|
|
267
|
+
return gateway.request({
|
|
268
|
+
path: `/api/platform/v1/workflow/topics${toQueryString({
|
|
269
|
+
includeShared: typeof query.includeShared === "boolean"
|
|
270
|
+
? query.includeShared
|
|
271
|
+
? "true"
|
|
272
|
+
: "false"
|
|
273
|
+
: undefined,
|
|
274
|
+
limit: query.limit,
|
|
275
|
+
})}`,
|
|
276
|
+
}).then((response) => mapGatewayData(response, (data) => {
|
|
277
|
+
const items = asListItems(data, "topics").map((item) => withTopicAlias(item));
|
|
278
|
+
const record = data && typeof data === "object"
|
|
279
|
+
? data
|
|
280
|
+
: {};
|
|
281
|
+
return {
|
|
282
|
+
...record,
|
|
283
|
+
...createListResult(items, "topics"),
|
|
284
|
+
total: typeof record.total === "number" ? record.total : items.length,
|
|
285
|
+
};
|
|
286
|
+
}));
|
|
287
|
+
},
|
|
288
|
+
/**
|
|
289
|
+
* Switch the active context by topic or project name.
|
|
290
|
+
*/
|
|
291
|
+
async switchTopicContext(input, idempotencyKey) {
|
|
292
|
+
return gateway.request({
|
|
293
|
+
path: "/api/platform/v1/workflow/topics/switch",
|
|
294
|
+
method: "POST",
|
|
295
|
+
body: {
|
|
296
|
+
targetTopicName: input.targetTopicName,
|
|
297
|
+
},
|
|
298
|
+
idempotencyKey: idempotencyKey ?? randomIdempotencyKey(),
|
|
299
|
+
}).then((response) => mapGatewayData(response, (data) => withTopicAlias(data)));
|
|
300
|
+
},
|
|
301
|
+
/**
|
|
302
|
+
* Create a workflow task.
|
|
303
|
+
*/
|
|
304
|
+
async createTask(input, idempotencyKey) {
|
|
305
|
+
return gateway.request({
|
|
306
|
+
path: "/api/platform/v1/workflow/tasks",
|
|
307
|
+
method: "POST",
|
|
308
|
+
body: normalizeTopicQuery(input),
|
|
309
|
+
idempotencyKey: idempotencyKey ?? randomIdempotencyKey(),
|
|
310
|
+
});
|
|
311
|
+
},
|
|
312
|
+
/**
|
|
313
|
+
* Complete a workflow task.
|
|
314
|
+
*/
|
|
315
|
+
async completeTask(taskId, input, idempotencyKey) {
|
|
316
|
+
return gateway.request({
|
|
317
|
+
path: `/api/platform/v1/workflow/tasks/${encodeURIComponent(taskId)}/complete`,
|
|
318
|
+
method: "POST",
|
|
319
|
+
body: input,
|
|
320
|
+
idempotencyKey: idempotencyKey ?? randomIdempotencyKey(),
|
|
321
|
+
});
|
|
322
|
+
},
|
|
323
|
+
/**
|
|
324
|
+
* Update a workflow task.
|
|
325
|
+
*/
|
|
326
|
+
async updateTask(taskId, input, idempotencyKey) {
|
|
327
|
+
return gateway.request({
|
|
328
|
+
path: `/api/platform/v1/workflow/tasks/${encodeURIComponent(taskId)}`,
|
|
329
|
+
method: "PATCH",
|
|
330
|
+
body: input,
|
|
331
|
+
idempotencyKey: idempotencyKey ?? randomIdempotencyKey(),
|
|
332
|
+
});
|
|
333
|
+
},
|
|
334
|
+
/**
|
|
335
|
+
* @deprecated Use createBranch.
|
|
336
|
+
*/
|
|
337
|
+
async createPillar(input, idempotencyKey) {
|
|
338
|
+
return client.createBranch(input, idempotencyKey);
|
|
339
|
+
},
|
|
340
|
+
/**
|
|
341
|
+
* @deprecated Use addWorktree.
|
|
342
|
+
*/
|
|
343
|
+
async createSprint(input, idempotencyKey) {
|
|
344
|
+
return client.createWorktree(input, idempotencyKey);
|
|
345
|
+
},
|
|
346
|
+
/**
|
|
347
|
+
* @deprecated Use merge.
|
|
348
|
+
*/
|
|
349
|
+
async completeSprint(worktreeId, input, idempotencyKey) {
|
|
350
|
+
return client.merge(worktreeId, input, idempotencyKey);
|
|
351
|
+
},
|
|
352
|
+
/**
|
|
353
|
+
* @deprecated Use openPullRequest.
|
|
354
|
+
*/
|
|
355
|
+
async requestReview(worktreeId, input, idempotencyKey) {
|
|
356
|
+
return client.openPullRequest(worktreeId, input, idempotencyKey);
|
|
357
|
+
},
|
|
358
|
+
/**
|
|
359
|
+
* @deprecated Use push.
|
|
360
|
+
*/
|
|
361
|
+
async publishFindings(worktreeId, input, idempotencyKey) {
|
|
362
|
+
return client.push(worktreeId, input, idempotencyKey);
|
|
363
|
+
},
|
|
364
|
+
};
|
|
365
|
+
return client;
|
|
366
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API Enum Contract Definitions
|
|
3
|
+
*
|
|
4
|
+
* Canonical enum values for all API-facing enumerations.
|
|
5
|
+
* These are co-equal with MCP contracts as external contracts.
|
|
6
|
+
* SDK types are DERIVED from these — not independently authored.
|
|
7
|
+
*
|
|
8
|
+
* CONTRACT SURFACE: Adding a new enum value is additive (non-breaking).
|
|
9
|
+
* Removing or renaming an existing value is a BREAKING CHANGE.
|
|
10
|
+
*/
|
|
11
|
+
/** Fork reasons — why a scored belief was branched */
|
|
12
|
+
export declare const FORK_REASONS: readonly ["refinement", "contradiction_response", "scope_change", "confidence_collapse", "manual"];
|
|
13
|
+
export type ForkReason = (typeof FORK_REASONS)[number];
|
|
14
|
+
/** Confidence modulation triggers — what caused a confidence change */
|
|
15
|
+
export declare const CONFIDENCE_TRIGGERS: readonly ["evidence_added", "contradiction_detected", "merge_outcome", "manual", "decay"];
|
|
16
|
+
export type ConfidenceTrigger = (typeof CONFIDENCE_TRIGGERS)[number];
|
|
17
|
+
/** Belief status — lifecycle state */
|
|
18
|
+
export declare const BELIEF_STATUSES: readonly ["unscored", "scored", "archived"];
|
|
19
|
+
export type BeliefStatus = (typeof BELIEF_STATUSES)[number];
|
|
20
|
+
/** Reasoning methods — how an edge relationship was determined */
|
|
21
|
+
export declare const REASONING_METHODS: readonly ["deductive", "inductive", "abductive", "analogical", "empirical"];
|
|
22
|
+
export type ReasoningMethod = (typeof REASONING_METHODS)[number];
|
|
23
|
+
/** Defeat types (Pollock taxonomy) — how a contradiction operates */
|
|
24
|
+
export declare const DEFEAT_TYPES: readonly ["rebuts", "undercuts", "undermines"];
|
|
25
|
+
export type DefeatType = (typeof DEFEAT_TYPES)[number];
|
|
26
|
+
/** Contradiction severity levels */
|
|
27
|
+
export declare const CONTRADICTION_SEVERITIES: readonly ["low", "medium", "high", "critical"];
|
|
28
|
+
export type ContradictionSeverity = (typeof CONTRADICTION_SEVERITIES)[number];
|
|
29
|
+
/** Contradiction resolution status */
|
|
30
|
+
export declare const CONTRADICTION_STATUSES: readonly ["unresolved", "resolved", "accepted"];
|
|
31
|
+
export type ContradictionStatus = (typeof CONTRADICTION_STATUSES)[number];
|
|
32
|
+
/** Merge outcome types — how a worktree merge resolved */
|
|
33
|
+
export declare const MERGE_OUTCOMES: readonly ["validated", "invalidated", "forked", "inconclusive"];
|
|
34
|
+
export type MergeOutcome = (typeof MERGE_OUTCOMES)[number];
|
|
35
|
+
/** Worktree phases — investigation lifecycle within a checked-out worktree */
|
|
36
|
+
export declare const WORKTREE_PHASES: readonly ["hypothesis", "investigation", "evaluation", "resolution"];
|
|
37
|
+
export type WorktreePhase = (typeof WORKTREE_PHASES)[number];
|
|
38
|
+
/** Branch status — thematic branch lifecycle */
|
|
39
|
+
export declare const BRANCH_STATUSES: readonly ["dormant", "active", "archived"];
|
|
40
|
+
export type BranchStatus = (typeof BRANCH_STATUSES)[number];
|
|
41
|
+
/** Pull request status — review lifecycle before merge */
|
|
42
|
+
export declare const PULL_REQUEST_STATUSES: readonly ["pending_review", "changes_requested", "approved", "blocked"];
|
|
43
|
+
export type PullRequestStatus = (typeof PULL_REQUEST_STATUSES)[number];
|
|
44
|
+
/** Epistemic layers — the hierarchy of knowledge */
|
|
45
|
+
export declare const EPISTEMIC_LAYERS: readonly ["L1", "L2", "L3", "L4"];
|
|
46
|
+
export type EpistemicLayer = (typeof EPISTEMIC_LAYERS)[number];
|
|
47
|
+
/**
|
|
48
|
+
* Judgment type — classification of the determination.
|
|
49
|
+
*
|
|
50
|
+
* Phase 1: These are new enum values for the Judgment (L4) vocabulary.
|
|
51
|
+
* The existing code uses "Decision" — these are the forward-looking terms
|
|
52
|
+
* that will eventually replace the Decision vocabulary (Phase 2-3).
|
|
53
|
+
*/
|
|
54
|
+
export declare const JUDGMENT_TYPES: readonly ["investment_thesis", "thesis_maturity", "contradiction_ruling", "scope_determination", "confidence_ruling"];
|
|
55
|
+
export type JudgmentType = (typeof JUDGMENT_TYPES)[number];
|
|
56
|
+
/** Core edge types used in the Integration Surfaces */
|
|
57
|
+
export declare const INTEGRATION_EDGE_TYPES: readonly ["informs", "grounds", "answers", "contradicts", "supports", "depends_on", "derived_from", "contains", "supersedes", "tests"];
|
|
58
|
+
export type IntegrationEdgeType = (typeof INTEGRATION_EDGE_TYPES)[number];
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API Enum Contract Definitions
|
|
3
|
+
*
|
|
4
|
+
* Canonical enum values for all API-facing enumerations.
|
|
5
|
+
* These are co-equal with MCP contracts as external contracts.
|
|
6
|
+
* SDK types are DERIVED from these — not independently authored.
|
|
7
|
+
*
|
|
8
|
+
* CONTRACT SURFACE: Adding a new enum value is additive (non-breaking).
|
|
9
|
+
* Removing or renaming an existing value is a BREAKING CHANGE.
|
|
10
|
+
*/
|
|
11
|
+
// =============================================================================
|
|
12
|
+
// BELIEF ENUMS
|
|
13
|
+
// =============================================================================
|
|
14
|
+
/** Fork reasons — why a scored belief was branched */
|
|
15
|
+
export const FORK_REASONS = [
|
|
16
|
+
"refinement", // Belief text evolved based on new understanding
|
|
17
|
+
"contradiction_response", // Created in response to a detected contradiction
|
|
18
|
+
"scope_change", // Belief scope narrowed or broadened
|
|
19
|
+
"confidence_collapse", // Confidence dropped below viability threshold
|
|
20
|
+
"manual", // User-initiated fork without specific trigger
|
|
21
|
+
];
|
|
22
|
+
/** Confidence modulation triggers — what caused a confidence change */
|
|
23
|
+
export const CONFIDENCE_TRIGGERS = [
|
|
24
|
+
"evidence_added", // New evidence bore on the belief
|
|
25
|
+
"contradiction_detected", // A contradiction was flagged involving this belief
|
|
26
|
+
"merge_outcome", // Merge scoring determined this confidence
|
|
27
|
+
"manual", // User manually adjusted confidence
|
|
28
|
+
"decay", // Time-based confidence erosion
|
|
29
|
+
];
|
|
30
|
+
/** Belief status — lifecycle state */
|
|
31
|
+
export const BELIEF_STATUSES = [
|
|
32
|
+
"unscored", // Draft — editable in worktree (on feature branch, pre-merge)
|
|
33
|
+
"scored", // Merged — formulation frozen (merged to main)
|
|
34
|
+
"archived", // Soft-deleted — preserved in history (git rm)
|
|
35
|
+
];
|
|
36
|
+
// =============================================================================
|
|
37
|
+
// EDGE ENUMS
|
|
38
|
+
// =============================================================================
|
|
39
|
+
/** Reasoning methods — how an edge relationship was determined */
|
|
40
|
+
export const REASONING_METHODS = [
|
|
41
|
+
"deductive", // Logically entailed
|
|
42
|
+
"inductive", // Generalized from instances
|
|
43
|
+
"abductive", // Best explanation inference
|
|
44
|
+
"analogical", // Reasoning by analogy
|
|
45
|
+
"empirical", // Direct observation/measurement
|
|
46
|
+
];
|
|
47
|
+
/** Defeat types (Pollock taxonomy) — how a contradiction operates */
|
|
48
|
+
export const DEFEAT_TYPES = [
|
|
49
|
+
"rebuts", // Direct contradiction — reasons for the negation
|
|
50
|
+
"undercuts", // Breaks the inference link between evidence and belief
|
|
51
|
+
"undermines", // Attacks a premise the belief depends on
|
|
52
|
+
];
|
|
53
|
+
/** Contradiction severity levels */
|
|
54
|
+
export const CONTRADICTION_SEVERITIES = [
|
|
55
|
+
"low", // Minor tension, may not require action
|
|
56
|
+
"medium", // Moderate conflict, should be investigated
|
|
57
|
+
"high", // Significant contradiction, likely needs resolution
|
|
58
|
+
"critical", // Blocks progress — must be addressed before judgment
|
|
59
|
+
];
|
|
60
|
+
/** Contradiction resolution status */
|
|
61
|
+
export const CONTRADICTION_STATUSES = [
|
|
62
|
+
"unresolved", // Open conflict — may persist indefinitely
|
|
63
|
+
"resolved", // Conflict addressed (one belief forked, archived, or confidence adjusted)
|
|
64
|
+
"accepted", // Explicitly accepted as irreconcilable — both beliefs maintained
|
|
65
|
+
];
|
|
66
|
+
// =============================================================================
|
|
67
|
+
// WORKTREE ENUMS (git worktree lifecycle)
|
|
68
|
+
// =============================================================================
|
|
69
|
+
/** Merge outcome types — how a worktree merge resolved */
|
|
70
|
+
export const MERGE_OUTCOMES = [
|
|
71
|
+
"validated", // Beliefs confirmed — clean merge to main
|
|
72
|
+
"invalidated", // Defeat recorded — confidence collapsed (merge with revert)
|
|
73
|
+
"forked", // Beliefs split into competing versions (fork from merge point)
|
|
74
|
+
"inconclusive", // Insufficient evidence — stashed (git stash)
|
|
75
|
+
];
|
|
76
|
+
/** Worktree phases — investigation lifecycle within a checked-out worktree */
|
|
77
|
+
export const WORKTREE_PHASES = [
|
|
78
|
+
"hypothesis", // Form testable claims (write the code — commits)
|
|
79
|
+
"investigation", // Collect evidence (run the tests — more commits)
|
|
80
|
+
"evaluation", // Update credences (review the results — amend as needed)
|
|
81
|
+
"resolution", // Determine outcome (merge to main, fork, or stash)
|
|
82
|
+
];
|
|
83
|
+
// =============================================================================
|
|
84
|
+
// BRANCH ENUMS (git branch lifecycle)
|
|
85
|
+
// =============================================================================
|
|
86
|
+
/** Branch status — thematic branch lifecycle */
|
|
87
|
+
export const BRANCH_STATUSES = [
|
|
88
|
+
"dormant", // Branch exists but no active worktree (no one investigating)
|
|
89
|
+
"active", // At least one worktree is investigating this branch
|
|
90
|
+
"archived", // Branch retired — no longer a relevant thematic container
|
|
91
|
+
];
|
|
92
|
+
// =============================================================================
|
|
93
|
+
// PULL REQUEST ENUMS (git pull request lifecycle)
|
|
94
|
+
// =============================================================================
|
|
95
|
+
/** Pull request status — review lifecycle before merge */
|
|
96
|
+
export const PULL_REQUEST_STATUSES = [
|
|
97
|
+
"pending_review", // PR opened — awaiting reviewer feedback
|
|
98
|
+
"changes_requested", // Reviewer requests changes before merge
|
|
99
|
+
"approved", // Approved — ready to merge
|
|
100
|
+
"blocked", // Blocked — cannot merge until contradiction is resolved
|
|
101
|
+
];
|
|
102
|
+
// =============================================================================
|
|
103
|
+
// LAYER ENUMS
|
|
104
|
+
// =============================================================================
|
|
105
|
+
/** Epistemic layers — the hierarchy of knowledge */
|
|
106
|
+
export const EPISTEMIC_LAYERS = [
|
|
107
|
+
"L1", // Source — the given (vendored deps)
|
|
108
|
+
"L2", // Evidence — the interpreted (test suite)
|
|
109
|
+
"L3", // Belief — the structural (source files)
|
|
110
|
+
"L4", // Judgment — the committed (release tags)
|
|
111
|
+
];
|
|
112
|
+
// =============================================================================
|
|
113
|
+
// JUDGMENT ENUMS (Phase 1: new vocabulary)
|
|
114
|
+
// =============================================================================
|
|
115
|
+
/**
|
|
116
|
+
* Judgment type — classification of the determination.
|
|
117
|
+
*
|
|
118
|
+
* Phase 1: These are new enum values for the Judgment (L4) vocabulary.
|
|
119
|
+
* The existing code uses "Decision" — these are the forward-looking terms
|
|
120
|
+
* that will eventually replace the Decision vocabulary (Phase 2-3).
|
|
121
|
+
*/
|
|
122
|
+
export const JUDGMENT_TYPES = [
|
|
123
|
+
"investment_thesis", // Judgment on an investment opportunity
|
|
124
|
+
"thesis_maturity", // Judgment that a thesis is ready for IC presentation
|
|
125
|
+
"contradiction_ruling", // Judgment on how to handle an irreconcilable contradiction
|
|
126
|
+
"scope_determination", // Judgment that defines or redefines investigation scope
|
|
127
|
+
"confidence_ruling", // Judgment that overrides automated confidence for policy reasons
|
|
128
|
+
];
|
|
129
|
+
// =============================================================================
|
|
130
|
+
// SUPPORT RELATION ENUMS
|
|
131
|
+
// =============================================================================
|
|
132
|
+
/** Core edge types used in the Integration Surfaces */
|
|
133
|
+
export const INTEGRATION_EDGE_TYPES = [
|
|
134
|
+
// Support relations
|
|
135
|
+
"informs", // Evidence bears on a belief (weight = direction/strength)
|
|
136
|
+
"grounds", // Source provides raw basis for evidence
|
|
137
|
+
"answers", // Evidence or belief resolves a question
|
|
138
|
+
// Defeat relations (Pollock) — weight carries direction
|
|
139
|
+
"contradicts", // Rebuts — direct contradiction
|
|
140
|
+
"supports", // Weight carries valence (negative = weakens/undercuts)
|
|
141
|
+
// Structural relations
|
|
142
|
+
"depends_on", // Belief B requires Belief A
|
|
143
|
+
"derived_from", // Provenance lineage
|
|
144
|
+
"contains", // Hierarchical containment
|
|
145
|
+
"supersedes", // New version replaces old (lineage)
|
|
146
|
+
"tests", // Question tests a belief
|
|
147
|
+
];
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lens Filter Criteria Contract
|
|
3
|
+
*
|
|
4
|
+
* Version-discriminated filter DSL for lenses. Each filter criteria document
|
|
5
|
+
* carries a `version` and `kind` discriminator so future shapes can coexist
|
|
6
|
+
* without schema migrations. The Convex `filterCriteria` field remains v.any()
|
|
7
|
+
* — all type enforcement happens here at the TypeScript contract layer.
|
|
8
|
+
*
|
|
9
|
+
* Forward-compatibility guarantees:
|
|
10
|
+
* - `version` field: new versions add fields, never remove or rename existing ones
|
|
11
|
+
* - `kind` field: new filter kinds (temporal, confidence-range) can be added
|
|
12
|
+
* without touching taxonomy code paths
|
|
13
|
+
* - `entityTypeFilters` array items are open to extension in future versions
|
|
14
|
+
* - Resolution logic switches on `version` + `kind` to select the right resolver
|
|
15
|
+
*
|
|
16
|
+
* @module lucern/contracts/src/lens-filter
|
|
17
|
+
*/
|
|
18
|
+
// Future: | TemporalFilterCriteriaV1 | ConfidenceRangeFilterCriteriaV1 | ...
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
// Type guards
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
export function isLensFilterCriteria(value) {
|
|
23
|
+
if (!value || typeof value !== "object")
|
|
24
|
+
return false;
|
|
25
|
+
const obj = value;
|
|
26
|
+
return typeof obj.version === "number" && typeof obj.kind === "string";
|
|
27
|
+
}
|
|
28
|
+
export function isTaxonomyFilterCriteriaV1(value) {
|
|
29
|
+
if (!isLensFilterCriteria(value))
|
|
30
|
+
return false;
|
|
31
|
+
return value.version === 1 && value.kind === "taxonomy";
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Validate a filter criteria document at the contract layer.
|
|
35
|
+
* This runs before persisting to Convex.
|
|
36
|
+
*/
|
|
37
|
+
export function validateFilterCriteria(value) {
|
|
38
|
+
if (value === undefined || value === null) {
|
|
39
|
+
return { valid: true }; // filterCriteria is optional
|
|
40
|
+
}
|
|
41
|
+
if (!isLensFilterCriteria(value)) {
|
|
42
|
+
return {
|
|
43
|
+
valid: false,
|
|
44
|
+
errors: [
|
|
45
|
+
'filterCriteria must have numeric "version" and string "kind" fields',
|
|
46
|
+
],
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
if (isTaxonomyFilterCriteriaV1(value)) {
|
|
50
|
+
return validateTaxonomyFilterV1(value);
|
|
51
|
+
}
|
|
52
|
+
// Cast to access properties — TypeScript narrows to `never` when all union
|
|
53
|
+
// members are exhausted, but at runtime unknown version/kind combos are possible.
|
|
54
|
+
const raw = value;
|
|
55
|
+
return {
|
|
56
|
+
valid: false,
|
|
57
|
+
errors: [
|
|
58
|
+
`Unsupported filter criteria: version=${raw.version}, kind=${raw.kind}`,
|
|
59
|
+
],
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
function validateTaxonomyFilterV1(criteria) {
|
|
63
|
+
const errors = [];
|
|
64
|
+
if (!Array.isArray(criteria.entityTypeFilters)) {
|
|
65
|
+
errors.push("entityTypeFilters must be an array");
|
|
66
|
+
return { valid: false, errors };
|
|
67
|
+
}
|
|
68
|
+
if (criteria.entityTypeFilters.length === 0) {
|
|
69
|
+
errors.push("entityTypeFilters must contain at least one entry");
|
|
70
|
+
return { valid: false, errors };
|
|
71
|
+
}
|
|
72
|
+
for (let i = 0; i < criteria.entityTypeFilters.length; i++) {
|
|
73
|
+
const filter = criteria.entityTypeFilters[i];
|
|
74
|
+
if (!filter || typeof filter.entityTypeValue !== "string") {
|
|
75
|
+
errors.push(`entityTypeFilters[${i}].entityTypeValue must be a non-empty string`);
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
if (filter.entityTypeValue.trim().length === 0) {
|
|
79
|
+
errors.push(`entityTypeFilters[${i}].entityTypeValue must be a non-empty string`);
|
|
80
|
+
}
|
|
81
|
+
if (filter.subtypeValues !== undefined &&
|
|
82
|
+
!Array.isArray(filter.subtypeValues)) {
|
|
83
|
+
errors.push(`entityTypeFilters[${i}].subtypeValues must be an array`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
if (criteria.ontologyScope !== undefined) {
|
|
87
|
+
if (typeof criteria.ontologyScope !== "object" ||
|
|
88
|
+
criteria.ontologyScope === null) {
|
|
89
|
+
errors.push("ontologyScope must be an object");
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return errors.length === 0
|
|
93
|
+
? { valid: true }
|
|
94
|
+
: { valid: false, errors };
|
|
95
|
+
}
|