@limeadelabs/launchpad-mcp 1.0.0 → 1.2.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 +10 -0
- package/dist/index.js +391 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -54,11 +54,21 @@ Or add manually to `~/.claude/claude_desktop_config.json`:
|
|
|
54
54
|
| `lp_list_pages` | List spec/doc pages for a project |
|
|
55
55
|
| `lp_get_page` | Get a page's full content |
|
|
56
56
|
| `lp_get_workflow` | Get valid workflow states and transitions |
|
|
57
|
+
| `lp_context_list` | List context entries with optional filters (project, type, search) |
|
|
58
|
+
| `lp_context_get` | Fetch a context entry's full content by slug or ID |
|
|
59
|
+
| `lp_context_package` | Get assembled context package for a task (org + project entries, specs, comments) |
|
|
60
|
+
| `lp_context_update` | Update a context entry's content (requires write access) |
|
|
57
61
|
|
|
58
62
|
## Resources
|
|
59
63
|
|
|
60
64
|
- `launchpad://project/{id}/context` — Project instructions, conventions, and page summaries
|
|
61
65
|
- `launchpad://task/{id}/spec` — Full generated task spec
|
|
66
|
+
- `context://entries` — Browse all active context entries
|
|
67
|
+
- `context://entries/{slug}` — Read a specific context entry
|
|
68
|
+
|
|
69
|
+
### Resources vs Tools
|
|
70
|
+
|
|
71
|
+
Resources are for **passive browsing** in the Claude Code resource panel. Tools are for **active agent invocation** during conversation. Both access the same underlying context registry API.
|
|
62
72
|
|
|
63
73
|
## Prompts
|
|
64
74
|
|
package/dist/index.js
CHANGED
|
@@ -20,8 +20,8 @@ var LaunchPadClient = class {
|
|
|
20
20
|
this.apiKey = config.apiKey;
|
|
21
21
|
this.timeoutMs = config.timeoutMs ?? 1e4;
|
|
22
22
|
}
|
|
23
|
-
async request(method,
|
|
24
|
-
const url = `${this.baseUrl}/api/v1${
|
|
23
|
+
async request(method, path2, body) {
|
|
24
|
+
const url = `${this.baseUrl}/api/v1${path2}`;
|
|
25
25
|
const res = await fetch(url, {
|
|
26
26
|
method,
|
|
27
27
|
headers: {
|
|
@@ -34,7 +34,7 @@ var LaunchPadClient = class {
|
|
|
34
34
|
if (!res.ok) {
|
|
35
35
|
const error = await res.json().catch(() => ({ error: res.statusText }));
|
|
36
36
|
throw new LaunchPadError(
|
|
37
|
-
`${method} ${
|
|
37
|
+
`${method} ${path2}: ${res.status} \u2014 ${error.error || res.statusText}`,
|
|
38
38
|
res.status
|
|
39
39
|
);
|
|
40
40
|
}
|
|
@@ -99,6 +99,44 @@ var LaunchPadClient = class {
|
|
|
99
99
|
getWorkflow(projectId) {
|
|
100
100
|
return this.request("GET", `/projects/${projectId}/workflow`);
|
|
101
101
|
}
|
|
102
|
+
listContextEntries(params) {
|
|
103
|
+
const searchParams = new URLSearchParams();
|
|
104
|
+
if (params?.project_id !== void 0) searchParams.set("project_id", String(params.project_id));
|
|
105
|
+
if (params?.entry_type) searchParams.set("entry_type", params.entry_type);
|
|
106
|
+
if (params?.search) searchParams.set("search", params.search);
|
|
107
|
+
if (params?.limit !== void 0) searchParams.set("limit", String(params.limit));
|
|
108
|
+
if (params?.offset !== void 0) searchParams.set("offset", String(params.offset));
|
|
109
|
+
const query = searchParams.toString();
|
|
110
|
+
return this.request("GET", `/contexts${query ? `?${query}` : ""}`);
|
|
111
|
+
}
|
|
112
|
+
getContextEntry(identifier) {
|
|
113
|
+
return this.request("GET", `/contexts/${encodeURIComponent(identifier)}`);
|
|
114
|
+
}
|
|
115
|
+
getTaskContextPackage(taskId) {
|
|
116
|
+
return this.request("GET", `/tasks/${taskId}/context`);
|
|
117
|
+
}
|
|
118
|
+
updateContextEntry(identifier, data) {
|
|
119
|
+
return this.request("PATCH", `/contexts/${encodeURIComponent(identifier)}`, data);
|
|
120
|
+
}
|
|
121
|
+
createSession(taskId, agentType, agentId) {
|
|
122
|
+
return this.request("POST", "/sessions", {
|
|
123
|
+
task_id: taskId,
|
|
124
|
+
agent_type: agentType ?? "claude_code",
|
|
125
|
+
...agentId !== void 0 && { agent_id: agentId }
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
sessionHeartbeat(sessionId) {
|
|
129
|
+
return this.request("POST", `/sessions/${sessionId}/heartbeat`);
|
|
130
|
+
}
|
|
131
|
+
updateSession(sessionId, data) {
|
|
132
|
+
return this.request("PATCH", `/sessions/${sessionId}`, data);
|
|
133
|
+
}
|
|
134
|
+
createSessionEvent(sessionId, eventType, payload) {
|
|
135
|
+
return this.request("POST", `/sessions/${sessionId}/events`, {
|
|
136
|
+
event_type: eventType,
|
|
137
|
+
payload
|
|
138
|
+
});
|
|
139
|
+
}
|
|
102
140
|
};
|
|
103
141
|
|
|
104
142
|
// src/tools/shared.ts
|
|
@@ -402,6 +440,281 @@ function registerPageTools(server2, client2) {
|
|
|
402
440
|
);
|
|
403
441
|
}
|
|
404
442
|
|
|
443
|
+
// src/tools/context.ts
|
|
444
|
+
import { z as z8 } from "zod";
|
|
445
|
+
function registerContextTools(server2, client2) {
|
|
446
|
+
server2.tool(
|
|
447
|
+
"lp_context_list",
|
|
448
|
+
"List available context entries with optional filters",
|
|
449
|
+
{
|
|
450
|
+
project_id: z8.number().optional().describe("Filter by project ID"),
|
|
451
|
+
entry_type: z8.string().optional().describe("Filter by entry type"),
|
|
452
|
+
search: z8.string().optional().describe("Text search on entry name"),
|
|
453
|
+
limit: z8.number().min(1).max(100).optional().describe("Max entries to return (default 50)"),
|
|
454
|
+
offset: z8.number().min(0).optional().describe("Offset for pagination")
|
|
455
|
+
},
|
|
456
|
+
async (params) => {
|
|
457
|
+
try {
|
|
458
|
+
const result = await client2.listContextEntries(params);
|
|
459
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
460
|
+
} catch (error) {
|
|
461
|
+
return handleError(error, client2.timeoutMs);
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
);
|
|
465
|
+
server2.tool(
|
|
466
|
+
"lp_context_get",
|
|
467
|
+
"Fetch a specific context entry by slug or ID",
|
|
468
|
+
{
|
|
469
|
+
slug: z8.string().optional().describe("Entry slug"),
|
|
470
|
+
id: z8.number().optional().describe("Entry ID")
|
|
471
|
+
},
|
|
472
|
+
async (params) => {
|
|
473
|
+
const identifier = params.slug || (params.id !== void 0 ? String(params.id) : void 0);
|
|
474
|
+
if (!identifier) {
|
|
475
|
+
return {
|
|
476
|
+
content: [{ type: "text", text: JSON.stringify({ error: true, code: "validation_error", message: "Either slug or id is required" }) }],
|
|
477
|
+
isError: true
|
|
478
|
+
};
|
|
479
|
+
}
|
|
480
|
+
try {
|
|
481
|
+
const result = await client2.getContextEntry(identifier);
|
|
482
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
483
|
+
} catch (error) {
|
|
484
|
+
return handleError(error, client2.timeoutMs);
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
);
|
|
488
|
+
server2.tool(
|
|
489
|
+
"lp_context_package",
|
|
490
|
+
"Get the assembled context package for a task \u2014 task details, context entries, specs, pages, comments",
|
|
491
|
+
{
|
|
492
|
+
task_id: z8.number().describe("Task ID")
|
|
493
|
+
},
|
|
494
|
+
async (params) => {
|
|
495
|
+
try {
|
|
496
|
+
const result = await client2.getTaskContextPackage(params.task_id);
|
|
497
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
498
|
+
} catch (error) {
|
|
499
|
+
return handleError(error, client2.timeoutMs);
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
);
|
|
503
|
+
server2.tool(
|
|
504
|
+
"lp_context_update",
|
|
505
|
+
"Update a context entry's content (requires write access)",
|
|
506
|
+
{
|
|
507
|
+
slug: z8.string().optional().describe("Entry slug"),
|
|
508
|
+
id: z8.number().optional().describe("Entry ID"),
|
|
509
|
+
content: z8.string().describe("New markdown content"),
|
|
510
|
+
change_summary: z8.string().describe("What changed and why")
|
|
511
|
+
},
|
|
512
|
+
async (params) => {
|
|
513
|
+
const identifier = params.slug || (params.id !== void 0 ? String(params.id) : void 0);
|
|
514
|
+
if (!identifier) {
|
|
515
|
+
return {
|
|
516
|
+
content: [{ type: "text", text: JSON.stringify({ error: true, code: "validation_error", message: "Either slug or id is required" }) }],
|
|
517
|
+
isError: true
|
|
518
|
+
};
|
|
519
|
+
}
|
|
520
|
+
try {
|
|
521
|
+
const result = await client2.updateContextEntry(identifier, {
|
|
522
|
+
content: params.content,
|
|
523
|
+
change_summary: params.change_summary
|
|
524
|
+
});
|
|
525
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
526
|
+
} catch (error) {
|
|
527
|
+
return handleError(error, client2.timeoutMs);
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
);
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
// src/tools/sessions.ts
|
|
534
|
+
import { z as z9 } from "zod";
|
|
535
|
+
|
|
536
|
+
// src/session-store.ts
|
|
537
|
+
import fs from "fs";
|
|
538
|
+
import os from "os";
|
|
539
|
+
import path from "path";
|
|
540
|
+
var SESSION_FILE = path.join(os.homedir(), ".launchpad", "active-session.json");
|
|
541
|
+
function saveSession(taskId, sessionId) {
|
|
542
|
+
const dir = path.dirname(SESSION_FILE);
|
|
543
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
544
|
+
const data = fs.existsSync(SESSION_FILE) ? JSON.parse(fs.readFileSync(SESSION_FILE, "utf8")) : {};
|
|
545
|
+
data[String(taskId)] = sessionId;
|
|
546
|
+
fs.writeFileSync(SESSION_FILE, JSON.stringify(data, null, 2));
|
|
547
|
+
}
|
|
548
|
+
function getSessionId(taskId) {
|
|
549
|
+
if (!fs.existsSync(SESSION_FILE)) return null;
|
|
550
|
+
const data = JSON.parse(fs.readFileSync(SESSION_FILE, "utf8"));
|
|
551
|
+
return data[String(taskId)] ?? null;
|
|
552
|
+
}
|
|
553
|
+
function clearSession(taskId) {
|
|
554
|
+
if (!fs.existsSync(SESSION_FILE)) return;
|
|
555
|
+
const data = JSON.parse(fs.readFileSync(SESSION_FILE, "utf8"));
|
|
556
|
+
delete data[String(taskId)];
|
|
557
|
+
fs.writeFileSync(SESSION_FILE, JSON.stringify(data, null, 2));
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
// src/tools/sessions.ts
|
|
561
|
+
function registerSessionTools(server2, client2) {
|
|
562
|
+
server2.tool(
|
|
563
|
+
"lp_session_start",
|
|
564
|
+
"Start a new agent session for a task. Creates session via API and saves session_id to disk for later lookup.",
|
|
565
|
+
{
|
|
566
|
+
task_id: z9.number().describe("LaunchPad task ID"),
|
|
567
|
+
agent_type: z9.string().optional().describe("Agent type (default: claude_code)")
|
|
568
|
+
},
|
|
569
|
+
async ({ task_id, agent_type }) => {
|
|
570
|
+
try {
|
|
571
|
+
const result = await client2.createSession(task_id, agent_type);
|
|
572
|
+
saveSession(task_id, result.session.id);
|
|
573
|
+
return {
|
|
574
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
575
|
+
};
|
|
576
|
+
} catch (error) {
|
|
577
|
+
return handleError(error, client2.timeoutMs);
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
);
|
|
581
|
+
server2.tool(
|
|
582
|
+
"lp_session_heartbeat",
|
|
583
|
+
"Send a heartbeat for an active session. Provide session_id directly or task_id to look up session from disk. Graceful no-op if neither provided.",
|
|
584
|
+
{
|
|
585
|
+
session_id: z9.number().optional().describe("Session ID"),
|
|
586
|
+
task_id: z9.number().optional().describe("Task ID to look up session from disk")
|
|
587
|
+
},
|
|
588
|
+
async ({ session_id, task_id }) => {
|
|
589
|
+
try {
|
|
590
|
+
const resolvedId = session_id ?? (task_id !== void 0 ? getSessionId(task_id) : null);
|
|
591
|
+
if (resolvedId === null) {
|
|
592
|
+
return {
|
|
593
|
+
content: [{ type: "text", text: "No active session found. Provide session_id or task_id." }]
|
|
594
|
+
};
|
|
595
|
+
}
|
|
596
|
+
const result = await client2.sessionHeartbeat(resolvedId);
|
|
597
|
+
return {
|
|
598
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
599
|
+
};
|
|
600
|
+
} catch (error) {
|
|
601
|
+
return handleError(error, client2.timeoutMs);
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
);
|
|
605
|
+
server2.tool(
|
|
606
|
+
"lp_session_progress",
|
|
607
|
+
'Report progress on an active session. Sends an activity update with action "progress".',
|
|
608
|
+
{
|
|
609
|
+
session_id: z9.number().describe("Session ID"),
|
|
610
|
+
detail: z9.string().describe("Description of progress made")
|
|
611
|
+
},
|
|
612
|
+
async ({ session_id, detail }) => {
|
|
613
|
+
try {
|
|
614
|
+
const result = await client2.updateSession(session_id, {
|
|
615
|
+
activity: { action: "progress", detail }
|
|
616
|
+
});
|
|
617
|
+
return {
|
|
618
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
619
|
+
};
|
|
620
|
+
} catch (error) {
|
|
621
|
+
return handleError(error, client2.timeoutMs);
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
);
|
|
625
|
+
server2.tool(
|
|
626
|
+
"lp_session_event",
|
|
627
|
+
"Log a discrete event for a session (commit, ci_pass, ci_fail, pr_opened, blocker, cost_update).",
|
|
628
|
+
{
|
|
629
|
+
session_id: z9.number().describe("Session ID"),
|
|
630
|
+
event_type: z9.enum(["commit", "ci_pass", "ci_fail", "pr_opened", "blocker", "cost_update"]).describe("Type of event"),
|
|
631
|
+
payload: z9.record(z9.unknown()).describe("Event payload data")
|
|
632
|
+
},
|
|
633
|
+
async ({ session_id, event_type, payload }) => {
|
|
634
|
+
try {
|
|
635
|
+
const result = await client2.createSessionEvent(session_id, event_type, payload);
|
|
636
|
+
return {
|
|
637
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
638
|
+
};
|
|
639
|
+
} catch (error) {
|
|
640
|
+
return handleError(error, client2.timeoutMs);
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
);
|
|
644
|
+
server2.tool(
|
|
645
|
+
"lp_session_blocked",
|
|
646
|
+
'Mark a session as blocked. Updates status to "blocked" and logs a blocker event.',
|
|
647
|
+
{
|
|
648
|
+
session_id: z9.number().describe("Session ID"),
|
|
649
|
+
reason: z9.string().describe("Reason the session is blocked")
|
|
650
|
+
},
|
|
651
|
+
async ({ session_id, reason }) => {
|
|
652
|
+
try {
|
|
653
|
+
const [sessionResult, eventResult] = await Promise.all([
|
|
654
|
+
client2.updateSession(session_id, { status: "blocked" }),
|
|
655
|
+
client2.createSessionEvent(session_id, "blocker", { reason })
|
|
656
|
+
]);
|
|
657
|
+
return {
|
|
658
|
+
content: [{
|
|
659
|
+
type: "text",
|
|
660
|
+
text: JSON.stringify({ session: sessionResult.session, event: eventResult.event }, null, 2)
|
|
661
|
+
}]
|
|
662
|
+
};
|
|
663
|
+
} catch (error) {
|
|
664
|
+
return handleError(error, client2.timeoutMs);
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
);
|
|
668
|
+
server2.tool(
|
|
669
|
+
"lp_session_complete",
|
|
670
|
+
"Mark a session as completed with a result summary. Clears session from disk.",
|
|
671
|
+
{
|
|
672
|
+
session_id: z9.number().describe("Session ID"),
|
|
673
|
+
result_summary: z9.string().describe("Summary of what was accomplished"),
|
|
674
|
+
task_id: z9.number().optional().describe("Task ID to clear from disk (if not provided, derived from session)")
|
|
675
|
+
},
|
|
676
|
+
async ({ session_id, result_summary, task_id }) => {
|
|
677
|
+
try {
|
|
678
|
+
const result = await client2.updateSession(session_id, {
|
|
679
|
+
status: "completed",
|
|
680
|
+
result_summary
|
|
681
|
+
});
|
|
682
|
+
const resolvedTaskId = task_id ?? result.session.task_id;
|
|
683
|
+
clearSession(resolvedTaskId);
|
|
684
|
+
return {
|
|
685
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
686
|
+
};
|
|
687
|
+
} catch (error) {
|
|
688
|
+
return handleError(error, client2.timeoutMs);
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
);
|
|
692
|
+
server2.tool(
|
|
693
|
+
"lp_session_fail",
|
|
694
|
+
"Mark a session as failed with an error detail. Clears session from disk.",
|
|
695
|
+
{
|
|
696
|
+
session_id: z9.number().describe("Session ID"),
|
|
697
|
+
error_detail: z9.string().describe("Description of the failure"),
|
|
698
|
+
task_id: z9.number().optional().describe("Task ID to clear from disk (if not provided, derived from session)")
|
|
699
|
+
},
|
|
700
|
+
async ({ session_id, error_detail, task_id }) => {
|
|
701
|
+
try {
|
|
702
|
+
const result = await client2.updateSession(session_id, {
|
|
703
|
+
status: "failed",
|
|
704
|
+
result_summary: error_detail
|
|
705
|
+
});
|
|
706
|
+
const resolvedTaskId = task_id ?? result.session.task_id;
|
|
707
|
+
clearSession(resolvedTaskId);
|
|
708
|
+
return {
|
|
709
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
710
|
+
};
|
|
711
|
+
} catch (error) {
|
|
712
|
+
return handleError(error, client2.timeoutMs);
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
);
|
|
716
|
+
}
|
|
717
|
+
|
|
405
718
|
// src/resources/project-context.ts
|
|
406
719
|
function registerProjectContextResource(server2, client2) {
|
|
407
720
|
server2.resource(
|
|
@@ -479,14 +792,80 @@ function registerTaskSpecResource(server2, client2) {
|
|
|
479
792
|
);
|
|
480
793
|
}
|
|
481
794
|
|
|
795
|
+
// src/resources/context-entries.ts
|
|
796
|
+
function registerContextEntriesResource(server2, client2) {
|
|
797
|
+
server2.resource(
|
|
798
|
+
"context-entries",
|
|
799
|
+
"context://entries",
|
|
800
|
+
{
|
|
801
|
+
description: "Browse all active context entries"
|
|
802
|
+
},
|
|
803
|
+
async (uri) => {
|
|
804
|
+
const result = await client2.listContextEntries();
|
|
805
|
+
const lines = ["# Context Entries\n"];
|
|
806
|
+
for (const entry of result.entries) {
|
|
807
|
+
const project = entry.project ? ` (${entry.project.name})` : "";
|
|
808
|
+
lines.push(`- **${entry.name}**${project} \u2014 \`${entry.slug}\` [${entry.entry_type}] (v${entry.version_count}, updated ${entry.updated_at})`);
|
|
809
|
+
}
|
|
810
|
+
return {
|
|
811
|
+
contents: [
|
|
812
|
+
{
|
|
813
|
+
uri: uri.href,
|
|
814
|
+
mimeType: "text/markdown",
|
|
815
|
+
text: lines.join("\n")
|
|
816
|
+
}
|
|
817
|
+
]
|
|
818
|
+
};
|
|
819
|
+
}
|
|
820
|
+
);
|
|
821
|
+
server2.resource(
|
|
822
|
+
"context-entry",
|
|
823
|
+
"context://entries/{slug}",
|
|
824
|
+
{
|
|
825
|
+
description: "Read a specific context entry by slug"
|
|
826
|
+
},
|
|
827
|
+
async (uri) => {
|
|
828
|
+
if (uri.host !== "entries" || !uri.pathname || uri.pathname === "/") {
|
|
829
|
+
throw new Error(`Invalid URI: ${uri.href}`);
|
|
830
|
+
}
|
|
831
|
+
const slug = decodeURIComponent(uri.pathname.slice(1));
|
|
832
|
+
if (!slug) throw new Error("Empty slug in context entry URI");
|
|
833
|
+
const result = await client2.getContextEntry(slug);
|
|
834
|
+
const entry = result.entry;
|
|
835
|
+
const text = [
|
|
836
|
+
`# ${entry.name}`,
|
|
837
|
+
``,
|
|
838
|
+
`- **Type:** ${entry.entry_type}`,
|
|
839
|
+
`- **Slug:** ${entry.slug}`,
|
|
840
|
+
`- **Version:** ${entry.version}`,
|
|
841
|
+
`- **Updated:** ${entry.updated_at}`,
|
|
842
|
+
entry.project ? `- **Project:** ${entry.project.name}` : null,
|
|
843
|
+
``,
|
|
844
|
+
`---`,
|
|
845
|
+
``,
|
|
846
|
+
entry.content
|
|
847
|
+
].filter(Boolean).join("\n");
|
|
848
|
+
return {
|
|
849
|
+
contents: [
|
|
850
|
+
{
|
|
851
|
+
uri: uri.href,
|
|
852
|
+
mimeType: "text/markdown",
|
|
853
|
+
text
|
|
854
|
+
}
|
|
855
|
+
]
|
|
856
|
+
};
|
|
857
|
+
}
|
|
858
|
+
);
|
|
859
|
+
}
|
|
860
|
+
|
|
482
861
|
// src/prompts/start-task.ts
|
|
483
|
-
import { z as
|
|
862
|
+
import { z as z10 } from "zod";
|
|
484
863
|
function registerStartTaskPrompt(server2) {
|
|
485
864
|
server2.prompt(
|
|
486
865
|
"lp_start_task",
|
|
487
866
|
"Guided workflow: find a task, claim it, get context, start working",
|
|
488
867
|
{
|
|
489
|
-
project_id:
|
|
868
|
+
project_id: z10.string().optional().describe("Optional project ID to filter tasks")
|
|
490
869
|
},
|
|
491
870
|
async (args) => {
|
|
492
871
|
const projectLine = args.project_id ? ` Project ID: ${args.project_id}.` : "";
|
|
@@ -516,14 +895,14 @@ IMPORTANT: If this task takes more than 20 minutes, call lp_heartbeat every 20 m
|
|
|
516
895
|
}
|
|
517
896
|
|
|
518
897
|
// src/prompts/submit-task.ts
|
|
519
|
-
import { z as
|
|
898
|
+
import { z as z11 } from "zod";
|
|
520
899
|
function registerSubmitTaskPrompt(server2) {
|
|
521
900
|
server2.prompt(
|
|
522
901
|
"lp_submit_task",
|
|
523
902
|
"Guided workflow: mark task done, add summary comment, release claim",
|
|
524
903
|
{
|
|
525
|
-
task_id:
|
|
526
|
-
summary:
|
|
904
|
+
task_id: z11.string().describe("Task ID to submit"),
|
|
905
|
+
summary: z11.string().describe("Summary of what was completed")
|
|
527
906
|
},
|
|
528
907
|
async (args) => {
|
|
529
908
|
return {
|
|
@@ -572,7 +951,7 @@ try {
|
|
|
572
951
|
}
|
|
573
952
|
var server = new McpServer({
|
|
574
953
|
name: "launchpad",
|
|
575
|
-
version: "1.
|
|
954
|
+
version: "1.2.0"
|
|
576
955
|
});
|
|
577
956
|
registerBootstrapTool(server, client);
|
|
578
957
|
registerProjectTools(server, client);
|
|
@@ -582,8 +961,11 @@ registerCommentTools(server, client);
|
|
|
582
961
|
registerTimeTools(server, client);
|
|
583
962
|
registerPromptTools(server, client);
|
|
584
963
|
registerPageTools(server, client);
|
|
964
|
+
registerContextTools(server, client);
|
|
965
|
+
registerSessionTools(server, client);
|
|
585
966
|
registerProjectContextResource(server, client);
|
|
586
967
|
registerTaskSpecResource(server, client);
|
|
968
|
+
registerContextEntriesResource(server, client);
|
|
587
969
|
registerStartTaskPrompt(server);
|
|
588
970
|
registerSubmitTaskPrompt(server);
|
|
589
971
|
var transport = new StdioServerTransport();
|