stepwell 0.0.0-stage → 0.2.4

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.
@@ -0,0 +1,131 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
4
+ import { TEMPLATE_KINDS, fileHashes, phaseContext, projectTemplates, } from "stepwell-core";
5
+ const MARKDOWN = "text/markdown";
6
+ const JSON_MIME = "application/json";
7
+ function decodeRoot(raw) {
8
+ try {
9
+ return decodeURIComponent(raw);
10
+ }
11
+ catch {
12
+ return raw;
13
+ }
14
+ }
15
+ function readOrThrow(path) {
16
+ try {
17
+ return readFileSync(path, "utf8");
18
+ }
19
+ catch {
20
+ throw new Error(`missing required file: ${path}`);
21
+ }
22
+ }
23
+ export function registerDocsResources(server) {
24
+ server.registerResource("templates", new ResourceTemplate("stepwell://templates/{kind}", {
25
+ list: () => ({
26
+ resources: TEMPLATE_KINDS.map((kind) => ({
27
+ uri: `stepwell://templates/${kind}`,
28
+ name: `template: ${kind}`,
29
+ description: "Canonical skeleton of a mandatory file (M8) — adopt unchanged.",
30
+ mimeType: MARKDOWN,
31
+ })),
32
+ }),
33
+ }), {
34
+ title: "Project templates",
35
+ description: "Canonical skeletons of the four mandatory files (M8): kind = \"backlog\" | \"progress\" | " +
36
+ "\"backlog-archive\" | \"progress-archive\" — the agent creates the files from these " +
37
+ "(variant A: read-only, no init_project).",
38
+ mimeType: MARKDOWN,
39
+ }, (uri, { kind }) => {
40
+ const k = String(kind);
41
+ if (!TEMPLATE_KINDS.includes(k)) {
42
+ throw new Error(`unknown template kind: ${String(kind)} (allowed: ${TEMPLATE_KINDS.join(" | ")})`);
43
+ }
44
+ return {
45
+ contents: [
46
+ { uri: uri.href, text: projectTemplates[k], mimeType: MARKDOWN },
47
+ ],
48
+ };
49
+ });
50
+ server.registerResource("backlog", new ResourceTemplate("stepwell://{root}/backlog", { list: undefined }), {
51
+ title: "BACKLOG.md",
52
+ description: "Open items of a STEPWELL project (verbatim; root percent-encoded in the URI).",
53
+ mimeType: MARKDOWN,
54
+ }, (uri, { root }) => ({
55
+ contents: [
56
+ {
57
+ uri: uri.href,
58
+ text: readOrThrow(join(decodeRoot(String(root)), "BACKLOG.md")),
59
+ mimeType: MARKDOWN,
60
+ },
61
+ ],
62
+ }));
63
+ server.registerResource("progress", new ResourceTemplate("stepwell://{root}/progress", { list: undefined }), {
64
+ title: "PROGRESS.md",
65
+ description: "Progress table + active phases (verbatim; root percent-encoded in the URI).",
66
+ mimeType: MARKDOWN,
67
+ }, (uri, { root }) => ({
68
+ contents: [
69
+ {
70
+ uri: uri.href,
71
+ text: readOrThrow(join(decodeRoot(String(root)), "PROGRESS.md")),
72
+ mimeType: MARKDOWN,
73
+ },
74
+ ],
75
+ }));
76
+ server.registerResource("hashes", new ResourceTemplate("stepwell://{root}/hashes", { list: undefined }), {
77
+ title: "File hashes",
78
+ description: "SHA256 per doc file as JSON (E2/12.5) — the client compares against the last known " +
79
+ "state and skips full reads when everything is unchanged (fast path E3). " +
80
+ "Root percent-encoded in the URI.",
81
+ mimeType: JSON_MIME,
82
+ }, (uri, { root }) => ({
83
+ contents: [
84
+ {
85
+ uri: uri.href,
86
+ text: JSON.stringify(fileHashes(decodeRoot(String(root)))),
87
+ mimeType: JSON_MIME,
88
+ },
89
+ ],
90
+ }));
91
+ server.registerResource("phase", new ResourceTemplate("stepwell://{root}/phase/{phase}", { list: undefined }), {
92
+ title: "Phase context",
93
+ description: "Phase verbatim + table rows + merged backlog item bodies in step order " +
94
+ "(G5/12.6 — composition at read time, no duplicate in the files). Search across active " +
95
+ "phases and archive; root and phase percent-encoded in the URI.",
96
+ mimeType: MARKDOWN,
97
+ }, (uri, { root, phase }) => ({
98
+ contents: [
99
+ {
100
+ uri: uri.href,
101
+ text: phaseContext(decodeRoot(String(root)), decodeRoot(String(phase))).markdown,
102
+ mimeType: MARKDOWN,
103
+ },
104
+ ],
105
+ }));
106
+ server.registerResource("archive", new ResourceTemplate("stepwell://{root}/archive/{kind}", { list: undefined }), {
107
+ title: "Archive",
108
+ description: "Append-only archives: kind = \"backlog\" (BACKLOG_ARCHIVE.md) or \"progress\" " +
109
+ "(PROGRESS_ARCHIVE.md); root percent-encoded in the URI.",
110
+ mimeType: MARKDOWN,
111
+ }, (uri, { root, kind }) => {
112
+ const archivePath = (k) => k === "backlog"
113
+ ? join("docs", "archive", "BACKLOG_ARCHIVE.md")
114
+ : k === "progress"
115
+ ? join("docs", "archive", "PROGRESS_ARCHIVE.md")
116
+ : undefined;
117
+ const rel = archivePath(String(kind));
118
+ if (rel === undefined) {
119
+ throw new Error(`unknown archive kind: ${String(kind)} (allowed: backlog | progress)`);
120
+ }
121
+ return {
122
+ contents: [
123
+ {
124
+ uri: uri.href,
125
+ text: readOrThrow(join(decodeRoot(String(root)), rel)),
126
+ mimeType: MARKDOWN,
127
+ },
128
+ ],
129
+ };
130
+ });
131
+ }
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/serve.js ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3
+ import { createDocsServer } from "./server.js";
4
+ const server = createDocsServer();
5
+ await server.connect(new StdioServerTransport());
@@ -0,0 +1,4 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare const SERVER_NAME = "stepwell";
3
+ export declare const SERVER_VERSION: string;
4
+ export declare function createDocsServer(): McpServer;
package/dist/server.js ADDED
@@ -0,0 +1,32 @@
1
+ import { createRequire } from "node:module";
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { z } from "zod";
4
+ import { registerDocsResources } from "./resources.js";
5
+ import { READ_ONLY_ANNOTATIONS, registerDocsTools } from "./tools.js";
6
+ export const SERVER_NAME = "stepwell";
7
+ // L31/38.1: derived from the workspace package.json — the release bump is the
8
+ // package.json edit alone; the handshake version can never decouple again.
9
+ const require = createRequire(import.meta.url);
10
+ const { version } = require("../package.json");
11
+ export const SERVER_VERSION = version;
12
+ export function createDocsServer() {
13
+ const server = new McpServer({ name: SERVER_NAME, version: SERVER_VERSION }, {
14
+ // M12: conditional, passive entry hint (findability without pushiness —
15
+ // opt-in per project, never auto-init in a foreign repo, M13 direction).
16
+ instructions: "STEPWELL structures the project via four markdown files (BACKLOG.md, PROGRESS.md, docs/archive/*). " +
17
+ "Use these tools only when the project root contains the four STEPWELL files OR the user explicitly asks for STEPWELL. " +
18
+ "Never create structure unrequested in a foreign repo. New to STEPWELL? Start from docs/QUICKSTART.md; " +
19
+ "templates are available as resources.",
20
+ });
21
+ server.registerTool("echo", {
22
+ title: "Echo",
23
+ description: "Echo tool for server verification (step 2.1).",
24
+ annotations: { ...READ_ONLY_ANNOTATIONS },
25
+ inputSchema: { text: z.string().describe("The text to return.") },
26
+ }, async ({ text }) => ({
27
+ content: [{ type: "text", text }],
28
+ }));
29
+ registerDocsTools(server);
30
+ registerDocsResources(server);
31
+ return server;
32
+ }
@@ -0,0 +1,19 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { type Priority } from "stepwell-core";
3
+ export declare const READ_ONLY_ANNOTATIONS: {
4
+ readonly readOnlyHint: true;
5
+ readonly destructiveHint: false;
6
+ readonly idempotentHint: true;
7
+ };
8
+ export declare const DESTRUCTIVE_ANNOTATIONS: {
9
+ readonly readOnlyHint: false;
10
+ readonly destructiveHint: true;
11
+ readonly idempotentHint: false;
12
+ };
13
+ export declare const MUTATING_ANNOTATIONS: {
14
+ readonly readOnlyHint: false;
15
+ readonly destructiveHint: false;
16
+ readonly idempotentHint: false;
17
+ };
18
+ export declare function registerDocsTools(server: McpServer): void;
19
+ export type { Priority };