tana-mcp-codemode 0.1.0
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 +344 -0
- package/package.json +54 -0
- package/src/api/client.ts +243 -0
- package/src/api/tana.ts +332 -0
- package/src/api/types.ts +207 -0
- package/src/generated/api.d.ts +1425 -0
- package/src/index.ts +90 -0
- package/src/prompts.ts +81 -0
- package/src/sandbox/executor.ts +270 -0
- package/src/sandbox/stdin.ts +69 -0
- package/src/sandbox/workflow.ts +197 -0
- package/src/storage/history.ts +202 -0
- package/src/types.ts +32 -0
package/src/api/tana.ts
ADDED
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tana API Wrapper
|
|
3
|
+
*
|
|
4
|
+
* Creates the `tana` object that gets injected into the sandbox.
|
|
5
|
+
* Maps high-level operations to Tana Local API HTTP endpoints.
|
|
6
|
+
*
|
|
7
|
+
* Types are generated from the Tana Local API OpenAPI spec.
|
|
8
|
+
* Run `bun run generate` to regenerate types from api-1.json.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type { TanaClient } from "./client";
|
|
12
|
+
import type {
|
|
13
|
+
Workspace,
|
|
14
|
+
SearchQuery,
|
|
15
|
+
SearchOptions,
|
|
16
|
+
SearchResult,
|
|
17
|
+
Children,
|
|
18
|
+
EditNodeOptions,
|
|
19
|
+
Tag,
|
|
20
|
+
CreateTagOptions,
|
|
21
|
+
AddFieldOptions,
|
|
22
|
+
SetCheckboxOptions,
|
|
23
|
+
ImportResult,
|
|
24
|
+
} from "./types";
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* TanaAPI Interface
|
|
28
|
+
*
|
|
29
|
+
* The main interface exposed to sandbox code as the `tana` object.
|
|
30
|
+
* Provides high-level methods organized by domain (workspaces, nodes, tags, etc.)
|
|
31
|
+
*/
|
|
32
|
+
export interface TanaAPI {
|
|
33
|
+
/** Check API health */
|
|
34
|
+
health(): Promise<{ status: string; timestamp: string; nodeSpaceReady: boolean }>;
|
|
35
|
+
|
|
36
|
+
workspaces: {
|
|
37
|
+
/** List available workspaces */
|
|
38
|
+
list(): Promise<Workspace[]>;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
nodes: {
|
|
42
|
+
/** Search for nodes */
|
|
43
|
+
search(query: SearchQuery, options?: SearchOptions): Promise<SearchResult[]>;
|
|
44
|
+
/** Read a node as markdown */
|
|
45
|
+
read(nodeId: string, maxDepth?: number): Promise<string>;
|
|
46
|
+
/** Get children of a node */
|
|
47
|
+
getChildren(
|
|
48
|
+
nodeId: string,
|
|
49
|
+
options?: { limit?: number; offset?: number }
|
|
50
|
+
): Promise<Children>;
|
|
51
|
+
/** Edit a node's name/description */
|
|
52
|
+
edit(options: EditNodeOptions): Promise<{ success: boolean }>;
|
|
53
|
+
/** Move node to trash */
|
|
54
|
+
trash(nodeId: string): Promise<{ success: boolean }>;
|
|
55
|
+
/** Check a node's checkbox */
|
|
56
|
+
check(nodeId: string): Promise<{ success: boolean }>;
|
|
57
|
+
/** Uncheck a node's checkbox */
|
|
58
|
+
uncheck(nodeId: string): Promise<{ success: boolean }>;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
tags: {
|
|
62
|
+
/** List tags in a workspace */
|
|
63
|
+
list(workspaceId: string, limit?: number): Promise<Tag[]>;
|
|
64
|
+
/** Get tag schema */
|
|
65
|
+
getSchema(tagId: string, includeEditInstructions?: boolean): Promise<string>;
|
|
66
|
+
/** Add/remove tags from a node */
|
|
67
|
+
modify(
|
|
68
|
+
nodeId: string,
|
|
69
|
+
action: "add" | "remove",
|
|
70
|
+
tagIds: string[]
|
|
71
|
+
): Promise<{ success: boolean }>;
|
|
72
|
+
/** Create a new tag */
|
|
73
|
+
create(options: CreateTagOptions): Promise<{ tagId: string }>;
|
|
74
|
+
/** Add a field to a tag */
|
|
75
|
+
addField(options: AddFieldOptions): Promise<{ fieldId: string }>;
|
|
76
|
+
/** Configure tag checkbox */
|
|
77
|
+
setCheckbox(options: SetCheckboxOptions): Promise<{ success: boolean }>;
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
fields: {
|
|
81
|
+
/** Set a field to an option value */
|
|
82
|
+
setOption(
|
|
83
|
+
nodeId: string,
|
|
84
|
+
attributeId: string,
|
|
85
|
+
optionId: string
|
|
86
|
+
): Promise<{ success: boolean }>;
|
|
87
|
+
/** Set a field to a string value */
|
|
88
|
+
setContent(
|
|
89
|
+
nodeId: string,
|
|
90
|
+
attributeId: string,
|
|
91
|
+
content: string
|
|
92
|
+
): Promise<{ success: boolean }>;
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
calendar: {
|
|
96
|
+
/** Get or create a calendar node */
|
|
97
|
+
getOrCreate(
|
|
98
|
+
workspaceId: string,
|
|
99
|
+
granularity: "day" | "week" | "month" | "year",
|
|
100
|
+
date?: string
|
|
101
|
+
): Promise<{ nodeId: string }>;
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
/** Import Tana Paste formatted content */
|
|
105
|
+
import(parentNodeId: string, content: string): Promise<ImportResult>;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export function createTanaAPI(client: TanaClient): TanaAPI {
|
|
109
|
+
return {
|
|
110
|
+
async health() {
|
|
111
|
+
return client.get<{ status: string; timestamp: string; nodeSpaceReady: boolean }>("/health");
|
|
112
|
+
},
|
|
113
|
+
|
|
114
|
+
workspaces: {
|
|
115
|
+
async list(): Promise<Workspace[]> {
|
|
116
|
+
return client.get<Workspace[]>("/workspaces");
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
|
|
120
|
+
nodes: {
|
|
121
|
+
async search(
|
|
122
|
+
query: SearchQuery,
|
|
123
|
+
options?: SearchOptions
|
|
124
|
+
): Promise<SearchResult[]> {
|
|
125
|
+
// Build deep object query params (style: deepObject, explode: true)
|
|
126
|
+
const params: string[] = [];
|
|
127
|
+
|
|
128
|
+
function addQueryParams(obj: Record<string, unknown>, prefix: string) {
|
|
129
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
130
|
+
const paramKey = prefix ? `${prefix}[${key}]` : key;
|
|
131
|
+
if (value === null || value === undefined) continue;
|
|
132
|
+
if (typeof value === "object" && !Array.isArray(value)) {
|
|
133
|
+
addQueryParams(value as Record<string, unknown>, paramKey);
|
|
134
|
+
} else if (Array.isArray(value)) {
|
|
135
|
+
value.forEach((item, i) => {
|
|
136
|
+
if (typeof item === "object") {
|
|
137
|
+
addQueryParams(item as Record<string, unknown>, `${paramKey}[${i}]`);
|
|
138
|
+
} else {
|
|
139
|
+
params.push(`${encodeURIComponent(`${paramKey}[${i}]`)}=${encodeURIComponent(String(item))}`);
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
} else {
|
|
143
|
+
params.push(`${encodeURIComponent(paramKey)}=${encodeURIComponent(String(value))}`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
addQueryParams(query as unknown as Record<string, unknown>, "query");
|
|
149
|
+
if (options?.limit) params.push(`limit=${options.limit}`);
|
|
150
|
+
if (options?.workspaceIds) {
|
|
151
|
+
options.workspaceIds.forEach((id, i) => {
|
|
152
|
+
params.push(`workspaceIds[${i}]=${encodeURIComponent(id)}`);
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return client.get<SearchResult[]>(`/nodes/search?${params.join("&")}`);
|
|
157
|
+
},
|
|
158
|
+
|
|
159
|
+
async read(nodeId: string, maxDepth = 1): Promise<string> {
|
|
160
|
+
const result = await client.get<{ markdown: string; name?: string; description?: string }>(
|
|
161
|
+
`/nodes/${nodeId}?maxDepth=${maxDepth}`
|
|
162
|
+
);
|
|
163
|
+
return result.markdown;
|
|
164
|
+
},
|
|
165
|
+
|
|
166
|
+
async getChildren(
|
|
167
|
+
nodeId: string,
|
|
168
|
+
options?: { limit?: number; offset?: number }
|
|
169
|
+
): Promise<Children> {
|
|
170
|
+
const params = new URLSearchParams();
|
|
171
|
+
if (options?.limit) params.set("limit", String(options.limit));
|
|
172
|
+
if (options?.offset) params.set("offset", String(options.offset));
|
|
173
|
+
const query = params.toString();
|
|
174
|
+
return client.get<Children>(
|
|
175
|
+
`/nodes/${nodeId}/children${query ? `?${query}` : ""}`
|
|
176
|
+
);
|
|
177
|
+
},
|
|
178
|
+
|
|
179
|
+
async edit(options: EditNodeOptions): Promise<{ success: boolean }> {
|
|
180
|
+
const result = await client.post<{ nodeId: string; message: string }>(
|
|
181
|
+
`/nodes/${options.nodeId}/update`,
|
|
182
|
+
{
|
|
183
|
+
name: options.name,
|
|
184
|
+
description: options.description,
|
|
185
|
+
}
|
|
186
|
+
);
|
|
187
|
+
return { success: !!result.nodeId };
|
|
188
|
+
},
|
|
189
|
+
|
|
190
|
+
async trash(nodeId: string): Promise<{ success: boolean }> {
|
|
191
|
+
const result = await client.post<{ nodeId: string; message: string }>(
|
|
192
|
+
`/nodes/${nodeId}/trash`,
|
|
193
|
+
{}
|
|
194
|
+
);
|
|
195
|
+
return { success: !!result.nodeId };
|
|
196
|
+
},
|
|
197
|
+
|
|
198
|
+
async check(nodeId: string): Promise<{ success: boolean }> {
|
|
199
|
+
const result = await client.post<{ nodeId: string; done: boolean; message: string }>(
|
|
200
|
+
`/nodes/${nodeId}/done`,
|
|
201
|
+
{ done: true }
|
|
202
|
+
);
|
|
203
|
+
return { success: result.done === true };
|
|
204
|
+
},
|
|
205
|
+
|
|
206
|
+
async uncheck(nodeId: string): Promise<{ success: boolean }> {
|
|
207
|
+
const result = await client.post<{ nodeId: string; done: boolean; message: string }>(
|
|
208
|
+
`/nodes/${nodeId}/done`,
|
|
209
|
+
{ done: false }
|
|
210
|
+
);
|
|
211
|
+
return { success: result.done === false };
|
|
212
|
+
},
|
|
213
|
+
},
|
|
214
|
+
|
|
215
|
+
tags: {
|
|
216
|
+
async list(workspaceId: string, limit = 50): Promise<Tag[]> {
|
|
217
|
+
return client.get<Tag[]>(
|
|
218
|
+
`/workspaces/${workspaceId}/tags?limit=${limit}`
|
|
219
|
+
);
|
|
220
|
+
},
|
|
221
|
+
|
|
222
|
+
async getSchema(
|
|
223
|
+
tagId: string,
|
|
224
|
+
includeEditInstructions = false
|
|
225
|
+
): Promise<string> {
|
|
226
|
+
const result = await client.get<{ markdown: string }>(
|
|
227
|
+
`/tags/${tagId}/schema?includeEditInstructions=${includeEditInstructions}`
|
|
228
|
+
);
|
|
229
|
+
return result.markdown;
|
|
230
|
+
},
|
|
231
|
+
|
|
232
|
+
async modify(
|
|
233
|
+
nodeId: string,
|
|
234
|
+
action: "add" | "remove",
|
|
235
|
+
tagIds: string[]
|
|
236
|
+
): Promise<{ success: boolean }> {
|
|
237
|
+
const result = await client.post<{ nodeId: string; action: string; results: unknown[] }>(
|
|
238
|
+
`/nodes/${nodeId}/tags`,
|
|
239
|
+
{ action, tagIds }
|
|
240
|
+
);
|
|
241
|
+
return { success: !!result.nodeId };
|
|
242
|
+
},
|
|
243
|
+
|
|
244
|
+
async create(options: CreateTagOptions): Promise<{ tagId: string }> {
|
|
245
|
+
return client.post<{ tagId: string }>(
|
|
246
|
+
`/workspaces/${options.workspaceId}/tags`,
|
|
247
|
+
{
|
|
248
|
+
name: options.name,
|
|
249
|
+
description: options.description,
|
|
250
|
+
extendsTagIds: options.extendsTagIds,
|
|
251
|
+
showCheckbox: options.showCheckbox,
|
|
252
|
+
}
|
|
253
|
+
);
|
|
254
|
+
},
|
|
255
|
+
|
|
256
|
+
async addField(options: AddFieldOptions): Promise<{ fieldId: string }> {
|
|
257
|
+
return client.post<{ fieldId: string }>(
|
|
258
|
+
`/tags/${options.tagId}/fields`,
|
|
259
|
+
{
|
|
260
|
+
name: options.name,
|
|
261
|
+
dataType: options.dataType,
|
|
262
|
+
description: options.description,
|
|
263
|
+
sourceTagId: options.sourceTagId,
|
|
264
|
+
options: options.options,
|
|
265
|
+
defaultValue: options.defaultValue,
|
|
266
|
+
isMultiValue: options.isMultiValue,
|
|
267
|
+
}
|
|
268
|
+
);
|
|
269
|
+
},
|
|
270
|
+
|
|
271
|
+
async setCheckbox(
|
|
272
|
+
options: SetCheckboxOptions
|
|
273
|
+
): Promise<{ success: boolean }> {
|
|
274
|
+
const result = await client.post<{ tagId: string; showCheckbox: boolean; message: string }>(
|
|
275
|
+
`/tags/${options.tagId}/checkbox`,
|
|
276
|
+
{
|
|
277
|
+
showCheckbox: options.showCheckbox,
|
|
278
|
+
doneStateMapping: options.doneStateMapping,
|
|
279
|
+
}
|
|
280
|
+
);
|
|
281
|
+
return { success: !!result.tagId };
|
|
282
|
+
},
|
|
283
|
+
},
|
|
284
|
+
|
|
285
|
+
fields: {
|
|
286
|
+
async setOption(
|
|
287
|
+
nodeId: string,
|
|
288
|
+
attributeId: string,
|
|
289
|
+
optionId: string
|
|
290
|
+
): Promise<{ success: boolean }> {
|
|
291
|
+
const result = await client.post<{ nodeId: string; message: string }>(
|
|
292
|
+
`/nodes/${nodeId}/fields/${attributeId}/option`,
|
|
293
|
+
{ optionId }
|
|
294
|
+
);
|
|
295
|
+
return { success: !!result.nodeId };
|
|
296
|
+
},
|
|
297
|
+
|
|
298
|
+
async setContent(
|
|
299
|
+
nodeId: string,
|
|
300
|
+
attributeId: string,
|
|
301
|
+
content: string
|
|
302
|
+
): Promise<{ success: boolean }> {
|
|
303
|
+
const result = await client.post<{ nodeId: string; message: string }>(
|
|
304
|
+
`/nodes/${nodeId}/fields/${attributeId}/content`,
|
|
305
|
+
{ content }
|
|
306
|
+
);
|
|
307
|
+
return { success: !!result.nodeId };
|
|
308
|
+
},
|
|
309
|
+
},
|
|
310
|
+
|
|
311
|
+
calendar: {
|
|
312
|
+
async getOrCreate(
|
|
313
|
+
workspaceId: string,
|
|
314
|
+
granularity: "day" | "week" | "month" | "year",
|
|
315
|
+
date?: string
|
|
316
|
+
): Promise<{ nodeId: string }> {
|
|
317
|
+
const params = new URLSearchParams();
|
|
318
|
+
params.set("granularity", granularity);
|
|
319
|
+
if (date) params.set("date", date);
|
|
320
|
+
return client.get<{ nodeId: string }>(
|
|
321
|
+
`/workspaces/${workspaceId}/calendar/node?${params.toString()}`
|
|
322
|
+
);
|
|
323
|
+
},
|
|
324
|
+
},
|
|
325
|
+
|
|
326
|
+
async import(parentNodeId: string, content: string): Promise<ImportResult> {
|
|
327
|
+
return client.post<ImportResult>(`/nodes/${parentNodeId}/import`, {
|
|
328
|
+
content,
|
|
329
|
+
});
|
|
330
|
+
},
|
|
331
|
+
};
|
|
332
|
+
}
|
package/src/api/types.ts
ADDED
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API Types - Re-exports of generated OpenAPI types with friendly names
|
|
3
|
+
*
|
|
4
|
+
* These types are auto-generated from the Tana Local API OpenAPI spec.
|
|
5
|
+
* Run `bun run generate` to regenerate from api-1.json.
|
|
6
|
+
*
|
|
7
|
+
* @see ./generated/api.d.ts for the full generated types
|
|
8
|
+
*/
|
|
9
|
+
import type { operations } from "../generated/api";
|
|
10
|
+
|
|
11
|
+
// ============================================================================
|
|
12
|
+
// Response Types (extracted from operation responses)
|
|
13
|
+
// ============================================================================
|
|
14
|
+
|
|
15
|
+
/** Health check response */
|
|
16
|
+
export type HealthResponse =
|
|
17
|
+
operations["health.ping"]["responses"]["200"]["content"]["application/json"];
|
|
18
|
+
|
|
19
|
+
/** Workspace info */
|
|
20
|
+
export type Workspace =
|
|
21
|
+
operations["workspaces.list"]["responses"]["200"]["content"]["application/json"][number];
|
|
22
|
+
|
|
23
|
+
/** Search result node */
|
|
24
|
+
export type SearchResult =
|
|
25
|
+
operations["nodes.search"]["responses"]["200"]["content"]["application/json"][number];
|
|
26
|
+
|
|
27
|
+
/** Node read response (markdown content) */
|
|
28
|
+
export type NodeReadResponse =
|
|
29
|
+
operations["nodes.read"]["responses"]["200"]["content"]["application/json"];
|
|
30
|
+
|
|
31
|
+
/** Children list response */
|
|
32
|
+
export type Children =
|
|
33
|
+
operations["nodes.getChildren"]["responses"]["200"]["content"]["application/json"];
|
|
34
|
+
|
|
35
|
+
/** Child node in children response */
|
|
36
|
+
export type ChildNode = Children["children"][number];
|
|
37
|
+
|
|
38
|
+
/** Tag info */
|
|
39
|
+
export type Tag =
|
|
40
|
+
operations["tags.list"]["responses"]["200"]["content"]["application/json"][number];
|
|
41
|
+
|
|
42
|
+
/** Tag schema response (markdown) */
|
|
43
|
+
export type TagSchemaResponse =
|
|
44
|
+
operations["tags.getSchema"]["responses"]["200"]["content"]["application/json"];
|
|
45
|
+
|
|
46
|
+
/** Tag creation response */
|
|
47
|
+
export type CreateTagResponse =
|
|
48
|
+
operations["tags.create"]["responses"]["200"]["content"]["application/json"];
|
|
49
|
+
|
|
50
|
+
/** Add field response */
|
|
51
|
+
export type AddFieldResponse =
|
|
52
|
+
operations["tags.addField"]["responses"]["200"]["content"]["application/json"];
|
|
53
|
+
|
|
54
|
+
/** Set checkbox response */
|
|
55
|
+
export type SetCheckboxResponse =
|
|
56
|
+
operations["tags.setCheckbox"]["responses"]["200"]["content"]["application/json"];
|
|
57
|
+
|
|
58
|
+
/** Calendar node response */
|
|
59
|
+
export type CalendarNodeResponse =
|
|
60
|
+
operations["calendar.getNodeId"]["responses"]["200"]["content"]["application/json"];
|
|
61
|
+
|
|
62
|
+
/** Import response */
|
|
63
|
+
export type ImportResponse =
|
|
64
|
+
operations["nodes.importTanaPaste"]["responses"]["200"]["content"]["application/json"];
|
|
65
|
+
|
|
66
|
+
/** Tag modification response */
|
|
67
|
+
export type ModifyTagsResponse =
|
|
68
|
+
operations["nodes.updateTags"]["responses"]["200"]["content"]["application/json"];
|
|
69
|
+
|
|
70
|
+
/** Node update response */
|
|
71
|
+
export type NodeUpdateResponse =
|
|
72
|
+
operations["nodes.update"]["responses"]["200"]["content"]["application/json"];
|
|
73
|
+
|
|
74
|
+
/** Trash node response */
|
|
75
|
+
export type TrashNodeResponse =
|
|
76
|
+
operations["nodes.trash"]["responses"]["200"]["content"]["application/json"];
|
|
77
|
+
|
|
78
|
+
/** Set done response */
|
|
79
|
+
export type SetDoneResponse =
|
|
80
|
+
operations["nodes.setDone"]["responses"]["200"]["content"]["application/json"];
|
|
81
|
+
|
|
82
|
+
/** Set field option response */
|
|
83
|
+
export type SetFieldOptionResponse =
|
|
84
|
+
operations["nodes.setFieldOption"]["responses"]["200"]["content"]["application/json"];
|
|
85
|
+
|
|
86
|
+
/** Set field content response */
|
|
87
|
+
export type SetFieldContentResponse =
|
|
88
|
+
operations["nodes.setFieldContent"]["responses"]["200"]["content"]["application/json"];
|
|
89
|
+
|
|
90
|
+
// ============================================================================
|
|
91
|
+
// Request/Query Types (extracted from operation parameters)
|
|
92
|
+
// ============================================================================
|
|
93
|
+
|
|
94
|
+
/** Search query structure */
|
|
95
|
+
export type SearchQuery = NonNullable<
|
|
96
|
+
operations["nodes.search"]["parameters"]["query"]
|
|
97
|
+
>["query"];
|
|
98
|
+
|
|
99
|
+
/** Calendar granularity */
|
|
100
|
+
export type CalendarGranularity = NonNullable<
|
|
101
|
+
operations["calendar.getNodeId"]["parameters"]["query"]
|
|
102
|
+
>["granularity"];
|
|
103
|
+
|
|
104
|
+
/** Field data type */
|
|
105
|
+
export type FieldDataType = NonNullable<
|
|
106
|
+
operations["tags.addField"]["requestBody"]
|
|
107
|
+
>["content"]["application/json"]["dataType"];
|
|
108
|
+
|
|
109
|
+
// ============================================================================
|
|
110
|
+
// Request Body Types
|
|
111
|
+
// ============================================================================
|
|
112
|
+
|
|
113
|
+
/** Create tag request body */
|
|
114
|
+
export type CreateTagBody = NonNullable<
|
|
115
|
+
operations["tags.create"]["requestBody"]
|
|
116
|
+
>["content"]["application/json"];
|
|
117
|
+
|
|
118
|
+
/** Add field request body */
|
|
119
|
+
export type AddFieldBody = NonNullable<
|
|
120
|
+
operations["tags.addField"]["requestBody"]
|
|
121
|
+
>["content"]["application/json"];
|
|
122
|
+
|
|
123
|
+
/** Set checkbox request body */
|
|
124
|
+
export type SetCheckboxBody = NonNullable<
|
|
125
|
+
operations["tags.setCheckbox"]["requestBody"]
|
|
126
|
+
>["content"]["application/json"];
|
|
127
|
+
|
|
128
|
+
/** Update tags request body */
|
|
129
|
+
export type UpdateTagsBody = NonNullable<
|
|
130
|
+
operations["nodes.updateTags"]["requestBody"]
|
|
131
|
+
>["content"]["application/json"];
|
|
132
|
+
|
|
133
|
+
/** Node update request body */
|
|
134
|
+
export type NodeUpdateBody = NonNullable<
|
|
135
|
+
operations["nodes.update"]["requestBody"]
|
|
136
|
+
>["content"]["application/json"];
|
|
137
|
+
|
|
138
|
+
// ============================================================================
|
|
139
|
+
// Derived Helper Types (for ergonomic API usage)
|
|
140
|
+
// ============================================================================
|
|
141
|
+
|
|
142
|
+
/** Options for search */
|
|
143
|
+
export interface SearchOptions {
|
|
144
|
+
limit?: number;
|
|
145
|
+
workspaceIds?: string[];
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/** Options for creating a tag */
|
|
149
|
+
export interface CreateTagOptions {
|
|
150
|
+
workspaceId: string;
|
|
151
|
+
name: string;
|
|
152
|
+
description?: string;
|
|
153
|
+
extendsTagIds?: string[];
|
|
154
|
+
showCheckbox?: boolean;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/** Options for adding a field to a tag */
|
|
158
|
+
export interface AddFieldOptions {
|
|
159
|
+
tagId: string;
|
|
160
|
+
name: string;
|
|
161
|
+
dataType: FieldDataType;
|
|
162
|
+
description?: string;
|
|
163
|
+
sourceTagId?: string;
|
|
164
|
+
options?: string[];
|
|
165
|
+
defaultValue?: string | boolean | number;
|
|
166
|
+
isMultiValue?: boolean;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/** Options for configuring tag checkbox */
|
|
170
|
+
export interface SetCheckboxOptions {
|
|
171
|
+
tagId: string;
|
|
172
|
+
showCheckbox: boolean;
|
|
173
|
+
doneStateMapping?: {
|
|
174
|
+
fieldId: string;
|
|
175
|
+
checkedValues: string[];
|
|
176
|
+
uncheckedValues?: string[];
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/** Options for editing a node */
|
|
181
|
+
export interface EditNodeOptions {
|
|
182
|
+
nodeId: string;
|
|
183
|
+
name?: {
|
|
184
|
+
old_string: string;
|
|
185
|
+
new_string: string;
|
|
186
|
+
replace_all?: boolean;
|
|
187
|
+
};
|
|
188
|
+
description?: {
|
|
189
|
+
old_string: string;
|
|
190
|
+
new_string: string;
|
|
191
|
+
replace_all?: boolean;
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/** Import result (simplified for API usage) */
|
|
196
|
+
export interface ImportResult {
|
|
197
|
+
success: boolean;
|
|
198
|
+
nodeIds?: string[];
|
|
199
|
+
error?: string;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// ============================================================================
|
|
203
|
+
// Re-export full generated types for escape hatch
|
|
204
|
+
// ============================================================================
|
|
205
|
+
|
|
206
|
+
export type { operations } from "../generated/api";
|
|
207
|
+
export type { paths } from "../generated/api";
|