@epic-web/workshop-mcp 6.54.1 → 6.55.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/index.js +2 -10
- package/dist/prompts.js +4 -3
- package/dist/resources.js +26 -21
- package/dist/server-metadata.d.ts +476 -0
- package/dist/server-metadata.js +666 -0
- package/dist/tools.js +413 -314
- package/dist/utils.js +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,666 @@
|
|
|
1
|
+
export const serverInstructions = `
|
|
2
|
+
Quick start
|
|
3
|
+
- Call \`get_what_is_next\` first to discover the next required action.
|
|
4
|
+
- If the user is not logged in, call \`login\` and wait for the verification flow.
|
|
5
|
+
- Use \`set_playground\` to move to a step, then \`open_exercise_step_files\` to open relevant files.
|
|
6
|
+
|
|
7
|
+
Default behavior
|
|
8
|
+
- \`workshopDirectory\` is required and must be an absolute path to the workshop root.
|
|
9
|
+
- Passing a \`/playground\` path is normalized to the workshop root.
|
|
10
|
+
- The user's work-in-progress lives in the \`playground\` directory.
|
|
11
|
+
- \`get_exercise_context\` defaults to the current playground exercise when \`exerciseNumber\` is omitted.
|
|
12
|
+
- \`set_playground\` uses the next incomplete step when arguments are omitted.
|
|
13
|
+
|
|
14
|
+
How to chain tools safely
|
|
15
|
+
- Use \`get_workshop_context\` to learn exercise numbers and topics.
|
|
16
|
+
- Use \`get_exercise_context\` or \`get_exercise_step_context\` for instructions and IDs.
|
|
17
|
+
- Use \`update_progress\` with \`epicLessonSlug\` from context tools.
|
|
18
|
+
- Re-run \`get_what_is_next\` after progress updates or when unsure.
|
|
19
|
+
|
|
20
|
+
Common patterns & examples
|
|
21
|
+
- "Help me continue" -> \`get_what_is_next\` -> follow steps -> \`update_progress\` -> \`get_what_is_next\`.
|
|
22
|
+
- "Show step 2.3 solution" -> \`set_playground\` { exerciseNumber: 2, stepNumber: 3, type: "solution" } -> \`open_exercise_step_files\`.
|
|
23
|
+
- "Diff between 02.03 problem and solution" -> \`get_diff_between_apps\` { app1: "02.03.problem", app2: "02.03.solution" }.
|
|
24
|
+
`.trim();
|
|
25
|
+
export const toolDocs = {
|
|
26
|
+
login: {
|
|
27
|
+
title: 'Login',
|
|
28
|
+
summary: 'Start device authorization and store credentials after the user verifies.',
|
|
29
|
+
inputs: [
|
|
30
|
+
{
|
|
31
|
+
name: 'workshopDirectory',
|
|
32
|
+
type: 'string',
|
|
33
|
+
required: true,
|
|
34
|
+
description: 'Absolute path to the workshop root. Passing a /playground path is allowed and normalized.',
|
|
35
|
+
examples: ['/Users/alice/workshops/react-fundamentals'],
|
|
36
|
+
},
|
|
37
|
+
],
|
|
38
|
+
returns: '{ verificationUrl, userCode, expiresInSeconds }',
|
|
39
|
+
examples: [
|
|
40
|
+
{
|
|
41
|
+
description: 'Start login for a workshop',
|
|
42
|
+
params: '{ "workshopDirectory": "/Users/alice/workshops/react" }',
|
|
43
|
+
},
|
|
44
|
+
],
|
|
45
|
+
nextSteps: [
|
|
46
|
+
'Ask the user to open the verification URL and enter the code.',
|
|
47
|
+
'Call `get_user_info` to confirm authentication.',
|
|
48
|
+
],
|
|
49
|
+
errorNextSteps: [
|
|
50
|
+
'Verify the workshop path points to a valid workshop root.',
|
|
51
|
+
],
|
|
52
|
+
annotations: {
|
|
53
|
+
readOnlyHint: false,
|
|
54
|
+
destructiveHint: false,
|
|
55
|
+
idempotentHint: false,
|
|
56
|
+
openWorldHint: true,
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
logout: {
|
|
60
|
+
title: 'Logout',
|
|
61
|
+
summary: 'Log the user out of the workshop host and clear cached credentials.',
|
|
62
|
+
inputs: [
|
|
63
|
+
{
|
|
64
|
+
name: 'workshopDirectory',
|
|
65
|
+
type: 'string',
|
|
66
|
+
required: true,
|
|
67
|
+
description: 'Absolute path to the workshop root.',
|
|
68
|
+
examples: ['/Users/alice/workshops/react-fundamentals'],
|
|
69
|
+
},
|
|
70
|
+
],
|
|
71
|
+
returns: '{ loggedOut: true }',
|
|
72
|
+
examples: [
|
|
73
|
+
{
|
|
74
|
+
description: 'Logout from the current workshop',
|
|
75
|
+
params: '{ "workshopDirectory": "/Users/alice/workshops/react" }',
|
|
76
|
+
},
|
|
77
|
+
],
|
|
78
|
+
nextSteps: ['Call `login` if the user wants to re-authenticate.'],
|
|
79
|
+
annotations: {
|
|
80
|
+
readOnlyHint: false,
|
|
81
|
+
destructiveHint: false,
|
|
82
|
+
idempotentHint: false,
|
|
83
|
+
openWorldHint: false,
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
set_playground: {
|
|
87
|
+
title: 'Set Playground',
|
|
88
|
+
summary: 'Set the playground to a specific exercise step or the next incomplete step.',
|
|
89
|
+
inputs: [
|
|
90
|
+
{
|
|
91
|
+
name: 'workshopDirectory',
|
|
92
|
+
type: 'string',
|
|
93
|
+
required: true,
|
|
94
|
+
description: 'Absolute path to the workshop root.',
|
|
95
|
+
examples: ['/Users/alice/workshops/react-fundamentals'],
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
name: 'exerciseNumber',
|
|
99
|
+
type: 'number',
|
|
100
|
+
required: false,
|
|
101
|
+
description: 'Exercise number to open. Omit to continue to the next incomplete step.',
|
|
102
|
+
examples: ['1', '5'],
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
name: 'stepNumber',
|
|
106
|
+
type: 'number',
|
|
107
|
+
required: false,
|
|
108
|
+
description: 'Step number within the exercise. Omit to use the current step or next step.',
|
|
109
|
+
examples: ['1', '3'],
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
name: 'type',
|
|
113
|
+
type: '"problem" | "solution"',
|
|
114
|
+
required: false,
|
|
115
|
+
description: 'Step type. Omit to keep the current type or default to the problem step.',
|
|
116
|
+
examples: ['problem', 'solution'],
|
|
117
|
+
},
|
|
118
|
+
],
|
|
119
|
+
returns: '{ playground: { exerciseNumber, stepNumber, type, appName, fullPath } }',
|
|
120
|
+
examples: [
|
|
121
|
+
{
|
|
122
|
+
description: 'Continue to the next incomplete step',
|
|
123
|
+
params: '{ "workshopDirectory": "/Users/alice/workshops/react" }',
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
description: 'Open exercise 2 step 3 solution',
|
|
127
|
+
params: '{ "workshopDirectory": "/Users/alice/workshops/react", "exerciseNumber": 2, "stepNumber": 3, "type": "solution" }',
|
|
128
|
+
},
|
|
129
|
+
],
|
|
130
|
+
nextSteps: [
|
|
131
|
+
'Call `open_exercise_step_files` to open the relevant files.',
|
|
132
|
+
'Use `get_exercise_step_progress_diff` to review remaining changes.',
|
|
133
|
+
],
|
|
134
|
+
errorNextSteps: [
|
|
135
|
+
'Verify exercise and step numbers exist in `get_workshop_context`.',
|
|
136
|
+
],
|
|
137
|
+
annotations: {
|
|
138
|
+
readOnlyHint: false,
|
|
139
|
+
destructiveHint: false,
|
|
140
|
+
idempotentHint: false,
|
|
141
|
+
openWorldHint: false,
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
update_progress: {
|
|
145
|
+
title: 'Update Progress',
|
|
146
|
+
summary: 'Mark an Epic lesson as complete or incomplete for the current user.',
|
|
147
|
+
inputs: [
|
|
148
|
+
{
|
|
149
|
+
name: 'workshopDirectory',
|
|
150
|
+
type: 'string',
|
|
151
|
+
required: true,
|
|
152
|
+
description: 'Absolute path to the workshop root.',
|
|
153
|
+
examples: ['/Users/alice/workshops/react-fundamentals'],
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
name: 'epicLessonSlug',
|
|
157
|
+
type: 'string',
|
|
158
|
+
required: true,
|
|
159
|
+
description: 'Lesson slug from `get_exercise_context`, `get_workshop_context`, or `get_what_is_next`.',
|
|
160
|
+
examples: ['react-basics-01-intro'],
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
name: 'complete',
|
|
164
|
+
type: 'boolean',
|
|
165
|
+
required: false,
|
|
166
|
+
description: 'Whether to mark complete (default: true).',
|
|
167
|
+
examples: ['true', 'false'],
|
|
168
|
+
},
|
|
169
|
+
],
|
|
170
|
+
returns: '{ epicLessonSlug, complete }',
|
|
171
|
+
examples: [
|
|
172
|
+
{
|
|
173
|
+
description: 'Mark a lesson complete',
|
|
174
|
+
params: '{ "workshopDirectory": "/Users/alice/workshops/react", "epicLessonSlug": "react-basics-01-intro", "complete": true }',
|
|
175
|
+
},
|
|
176
|
+
],
|
|
177
|
+
nextSteps: [
|
|
178
|
+
'Call `get_what_is_next` to get the next action.',
|
|
179
|
+
'Use `get_user_progress` to verify updates.',
|
|
180
|
+
],
|
|
181
|
+
errorNextSteps: ['Confirm the slug matches one from the context tools.'],
|
|
182
|
+
annotations: {
|
|
183
|
+
readOnlyHint: false,
|
|
184
|
+
destructiveHint: false,
|
|
185
|
+
idempotentHint: false,
|
|
186
|
+
openWorldHint: true,
|
|
187
|
+
},
|
|
188
|
+
},
|
|
189
|
+
get_workshop_context: {
|
|
190
|
+
title: 'Get Workshop Context',
|
|
191
|
+
summary: 'Return a high-level view of the workshop, including exercises and progress.',
|
|
192
|
+
inputs: [
|
|
193
|
+
{
|
|
194
|
+
name: 'workshopDirectory',
|
|
195
|
+
type: 'string',
|
|
196
|
+
required: true,
|
|
197
|
+
description: 'Absolute path to the workshop root.',
|
|
198
|
+
examples: ['/Users/alice/workshops/react-fundamentals'],
|
|
199
|
+
},
|
|
200
|
+
],
|
|
201
|
+
returns: '{ meta, exercises[] }',
|
|
202
|
+
examples: [
|
|
203
|
+
{
|
|
204
|
+
description: 'Fetch workshop context',
|
|
205
|
+
params: '{ "workshopDirectory": "/Users/alice/workshops/react" }',
|
|
206
|
+
},
|
|
207
|
+
],
|
|
208
|
+
nextSteps: [
|
|
209
|
+
'Use `get_exercise_context` for a specific exercise.',
|
|
210
|
+
'Use `get_what_is_next` to find the next action.',
|
|
211
|
+
],
|
|
212
|
+
annotations: {
|
|
213
|
+
readOnlyHint: true,
|
|
214
|
+
destructiveHint: false,
|
|
215
|
+
idempotentHint: true,
|
|
216
|
+
openWorldHint: true,
|
|
217
|
+
},
|
|
218
|
+
},
|
|
219
|
+
get_exercise_context: {
|
|
220
|
+
title: 'Get Exercise Context',
|
|
221
|
+
summary: 'Return instructions, transcripts, and progress for a single exercise.',
|
|
222
|
+
inputs: [
|
|
223
|
+
{
|
|
224
|
+
name: 'workshopDirectory',
|
|
225
|
+
type: 'string',
|
|
226
|
+
required: true,
|
|
227
|
+
description: 'Absolute path to the workshop root.',
|
|
228
|
+
examples: ['/Users/alice/workshops/react-fundamentals'],
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
name: 'exerciseNumber',
|
|
232
|
+
type: 'number',
|
|
233
|
+
required: false,
|
|
234
|
+
description: 'Exercise number to fetch. Omit to use the current playground exercise.',
|
|
235
|
+
examples: ['1', '4'],
|
|
236
|
+
},
|
|
237
|
+
],
|
|
238
|
+
returns: '{ exerciseInfo, steps[], currentContext }',
|
|
239
|
+
examples: [
|
|
240
|
+
{
|
|
241
|
+
description: 'Fetch context for exercise 3',
|
|
242
|
+
params: '{ "workshopDirectory": "/Users/alice/workshops/react", "exerciseNumber": 3 }',
|
|
243
|
+
},
|
|
244
|
+
],
|
|
245
|
+
nextSteps: [
|
|
246
|
+
'Use `get_exercise_step_context` for a specific step.',
|
|
247
|
+
'Use `get_exercise_step_progress_diff` to compare progress.',
|
|
248
|
+
],
|
|
249
|
+
annotations: {
|
|
250
|
+
readOnlyHint: true,
|
|
251
|
+
destructiveHint: false,
|
|
252
|
+
idempotentHint: true,
|
|
253
|
+
openWorldHint: true,
|
|
254
|
+
},
|
|
255
|
+
},
|
|
256
|
+
get_diff_between_apps: {
|
|
257
|
+
title: 'Get Diff Between Apps',
|
|
258
|
+
summary: 'Return a git diff between two exercise apps by ID (problem vs solution).',
|
|
259
|
+
inputs: [
|
|
260
|
+
{
|
|
261
|
+
name: 'workshopDirectory',
|
|
262
|
+
type: 'string',
|
|
263
|
+
required: true,
|
|
264
|
+
description: 'Absolute path to the workshop root.',
|
|
265
|
+
examples: ['/Users/alice/workshops/react-fundamentals'],
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
name: 'app1',
|
|
269
|
+
type: 'string',
|
|
270
|
+
required: true,
|
|
271
|
+
description: 'First app ID, e.g. "02.03.problem" or "02.03.solution".',
|
|
272
|
+
examples: ['02.03.problem'],
|
|
273
|
+
},
|
|
274
|
+
{
|
|
275
|
+
name: 'app2',
|
|
276
|
+
type: 'string',
|
|
277
|
+
required: true,
|
|
278
|
+
description: 'Second app ID, e.g. "02.03.solution" or "02.03.problem".',
|
|
279
|
+
examples: ['02.03.solution'],
|
|
280
|
+
},
|
|
281
|
+
],
|
|
282
|
+
returns: '{ diff }',
|
|
283
|
+
examples: [
|
|
284
|
+
{
|
|
285
|
+
description: 'Compare problem and solution for step 2.3',
|
|
286
|
+
params: '{ "workshopDirectory": "/Users/alice/workshops/react", "app1": "02.03.problem", "app2": "02.03.solution" }',
|
|
287
|
+
},
|
|
288
|
+
],
|
|
289
|
+
nextSteps: [
|
|
290
|
+
'Use `set_playground` to open the relevant step.',
|
|
291
|
+
'Use `open_exercise_step_files` to review changed files.',
|
|
292
|
+
],
|
|
293
|
+
annotations: {
|
|
294
|
+
readOnlyHint: true,
|
|
295
|
+
destructiveHint: false,
|
|
296
|
+
idempotentHint: true,
|
|
297
|
+
openWorldHint: false,
|
|
298
|
+
},
|
|
299
|
+
},
|
|
300
|
+
get_exercise_step_progress_diff: {
|
|
301
|
+
title: 'Get Exercise Step Progress Diff',
|
|
302
|
+
summary: 'Return a diff between the playground and the current step solution.',
|
|
303
|
+
inputs: [
|
|
304
|
+
{
|
|
305
|
+
name: 'workshopDirectory',
|
|
306
|
+
type: 'string',
|
|
307
|
+
required: true,
|
|
308
|
+
description: 'Absolute path to the workshop root.',
|
|
309
|
+
examples: ['/Users/alice/workshops/react-fundamentals'],
|
|
310
|
+
},
|
|
311
|
+
],
|
|
312
|
+
returns: '{ diff }',
|
|
313
|
+
examples: [
|
|
314
|
+
{
|
|
315
|
+
description: 'Check current step progress',
|
|
316
|
+
params: '{ "workshopDirectory": "/Users/alice/workshops/react" }',
|
|
317
|
+
},
|
|
318
|
+
],
|
|
319
|
+
nextSteps: [
|
|
320
|
+
'Use `open_exercise_step_files` to edit missing changes.',
|
|
321
|
+
'Re-run this tool to verify progress.',
|
|
322
|
+
],
|
|
323
|
+
annotations: {
|
|
324
|
+
readOnlyHint: true,
|
|
325
|
+
destructiveHint: false,
|
|
326
|
+
idempotentHint: true,
|
|
327
|
+
openWorldHint: false,
|
|
328
|
+
},
|
|
329
|
+
},
|
|
330
|
+
get_exercise_step_context: {
|
|
331
|
+
title: 'Get Exercise Step Context',
|
|
332
|
+
summary: 'Return instructions, transcripts, and progress for a single step.',
|
|
333
|
+
inputs: [
|
|
334
|
+
{
|
|
335
|
+
name: 'workshopDirectory',
|
|
336
|
+
type: 'string',
|
|
337
|
+
required: true,
|
|
338
|
+
description: 'Absolute path to the workshop root.',
|
|
339
|
+
examples: ['/Users/alice/workshops/react-fundamentals'],
|
|
340
|
+
},
|
|
341
|
+
{
|
|
342
|
+
name: 'exerciseNumber',
|
|
343
|
+
type: 'number',
|
|
344
|
+
required: true,
|
|
345
|
+
description: 'Exercise number (1-based).',
|
|
346
|
+
examples: ['2'],
|
|
347
|
+
},
|
|
348
|
+
{
|
|
349
|
+
name: 'stepNumber',
|
|
350
|
+
type: 'number',
|
|
351
|
+
required: true,
|
|
352
|
+
description: 'Step number within the exercise (1-based).',
|
|
353
|
+
examples: ['3'],
|
|
354
|
+
},
|
|
355
|
+
],
|
|
356
|
+
returns: '{ stepInfo, problem, solution, currentContext }',
|
|
357
|
+
examples: [
|
|
358
|
+
{
|
|
359
|
+
description: 'Fetch context for exercise 2 step 3',
|
|
360
|
+
params: '{ "workshopDirectory": "/Users/alice/workshops/react", "exerciseNumber": 2, "stepNumber": 3 }',
|
|
361
|
+
},
|
|
362
|
+
],
|
|
363
|
+
nextSteps: [
|
|
364
|
+
'Use `set_playground` to open the step.',
|
|
365
|
+
'Use `get_exercise_step_progress_diff` to compare progress.',
|
|
366
|
+
],
|
|
367
|
+
annotations: {
|
|
368
|
+
readOnlyHint: true,
|
|
369
|
+
destructiveHint: false,
|
|
370
|
+
idempotentHint: true,
|
|
371
|
+
openWorldHint: true,
|
|
372
|
+
},
|
|
373
|
+
},
|
|
374
|
+
view_video: {
|
|
375
|
+
title: 'View Video',
|
|
376
|
+
summary: 'Open an Epic lesson video in the embedded UI player for the user.',
|
|
377
|
+
inputs: [
|
|
378
|
+
{
|
|
379
|
+
name: 'videoUrl',
|
|
380
|
+
type: 'string',
|
|
381
|
+
required: true,
|
|
382
|
+
description: 'Video URL from exercise context or from `get_what_is_next` results.',
|
|
383
|
+
examples: ['https://epicweb.dev/workshops/react/01-intro'],
|
|
384
|
+
},
|
|
385
|
+
],
|
|
386
|
+
returns: '{ iframeUrl, videoUrl }',
|
|
387
|
+
examples: [
|
|
388
|
+
{
|
|
389
|
+
description: 'Show the intro video',
|
|
390
|
+
params: '{ "videoUrl": "https://epicweb.dev/workshops/react/intro" }',
|
|
391
|
+
},
|
|
392
|
+
],
|
|
393
|
+
nextSteps: ['Use `update_progress` when the user finishes the video.'],
|
|
394
|
+
annotations: {
|
|
395
|
+
readOnlyHint: true,
|
|
396
|
+
destructiveHint: false,
|
|
397
|
+
idempotentHint: true,
|
|
398
|
+
openWorldHint: true,
|
|
399
|
+
},
|
|
400
|
+
},
|
|
401
|
+
open_exercise_step_files: {
|
|
402
|
+
title: 'Open Exercise Step Files',
|
|
403
|
+
summary: 'Open the files that differ between the current playground and solution.',
|
|
404
|
+
inputs: [
|
|
405
|
+
{
|
|
406
|
+
name: 'workshopDirectory',
|
|
407
|
+
type: 'string',
|
|
408
|
+
required: true,
|
|
409
|
+
description: 'Absolute path to the workshop root.',
|
|
410
|
+
examples: ['/Users/alice/workshops/react-fundamentals'],
|
|
411
|
+
},
|
|
412
|
+
],
|
|
413
|
+
returns: '{ files: Array<{ path, line }> }',
|
|
414
|
+
examples: [
|
|
415
|
+
{
|
|
416
|
+
description: 'Open files for the current step',
|
|
417
|
+
params: '{ "workshopDirectory": "/Users/alice/workshops/react" }',
|
|
418
|
+
},
|
|
419
|
+
],
|
|
420
|
+
nextSteps: [
|
|
421
|
+
'Edit the opened files in the editor.',
|
|
422
|
+
'Run tests or the dev server to verify progress.',
|
|
423
|
+
],
|
|
424
|
+
annotations: {
|
|
425
|
+
readOnlyHint: false,
|
|
426
|
+
destructiveHint: false,
|
|
427
|
+
idempotentHint: false,
|
|
428
|
+
openWorldHint: false,
|
|
429
|
+
},
|
|
430
|
+
},
|
|
431
|
+
get_user_info: {
|
|
432
|
+
title: 'Get User Info',
|
|
433
|
+
summary: 'Return the current authenticated user details (or null if logged out).',
|
|
434
|
+
inputs: [
|
|
435
|
+
{
|
|
436
|
+
name: 'workshopDirectory',
|
|
437
|
+
type: 'string',
|
|
438
|
+
required: true,
|
|
439
|
+
description: 'Absolute path to the workshop root.',
|
|
440
|
+
examples: ['/Users/alice/workshops/react-fundamentals'],
|
|
441
|
+
},
|
|
442
|
+
],
|
|
443
|
+
returns: '{ id, email, name } | null',
|
|
444
|
+
examples: [
|
|
445
|
+
{
|
|
446
|
+
description: 'Check authentication status',
|
|
447
|
+
params: '{ "workshopDirectory": "/Users/alice/workshops/react" }',
|
|
448
|
+
},
|
|
449
|
+
],
|
|
450
|
+
nextSteps: ['Call `login` if the user is not authenticated.'],
|
|
451
|
+
annotations: {
|
|
452
|
+
readOnlyHint: true,
|
|
453
|
+
destructiveHint: false,
|
|
454
|
+
idempotentHint: true,
|
|
455
|
+
openWorldHint: true,
|
|
456
|
+
},
|
|
457
|
+
},
|
|
458
|
+
get_user_access: {
|
|
459
|
+
title: 'Get User Access',
|
|
460
|
+
summary: 'Check whether the user has paid access to workshop features.',
|
|
461
|
+
inputs: [
|
|
462
|
+
{
|
|
463
|
+
name: 'workshopDirectory',
|
|
464
|
+
type: 'string',
|
|
465
|
+
required: true,
|
|
466
|
+
description: 'Absolute path to the workshop root.',
|
|
467
|
+
examples: ['/Users/alice/workshops/react-fundamentals'],
|
|
468
|
+
},
|
|
469
|
+
],
|
|
470
|
+
returns: '{ userHasAccess }',
|
|
471
|
+
examples: [
|
|
472
|
+
{
|
|
473
|
+
description: 'Check paid access status',
|
|
474
|
+
params: '{ "workshopDirectory": "/Users/alice/workshops/react" }',
|
|
475
|
+
},
|
|
476
|
+
],
|
|
477
|
+
nextSteps: ['Encourage upgrade if access is required.'],
|
|
478
|
+
annotations: {
|
|
479
|
+
readOnlyHint: true,
|
|
480
|
+
destructiveHint: false,
|
|
481
|
+
idempotentHint: true,
|
|
482
|
+
openWorldHint: true,
|
|
483
|
+
},
|
|
484
|
+
},
|
|
485
|
+
get_user_progress: {
|
|
486
|
+
title: 'Get User Progress',
|
|
487
|
+
summary: 'Return the full progress list for the current user across the workshop.',
|
|
488
|
+
inputs: [
|
|
489
|
+
{
|
|
490
|
+
name: 'workshopDirectory',
|
|
491
|
+
type: 'string',
|
|
492
|
+
required: true,
|
|
493
|
+
description: 'Absolute path to the workshop root.',
|
|
494
|
+
examples: ['/Users/alice/workshops/react-fundamentals'],
|
|
495
|
+
},
|
|
496
|
+
],
|
|
497
|
+
returns: '{ progress[] }',
|
|
498
|
+
examples: [
|
|
499
|
+
{
|
|
500
|
+
description: 'Fetch progress list',
|
|
501
|
+
params: '{ "workshopDirectory": "/Users/alice/workshops/react" }',
|
|
502
|
+
},
|
|
503
|
+
],
|
|
504
|
+
nextSteps: [
|
|
505
|
+
'Use `update_progress` to mark lessons complete.',
|
|
506
|
+
'Use `get_what_is_next` to focus on the next item.',
|
|
507
|
+
],
|
|
508
|
+
annotations: {
|
|
509
|
+
readOnlyHint: true,
|
|
510
|
+
destructiveHint: false,
|
|
511
|
+
idempotentHint: true,
|
|
512
|
+
openWorldHint: true,
|
|
513
|
+
},
|
|
514
|
+
},
|
|
515
|
+
get_quiz_instructions: {
|
|
516
|
+
title: 'Get Quiz Instructions',
|
|
517
|
+
summary: 'Return a prompt that guides the assistant to quiz the user on a topic.',
|
|
518
|
+
inputs: [
|
|
519
|
+
{
|
|
520
|
+
name: 'workshopDirectory',
|
|
521
|
+
type: 'string',
|
|
522
|
+
required: true,
|
|
523
|
+
description: 'Absolute path to the workshop root.',
|
|
524
|
+
examples: ['/Users/alice/workshops/react-fundamentals'],
|
|
525
|
+
},
|
|
526
|
+
{
|
|
527
|
+
name: 'exerciseNumber',
|
|
528
|
+
type: 'string',
|
|
529
|
+
required: false,
|
|
530
|
+
description: 'Exercise number to quiz. Omit for a random exercise.',
|
|
531
|
+
examples: ['4'],
|
|
532
|
+
},
|
|
533
|
+
],
|
|
534
|
+
returns: '{ messages[] }',
|
|
535
|
+
examples: [
|
|
536
|
+
{
|
|
537
|
+
description: 'Quiz the user on exercise 4',
|
|
538
|
+
params: '{ "workshopDirectory": "/Users/alice/workshops/react", "exerciseNumber": "4" }',
|
|
539
|
+
},
|
|
540
|
+
],
|
|
541
|
+
nextSteps: ['Follow the prompt and ask questions one at a time.'],
|
|
542
|
+
annotations: {
|
|
543
|
+
readOnlyHint: true,
|
|
544
|
+
destructiveHint: false,
|
|
545
|
+
idempotentHint: true,
|
|
546
|
+
openWorldHint: false,
|
|
547
|
+
},
|
|
548
|
+
},
|
|
549
|
+
get_what_is_next: {
|
|
550
|
+
title: 'Get What Is Next',
|
|
551
|
+
summary: 'Determine the next action a user should take in the workshop.',
|
|
552
|
+
inputs: [
|
|
553
|
+
{
|
|
554
|
+
name: 'workshopDirectory',
|
|
555
|
+
type: 'string',
|
|
556
|
+
required: true,
|
|
557
|
+
description: 'Absolute path to the workshop root.',
|
|
558
|
+
examples: ['/Users/alice/workshops/react-fundamentals'],
|
|
559
|
+
},
|
|
560
|
+
],
|
|
561
|
+
returns: '{ nextStep, context }',
|
|
562
|
+
examples: [
|
|
563
|
+
{
|
|
564
|
+
description: 'Find the next step for a user',
|
|
565
|
+
params: '{ "workshopDirectory": "/Users/alice/workshops/react" }',
|
|
566
|
+
},
|
|
567
|
+
],
|
|
568
|
+
nextSteps: [
|
|
569
|
+
'Follow the instructions returned in the response.',
|
|
570
|
+
'Call `update_progress` when the user completes the step.',
|
|
571
|
+
],
|
|
572
|
+
annotations: {
|
|
573
|
+
readOnlyHint: true,
|
|
574
|
+
destructiveHint: false,
|
|
575
|
+
idempotentHint: false,
|
|
576
|
+
openWorldHint: true,
|
|
577
|
+
},
|
|
578
|
+
},
|
|
579
|
+
};
|
|
580
|
+
export const promptDocs = {
|
|
581
|
+
quiz_me: {
|
|
582
|
+
title: 'Quiz Me',
|
|
583
|
+
description: 'Guide the assistant to quiz the user on a workshop exercise using context.',
|
|
584
|
+
examples: ['Quiz me on exercise 4', 'Quiz me on a random exercise'],
|
|
585
|
+
nextSteps: [
|
|
586
|
+
'Ask one question at a time and give hints if the user struggles.',
|
|
587
|
+
],
|
|
588
|
+
},
|
|
589
|
+
};
|
|
590
|
+
export const resourceDocs = {
|
|
591
|
+
workshop_context: {
|
|
592
|
+
name: 'workshop_context',
|
|
593
|
+
description: 'Workshop overview with README, config, exercises, and progress.',
|
|
594
|
+
},
|
|
595
|
+
exercise_context: {
|
|
596
|
+
name: 'exercise_context',
|
|
597
|
+
description: 'Exercise details with instructions, transcripts, and step progress.',
|
|
598
|
+
},
|
|
599
|
+
exercise_step_context: {
|
|
600
|
+
name: 'exercise_step_context',
|
|
601
|
+
description: 'Step-specific instructions, transcripts, and progress details.',
|
|
602
|
+
},
|
|
603
|
+
diff_between_apps: {
|
|
604
|
+
name: 'diff_between_apps',
|
|
605
|
+
description: 'Git diff between two exercise apps.',
|
|
606
|
+
},
|
|
607
|
+
exercise_step_progress_diff: {
|
|
608
|
+
name: 'exercise_step_progress_diff',
|
|
609
|
+
description: 'Git diff between playground and solution for current step.',
|
|
610
|
+
},
|
|
611
|
+
user_info: {
|
|
612
|
+
name: 'user_info',
|
|
613
|
+
description: 'Authenticated user info for the current workshop.',
|
|
614
|
+
},
|
|
615
|
+
user_access: {
|
|
616
|
+
name: 'user_access',
|
|
617
|
+
description: 'Paid access status for the current user.',
|
|
618
|
+
},
|
|
619
|
+
user_progress: {
|
|
620
|
+
name: 'user_progress',
|
|
621
|
+
description: 'Progress list for the current user.',
|
|
622
|
+
},
|
|
623
|
+
};
|
|
624
|
+
export function formatToolDescription(doc) {
|
|
625
|
+
const lines = [doc.summary];
|
|
626
|
+
if (doc.inputs.length) {
|
|
627
|
+
lines.push('', 'Inputs:');
|
|
628
|
+
for (const input of doc.inputs) {
|
|
629
|
+
const requiredLabel = input.required ? 'required' : 'optional';
|
|
630
|
+
const exampleText = input.examples?.length
|
|
631
|
+
? ` Examples: ${input.examples.join(', ')}.`
|
|
632
|
+
: '';
|
|
633
|
+
lines.push(`- \`${input.name}\` (${input.type}, ${requiredLabel}) - ${input.description}${exampleText}`);
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
lines.push('', `Returns: ${doc.returns}`);
|
|
637
|
+
if (doc.examples.length) {
|
|
638
|
+
lines.push('', 'Examples:');
|
|
639
|
+
for (const example of doc.examples) {
|
|
640
|
+
lines.push(`- "${example.description}" -> ${example.params}`);
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
if (doc.nextSteps.length) {
|
|
644
|
+
lines.push('', 'Next steps:');
|
|
645
|
+
for (const step of doc.nextSteps) {
|
|
646
|
+
lines.push(`- ${step}`);
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
return lines.join('\n').trim();
|
|
650
|
+
}
|
|
651
|
+
export function formatPromptDescription(doc) {
|
|
652
|
+
const lines = [doc.description];
|
|
653
|
+
if (doc.examples.length) {
|
|
654
|
+
lines.push('', 'Examples:');
|
|
655
|
+
for (const example of doc.examples) {
|
|
656
|
+
lines.push(`- ${example}`);
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
if (doc.nextSteps.length) {
|
|
660
|
+
lines.push('', 'Next steps:');
|
|
661
|
+
for (const step of doc.nextSteps) {
|
|
662
|
+
lines.push(`- ${step}`);
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
return lines.join('\n').trim();
|
|
666
|
+
}
|