@thehammer/danx-dashboard-mcp 0.1.47 → 0.1.48
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/handlers.js +11 -11
- package/dist/index.js +15 -15
- package/package.json +1 -1
package/dist/handlers.js
CHANGED
|
@@ -95,49 +95,49 @@ export async function repoKnowledgeSet(client, args) {
|
|
|
95
95
|
board,
|
|
96
96
|
});
|
|
97
97
|
}
|
|
98
|
-
// ----------------
|
|
99
|
-
const
|
|
98
|
+
// ---------------- brief_list / brief_get_page / brief_set_page ----------------
|
|
99
|
+
const BRIEF_BASE_PATH = "/api/brief";
|
|
100
100
|
/**
|
|
101
|
-
* List the board's named
|
|
101
|
+
* List the board's named Brief pages via GET /api/brief (DX-2083).
|
|
102
102
|
* Mirrors `repoKnowledgeGet`'s shape (a bare board-scoped GET, no id) but
|
|
103
103
|
* targets the list-shaped sibling surface — many named pages per board,
|
|
104
104
|
* not one document.
|
|
105
105
|
*/
|
|
106
|
-
export async function
|
|
106
|
+
export async function briefList(client, args = {}) {
|
|
107
107
|
return client.request({
|
|
108
108
|
method: "GET",
|
|
109
109
|
path: "",
|
|
110
|
-
basePath:
|
|
110
|
+
basePath: BRIEF_BASE_PATH,
|
|
111
111
|
board: args.board,
|
|
112
112
|
});
|
|
113
113
|
}
|
|
114
114
|
/**
|
|
115
|
-
* Fetch one
|
|
115
|
+
* Fetch one Brief page by slug via GET /api/brief/page?slug=
|
|
116
116
|
* (DX-2083). A missing row (including a not-yet-created page) reads as the
|
|
117
117
|
* same empty-view convention `repoKnowledgeGet` uses — never a 404.
|
|
118
118
|
*/
|
|
119
|
-
export async function
|
|
119
|
+
export async function briefGetPage(client, args) {
|
|
120
120
|
return client.request({
|
|
121
121
|
method: "GET",
|
|
122
122
|
path: "/page",
|
|
123
|
-
basePath:
|
|
123
|
+
basePath: BRIEF_BASE_PATH,
|
|
124
124
|
query: { slug: args.slug },
|
|
125
125
|
board: args.board,
|
|
126
126
|
});
|
|
127
127
|
}
|
|
128
128
|
/**
|
|
129
|
-
* Write one
|
|
129
|
+
* Write one Brief page via PUT /api/brief/page?slug= (DX-2083).
|
|
130
130
|
* Mirrors `repoKnowledgeSet`'s shape (optimistic-concurrency `base_hash`,
|
|
131
131
|
* verbatim 409 passthrough on a stale write) but targets one named page
|
|
132
132
|
* instead of the board's single working-knowledge doc. `slug` rides the
|
|
133
133
|
* query string (matching the route), never the body.
|
|
134
134
|
*/
|
|
135
|
-
export async function
|
|
135
|
+
export async function briefSetPage(client, args) {
|
|
136
136
|
const { slug, board, ...body } = args;
|
|
137
137
|
return client.request({
|
|
138
138
|
method: "PUT",
|
|
139
139
|
path: "/page",
|
|
140
|
-
basePath:
|
|
140
|
+
basePath: BRIEF_BASE_PATH,
|
|
141
141
|
query: { slug },
|
|
142
142
|
body,
|
|
143
143
|
board,
|
package/dist/index.js
CHANGED
|
@@ -28,9 +28,9 @@
|
|
|
28
28
|
* - issue_attach POST /api/issues/:id/attachments (reads a local file)
|
|
29
29
|
* - repo_knowledge_get GET /api/repo-knowledge
|
|
30
30
|
* - repo_knowledge_set PUT /api/repo-knowledge (DX-1128, Story 2)
|
|
31
|
-
* -
|
|
32
|
-
* -
|
|
33
|
-
* -
|
|
31
|
+
* - brief_list GET /api/brief
|
|
32
|
+
* - brief_get_page GET /api/brief/page (DX-2083 / DX-2484)
|
|
33
|
+
* - brief_set_page PUT /api/brief/page (DX-2083 / DX-2484)
|
|
34
34
|
* - plan_list GET /api/plans (DX-2683)
|
|
35
35
|
* - plan_get GET /api/plans/:id/full | /api/plans/mine
|
|
36
36
|
* - plan_connect POST /api/plan-sessions/me/plan
|
|
@@ -75,7 +75,7 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
|
75
75
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
76
76
|
import { z } from "zod";
|
|
77
77
|
import { DashboardHttpClient } from "./http-client.js";
|
|
78
|
-
import { issueAttach, issueChecklist, issueComment, issueCreate, issueDependency, issueEdit, issueGet, issueList, issueQualityGate, issueQualityGateVerdict, issueRequiresHuman, issueRetro, issueTransition, issueTriage,
|
|
78
|
+
import { issueAttach, issueChecklist, issueComment, issueCreate, issueDependency, issueEdit, issueGet, issueList, issueQualityGate, issueQualityGateVerdict, issueRequiresHuman, issueRetro, issueTransition, issueTriage, briefGetPage, briefList, briefSetPage, planAddCard, planAddRecord, planConnect, planGet, planList, planSetArchitecture, repoKnowledgeGet, repoKnowledgeSet, } from "./handlers.js";
|
|
79
79
|
import { PRIORITY_TIER_WORDS } from "./priority.js";
|
|
80
80
|
function readEnvOrDie(name) {
|
|
81
81
|
const v = process.env[name];
|
|
@@ -522,20 +522,20 @@ server.tool("repo_knowledge_set", 'Write the board\'s working-knowledge markdown
|
|
|
522
522
|
.describe('The contentHash last read via repo_knowledge_get ("" for a true first write). Omitted also normalizes to "" server-side, so it only succeeds against an empty/absent doc — always get immediately before set.'),
|
|
523
523
|
...boardField,
|
|
524
524
|
}, async (args) => jsonResult(await repoKnowledgeSet(client, args)));
|
|
525
|
-
// ----------------
|
|
526
|
-
server.tool("
|
|
525
|
+
// ---------------- brief_list ----------------
|
|
526
|
+
server.tool("brief_list", "List the board's named Brief pages via GET /api/brief (DX-2083 / DX-2484). Board-scoped; defaults to the dispatch's board. Pass `board` (a qualified id `<repo>:<slug>`) to list another board's pages. Returns `{boardId, pages: [{slug, title, contentHash, sortOrder, updatedAt, updatedBy}]}` — metadata only, no page content (use `brief_get_page` for that). This is the list+page-shaped sibling of `repo_knowledge_get`/`repo_knowledge_set` (one board-level doc) — Brief pages are MANY named pages per board (the Goals / Architecture / Rules / Caveats tabs), keyed by `(board, slug)`. The reserved `index` slug always exists — every board carries exactly one.", {
|
|
527
527
|
...boardField,
|
|
528
|
-
}, async (args) => jsonResult(await
|
|
529
|
-
// ----------------
|
|
530
|
-
server.tool("
|
|
528
|
+
}, async (args) => jsonResult(await briefList(client, args)));
|
|
529
|
+
// ---------------- brief_get_page ----------------
|
|
530
|
+
server.tool("brief_get_page", 'Fetch one Brief page by slug via GET /api/brief/page?slug=<slug> (DX-2083 / DX-2484). Board-scoped; defaults to the dispatch\'s board. Returns `{boardId, slug, title, content, contentHash, sortOrder, updatedAt, updatedBy}` — a missing/not-yet-created page reads as the empty view (`content: ""`, `contentHash: ""`), NOT a 404, matching `repo_knowledge_get`\'s convention. Before `brief_set_page`, ALWAYS `brief_get_page` immediately first and pass its `contentHash` back as `base_hash` — the server\'s optimistic-concurrency guard rejects a stale write.', {
|
|
531
531
|
slug: z
|
|
532
532
|
.string()
|
|
533
533
|
.min(1)
|
|
534
534
|
.describe("The page's slug. The reserved `index` slug always exists on every board."),
|
|
535
535
|
...boardField,
|
|
536
|
-
}, async (args) => jsonResult(await
|
|
537
|
-
// ----------------
|
|
538
|
-
server.tool("
|
|
536
|
+
}, async (args) => jsonResult(await briefGetPage(client, args)));
|
|
537
|
+
// ---------------- brief_set_page ----------------
|
|
538
|
+
server.tool("brief_set_page", 'Write one Brief page via PUT /api/brief/page?slug=<slug> (DX-2083 / DX-2484). Board-scoped; defaults to the dispatch\'s board. Body: `{content, title?, sortOrder?, base_hash?}` — mirrors `repo_knowledge_set`\'s optimistic-concurrency shape but targets one named page instead of the board\'s single working-knowledge doc. `base_hash` MUST be the `contentHash` from the immediately-prior `brief_get_page` call ("" for a true first write, when the page doesn\'t exist yet) — the server compares it against the CURRENT hash and, on mismatch, fails loud with `{ok: false, body: {error: "stale_brief_page", currentHash}}` rather than silently overwriting a concurrent write — re-get, re-merge, and retry on that refusal, never retry blindly or overwrite. On success, persists to the DB, publishes `brief:updated` over SSE, and returns the new view. NO delete tool is exposed on this surface — the reserved `index` slug can never be deleted through the tool surface, matching the route\'s own refusal; deleting a non-index page is dashboard-UI-only for now.', {
|
|
539
539
|
slug: z
|
|
540
540
|
.string()
|
|
541
541
|
.min(1)
|
|
@@ -546,9 +546,9 @@ server.tool("master_plan_set_page", 'Write one Master Plan page via PUT /api/mas
|
|
|
546
546
|
base_hash: z
|
|
547
547
|
.string()
|
|
548
548
|
.optional()
|
|
549
|
-
.describe('The contentHash last read via
|
|
549
|
+
.describe('The contentHash last read via brief_get_page ("" for a true first write). Omitted also normalizes to "" server-side, so it only succeeds against an empty/absent page — always get immediately before set.'),
|
|
550
550
|
...boardField,
|
|
551
|
-
}, async (args) => jsonResult(await
|
|
551
|
+
}, async (args) => jsonResult(await briefSetPage(client, args)));
|
|
552
552
|
// ---------------- plans (DX-2683) ----------------
|
|
553
553
|
// THE BINDING ASYMMETRY IS IN THE SCHEMAS, NOT IN PROSE. `plan_get` takes an
|
|
554
554
|
// optional `plan_id`; `plan_add_record`, `plan_add_card` and
|
|
@@ -556,7 +556,7 @@ server.tool("master_plan_set_page", 'Write one Master Plan page via PUT /api/mas
|
|
|
556
556
|
// cannot even express "write to that other plan". `plan_connect` takes one
|
|
557
557
|
// because binding a session to a plan is the one operation that is ABOUT a
|
|
558
558
|
// plan id — and it can only ever bind the caller's own session.
|
|
559
|
-
server.tool("plan_list", "List every plan via GET /api/plans (DX-2683), and learn which plan THIS session is connected to. Plans are GLOBAL, not board-scoped: a plan is a named, dated set of cards an operator assembled by hand, and its cards may come from any repository. Returns `{ok, status, body: {plans: [{id, name, createdAt, cardCount, boards}], session}}`. `session` is your own registration — `{sessionId, title, planId, planName, firstSeenAt, lastActiveAt}` — or `null` if this process is not running inside a Claude Code session. A `planId` of null means you are connected to no plan: read any plan with `plan_get`, then `plan_connect` to the one you are working on (or ask the operator to connect you from the Plans list). NOTE this is NOT the board
|
|
559
|
+
server.tool("plan_list", "List every plan via GET /api/plans (DX-2683), and learn which plan THIS session is connected to. Plans are GLOBAL, not board-scoped: a plan is a named, dated set of cards an operator assembled by hand, and its cards may come from any repository. Returns `{ok, status, body: {plans: [{id, name, createdAt, cardCount, boards}], session}}`. `session` is your own registration — `{sessionId, title, planId, planName, firstSeenAt, lastActiveAt}` — or `null` if this process is not running inside a Claude Code session. A `planId` of null means you are connected to no plan: read any plan with `plan_get`, then `plan_connect` to the one you are working on (or ask the operator to connect you from the Plans list). NOTE this is NOT the board Brief (`brief_list`), which is a different feature entirely.", {}, async () => jsonResult(await planList(client)));
|
|
560
560
|
server.tool("plan_get", "Read one plan WHOLE via GET /api/plans (DX-2683) — its member cards (with the boards they cover), its goals, rules and caveats, its architecture document, the sessions working on it, and your own session state. One call, not five. Pass `plan_id` to read ANY plan (browsing another plan is useful and changes nothing); OMIT it to read the plan this session is connected to. Omitting it while connected to no plan fails loud with `{error: \"session_not_connected\"}` — connect first. Returns `{plan, cards, boards, records: {goal: [], rule: [], caveat: []}, architecture: {content, contentHash, updatedAt, updatedBy}, sessions, session}`. ALWAYS `plan_get` immediately before `plan_set_architecture` and pass the returned `architecture.contentHash` back as `base_hash`.", {
|
|
561
561
|
plan_id: z
|
|
562
562
|
.number()
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thehammer/danx-dashboard-mcp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.48",
|
|
4
4
|
"description": "Stdio MCP server wrapping danxbot's dashboard /api/issues/* normalized DB-backed HTTP routes for dispatched agents (DX-704 Phase 2).",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|