@extenshi/mcp 0.24.0 → 0.25.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 +3 -0
- package/dist/build-map-app.d.ts +135 -0
- package/dist/build-map-app.d.ts.map +1 -0
- package/dist/build-map-app.js +238 -0
- package/dist/build-map-app.js.map +1 -0
- package/dist/build-map-page.d.ts +58 -0
- package/dist/build-map-page.d.ts.map +1 -0
- package/dist/build-map-page.js +1327 -0
- package/dist/build-map-page.js.map +1 -0
- package/dist/build-map-tools.d.ts +5 -1
- package/dist/build-map-tools.d.ts.map +1 -1
- package/dist/build-map-tools.js +26 -1
- package/dist/build-map-tools.js.map +1 -1
- package/dist/build-map-ui.d.ts +16 -0
- package/dist/build-map-ui.d.ts.map +1 -0
- package/dist/build-map-ui.js +20 -0
- package/dist/build-map-ui.js.map +1 -0
- package/dist/development-guide.d.ts +19 -19
- package/dist/development-guide.d.ts.map +1 -1
- package/dist/development-guide.js +3 -2
- package/dist/development-guide.js.map +1 -1
- package/dist/feedback-form-tools.d.ts +4 -4
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -1
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +19 -0
- package/dist/tools.js.map +1 -1
- package/dist/uninstall-form-tools.d.ts +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -125,9 +125,12 @@ stdio or CLI. See the [development workflow](https://docs.extenshi.io/developers
|
|
|
125
125
|
| `scan_extension` | Pre-publish security scan of a local artifact (.zip/.crx/.xpi), with live progress | 1 scan |
|
|
126
126
|
| `publish_extension` | Publish to Chrome/Firefox/Edge with your own store credentials (fully local) | Free |
|
|
127
127
|
| `get_build_map` | The author's build map of `projectDir` (`npx @extenshi/cli map`): progress, steps waiting on the author, steps that can start now, every step's current task, and the variants offered with the author's answer. Local server only | Free (no key) |
|
|
128
|
+
| `show_build_map` | Draw the build map in the conversation in a client that shows MCP Apps (Claude), optionally open at one step, where the author picks variants, marks their own tasks or skips a step; elsewhere returns the link to the author's map. Local server only | Free (no key) |
|
|
128
129
|
| `report_build_step` | Report on a build map step (start, progress, done with hashed file proof, stop), or record the author's answer from the chat (`choice` / `redo`). Local server only | Free (no key) |
|
|
129
130
|
| `request_build_review` | Offer the author 1–8 variants to choose from on the map (icon concepts, screenshots, listing copy), each a preview page or image in the project; returns the link to the step. Local server only | Free (no key) |
|
|
130
131
|
|
|
132
|
+
In a client that shows [MCP Apps](https://modelcontextprotocol.io/extensions/apps/overview), `show_build_map` draws the map in the conversation (the page `ui://extenshi/build-map`). The page calls three app-only tools, `build_map_view`, `build_map_answer` and `build_map_file`; the server keeps them from any client that does not advertise `io.modelcontextprotocol/ui`.
|
|
133
|
+
|
|
131
134
|
### Identifying an extension by its store id
|
|
132
135
|
|
|
133
136
|
`get_extension`, `get_reviews`, `get_security` and `scan_extension` accept **either** the numeric
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The build map in a chat (plan 2026-11-03-extension-build-map §6.6, phase 4):
|
|
3
|
+
* MCP Apps (2026-01-26) on the local (stdio) server.
|
|
4
|
+
*
|
|
5
|
+
* show_build_map (tools.ts) links to the page `ui://extenshi/build-map`, the
|
|
6
|
+
* same page `extenshi map` serves (build-map-page.ts, a byte-identical copy of
|
|
7
|
+
* the CLI's) built with `app`. A client that shows apps draws it in the
|
|
8
|
+
* conversation; the page then talks to the host, which calls three tools on
|
|
9
|
+
* this server for it, tools the host keeps from the model (`visibility: app`):
|
|
10
|
+
*
|
|
11
|
+
* - build_map_view: the snapshot the page draws. While the author's map server
|
|
12
|
+
* runs, its snapshot as it is (the project facts are read by the CLI only);
|
|
13
|
+
* otherwise one derived from the state file, which says it has no facts.
|
|
14
|
+
* - build_map_answer: the author's answers, the same three writes the map
|
|
15
|
+
* server takes from its page (a mark, a route, a pick or another round),
|
|
16
|
+
* to the same state file under the same lock, checked the same way.
|
|
17
|
+
* - build_map_file: a variant's thumbnail as a data: URL, since the page in a
|
|
18
|
+
* chat may show data: images only (the default MCP Apps CSP).
|
|
19
|
+
*
|
|
20
|
+
* The answers are the author's (`via: 'map'`, who `you`), so build_map_answer
|
|
21
|
+
* refuses unless the client said it shows apps, and index.ts removes all three
|
|
22
|
+
* tools from a client that did not: a client that ignores `visibility` would
|
|
23
|
+
* otherwise list them to the model.
|
|
24
|
+
*
|
|
25
|
+
* Local only: the hosted connector has no access to the author's files and
|
|
26
|
+
* registers none of this.
|
|
27
|
+
*/
|
|
28
|
+
import type { FastMCP } from 'fastmcp';
|
|
29
|
+
import { z } from 'zod';
|
|
30
|
+
/** A thumbnail larger than this shows as its number. */
|
|
31
|
+
export declare const THUMB_MAX_BYTES: number;
|
|
32
|
+
/** The bodies the map server's /api/confirm, /api/route and /api/review take (build-map-server.ts). */
|
|
33
|
+
declare const ANSWERS: {
|
|
34
|
+
readonly confirm: z.ZodObject<{
|
|
35
|
+
node: z.ZodString;
|
|
36
|
+
task: z.ZodNumber;
|
|
37
|
+
done: z.ZodBoolean;
|
|
38
|
+
note: z.ZodEffects<z.ZodOptional<z.ZodString>, string | undefined, string | undefined>;
|
|
39
|
+
}, "strip", z.ZodTypeAny, {
|
|
40
|
+
node: string;
|
|
41
|
+
task: number;
|
|
42
|
+
done: boolean;
|
|
43
|
+
note?: string | undefined;
|
|
44
|
+
}, {
|
|
45
|
+
node: string;
|
|
46
|
+
task: number;
|
|
47
|
+
done: boolean;
|
|
48
|
+
note?: string | undefined;
|
|
49
|
+
}>;
|
|
50
|
+
readonly route: z.ZodObject<{
|
|
51
|
+
node: z.ZodString;
|
|
52
|
+
how: z.ZodNullable<z.ZodEnum<["self", "skip"]>>;
|
|
53
|
+
value: z.ZodOptional<z.ZodString>;
|
|
54
|
+
since: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
55
|
+
note: z.ZodEffects<z.ZodOptional<z.ZodString>, string | undefined, string | undefined>;
|
|
56
|
+
}, "strip", z.ZodTypeAny, {
|
|
57
|
+
node: string;
|
|
58
|
+
how: "self" | "skip" | null;
|
|
59
|
+
value?: string | undefined;
|
|
60
|
+
note?: string | undefined;
|
|
61
|
+
since?: string | null | undefined;
|
|
62
|
+
}, {
|
|
63
|
+
node: string;
|
|
64
|
+
how: "self" | "skip" | null;
|
|
65
|
+
value?: string | undefined;
|
|
66
|
+
note?: string | undefined;
|
|
67
|
+
since?: string | null | undefined;
|
|
68
|
+
}>;
|
|
69
|
+
readonly review: z.ZodObject<{
|
|
70
|
+
node: z.ZodString;
|
|
71
|
+
round: z.ZodNumber;
|
|
72
|
+
revision: z.ZodOptional<z.ZodNumber>;
|
|
73
|
+
choice: z.ZodOptional<z.ZodString>;
|
|
74
|
+
redo: z.ZodOptional<z.ZodString>;
|
|
75
|
+
}, "strip", z.ZodTypeAny, {
|
|
76
|
+
node: string;
|
|
77
|
+
round: number;
|
|
78
|
+
redo?: string | undefined;
|
|
79
|
+
choice?: string | undefined;
|
|
80
|
+
revision?: number | undefined;
|
|
81
|
+
}, {
|
|
82
|
+
node: string;
|
|
83
|
+
round: number;
|
|
84
|
+
redo?: string | undefined;
|
|
85
|
+
choice?: string | undefined;
|
|
86
|
+
revision?: number | undefined;
|
|
87
|
+
}>;
|
|
88
|
+
};
|
|
89
|
+
export type BuildMapAnswerKind = keyof typeof ANSWERS;
|
|
90
|
+
/** Like the map server's answer: ok, or the HTTP status it would send and why. */
|
|
91
|
+
export type BuildMapAnswerResult = {
|
|
92
|
+
ok: true;
|
|
93
|
+
} | {
|
|
94
|
+
ok: false;
|
|
95
|
+
status: number;
|
|
96
|
+
error: string;
|
|
97
|
+
message: string;
|
|
98
|
+
};
|
|
99
|
+
export type BuildMapFileRef = {
|
|
100
|
+
step: string;
|
|
101
|
+
round: number;
|
|
102
|
+
variant: string;
|
|
103
|
+
which: 'image' | 'preview';
|
|
104
|
+
};
|
|
105
|
+
export type BuildMapApp = {
|
|
106
|
+
/** The page, built for a chat. */
|
|
107
|
+
page(): string;
|
|
108
|
+
/** The snapshot to draw; `unchanged` when it is the one `since` names. */
|
|
109
|
+
view(projectDir?: string, since?: string): Promise<{
|
|
110
|
+
etag: string;
|
|
111
|
+
unchanged: true;
|
|
112
|
+
} | {
|
|
113
|
+
etag: string;
|
|
114
|
+
snapshot: Record<string, unknown>;
|
|
115
|
+
}>;
|
|
116
|
+
answer(projectDir: string | undefined, kind: BuildMapAnswerKind, body: unknown): Promise<BuildMapAnswerResult>;
|
|
117
|
+
/** A variant's image as a data: URL, when it is an image the map may show. */
|
|
118
|
+
file(projectDir: string | undefined, ref: BuildMapFileRef): Promise<{
|
|
119
|
+
src?: string;
|
|
120
|
+
}>;
|
|
121
|
+
};
|
|
122
|
+
export declare function buildMapApp(options: {
|
|
123
|
+
version: string;
|
|
124
|
+
/** Whether the client shows apps, so the page's answers are the author's. */
|
|
125
|
+
writable: () => boolean;
|
|
126
|
+
cwd?: string;
|
|
127
|
+
}): BuildMapApp;
|
|
128
|
+
/**
|
|
129
|
+
* The page resource and its three app-only tools. Not through registerTools:
|
|
130
|
+
* they are not the agent's tools (no guide entry, no docs table), and the page
|
|
131
|
+
* calls build_map_view every few seconds, which must not reach the usage events.
|
|
132
|
+
*/
|
|
133
|
+
export declare function registerBuildMapApp(server: FastMCP, app: BuildMapApp): void;
|
|
134
|
+
export {};
|
|
135
|
+
//# sourceMappingURL=build-map-app.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build-map-app.d.ts","sourceRoot":"","sources":["../src/build-map-app.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAiBH,OAAO,KAAK,EAAE,OAAO,EAAkB,MAAM,SAAS,CAAA;AACtD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAMvB,wDAAwD;AACxD,eAAO,MAAM,eAAe,QAAa,CAAA;AASzC,uGAAuG;AACvG,QAAA,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuBH,CAAA;AAEV,MAAM,MAAM,kBAAkB,GAAG,MAAM,OAAO,OAAO,CAAA;AAErD,kFAAkF;AAClF,MAAM,MAAM,oBAAoB,GAC7B;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GACZ;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAA;AAEhE,MAAM,MAAM,eAAe,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,GAAG,SAAS,CAAA;CAAE,CAAA;AAE1G,MAAM,MAAM,WAAW,GAAG;IACzB,kCAAkC;IAClC,IAAI,IAAI,MAAM,CAAA;IACd,0EAA0E;IAC1E,IAAI,CACH,UAAU,CAAC,EAAE,MAAM,EACnB,KAAK,CAAC,EAAE,MAAM,GACZ,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,IAAI,CAAA;KAAE,GAAG;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC,CAAA;IACnG,MAAM,CACL,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,IAAI,EAAE,kBAAkB,EACxB,IAAI,EAAE,OAAO,GACX,OAAO,CAAC,oBAAoB,CAAC,CAAA;IAChC,8EAA8E;IAC9E,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,EAAE,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC;QAAE,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CACrF,CAAA;AAeD,wBAAgB,WAAW,CAAC,OAAO,EAAE;IACpC,OAAO,EAAE,MAAM,CAAA;IACf,6EAA6E;IAC7E,QAAQ,EAAE,MAAM,OAAO,CAAA;IACvB,GAAG,CAAC,EAAE,MAAM,CAAA;CACZ,GAAG,WAAW,CAoGd;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,WAAW,GAAG,IAAI,CA6D3E"}
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The build map in a chat (plan 2026-11-03-extension-build-map §6.6, phase 4):
|
|
3
|
+
* MCP Apps (2026-01-26) on the local (stdio) server.
|
|
4
|
+
*
|
|
5
|
+
* show_build_map (tools.ts) links to the page `ui://extenshi/build-map`, the
|
|
6
|
+
* same page `extenshi map` serves (build-map-page.ts, a byte-identical copy of
|
|
7
|
+
* the CLI's) built with `app`. A client that shows apps draws it in the
|
|
8
|
+
* conversation; the page then talks to the host, which calls three tools on
|
|
9
|
+
* this server for it, tools the host keeps from the model (`visibility: app`):
|
|
10
|
+
*
|
|
11
|
+
* - build_map_view: the snapshot the page draws. While the author's map server
|
|
12
|
+
* runs, its snapshot as it is (the project facts are read by the CLI only);
|
|
13
|
+
* otherwise one derived from the state file, which says it has no facts.
|
|
14
|
+
* - build_map_answer: the author's answers, the same three writes the map
|
|
15
|
+
* server takes from its page (a mark, a route, a pick or another round),
|
|
16
|
+
* to the same state file under the same lock, checked the same way.
|
|
17
|
+
* - build_map_file: a variant's thumbnail as a data: URL, since the page in a
|
|
18
|
+
* chat may show data: images only (the default MCP Apps CSP).
|
|
19
|
+
*
|
|
20
|
+
* The answers are the author's (`via: 'map'`, who `you`), so build_map_answer
|
|
21
|
+
* refuses unless the client said it shows apps, and index.ts removes all three
|
|
22
|
+
* tools from a client that did not: a client that ignores `visibility` would
|
|
23
|
+
* otherwise list them to the model.
|
|
24
|
+
*
|
|
25
|
+
* Local only: the hosted connector has no access to the author's files and
|
|
26
|
+
* registers none of this.
|
|
27
|
+
*/
|
|
28
|
+
import { createHash, randomBytes } from 'node:crypto';
|
|
29
|
+
import { readFile } from 'node:fs/promises';
|
|
30
|
+
import path from 'node:path';
|
|
31
|
+
import { answerBuildReview, BUILD_EVIDENCE_NOTE_MAX, BUILD_REVIEW_FEEDBACK_MAX, BUILD_ROUTE_TEXT_MAX, BuildConfirmError, BuildRouteError, BuildStepError, confirmBuildTask, deriveBuildMap, setBuildRoute, } from '@extenshi/contracts';
|
|
32
|
+
import { z } from 'zod';
|
|
33
|
+
import { reviewFileOnDisk, serverSnapshot } from './build-map-agent.js';
|
|
34
|
+
import { buildMapPage } from './build-map-page.js';
|
|
35
|
+
import { MAP_PROTOCOL, readMapState, resolveMapHome, updateMapState } from './build-map-store.js';
|
|
36
|
+
import { BUILD_MAP_UI, MCP_APP_MIME } from './build-map-ui.js';
|
|
37
|
+
/** A thumbnail larger than this shows as its number. */
|
|
38
|
+
export const THUMB_MAX_BYTES = 512 * 1024;
|
|
39
|
+
const noteField = z
|
|
40
|
+
.string()
|
|
41
|
+
.max(BUILD_EVIDENCE_NOTE_MAX * 4)
|
|
42
|
+
.optional()
|
|
43
|
+
.transform((note) => (note?.trim() ? note : undefined));
|
|
44
|
+
const nodeField = z.string().min(1).max(64);
|
|
45
|
+
/** The bodies the map server's /api/confirm, /api/route and /api/review take (build-map-server.ts). */
|
|
46
|
+
const ANSWERS = {
|
|
47
|
+
confirm: z.object({ node: nodeField, task: z.number().int().min(0), done: z.boolean(), note: noteField }),
|
|
48
|
+
route: z.object({
|
|
49
|
+
node: nodeField,
|
|
50
|
+
how: z.enum(['self', 'skip']).nullable(),
|
|
51
|
+
value: z
|
|
52
|
+
.string()
|
|
53
|
+
.max(BUILD_ROUTE_TEXT_MAX * 2)
|
|
54
|
+
.optional(),
|
|
55
|
+
since: z.string().nullable().optional(),
|
|
56
|
+
note: noteField,
|
|
57
|
+
}),
|
|
58
|
+
review: z.object({
|
|
59
|
+
node: nodeField,
|
|
60
|
+
round: z.number().int().min(1),
|
|
61
|
+
revision: z.number().int().min(1).optional(),
|
|
62
|
+
choice: z.string().min(1).max(16).optional(),
|
|
63
|
+
redo: z
|
|
64
|
+
.string()
|
|
65
|
+
.min(1)
|
|
66
|
+
.max(BUILD_REVIEW_FEEDBACK_MAX * 2)
|
|
67
|
+
.optional(),
|
|
68
|
+
}),
|
|
69
|
+
};
|
|
70
|
+
const refused = (status, error, message) => ({
|
|
71
|
+
ok: false,
|
|
72
|
+
status,
|
|
73
|
+
error,
|
|
74
|
+
message,
|
|
75
|
+
});
|
|
76
|
+
/** The snapshot without the time it was made, which changes on every read. */
|
|
77
|
+
function etagOf(snapshot) {
|
|
78
|
+
const { generatedAt: _generatedAt, ...rest } = snapshot;
|
|
79
|
+
return createHash('sha256').update(JSON.stringify(rest)).digest('base64url').slice(0, 22);
|
|
80
|
+
}
|
|
81
|
+
export function buildMapApp(options) {
|
|
82
|
+
const cwd = options.cwd ?? process.cwd();
|
|
83
|
+
const homeOf = async (projectDir) => (await resolveMapHome(path.resolve(cwd, projectDir ?? '.'))).home;
|
|
84
|
+
return {
|
|
85
|
+
page() {
|
|
86
|
+
return buildMapPage({ nonce: randomBytes(16).toString('base64url'), app: { version: options.version } });
|
|
87
|
+
},
|
|
88
|
+
async view(projectDir, since) {
|
|
89
|
+
const home = await homeOf(projectDir);
|
|
90
|
+
const writable = options.writable();
|
|
91
|
+
const running = await serverSnapshot(home);
|
|
92
|
+
let snapshot;
|
|
93
|
+
if (running)
|
|
94
|
+
snapshot = { ...running.snapshot, app: { facts: true, url: running.url, writable } };
|
|
95
|
+
else {
|
|
96
|
+
const read = await readMapState(home);
|
|
97
|
+
const { state } = read;
|
|
98
|
+
snapshot = {
|
|
99
|
+
protocol: MAP_PROTOCOL,
|
|
100
|
+
home,
|
|
101
|
+
project: { name: path.basename(home) },
|
|
102
|
+
checkouts: 1,
|
|
103
|
+
view: deriveBuildMap(state, { done: {} }),
|
|
104
|
+
reviews: state.reviews,
|
|
105
|
+
log: state.log,
|
|
106
|
+
evidence: state.evidence,
|
|
107
|
+
routes: state.routes,
|
|
108
|
+
offer: state.offer,
|
|
109
|
+
...(read.problem ? { problem: read.problem } : {}),
|
|
110
|
+
generatedAt: new Date().toISOString(),
|
|
111
|
+
app: { facts: false, writable },
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
const etag = etagOf(snapshot);
|
|
115
|
+
return since === etag ? { etag, unchanged: true } : { etag, snapshot };
|
|
116
|
+
},
|
|
117
|
+
async answer(projectDir, kind, body) {
|
|
118
|
+
if (!options.writable())
|
|
119
|
+
return refused(403, 'not_an_app', 'Only the build map drawn in a chat that shows MCP Apps answers here. An agent records the author’s answer from the chat with report_build_step.');
|
|
120
|
+
const schema = ANSWERS[kind];
|
|
121
|
+
const parsed = schema?.safeParse(body);
|
|
122
|
+
if (!parsed?.success)
|
|
123
|
+
return refused(400, 'bad_request', `That is not a ${kind} answer the map takes.`);
|
|
124
|
+
const home = await homeOf(projectDir);
|
|
125
|
+
const at = new Date().toISOString();
|
|
126
|
+
try {
|
|
127
|
+
if (kind === 'confirm') {
|
|
128
|
+
const change = parsed.data;
|
|
129
|
+
await updateMapState(home, (state) => confirmBuildTask(state, { ...change, at }));
|
|
130
|
+
}
|
|
131
|
+
else if (kind === 'route') {
|
|
132
|
+
const change = parsed.data;
|
|
133
|
+
// The credits the author's map server knows: "did it myself" opens once the free ones are spent.
|
|
134
|
+
const account = (await serverSnapshot(home))?.snapshot.account;
|
|
135
|
+
const credits = account?.signedIn ? account.credits : undefined;
|
|
136
|
+
await updateMapState(home, (state) => setBuildRoute(state, { ...change, credits, at }));
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
const change = parsed.data;
|
|
140
|
+
// The view the page showed: a changed pick sends the steps built from the old one back to run again.
|
|
141
|
+
const view = (await serverSnapshot(home))?.snapshot.view;
|
|
142
|
+
await updateMapState(home, (state) => answerBuildReview(state, view, { ...change, via: 'map', at }));
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
catch (error) {
|
|
146
|
+
if (error instanceof BuildConfirmError)
|
|
147
|
+
return refused(error.code === 'out_of_order' ? 409 : 400, error.code, error.message);
|
|
148
|
+
if (error instanceof BuildRouteError)
|
|
149
|
+
return refused(error.code === 'stale' || error.code === 'credits' ? 409 : 400, error.code, error.message);
|
|
150
|
+
if (error instanceof BuildStepError)
|
|
151
|
+
return refused(error.code === 'stale' ? 409 : 400, error.code, error.message);
|
|
152
|
+
throw error;
|
|
153
|
+
}
|
|
154
|
+
return { ok: true };
|
|
155
|
+
},
|
|
156
|
+
async file(projectDir, ref) {
|
|
157
|
+
const home = await homeOf(projectDir);
|
|
158
|
+
const { state } = await readMapState(home);
|
|
159
|
+
const review = state.reviews[ref.step];
|
|
160
|
+
const variants = review?.round === ref.round
|
|
161
|
+
? review.variants
|
|
162
|
+
: review?.history.find((round) => round.round === ref.round)?.variants;
|
|
163
|
+
const variant = variants?.find((candidate) => candidate.id === ref.variant);
|
|
164
|
+
const stored = ref.which === 'image' ? variant?.image : variant?.preview;
|
|
165
|
+
const file = stored ? await reviewFileOnDisk(home, stored) : undefined;
|
|
166
|
+
if (!file || !file.type.startsWith('image/') || file.bytes > THUMB_MAX_BYTES)
|
|
167
|
+
return {};
|
|
168
|
+
return { src: `data:${file.type};base64,${(await readFile(file.file)).toString('base64')}` };
|
|
169
|
+
},
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* The page resource and its three app-only tools. Not through registerTools:
|
|
174
|
+
* they are not the agent's tools (no guide entry, no docs table), and the page
|
|
175
|
+
* calls build_map_view every few seconds, which must not reach the usage events.
|
|
176
|
+
*/
|
|
177
|
+
export function registerBuildMapApp(server, app) {
|
|
178
|
+
// The page they belong to, and only the page may call them (MCP Apps visibility).
|
|
179
|
+
const appOnly = { ui: { resourceUri: BUILD_MAP_UI, visibility: ['app'] } };
|
|
180
|
+
const projectDir = z.string().min(1).optional();
|
|
181
|
+
const json = (value) => JSON.stringify(value);
|
|
182
|
+
server.addResource({
|
|
183
|
+
uri: BUILD_MAP_UI,
|
|
184
|
+
name: 'Extension Build Map',
|
|
185
|
+
description: 'The author’s build map of the extension project, drawn in the conversation.',
|
|
186
|
+
mimeType: MCP_APP_MIME,
|
|
187
|
+
load: async () =>
|
|
188
|
+
// _meta reaches the client as it is: no outside origins (the default CSP), and a border around the map.
|
|
189
|
+
({
|
|
190
|
+
text: app.page(),
|
|
191
|
+
mimeType: MCP_APP_MIME,
|
|
192
|
+
_meta: { ui: { prefersBorder: true } },
|
|
193
|
+
}),
|
|
194
|
+
});
|
|
195
|
+
server.addTool({
|
|
196
|
+
name: 'build_map_view',
|
|
197
|
+
description: 'The build map page reads its snapshot. Called by the page only.',
|
|
198
|
+
annotations: { title: 'Build map: read for the page', readOnlyHint: true, openWorldHint: false },
|
|
199
|
+
_meta: appOnly,
|
|
200
|
+
parameters: z.object({ projectDir, since: z.string().max(64).optional() }),
|
|
201
|
+
execute: async (args) => json(await app.view(args.projectDir, args.since)),
|
|
202
|
+
});
|
|
203
|
+
server.addTool({
|
|
204
|
+
name: 'build_map_answer',
|
|
205
|
+
description: 'The author answers on the build map page: marks a task, does a step themselves or skips it, picks a variant or asks for another round. Called by the page only, when the author clicks.',
|
|
206
|
+
annotations: {
|
|
207
|
+
title: 'Build map: the author’s answer',
|
|
208
|
+
readOnlyHint: false,
|
|
209
|
+
destructiveHint: false,
|
|
210
|
+
openWorldHint: false,
|
|
211
|
+
},
|
|
212
|
+
_meta: appOnly,
|
|
213
|
+
parameters: z.object({
|
|
214
|
+
projectDir,
|
|
215
|
+
kind: z.enum(['confirm', 'route', 'review']),
|
|
216
|
+
body: z.record(z.string(), z.unknown()),
|
|
217
|
+
}),
|
|
218
|
+
execute: async (args) => json(await app.answer(args.projectDir, args.kind, args.body)),
|
|
219
|
+
});
|
|
220
|
+
server.addTool({
|
|
221
|
+
name: 'build_map_file',
|
|
222
|
+
description: 'The build map page loads a variant thumbnail. Called by the page only.',
|
|
223
|
+
annotations: { title: 'Build map: a variant thumbnail', readOnlyHint: true, openWorldHint: false },
|
|
224
|
+
_meta: appOnly,
|
|
225
|
+
parameters: z.object({
|
|
226
|
+
projectDir,
|
|
227
|
+
step: z.string().min(1).max(64),
|
|
228
|
+
round: z.number().int().min(1),
|
|
229
|
+
variant: z.string().min(1).max(16),
|
|
230
|
+
which: z.enum(['image', 'preview']),
|
|
231
|
+
}),
|
|
232
|
+
execute: async (args) => {
|
|
233
|
+
const { projectDir: dir, ...ref } = args;
|
|
234
|
+
return json(await app.file(dir, ref));
|
|
235
|
+
},
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
//# sourceMappingURL=build-map-app.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build-map-app.js","sourceRoot":"","sources":["../src/build-map-app.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The build map page `extenshi map` serves (plan 2026-11-03-extension-build-map
|
|
3
|
+
* §4, §6.6). One self-contained HTML document — no network, no fonts to fetch —
|
|
4
|
+
* drawn from the static graph inlined here and the live snapshot the local
|
|
5
|
+
* server pushes over SSE (`/events`). Phase 1 is read-only, with three
|
|
6
|
+
* exceptions, all posted with the page token (build-map-server.ts):
|
|
7
|
+
* - a task only the author can do outside extenshi (`confirm` in the graph,
|
|
8
|
+
* such as a store account) gets a "Mark as done" button (/api/confirm);
|
|
9
|
+
* - a step the author can do themselves or skip (`manual` / `skip` in the
|
|
10
|
+
* graph) gets a form with what to give, and a skip button (/api/route).
|
|
11
|
+
* The store submits show what an upload by hand needs: the package on
|
|
12
|
+
* disk, the dashboard, the values to paste, the steps left to do there;
|
|
13
|
+
* - a step that spends credits (`credits` in the graph) shows what is left
|
|
14
|
+
* of its pool, and to an author with no account a sign-in for the free
|
|
15
|
+
* credits (/api/login) with the pairing code to check (phase 1g). Its own
|
|
16
|
+
* mark opens only once the free credits of that pool are spent.
|
|
17
|
+
* The header also offers an Update button while a newer @extenshi/cli is out
|
|
18
|
+
* (snap.update): it restarts the map on that release (/api/update), and the
|
|
19
|
+
* page reloads when the new server answers on the same port.
|
|
20
|
+
*
|
|
21
|
+
* The same page is the map in a chat (plan phase 4): the local MCP server
|
|
22
|
+
* (@extenshi/mcp, which keeps a byte-identical copy of this file) serves it as
|
|
23
|
+
* an MCP Apps resource with `app: true`. There it has no server to fetch from:
|
|
24
|
+
* it talks to the host over postMessage (JSON-RPC, MCP Apps 2026-01-26), reads
|
|
25
|
+
* the snapshot through the app-only tool `build_map_view` every few seconds,
|
|
26
|
+
* writes the author's answers through `build_map_answer` and loads variant
|
|
27
|
+
* thumbnails through `build_map_file`. Links open through the host. Sign-in
|
|
28
|
+
* stays on the browser map, which runs the pairing.
|
|
29
|
+
*
|
|
30
|
+
* Look and interaction follow the prototype in
|
|
31
|
+
* internal-docs/prototypes/extension-progress-map/index.html (catalog design
|
|
32
|
+
* tokens, both themes, pan/zoom, inspector). Everything the project or an agent
|
|
33
|
+
* wrote (extension name, fact sentences, log lines) reaches the DOM through
|
|
34
|
+
* textContent or `esc()`, never as markup.
|
|
35
|
+
*
|
|
36
|
+
* The client script is plain ES2017 inside a template literal: it must not
|
|
37
|
+
* contain backticks or `${`, so it concatenates strings.
|
|
38
|
+
*/
|
|
39
|
+
/**
|
|
40
|
+
* `token` authorises the page's writes (/api/confirm); without it, as in a
|
|
41
|
+
* saved copy, the page shows no write buttons. The token belongs to one server
|
|
42
|
+
* run, so `instance` names that run: when the page reconnects to a server
|
|
43
|
+
* restarted on the same port, the stream's hello carries another instance and
|
|
44
|
+
* the page reloads for the new token. `protocol` does the same when a newer
|
|
45
|
+
* server takes over the port.
|
|
46
|
+
*
|
|
47
|
+
* `app` makes it the map in a chat (see the top of this file): no token, no
|
|
48
|
+
* stream; the host and the MCP server's app-only tools stand in for both.
|
|
49
|
+
*/
|
|
50
|
+
export declare function buildMapPage(options: {
|
|
51
|
+
nonce: string;
|
|
52
|
+
token?: string;
|
|
53
|
+
instance?: string;
|
|
54
|
+
app?: {
|
|
55
|
+
version: string;
|
|
56
|
+
};
|
|
57
|
+
}): string;
|
|
58
|
+
//# sourceMappingURL=build-map-page.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build-map-page.d.ts","sourceRoot":"","sources":["../src/build-map-page.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAwEH;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE;IACrC,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,GAAG,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAA;CACzB,GAAG,MAAM,CA8BT"}
|