@tacitai/mcp-server 0.1.1 → 0.3.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/dist/auth.d.ts +32 -0
- package/dist/auth.js +64 -0
- package/dist/client.d.ts +60 -5
- package/dist/client.js +234 -53
- package/dist/index.js +130 -106
- package/dist/oauth.d.ts +115 -0
- package/dist/oauth.js +619 -0
- package/dist/prompts.d.ts +2 -0
- package/dist/prompts.js +12 -0
- package/dist/setup.d.ts +28 -5
- package/dist/setup.js +266 -59
- package/dist/tools/agents.d.ts +277 -0
- package/dist/tools/agents.js +335 -0
- package/dist/tools/annotations.d.ts +117 -0
- package/dist/tools/annotations.js +130 -0
- package/dist/tools/artifacts.d.ts +178 -8
- package/dist/tools/artifacts.js +372 -81
- package/dist/tools/chronicle.d.ts +3 -0
- package/dist/tools/chronicle.js +165 -0
- package/dist/tools/connector_write_back.d.ts +3 -0
- package/dist/tools/connector_write_back.js +27 -0
- package/dist/tools/converse.d.ts +10 -0
- package/dist/tools/converse.js +88 -0
- package/dist/tools/crews.d.ts +3 -0
- package/dist/tools/crews.js +115 -0
- package/dist/tools/drafts.d.ts +83 -0
- package/dist/tools/drafts.js +86 -0
- package/dist/tools/errors.d.ts +15 -0
- package/dist/tools/errors.js +21 -0
- package/dist/tools/export.d.ts +54 -0
- package/dist/tools/export.js +55 -0
- package/dist/tools/gm.d.ts +214 -0
- package/dist/tools/gm.js +198 -0
- package/dist/tools/ingest.d.ts +58 -4
- package/dist/tools/ingest.js +109 -76
- package/dist/tools/kb.d.ts +544 -0
- package/dist/tools/kb.js +687 -0
- package/dist/tools/lake-structure.d.ts +3 -0
- package/dist/tools/lake-structure.js +126 -0
- package/dist/tools/lake.d.ts +932 -0
- package/dist/tools/lake.js +1017 -0
- package/dist/tools/move.d.ts +200 -0
- package/dist/tools/move.js +96 -0
- package/dist/tools/outbox.d.ts +274 -0
- package/dist/tools/outbox.js +223 -0
- package/dist/tools/people.d.ts +3 -0
- package/dist/tools/people.js +59 -0
- package/dist/tools/pyramid.d.ts +554 -0
- package/dist/tools/pyramid.js +758 -0
- package/dist/tools/recall.d.ts +2 -0
- package/dist/tools/recall.js +28 -17
- package/dist/tools/registry.d.ts +17 -0
- package/dist/tools/registry.js +199 -0
- package/dist/tools/research.d.ts +47 -0
- package/dist/tools/research.js +575 -0
- package/dist/tools/search.d.ts +9 -0
- package/dist/tools/search.js +86 -25
- package/dist/tools/sharing.d.ts +63 -0
- package/dist/tools/sharing.js +157 -0
- package/dist/tools/skills.d.ts +9 -0
- package/dist/tools/skills.js +98 -0
- package/dist/tools/synthesize.d.ts +54 -2
- package/dist/tools/synthesize.js +80 -23
- package/dist/tools/web-url.d.ts +57 -0
- package/dist/tools/web-url.js +74 -0
- package/dist/tools/workspaces.d.ts +3 -0
- package/dist/tools/workspaces.js +47 -0
- package/dist/transport.d.ts +9 -0
- package/dist/transport.js +209 -0
- package/package.json +5 -4
|
@@ -0,0 +1,758 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
/**
|
|
3
|
+
* Pyramid tools — CLI wrappers for portfolio, program, dossier, and
|
|
4
|
+
* value-stream CRUD on the Axum REST API.
|
|
5
|
+
*
|
|
6
|
+
* Routes (Axum, all under /api/v1):
|
|
7
|
+
* GET/POST /portfolios
|
|
8
|
+
* GET/POST /portfolios/:id/programs
|
|
9
|
+
* GET/POST /dossiers
|
|
10
|
+
* GET/PUT/DELETE /dossiers/:id
|
|
11
|
+
* GET/POST /alignment/value-streams
|
|
12
|
+
*/
|
|
13
|
+
import { z } from 'zod';
|
|
14
|
+
import { getClient, TacitApiError, TokenExpiredError } from '../client.js';
|
|
15
|
+
import { apiErrorResult as sharedApiErrorResult } from './errors.js';
|
|
16
|
+
function apiErrorResult(err, toolName) {
|
|
17
|
+
if (err instanceof TokenExpiredError) {
|
|
18
|
+
return {
|
|
19
|
+
content: [{ type: 'text', text: err.message }],
|
|
20
|
+
isError: true,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
if (err instanceof TacitApiError) {
|
|
24
|
+
return { content: [{ type: 'text', text: `API error ${err.statusCode} on ${toolName}: ${err.body}` }], isError: true };
|
|
25
|
+
}
|
|
26
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
27
|
+
return { content: [{ type: 'text', text: `Error: ${msg}` }], isError: true };
|
|
28
|
+
}
|
|
29
|
+
// ─── tacit_pyramid_list_portfolios ──────────────────────────────────────────
|
|
30
|
+
export const listPortfoliosInputSchema = z.object({});
|
|
31
|
+
export const LIST_PORTFOLIOS_TOOL_DEF = {
|
|
32
|
+
name: 'tacit_pyramid_list_portfolios',
|
|
33
|
+
description: 'List all portfolios in the workspace with artifact counts.',
|
|
34
|
+
inputSchema: {
|
|
35
|
+
type: 'object',
|
|
36
|
+
properties: {},
|
|
37
|
+
required: [],
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
export function buildListPortfoliosRequest(client, _input) {
|
|
41
|
+
return {
|
|
42
|
+
async execute() {
|
|
43
|
+
try {
|
|
44
|
+
const result = await client.get('/api/v1/portfolios');
|
|
45
|
+
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
|
|
46
|
+
}
|
|
47
|
+
catch (err) {
|
|
48
|
+
return apiErrorResult(err, 'tacit_pyramid_list_portfolios');
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
export async function handleListPortfolios(args) {
|
|
54
|
+
const parsed = listPortfoliosInputSchema.safeParse(args);
|
|
55
|
+
if (!parsed.success) {
|
|
56
|
+
return { content: [{ type: 'text', text: `Invalid input: ${parsed.error.message}` }], isError: true };
|
|
57
|
+
}
|
|
58
|
+
return buildListPortfoliosRequest(getClient(), parsed.data).execute();
|
|
59
|
+
}
|
|
60
|
+
// ─── tacit_pyramid_create_portfolio ─────────────────────────────────────────
|
|
61
|
+
export const createPortfolioInputSchema = z.object({
|
|
62
|
+
name: z.string().min(1).describe('Portfolio name'),
|
|
63
|
+
pillar: z.enum(['INTERNAL', 'PRODUCT', 'BUSINESS']).describe('Pillar: INTERNAL, PRODUCT, or BUSINESS'),
|
|
64
|
+
domain_schema_id: z.string().optional().describe('Optional domain schema ID'),
|
|
65
|
+
});
|
|
66
|
+
export const CREATE_PORTFOLIO_TOOL_DEF = {
|
|
67
|
+
name: 'tacit_pyramid_create_portfolio',
|
|
68
|
+
description: 'Create a new portfolio in the workspace. Pillar must be INTERNAL, PRODUCT, or BUSINESS.',
|
|
69
|
+
inputSchema: {
|
|
70
|
+
type: 'object',
|
|
71
|
+
properties: {
|
|
72
|
+
name: { type: 'string', description: 'Portfolio name' },
|
|
73
|
+
pillar: { type: 'string', enum: ['INTERNAL', 'PRODUCT', 'BUSINESS'], description: 'Pillar' },
|
|
74
|
+
domain_schema_id: { type: 'string', description: 'Optional domain schema ID' },
|
|
75
|
+
},
|
|
76
|
+
required: ['name', 'pillar'],
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
export function buildCreatePortfolioRequest(client, input) {
|
|
80
|
+
return {
|
|
81
|
+
async execute() {
|
|
82
|
+
try {
|
|
83
|
+
const body = { name: input.name, pillar: input.pillar };
|
|
84
|
+
if (input.domain_schema_id)
|
|
85
|
+
body['domain_schema_id'] = input.domain_schema_id;
|
|
86
|
+
const result = await client.post('/api/v1/portfolios', body);
|
|
87
|
+
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
|
|
88
|
+
}
|
|
89
|
+
catch (err) {
|
|
90
|
+
return apiErrorResult(err, 'tacit_pyramid_create_portfolio');
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
export async function handleCreatePortfolio(args) {
|
|
96
|
+
const parsed = createPortfolioInputSchema.safeParse(args);
|
|
97
|
+
if (!parsed.success) {
|
|
98
|
+
return { content: [{ type: 'text', text: `Invalid input: ${parsed.error.message}` }], isError: true };
|
|
99
|
+
}
|
|
100
|
+
return buildCreatePortfolioRequest(getClient(), parsed.data).execute();
|
|
101
|
+
}
|
|
102
|
+
// ─── tacit_pyramid_list_programs ────────────────────────────────────────────
|
|
103
|
+
export const listProgramsInputSchema = z.object({
|
|
104
|
+
portfolio_id: z.string().min(1).describe('UUID of the portfolio'),
|
|
105
|
+
});
|
|
106
|
+
export const LIST_PROGRAMS_TOOL_DEF = {
|
|
107
|
+
name: 'tacit_pyramid_list_programs',
|
|
108
|
+
description: 'List programs within a portfolio, with artifact counts.',
|
|
109
|
+
inputSchema: {
|
|
110
|
+
type: 'object',
|
|
111
|
+
properties: {
|
|
112
|
+
portfolio_id: { type: 'string', description: 'UUID of the portfolio' },
|
|
113
|
+
},
|
|
114
|
+
required: ['portfolio_id'],
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
export function buildListProgramsRequest(client, input) {
|
|
118
|
+
return {
|
|
119
|
+
async execute() {
|
|
120
|
+
try {
|
|
121
|
+
const result = await client.get(`/api/v1/portfolios/${input.portfolio_id}/programs`);
|
|
122
|
+
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
|
|
123
|
+
}
|
|
124
|
+
catch (err) {
|
|
125
|
+
return apiErrorResult(err, 'tacit_pyramid_list_programs');
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
export async function handleListPrograms(args) {
|
|
131
|
+
const parsed = listProgramsInputSchema.safeParse(args);
|
|
132
|
+
if (!parsed.success) {
|
|
133
|
+
return { content: [{ type: 'text', text: `Invalid input: ${parsed.error.message}` }], isError: true };
|
|
134
|
+
}
|
|
135
|
+
return buildListProgramsRequest(getClient(), parsed.data).execute();
|
|
136
|
+
}
|
|
137
|
+
// ─── tacit_pyramid_create_program ───────────────────────────────────────────
|
|
138
|
+
export const createProgramInputSchema = z.object({
|
|
139
|
+
portfolio_id: z.string().min(1).describe('UUID of the parent portfolio'),
|
|
140
|
+
name: z.string().min(1).describe('Program name'),
|
|
141
|
+
domain: z.string().optional().describe('Domain tag (e.g. ENGINEERING, DESIGN, MARKETING)'),
|
|
142
|
+
description: z.string().optional().describe('Program description'),
|
|
143
|
+
value_stream_id: z.string().optional().describe('Optional UUID of the value stream to assign this program to'),
|
|
144
|
+
weight: z.number().int().optional().describe('Sort weight (default 1)'),
|
|
145
|
+
target_starts_at: z.string().optional().describe('ISO 8601 start date'),
|
|
146
|
+
target_ends_at: z.string().optional().describe('ISO 8601 end date'),
|
|
147
|
+
});
|
|
148
|
+
export const CREATE_PROGRAM_TOOL_DEF = {
|
|
149
|
+
name: 'tacit_pyramid_create_program',
|
|
150
|
+
description: 'Create a new program within a portfolio. Optionally set domain, description, dates, and weight. Optionally assign to a value stream via value_stream_id.',
|
|
151
|
+
inputSchema: {
|
|
152
|
+
type: 'object',
|
|
153
|
+
properties: {
|
|
154
|
+
portfolio_id: { type: 'string', description: 'UUID of the parent portfolio' },
|
|
155
|
+
name: { type: 'string', description: 'Program name' },
|
|
156
|
+
domain: { type: 'string', description: 'Domain tag (e.g. ENGINEERING, DESIGN)' },
|
|
157
|
+
description: { type: 'string', description: 'Program description' },
|
|
158
|
+
value_stream_id: { type: 'string', description: 'Optional UUID of the value stream to assign this program to' },
|
|
159
|
+
weight: { type: 'number', description: 'Sort weight (default 1)' },
|
|
160
|
+
target_starts_at: { type: 'string', description: 'ISO 8601 start date' },
|
|
161
|
+
target_ends_at: { type: 'string', description: 'ISO 8601 end date' },
|
|
162
|
+
},
|
|
163
|
+
required: ['portfolio_id', 'name'],
|
|
164
|
+
},
|
|
165
|
+
};
|
|
166
|
+
export function buildCreateProgramRequest(client, input) {
|
|
167
|
+
return {
|
|
168
|
+
async execute() {
|
|
169
|
+
try {
|
|
170
|
+
const body = { name: input.name };
|
|
171
|
+
if (input.domain)
|
|
172
|
+
body['domain'] = input.domain;
|
|
173
|
+
if (input.description)
|
|
174
|
+
body['description'] = input.description;
|
|
175
|
+
if (input.weight !== undefined)
|
|
176
|
+
body['weight'] = input.weight;
|
|
177
|
+
if (input.value_stream_id)
|
|
178
|
+
body['value_stream_id'] = input.value_stream_id;
|
|
179
|
+
if (input.target_starts_at)
|
|
180
|
+
body['target_starts_at'] = input.target_starts_at;
|
|
181
|
+
if (input.target_ends_at)
|
|
182
|
+
body['target_ends_at'] = input.target_ends_at;
|
|
183
|
+
const result = await client.post(`/api/v1/portfolios/${input.portfolio_id}/programs`, body);
|
|
184
|
+
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
|
|
185
|
+
}
|
|
186
|
+
catch (err) {
|
|
187
|
+
return apiErrorResult(err, 'tacit_pyramid_create_program');
|
|
188
|
+
}
|
|
189
|
+
},
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
export async function handleCreateProgram(args) {
|
|
193
|
+
const parsed = createProgramInputSchema.safeParse(args);
|
|
194
|
+
if (!parsed.success) {
|
|
195
|
+
return { content: [{ type: 'text', text: `Invalid input: ${parsed.error.message}` }], isError: true };
|
|
196
|
+
}
|
|
197
|
+
return buildCreateProgramRequest(getClient(), parsed.data).execute();
|
|
198
|
+
}
|
|
199
|
+
// ─── tacit_pyramid_list_dossiers ────────────────────────────────────────────
|
|
200
|
+
export const listDossiersInputSchema = z.object({});
|
|
201
|
+
export const LIST_DOSSIERS_TOOL_DEF = {
|
|
202
|
+
name: 'tacit_pyramid_list_dossiers',
|
|
203
|
+
description: 'List dossiers in the workspace. Returns name, document count, portfolio/program placement, and staleness info.',
|
|
204
|
+
inputSchema: {
|
|
205
|
+
type: 'object',
|
|
206
|
+
properties: {},
|
|
207
|
+
required: [],
|
|
208
|
+
},
|
|
209
|
+
};
|
|
210
|
+
export function buildListDossiersRequest(client, _input) {
|
|
211
|
+
return {
|
|
212
|
+
async execute() {
|
|
213
|
+
try {
|
|
214
|
+
const result = await client.get('/api/v1/dossiers');
|
|
215
|
+
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
|
|
216
|
+
}
|
|
217
|
+
catch (err) {
|
|
218
|
+
return apiErrorResult(err, 'tacit_pyramid_list_dossiers');
|
|
219
|
+
}
|
|
220
|
+
},
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
export async function handleListDossiers(args) {
|
|
224
|
+
const parsed = listDossiersInputSchema.safeParse(args);
|
|
225
|
+
if (!parsed.success) {
|
|
226
|
+
return { content: [{ type: 'text', text: `Invalid input: ${parsed.error.message}` }], isError: true };
|
|
227
|
+
}
|
|
228
|
+
return buildListDossiersRequest(getClient(), parsed.data).execute();
|
|
229
|
+
}
|
|
230
|
+
// ─── tacit_pyramid_get_dossier ──────────────────────────────────────────────
|
|
231
|
+
export const getDossierInputSchema = z.object({
|
|
232
|
+
dossier_id: z.string().min(1).describe('UUID of the dossier'),
|
|
233
|
+
});
|
|
234
|
+
export const GET_DOSSIER_TOOL_DEF = {
|
|
235
|
+
name: 'tacit_pyramid_get_dossier',
|
|
236
|
+
description: 'Get a single dossier by ID, including its document list and stale document IDs.',
|
|
237
|
+
inputSchema: {
|
|
238
|
+
type: 'object',
|
|
239
|
+
properties: {
|
|
240
|
+
dossier_id: { type: 'string', description: 'UUID of the dossier' },
|
|
241
|
+
},
|
|
242
|
+
required: ['dossier_id'],
|
|
243
|
+
},
|
|
244
|
+
};
|
|
245
|
+
export function buildGetDossierRequest(client, input) {
|
|
246
|
+
return {
|
|
247
|
+
async execute() {
|
|
248
|
+
try {
|
|
249
|
+
const result = await client.get(`/api/v1/dossiers/${input.dossier_id}`);
|
|
250
|
+
const url = client.webUrl('dossier_summary', input.dossier_id);
|
|
251
|
+
const enriched = url ? { ...result, web_url: url } : result;
|
|
252
|
+
return { content: [{ type: 'text', text: JSON.stringify(enriched) }] };
|
|
253
|
+
}
|
|
254
|
+
catch (err) {
|
|
255
|
+
return apiErrorResult(err, 'tacit_pyramid_get_dossier');
|
|
256
|
+
}
|
|
257
|
+
},
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
export async function handleGetDossier(args) {
|
|
261
|
+
const parsed = getDossierInputSchema.safeParse(args);
|
|
262
|
+
if (!parsed.success) {
|
|
263
|
+
return { content: [{ type: 'text', text: `Invalid input: ${parsed.error.message}` }], isError: true };
|
|
264
|
+
}
|
|
265
|
+
return buildGetDossierRequest(getClient(), parsed.data).execute();
|
|
266
|
+
}
|
|
267
|
+
// ─── tacit_pyramid_create_dossier ───────────────────────────────────────────
|
|
268
|
+
export const createDossierInputSchema = z.object({
|
|
269
|
+
name: z.string().min(1).describe('Dossier name'),
|
|
270
|
+
document_ids: z.array(z.string()).optional().describe('UUIDs of published artifacts to include'),
|
|
271
|
+
portfolio_id: z.string().optional().describe('UUID of the portfolio to place this dossier in'),
|
|
272
|
+
program_id: z.string().optional().describe('UUID of the program to place this dossier in'),
|
|
273
|
+
dossier_kind: z.string().optional().describe('Kind: SCOPING_SESSION (default) or PROJECT_DOSSIER'),
|
|
274
|
+
status: z.string().optional().describe('Status (default ACTIVE)'),
|
|
275
|
+
weight: z.number().int().optional().describe('Sort weight (default 1)'),
|
|
276
|
+
target_starts_at: z.string().optional().describe('ISO 8601 start date'),
|
|
277
|
+
target_ends_at: z.string().optional().describe('ISO 8601 end date'),
|
|
278
|
+
});
|
|
279
|
+
export const CREATE_DOSSIER_TOOL_DEF = {
|
|
280
|
+
name: 'tacit_pyramid_create_dossier',
|
|
281
|
+
description: 'Create a new dossier. Optionally place it in a portfolio/program and include document IDs.',
|
|
282
|
+
inputSchema: {
|
|
283
|
+
type: 'object',
|
|
284
|
+
properties: {
|
|
285
|
+
name: { type: 'string', description: 'Dossier name' },
|
|
286
|
+
document_ids: { type: 'array', items: { type: 'string' }, description: 'Artifact UUIDs to include' },
|
|
287
|
+
portfolio_id: { type: 'string', description: 'Portfolio UUID' },
|
|
288
|
+
program_id: { type: 'string', description: 'Program UUID' },
|
|
289
|
+
dossier_kind: { type: 'string', description: 'SCOPING_SESSION or PROJECT_DOSSIER' },
|
|
290
|
+
status: { type: 'string', description: 'Status (default ACTIVE)' },
|
|
291
|
+
weight: { type: 'number', description: 'Sort weight' },
|
|
292
|
+
target_starts_at: { type: 'string', description: 'ISO 8601 start date' },
|
|
293
|
+
target_ends_at: { type: 'string', description: 'ISO 8601 end date' },
|
|
294
|
+
},
|
|
295
|
+
required: ['name'],
|
|
296
|
+
},
|
|
297
|
+
};
|
|
298
|
+
export function buildCreateDossierRequest(client, input) {
|
|
299
|
+
return {
|
|
300
|
+
async execute() {
|
|
301
|
+
try {
|
|
302
|
+
const body = { name: input.name };
|
|
303
|
+
if (input.document_ids)
|
|
304
|
+
body['document_ids'] = input.document_ids;
|
|
305
|
+
if (input.portfolio_id)
|
|
306
|
+
body['portfolio_id'] = input.portfolio_id;
|
|
307
|
+
if (input.program_id)
|
|
308
|
+
body['program_id'] = input.program_id;
|
|
309
|
+
if (input.dossier_kind)
|
|
310
|
+
body['dossier_kind'] = input.dossier_kind;
|
|
311
|
+
if (input.status)
|
|
312
|
+
body['status'] = input.status;
|
|
313
|
+
if (input.weight !== undefined)
|
|
314
|
+
body['weight'] = input.weight;
|
|
315
|
+
if (input.target_starts_at)
|
|
316
|
+
body['target_starts_at'] = input.target_starts_at;
|
|
317
|
+
if (input.target_ends_at)
|
|
318
|
+
body['target_ends_at'] = input.target_ends_at;
|
|
319
|
+
const result = await client.post('/api/v1/dossiers', body);
|
|
320
|
+
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
|
|
321
|
+
}
|
|
322
|
+
catch (err) {
|
|
323
|
+
return apiErrorResult(err, 'tacit_pyramid_create_dossier');
|
|
324
|
+
}
|
|
325
|
+
},
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
export async function handleCreateDossier(args) {
|
|
329
|
+
const parsed = createDossierInputSchema.safeParse(args);
|
|
330
|
+
if (!parsed.success) {
|
|
331
|
+
return { content: [{ type: 'text', text: `Invalid input: ${parsed.error.message}` }], isError: true };
|
|
332
|
+
}
|
|
333
|
+
return buildCreateDossierRequest(getClient(), parsed.data).execute();
|
|
334
|
+
}
|
|
335
|
+
// ─── tacit_pyramid_update_dossier ───────────────────────────────────────────
|
|
336
|
+
export const updateDossierInputSchema = z.object({
|
|
337
|
+
dossier_id: z.string().min(1).describe('UUID of the dossier to update'),
|
|
338
|
+
name: z.string().optional().describe('Updated dossier name (keeps current if omitted)'),
|
|
339
|
+
document_ids: z.array(z.string()).optional().describe('Updated document ID list (keeps current if omitted)'),
|
|
340
|
+
portfolio_id: z.string().optional().describe('Portfolio UUID (keeps current if omitted)'),
|
|
341
|
+
program_id: z.string().optional().describe('Program UUID (keeps current if omitted)'),
|
|
342
|
+
status: z.string().optional().describe('Status (keeps current if omitted)'),
|
|
343
|
+
weight: z.number().int().optional().describe('Sort weight (keeps current if omitted)'),
|
|
344
|
+
target_starts_at: z.string().nullable().optional().describe('ISO 8601 start date (null to clear, omit to keep)'),
|
|
345
|
+
target_ends_at: z.string().nullable().optional().describe('ISO 8601 end date (null to clear, omit to keep)'),
|
|
346
|
+
});
|
|
347
|
+
export const UPDATE_DOSSIER_TOOL_DEF = {
|
|
348
|
+
name: 'tacit_pyramid_update_dossier',
|
|
349
|
+
description: 'Update an existing dossier. Only supply the fields you want to change — omitted fields keep their current values. ' +
|
|
350
|
+
'The backend is a full-replace PUT, so this tool fetches the current state first and merges your changes.',
|
|
351
|
+
inputSchema: {
|
|
352
|
+
type: 'object',
|
|
353
|
+
properties: {
|
|
354
|
+
dossier_id: { type: 'string', description: 'UUID of the dossier' },
|
|
355
|
+
name: { type: 'string', description: 'Updated name' },
|
|
356
|
+
document_ids: { type: 'array', items: { type: 'string' }, description: 'Updated document IDs' },
|
|
357
|
+
portfolio_id: { type: 'string', description: 'Portfolio UUID' },
|
|
358
|
+
program_id: { type: 'string', description: 'Program UUID' },
|
|
359
|
+
status: { type: 'string', description: 'Status' },
|
|
360
|
+
weight: { type: 'number', description: 'Sort weight' },
|
|
361
|
+
target_starts_at: { type: ['string', 'null'], description: 'ISO 8601 start date (null to clear)' },
|
|
362
|
+
target_ends_at: { type: ['string', 'null'], description: 'ISO 8601 end date (null to clear)' },
|
|
363
|
+
},
|
|
364
|
+
required: ['dossier_id'],
|
|
365
|
+
},
|
|
366
|
+
};
|
|
367
|
+
export function buildUpdateDossierRequest(client, input) {
|
|
368
|
+
return {
|
|
369
|
+
async execute() {
|
|
370
|
+
try {
|
|
371
|
+
// Fetch current state — the backend PUT is full-replace, so we must
|
|
372
|
+
// merge caller-supplied fields onto the existing dossier to avoid
|
|
373
|
+
// silently wiping omitted fields (document_ids, status, weight, dates).
|
|
374
|
+
const current = await client.get(`/api/v1/dossiers/${input.dossier_id}`);
|
|
375
|
+
const body = {
|
|
376
|
+
name: input.name ?? current['name'],
|
|
377
|
+
document_ids: input.document_ids ?? current['document_ids'] ?? [],
|
|
378
|
+
portfolio_id: input.portfolio_id !== undefined ? input.portfolio_id : current['portfolio_id'],
|
|
379
|
+
program_id: input.program_id !== undefined ? input.program_id : current['program_id'],
|
|
380
|
+
status: input.status ?? current['status'] ?? 'ACTIVE',
|
|
381
|
+
weight: input.weight ?? current['weight'] ?? 1,
|
|
382
|
+
};
|
|
383
|
+
// Dates: explicit null clears, undefined keeps current
|
|
384
|
+
body['target_starts_at'] = input.target_starts_at !== undefined
|
|
385
|
+
? input.target_starts_at
|
|
386
|
+
: current['target_starts_at'] ?? null;
|
|
387
|
+
body['target_ends_at'] = input.target_ends_at !== undefined
|
|
388
|
+
? input.target_ends_at
|
|
389
|
+
: current['target_ends_at'] ?? null;
|
|
390
|
+
const result = await client.put(`/api/v1/dossiers/${input.dossier_id}`, body);
|
|
391
|
+
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
|
|
392
|
+
}
|
|
393
|
+
catch (err) {
|
|
394
|
+
return apiErrorResult(err, 'tacit_pyramid_update_dossier');
|
|
395
|
+
}
|
|
396
|
+
},
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
export async function handleUpdateDossier(args) {
|
|
400
|
+
const parsed = updateDossierInputSchema.safeParse(args);
|
|
401
|
+
if (!parsed.success) {
|
|
402
|
+
return { content: [{ type: 'text', text: `Invalid input: ${parsed.error.message}` }], isError: true };
|
|
403
|
+
}
|
|
404
|
+
return buildUpdateDossierRequest(getClient(), parsed.data).execute();
|
|
405
|
+
}
|
|
406
|
+
// ─── tacit_pyramid_delete_dossier ───────────────────────────────────────────
|
|
407
|
+
export const deleteDossierInputSchema = z.object({
|
|
408
|
+
dossier_id: z.string().min(1).describe('UUID of the dossier to delete'),
|
|
409
|
+
});
|
|
410
|
+
export const DELETE_DOSSIER_TOOL_DEF = {
|
|
411
|
+
name: 'tacit_pyramid_delete_dossier',
|
|
412
|
+
description: 'Permanently delete a dossier. This is irreversible.',
|
|
413
|
+
inputSchema: {
|
|
414
|
+
type: 'object',
|
|
415
|
+
properties: {
|
|
416
|
+
dossier_id: { type: 'string', description: 'UUID of the dossier to delete' },
|
|
417
|
+
},
|
|
418
|
+
required: ['dossier_id'],
|
|
419
|
+
},
|
|
420
|
+
};
|
|
421
|
+
export function buildDeleteDossierRequest(client, input) {
|
|
422
|
+
return {
|
|
423
|
+
async execute() {
|
|
424
|
+
try {
|
|
425
|
+
await client.delete(`/api/v1/dossiers/${input.dossier_id}`);
|
|
426
|
+
return { content: [{ type: 'text', text: JSON.stringify({ deleted: true, dossier_id: input.dossier_id }) }] };
|
|
427
|
+
}
|
|
428
|
+
catch (err) {
|
|
429
|
+
return apiErrorResult(err, 'tacit_pyramid_delete_dossier');
|
|
430
|
+
}
|
|
431
|
+
},
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
export async function handleDeleteDossier(args) {
|
|
435
|
+
const parsed = deleteDossierInputSchema.safeParse(args);
|
|
436
|
+
if (!parsed.success) {
|
|
437
|
+
return { content: [{ type: 'text', text: `Invalid input: ${parsed.error.message}` }], isError: true };
|
|
438
|
+
}
|
|
439
|
+
return buildDeleteDossierRequest(getClient(), parsed.data).execute();
|
|
440
|
+
}
|
|
441
|
+
// ─── tacit_pyramid_list_value_streams ───────────────────────────────────────
|
|
442
|
+
export const listValueStreamsInputSchema = z.object({});
|
|
443
|
+
export const LIST_VALUE_STREAMS_TOOL_DEF = {
|
|
444
|
+
name: 'tacit_pyramid_list_value_streams',
|
|
445
|
+
description: 'List all value streams in the workspace.',
|
|
446
|
+
inputSchema: {
|
|
447
|
+
type: 'object',
|
|
448
|
+
properties: {},
|
|
449
|
+
required: [],
|
|
450
|
+
},
|
|
451
|
+
};
|
|
452
|
+
export function buildListValueStreamsRequest(client, _input) {
|
|
453
|
+
return {
|
|
454
|
+
async execute() {
|
|
455
|
+
try {
|
|
456
|
+
const result = await client.get('/api/v1/alignment/value-streams');
|
|
457
|
+
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
|
|
458
|
+
}
|
|
459
|
+
catch (err) {
|
|
460
|
+
return apiErrorResult(err, 'tacit_pyramid_list_value_streams');
|
|
461
|
+
}
|
|
462
|
+
},
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
export async function handleListValueStreams(args) {
|
|
466
|
+
const parsed = listValueStreamsInputSchema.safeParse(args);
|
|
467
|
+
if (!parsed.success) {
|
|
468
|
+
return { content: [{ type: 'text', text: `Invalid input: ${parsed.error.message}` }], isError: true };
|
|
469
|
+
}
|
|
470
|
+
return buildListValueStreamsRequest(getClient(), parsed.data).execute();
|
|
471
|
+
}
|
|
472
|
+
// ─── tacit_pyramid_create_value_stream ──────────────────────────────────────
|
|
473
|
+
export const createValueStreamInputSchema = z.object({
|
|
474
|
+
portfolio_id: z.string().min(1).describe('UUID of the parent portfolio'),
|
|
475
|
+
name: z.string().min(1).describe('Value stream name (1–200 chars)'),
|
|
476
|
+
description: z.string().optional().describe('Optional description'),
|
|
477
|
+
});
|
|
478
|
+
export const CREATE_VALUE_STREAM_TOOL_DEF = {
|
|
479
|
+
name: 'tacit_pyramid_create_value_stream',
|
|
480
|
+
description: 'Create a new value stream under a portfolio. Requires MENTAT autonomy level.',
|
|
481
|
+
inputSchema: {
|
|
482
|
+
type: 'object',
|
|
483
|
+
properties: {
|
|
484
|
+
portfolio_id: { type: 'string', description: 'UUID of the parent portfolio' },
|
|
485
|
+
name: { type: 'string', description: 'Value stream name' },
|
|
486
|
+
description: { type: 'string', description: 'Optional description' },
|
|
487
|
+
},
|
|
488
|
+
required: ['portfolio_id', 'name'],
|
|
489
|
+
},
|
|
490
|
+
};
|
|
491
|
+
export function buildCreateValueStreamRequest(client, input) {
|
|
492
|
+
return {
|
|
493
|
+
async execute() {
|
|
494
|
+
try {
|
|
495
|
+
const body = { portfolio_id: input.portfolio_id, name: input.name };
|
|
496
|
+
if (input.description)
|
|
497
|
+
body['description'] = input.description;
|
|
498
|
+
const result = await client.post('/api/v1/alignment/value-streams', body);
|
|
499
|
+
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
|
|
500
|
+
}
|
|
501
|
+
catch (err) {
|
|
502
|
+
return apiErrorResult(err, 'tacit_pyramid_create_value_stream');
|
|
503
|
+
}
|
|
504
|
+
},
|
|
505
|
+
};
|
|
506
|
+
}
|
|
507
|
+
export async function handleCreateValueStream(args) {
|
|
508
|
+
const parsed = createValueStreamInputSchema.safeParse(args);
|
|
509
|
+
if (!parsed.success) {
|
|
510
|
+
return { content: [{ type: 'text', text: `Invalid input: ${parsed.error.message}` }], isError: true };
|
|
511
|
+
}
|
|
512
|
+
return buildCreateValueStreamRequest(getClient(), parsed.data).execute();
|
|
513
|
+
}
|
|
514
|
+
// ─── tacit_pyramid_assign_program_to_value_stream ─────────────────────────
|
|
515
|
+
export const assignProgramToVSInputSchema = z.object({
|
|
516
|
+
value_stream_id: z.string().min(1).describe('UUID of the value stream'),
|
|
517
|
+
program_id: z.string().min(1).describe('UUID of the program to assign'),
|
|
518
|
+
});
|
|
519
|
+
export const ASSIGN_PROGRAM_TO_VS_TOOL_DEF = {
|
|
520
|
+
name: 'tacit_pyramid_assign_program_to_value_stream',
|
|
521
|
+
description: 'Assign an existing program to a value stream. Requires MENTAT autonomy level.',
|
|
522
|
+
inputSchema: {
|
|
523
|
+
type: 'object',
|
|
524
|
+
properties: {
|
|
525
|
+
value_stream_id: { type: 'string', description: 'UUID of the value stream' },
|
|
526
|
+
program_id: { type: 'string', description: 'UUID of the program to assign' },
|
|
527
|
+
},
|
|
528
|
+
required: ['value_stream_id', 'program_id'],
|
|
529
|
+
},
|
|
530
|
+
};
|
|
531
|
+
export function buildAssignProgramToVSRequest(client, input) {
|
|
532
|
+
return {
|
|
533
|
+
async execute() {
|
|
534
|
+
try {
|
|
535
|
+
const body = { program_id: input.program_id, value_stream_id: input.value_stream_id };
|
|
536
|
+
await client.patch(`/api/v1/alignment/value-streams/${input.value_stream_id}/programs`, body);
|
|
537
|
+
return { content: [{ type: 'text', text: JSON.stringify({ assigned: true, program_id: input.program_id, value_stream_id: input.value_stream_id }) }] };
|
|
538
|
+
}
|
|
539
|
+
catch (err) {
|
|
540
|
+
return apiErrorResult(err, 'tacit_pyramid_assign_program_to_value_stream');
|
|
541
|
+
}
|
|
542
|
+
},
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
export async function handleAssignProgramToVS(args) {
|
|
546
|
+
const parsed = assignProgramToVSInputSchema.safeParse(args);
|
|
547
|
+
if (!parsed.success) {
|
|
548
|
+
return { content: [{ type: 'text', text: `Invalid input: ${parsed.error.message}` }], isError: true };
|
|
549
|
+
}
|
|
550
|
+
return buildAssignProgramToVSRequest(getClient(), parsed.data).execute();
|
|
551
|
+
}
|
|
552
|
+
export function registerPyramidTools(server, getClientFn) {
|
|
553
|
+
server.tool('tacit_pyramid_list_portfolios', 'List all portfolios in the workspace.', {}, async () => {
|
|
554
|
+
const client = await getClientFn();
|
|
555
|
+
return buildListPortfoliosRequest(client, {}).execute();
|
|
556
|
+
});
|
|
557
|
+
server.tool('tacit_pyramid_create_portfolio', 'Create a new portfolio.', {
|
|
558
|
+
name: z.string().min(1).describe('Portfolio name'),
|
|
559
|
+
pillar: z.enum(['INTERNAL', 'PRODUCT', 'BUSINESS']).describe('Pillar'),
|
|
560
|
+
domain_schema_id: z.string().optional().describe('Optional domain schema ID'),
|
|
561
|
+
}, async (args) => {
|
|
562
|
+
const client = await getClientFn();
|
|
563
|
+
return buildCreatePortfolioRequest(client, args).execute();
|
|
564
|
+
});
|
|
565
|
+
server.tool('tacit_pyramid_list_programs', 'List programs within a portfolio.', {
|
|
566
|
+
portfolio_id: z.string().min(1).describe('Portfolio UUID'),
|
|
567
|
+
}, async (args) => {
|
|
568
|
+
const client = await getClientFn();
|
|
569
|
+
return buildListProgramsRequest(client, args).execute();
|
|
570
|
+
});
|
|
571
|
+
server.tool('tacit_pyramid_create_program', 'Create a new program within a portfolio.', {
|
|
572
|
+
portfolio_id: z.string().min(1).describe('Parent portfolio UUID'),
|
|
573
|
+
name: z.string().min(1).describe('Program name'),
|
|
574
|
+
domain: z.string().optional().describe('Domain tag'),
|
|
575
|
+
description: z.string().optional().describe('Description'),
|
|
576
|
+
value_stream_id: z.string().optional().describe('Value stream UUID'),
|
|
577
|
+
weight: z.number().int().optional().describe('Sort weight'),
|
|
578
|
+
target_starts_at: z.string().optional().describe('ISO 8601 start date'),
|
|
579
|
+
target_ends_at: z.string().optional().describe('ISO 8601 end date'),
|
|
580
|
+
}, async (args) => {
|
|
581
|
+
const client = await getClientFn();
|
|
582
|
+
return buildCreateProgramRequest(client, args).execute();
|
|
583
|
+
});
|
|
584
|
+
server.tool('tacit_pyramid_list_dossiers', 'List dossiers in the workspace.', {}, async () => {
|
|
585
|
+
const client = await getClientFn();
|
|
586
|
+
return buildListDossiersRequest(client, {}).execute();
|
|
587
|
+
});
|
|
588
|
+
server.tool('tacit_pyramid_get_dossier', 'Get a single dossier by ID.', {
|
|
589
|
+
dossier_id: z.string().min(1).describe('Dossier UUID'),
|
|
590
|
+
}, async (args) => {
|
|
591
|
+
const client = await getClientFn();
|
|
592
|
+
return buildGetDossierRequest(client, args).execute();
|
|
593
|
+
});
|
|
594
|
+
server.tool('tacit_pyramid_create_dossier', 'Create a new dossier.', {
|
|
595
|
+
name: z.string().min(1).describe('Dossier name'),
|
|
596
|
+
document_ids: z.array(z.string()).optional().describe('Artifact UUIDs to include'),
|
|
597
|
+
portfolio_id: z.string().optional().describe('Portfolio UUID'),
|
|
598
|
+
program_id: z.string().optional().describe('Program UUID'),
|
|
599
|
+
dossier_kind: z.string().optional().describe('SCOPING_SESSION or PROJECT_DOSSIER'),
|
|
600
|
+
status: z.string().optional().describe('Status'),
|
|
601
|
+
weight: z.number().int().optional().describe('Sort weight'),
|
|
602
|
+
target_starts_at: z.string().optional().describe('ISO 8601 start date'),
|
|
603
|
+
target_ends_at: z.string().optional().describe('ISO 8601 end date'),
|
|
604
|
+
}, async (args) => {
|
|
605
|
+
const client = await getClientFn();
|
|
606
|
+
return buildCreateDossierRequest(client, args).execute();
|
|
607
|
+
});
|
|
608
|
+
server.tool('tacit_pyramid_update_dossier', 'Update an existing dossier (fetch-then-merge PUT).', {
|
|
609
|
+
dossier_id: z.string().min(1).describe('Dossier UUID'),
|
|
610
|
+
name: z.string().optional().describe('Updated name'),
|
|
611
|
+
document_ids: z.array(z.string()).optional().describe('Updated document IDs'),
|
|
612
|
+
portfolio_id: z.string().optional().describe('Portfolio UUID'),
|
|
613
|
+
program_id: z.string().optional().describe('Program UUID'),
|
|
614
|
+
status: z.string().optional().describe('Status'),
|
|
615
|
+
weight: z.number().int().optional().describe('Sort weight'),
|
|
616
|
+
target_starts_at: z.string().nullable().optional().describe('Start date (null to clear)'),
|
|
617
|
+
target_ends_at: z.string().nullable().optional().describe('End date (null to clear)'),
|
|
618
|
+
}, async (args) => {
|
|
619
|
+
const client = await getClientFn();
|
|
620
|
+
return buildUpdateDossierRequest(client, args).execute();
|
|
621
|
+
});
|
|
622
|
+
server.tool('tacit_pyramid_delete_dossier', 'Permanently delete a dossier.', {
|
|
623
|
+
dossier_id: z.string().min(1).describe('Dossier UUID'),
|
|
624
|
+
}, async (args) => {
|
|
625
|
+
const client = await getClientFn();
|
|
626
|
+
return buildDeleteDossierRequest(client, args).execute();
|
|
627
|
+
});
|
|
628
|
+
server.tool('tacit_pyramid_list_value_streams', 'List all value streams in the workspace.', {}, async () => {
|
|
629
|
+
const client = await getClientFn();
|
|
630
|
+
return buildListValueStreamsRequest(client, {}).execute();
|
|
631
|
+
});
|
|
632
|
+
server.tool('tacit_pyramid_create_value_stream', 'Create a new value stream under a portfolio.', {
|
|
633
|
+
portfolio_id: z.string().min(1).describe('Parent portfolio UUID'),
|
|
634
|
+
name: z.string().min(1).describe('Value stream name'),
|
|
635
|
+
description: z.string().optional().describe('Description'),
|
|
636
|
+
}, async (args) => {
|
|
637
|
+
const client = await getClientFn();
|
|
638
|
+
return buildCreateValueStreamRequest(client, args).execute();
|
|
639
|
+
});
|
|
640
|
+
server.tool('tacit_pyramid_assign_program_to_value_stream', 'Assign a program to a value stream.', {
|
|
641
|
+
value_stream_id: z.string().min(1).describe('Value stream UUID'),
|
|
642
|
+
program_id: z.string().min(1).describe('Program UUID'),
|
|
643
|
+
}, async (args) => {
|
|
644
|
+
const client = await getClientFn();
|
|
645
|
+
return buildAssignProgramToVSRequest(client, args).execute();
|
|
646
|
+
});
|
|
647
|
+
server.tool('tacit_patch_portfolio', "Update a portfolio's name or pillar.", {
|
|
648
|
+
portfolio_id: z.string().uuid().describe('Portfolio UUID'),
|
|
649
|
+
name: z.string().optional().describe('New name'),
|
|
650
|
+
pillar: z.string().optional().describe('New pillar'),
|
|
651
|
+
}, async (args) => {
|
|
652
|
+
try {
|
|
653
|
+
const client = await getClientFn();
|
|
654
|
+
const { portfolio_id, ...body } = args;
|
|
655
|
+
const data = await client.patch(`/api/v1/portfolios/${portfolio_id}`, body);
|
|
656
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
|
|
657
|
+
}
|
|
658
|
+
catch (err) {
|
|
659
|
+
return sharedApiErrorResult(err, '/api/v1/portfolios');
|
|
660
|
+
}
|
|
661
|
+
});
|
|
662
|
+
server.tool('tacit_delete_portfolio', 'Delete a portfolio.', {
|
|
663
|
+
portfolio_id: z.string().uuid().describe('Portfolio UUID to delete'),
|
|
664
|
+
}, async (args) => {
|
|
665
|
+
try {
|
|
666
|
+
const client = await getClientFn();
|
|
667
|
+
const data = await client.delete(`/api/v1/portfolios/${args.portfolio_id}`);
|
|
668
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
|
|
669
|
+
}
|
|
670
|
+
catch (err) {
|
|
671
|
+
return sharedApiErrorResult(err, '/api/v1/portfolios');
|
|
672
|
+
}
|
|
673
|
+
});
|
|
674
|
+
server.tool('tacit_patch_program', "Update a program's fields.", {
|
|
675
|
+
portfolio_id: z.string().uuid().describe('Portfolio UUID'),
|
|
676
|
+
program_id: z.string().uuid().describe('Program UUID'),
|
|
677
|
+
name: z.string().optional().describe('New name'),
|
|
678
|
+
description: z.string().optional().describe('New description'),
|
|
679
|
+
weight: z.number().int().optional().describe('New sort weight'),
|
|
680
|
+
target_starts_at: z.string().datetime().nullable().optional().describe('ISO 8601 start date'),
|
|
681
|
+
target_ends_at: z.string().datetime().nullable().optional().describe('ISO 8601 end date'),
|
|
682
|
+
}, async (args) => {
|
|
683
|
+
try {
|
|
684
|
+
const client = await getClientFn();
|
|
685
|
+
const { portfolio_id, program_id, ...body } = args;
|
|
686
|
+
const data = await client.patch(`/api/v1/portfolios/${portfolio_id}/programs/${program_id}`, body);
|
|
687
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
|
|
688
|
+
}
|
|
689
|
+
catch (err) {
|
|
690
|
+
return sharedApiErrorResult(err, '/api/v1/portfolios/programs');
|
|
691
|
+
}
|
|
692
|
+
});
|
|
693
|
+
server.tool('tacit_delete_program', 'Delete a program.', {
|
|
694
|
+
portfolio_id: z.string().uuid().describe('Portfolio UUID'),
|
|
695
|
+
program_id: z.string().uuid().describe('Program UUID to delete'),
|
|
696
|
+
}, async (args) => {
|
|
697
|
+
try {
|
|
698
|
+
const client = await getClientFn();
|
|
699
|
+
const data = await client.delete(`/api/v1/portfolios/${args.portfolio_id}/programs/${args.program_id}`);
|
|
700
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
|
|
701
|
+
}
|
|
702
|
+
catch (err) {
|
|
703
|
+
return sharedApiErrorResult(err, '/api/v1/portfolios/programs');
|
|
704
|
+
}
|
|
705
|
+
});
|
|
706
|
+
server.tool('tacit_portfolio_artifacts', 'List artifacts within a portfolio.', {
|
|
707
|
+
portfolio_id: z.string().uuid().describe('Portfolio UUID'),
|
|
708
|
+
}, async (args) => {
|
|
709
|
+
try {
|
|
710
|
+
const client = await getClientFn();
|
|
711
|
+
const data = await client.get(`/api/v1/portfolios/${args.portfolio_id}/artifacts`);
|
|
712
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
|
|
713
|
+
}
|
|
714
|
+
catch (err) {
|
|
715
|
+
return sharedApiErrorResult(err, '/api/v1/portfolios/artifacts');
|
|
716
|
+
}
|
|
717
|
+
});
|
|
718
|
+
server.tool('tacit_get_value_stream', 'Get a value stream by ID.', {
|
|
719
|
+
value_stream_id: z.string().uuid().describe('Value stream UUID'),
|
|
720
|
+
}, async (args) => {
|
|
721
|
+
try {
|
|
722
|
+
const client = await getClientFn();
|
|
723
|
+
const data = await client.get(`/api/v1/alignment/value-streams/${args.value_stream_id}`);
|
|
724
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
|
|
725
|
+
}
|
|
726
|
+
catch (err) {
|
|
727
|
+
return sharedApiErrorResult(err, '/api/v1/alignment/value-streams');
|
|
728
|
+
}
|
|
729
|
+
});
|
|
730
|
+
server.tool('tacit_patch_value_stream', "Update a value stream's name, description, or status.", {
|
|
731
|
+
value_stream_id: z.string().uuid().describe('Value stream UUID'),
|
|
732
|
+
name: z.string().optional().describe('New name'),
|
|
733
|
+
description: z.string().optional().describe('New description'),
|
|
734
|
+
status: z.string().optional().describe('New status'),
|
|
735
|
+
}, async (args) => {
|
|
736
|
+
try {
|
|
737
|
+
const client = await getClientFn();
|
|
738
|
+
const { value_stream_id, ...body } = args;
|
|
739
|
+
const data = await client.patch(`/api/v1/alignment/value-streams/${value_stream_id}`, body);
|
|
740
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
|
|
741
|
+
}
|
|
742
|
+
catch (err) {
|
|
743
|
+
return sharedApiErrorResult(err, '/api/v1/alignment/value-streams');
|
|
744
|
+
}
|
|
745
|
+
});
|
|
746
|
+
server.tool('tacit_delete_value_stream', 'Delete a value stream.', {
|
|
747
|
+
value_stream_id: z.string().uuid().describe('Value stream UUID to delete'),
|
|
748
|
+
}, async (args) => {
|
|
749
|
+
try {
|
|
750
|
+
const client = await getClientFn();
|
|
751
|
+
const data = await client.delete(`/api/v1/alignment/value-streams/${args.value_stream_id}`);
|
|
752
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
|
|
753
|
+
}
|
|
754
|
+
catch (err) {
|
|
755
|
+
return sharedApiErrorResult(err, '/api/v1/alignment/value-streams');
|
|
756
|
+
}
|
|
757
|
+
});
|
|
758
|
+
}
|