@extenshi/mcp 0.9.0 → 0.10.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 +6 -1
- package/dist/bff.d.ts +21 -0
- package/dist/bff.d.ts.map +1 -1
- package/dist/bff.js +4 -0
- package/dist/bff.js.map +1 -1
- package/dist/development-guide.d.ts +118 -34
- package/dist/development-guide.d.ts.map +1 -1
- package/dist/development-guide.js +85 -9
- package/dist/development-guide.js.map +1 -1
- package/dist/icon-workflow.d.ts.map +1 -1
- package/dist/icon-workflow.js +15 -2
- package/dist/icon-workflow.js.map +1 -1
- package/dist/pay.d.ts +8 -1
- package/dist/pay.d.ts.map +1 -1
- package/dist/pay.js +9 -0
- package/dist/pay.js.map +1 -1
- package/dist/project-media.d.ts +29 -0
- package/dist/project-media.d.ts.map +1 -0
- package/dist/project-media.js +72 -0
- package/dist/project-media.js.map +1 -0
- package/dist/publish.d.ts +101 -0
- package/dist/publish.d.ts.map +1 -1
- package/dist/publish.js +81 -2
- package/dist/publish.js.map +1 -1
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +237 -11
- package/dist/tools.js.map +1 -1
- package/package.json +3 -3
package/dist/publish.js
CHANGED
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
* API key, nothing passes through Extenshi servers.
|
|
8
8
|
*/
|
|
9
9
|
import * as fs from 'node:fs';
|
|
10
|
+
import path from 'node:path';
|
|
11
|
+
import { isPlaceholderGeckoId, isValidGeckoId } from '@extenshi/contracts';
|
|
10
12
|
import { ChromeAPI, EdgeAPI, FirefoxAPI, publishToStores, } from '@extenshi/publisher';
|
|
11
13
|
import { assertValidArtifact } from './validate-artifact.js';
|
|
12
14
|
export const ENV_DOCS = {
|
|
@@ -14,6 +16,16 @@ export const ENV_DOCS = {
|
|
|
14
16
|
firefox: ['FIREFOX_ADDON_GUID', 'FIREFOX_JWT_ISSUER', 'FIREFOX_JWT_SECRET'],
|
|
15
17
|
edge: ['EDGE_PRODUCT_ID', 'EDGE_CLIENT_ID', 'EDGE_CLIENT_SECRET', 'EDGE_TENANT_ID'],
|
|
16
18
|
};
|
|
19
|
+
/**
|
|
20
|
+
* Store credentials, with an explicitly stated AMO add-on id filling
|
|
21
|
+
* FIREFOX_ADDON_GUID when the environment has none. A different environment
|
|
22
|
+
* value is refused: one run publishes to one add-on id.
|
|
23
|
+
*/
|
|
24
|
+
export function storeCredentialsFor(addonId, env = process.env) {
|
|
25
|
+
if (addonId && env.FIREFOX_ADDON_GUID && env.FIREFOX_ADDON_GUID !== addonId)
|
|
26
|
+
throw new PublishSetupError(`addon_id (${addonId}) differs from FIREFOX_ADDON_GUID (${env.FIREFOX_ADDON_GUID}); state one add-on id.`);
|
|
27
|
+
return readStoreCredentials(addonId && !env.FIREFOX_ADDON_GUID ? { ...env, FIREFOX_ADDON_GUID: addonId } : env);
|
|
28
|
+
}
|
|
17
29
|
export function readStoreCredentials(env = process.env) {
|
|
18
30
|
const creds = {};
|
|
19
31
|
if (env.CHROME_APP_ID && env.CHROME_CLIENT_ID && env.CHROME_CLIENT_SECRET && env.CHROME_REFRESH_TOKEN) {
|
|
@@ -46,6 +58,70 @@ export function credentialsHelp(stores) {
|
|
|
46
58
|
}
|
|
47
59
|
export class PublishSetupError extends Error {
|
|
48
60
|
}
|
|
61
|
+
/**
|
|
62
|
+
* Whether this call may CREATE a new AMO add-on. With a project, its
|
|
63
|
+
* owner-decided `amo.addonId` governs (and a different FIREFOX_ADDON_GUID is
|
|
64
|
+
* refused). Without one, `allowNewAddon` is the switch and `addonId` has to
|
|
65
|
+
* state the id explicitly — it is never taken silently from the environment.
|
|
66
|
+
* Mirrors the CLI's gate.
|
|
67
|
+
*/
|
|
68
|
+
export function amoCreateAllowed(opts) {
|
|
69
|
+
if (opts.addonId !== undefined && opts.addonId !== opts.addonGuid)
|
|
70
|
+
throw new PublishSetupError(`addon_id (${opts.addonId}) differs from FIREFOX_ADDON_GUID (${opts.addonGuid}); state one add-on id.`);
|
|
71
|
+
if (!opts.projectId) {
|
|
72
|
+
if (!opts.allowNewAddon)
|
|
73
|
+
return false;
|
|
74
|
+
if (!opts.addonId)
|
|
75
|
+
throw new PublishSetupError('allow_new_addon without project_id needs addon_id: the AMO add-on id to create, stated explicitly. ' +
|
|
76
|
+
'It becomes permanent at the first upload and is never invented. With project_id the owner decides it in Dojo instead.');
|
|
77
|
+
if (!isValidGeckoId(opts.addonId))
|
|
78
|
+
throw new PublishSetupError(`addon_id ${opts.addonId} is not an AMO add-on id: use a braced GUID ({xxxxxxxx-xxxx-…}) or name@domain.`);
|
|
79
|
+
if (isPlaceholderGeckoId(opts.addonId))
|
|
80
|
+
throw new PublishSetupError(`addon_id ${opts.addonId} is a placeholder; AMO would bind the new add-on to it forever. State the real id.`);
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
if (opts.decision?.status === 'decided') {
|
|
84
|
+
if (opts.decision.value !== opts.addonGuid)
|
|
85
|
+
throw new PublishSetupError(`FIREFOX_ADDON_GUID (${opts.addonGuid}) differs from the add-on id the project owner decided (${String(opts.decision.value)}). ` +
|
|
86
|
+
'Set the manifest gecko.id and FIREFOX_ADDON_GUID to the decided id; AMO never renames an add-on.');
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
if (opts.allowNewAddon)
|
|
90
|
+
throw new PublishSetupError(`The owner of project ${opts.projectId} has not decided amo.addonId, and creating the AMO add-on fixes it permanently. ` +
|
|
91
|
+
'Propose it with propose_decision; the owner decides it on the Dojo project page.');
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
/** Load the listing, source and screenshots for a listed AMO submission. */
|
|
95
|
+
export function loadFirefoxListing(listing) {
|
|
96
|
+
if (typeof FirefoxAPI.submitListing !== 'function' || typeof FirefoxAPI.loadAmoListing !== 'function')
|
|
97
|
+
throw new PublishSetupError("This installation's @extenshi/publisher predates AMO listing submission. Reinstall @extenshi/mcp to update it.");
|
|
98
|
+
try {
|
|
99
|
+
const parsed = FirefoxAPI.loadAmoListing(path.resolve(listing.listingPath));
|
|
100
|
+
const sourceFilePath = listing.sourcePath ? path.resolve(listing.sourcePath) : undefined;
|
|
101
|
+
if (sourceFilePath) {
|
|
102
|
+
if (!fs.existsSync(sourceFilePath))
|
|
103
|
+
throw new Error(`Source archive not found: ${listing.sourcePath}`);
|
|
104
|
+
FirefoxAPI.assertSourceArchive(sourceFilePath);
|
|
105
|
+
}
|
|
106
|
+
const screenshotPaths = listing.screenshotsDir
|
|
107
|
+
? FirefoxAPI.listScreenshots(path.resolve(listing.screenshotsDir), parsed.defaultLocale)
|
|
108
|
+
: undefined;
|
|
109
|
+
if (screenshotPaths && !screenshotPaths.length)
|
|
110
|
+
throw new Error(`No .png, .jpg or .gif screenshots in ${listing.screenshotsDir}`);
|
|
111
|
+
return {
|
|
112
|
+
listing: parsed,
|
|
113
|
+
sourceFilePath,
|
|
114
|
+
screenshotPaths,
|
|
115
|
+
allowCreate: listing.allowCreate,
|
|
116
|
+
replaceScreenshots: listing.replaceScreenshots ?? false,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
catch (err) {
|
|
120
|
+
if (err instanceof PublishSetupError)
|
|
121
|
+
throw err;
|
|
122
|
+
throw new PublishSetupError(err instanceof Error ? err.message : String(err));
|
|
123
|
+
}
|
|
124
|
+
}
|
|
49
125
|
export async function publishArtifact(args) {
|
|
50
126
|
if (!fs.existsSync(args.artifactPath)) {
|
|
51
127
|
throw new PublishSetupError(`Artifact not found: ${args.artifactPath}`);
|
|
@@ -62,7 +138,7 @@ export async function publishArtifact(args) {
|
|
|
62
138
|
catch (err) {
|
|
63
139
|
throw new PublishSetupError(err instanceof Error ? err.message : String(err));
|
|
64
140
|
}
|
|
65
|
-
const creds =
|
|
141
|
+
const creds = storeCredentialsFor(args.addonId);
|
|
66
142
|
const configured = ['chrome', 'firefox', 'edge'].filter((s) => creds[s]);
|
|
67
143
|
const stores = args.stores?.length ? args.stores : configured;
|
|
68
144
|
if (!stores.length) {
|
|
@@ -74,6 +150,9 @@ export async function publishArtifact(args) {
|
|
|
74
150
|
if (missing.length) {
|
|
75
151
|
throw new PublishSetupError(`Missing credentials for: ${missing.join(', ')}\n${credentialsHelp(missing)}`);
|
|
76
152
|
}
|
|
153
|
+
if (args.firefoxListing && !stores.includes('firefox'))
|
|
154
|
+
throw new PublishSetupError('listing_path, source_path and screenshots_dir apply to Firefox (AMO); include firefox in stores.');
|
|
155
|
+
const firefoxListing = args.firefoxListing ? loadFirefoxListing(args.firefoxListing) : undefined;
|
|
77
156
|
return publishToStores({
|
|
78
157
|
extensionId: creds.chrome?.appId ?? creds.firefox?.addonGuid ?? creds.edge?.productId ?? 'extension',
|
|
79
158
|
stores,
|
|
@@ -84,7 +163,7 @@ export async function publishArtifact(args) {
|
|
|
84
163
|
},
|
|
85
164
|
storeConfigs: {
|
|
86
165
|
chrome: creds.chrome,
|
|
87
|
-
firefox: creds.firefox,
|
|
166
|
+
firefox: creds.firefox ? { ...creds.firefox, ...(firefoxListing ?? {}) } : undefined,
|
|
88
167
|
edge: creds.edge,
|
|
89
168
|
},
|
|
90
169
|
releaseNotes: args.releaseNotes,
|
package/dist/publish.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"publish.js","sourceRoot":"","sources":["../src/publish.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,MAAM,SAAS,CAAA;AAC7B,OAAO,EACN,SAAS,EACT,OAAO,EACP,UAAU,EACV,eAAe,GAGf,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAA;AAQ5D,MAAM,CAAC,MAAM,QAAQ,GAAgC;IACpD,MAAM,EAAE,CAAC,eAAe,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,sBAAsB,CAAC;IAC7F,OAAO,EAAE,CAAC,oBAAoB,EAAE,oBAAoB,EAAE,oBAAoB,CAAC;IAC3E,IAAI,EAAE,CAAC,iBAAiB,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,gBAAgB,CAAC;CACnF,CAAA;AAED,MAAM,UAAU,oBAAoB,CAAC,MAAyB,OAAO,CAAC,GAAG;IACxE,MAAM,KAAK,GAAqB,EAAE,CAAA;IAClC,IAAI,GAAG,CAAC,aAAa,IAAI,GAAG,CAAC,gBAAgB,IAAI,GAAG,CAAC,oBAAoB,IAAI,GAAG,CAAC,oBAAoB,EAAE,CAAC;QACvG,KAAK,CAAC,MAAM,GAAG;YACd,KAAK,EAAE,GAAG,CAAC,aAAa;YACxB,QAAQ,EAAE,GAAG,CAAC,gBAAgB;YAC9B,YAAY,EAAE,GAAG,CAAC,oBAAoB;YACtC,YAAY,EAAE,GAAG,CAAC,oBAAoB;SACtC,CAAA;IACF,CAAC;IACD,IAAI,GAAG,CAAC,kBAAkB,IAAI,GAAG,CAAC,kBAAkB,IAAI,GAAG,CAAC,kBAAkB,EAAE,CAAC;QAChF,KAAK,CAAC,OAAO,GAAG;YACf,SAAS,EAAE,GAAG,CAAC,kBAAkB;YACjC,SAAS,EAAE,GAAG,CAAC,kBAAkB;YACjC,SAAS,EAAE,GAAG,CAAC,kBAAkB;SACjC,CAAA;IACF,CAAC;IACD,IAAI,GAAG,CAAC,eAAe,IAAI,GAAG,CAAC,cAAc,IAAI,GAAG,CAAC,kBAAkB,IAAI,GAAG,CAAC,cAAc,EAAE,CAAC;QAC/F,KAAK,CAAC,IAAI,GAAG;YACZ,SAAS,EAAE,GAAG,CAAC,eAAe;YAC9B,QAAQ,EAAE,GAAG,CAAC,cAAc;YAC5B,YAAY,EAAE,GAAG,CAAC,kBAAkB;YACpC,QAAQ,EAAE,GAAG,CAAC,cAAc;SAC5B,CAAA;IACF,CAAC;IACD,OAAO,KAAK,CAAA;AACb,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,MAAmB;IAClD,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACzE,CAAC;
|
|
1
|
+
{"version":3,"file":"publish.js","sourceRoot":"","sources":["../src/publish.ts"],"names":[],"mappings":"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"}
|
package/dist/tools.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AASH,OAAO,EAAE,KAAK,OAAO,EAAE,KAAK,kBAAkB,EAA6C,MAAM,SAAS,CAAA;AAG1G,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AAqDnC,eAAO,MAAM,QAAQ,sCAAsC,CAAA;AAC3D,eAAO,MAAM,WAAW,oCAAoC,CAAA;AAC5D,eAAO,MAAM,YAAY,qCAAqC,CAAA;AAC9D,eAAO,MAAM,iBAAiB,+EAA+E,CAAA;AAO7G,eAAO,MAAM,mBAAmB,QAWS,CAAA;AAEzC;;;;;;;;;GASG;AACH,eAAO,MAAM,oBAAoB,KAAK,CAAA;AAEtC,eAAO,MAAM,WAAW,aAAa,CAAA;AAErC,eAAO,MAAM,mBAAmB,QAmBmB,CAAA;AAEnD,oFAAoF;AACpF,wBAAgB,qBAAqB,CAAC,YAAY,EAAE,WAAW,CAAC,UAAU,CAAC,GAAG,MAAM,CAWnF;AAID,uDAAuD;AACvD,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,CAAA;AAE7D;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC/B,OAAO,CAAC,EAAE,kBAAkB,CAAA;CAC5B;AAED,MAAM,WAAW,QAAQ;IACxB,kEAAkE;IAClE,GAAG,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAA;IACzD,+BAA+B;IAC/B,YAAY,EAAE,WAAW,CAAC,UAAU,CAAC,CAAA;IACrC;;;;;OAKG;IACH,MAAM,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,GAAG,CAAA;IACrC;;;;;OAKG;IACH,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,MAAM,CAAA;IAChD;;;;OAIG;IACH,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,MAAM,GAAG,SAAS,CAAA;IACxD,sFAAsF;IACtF,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAC1B;AAiFD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,GAAE,MAA2B,GAAG,OAAO,CAGxF;AAkgBD;;;GAGG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,GAAG,IAAI,CAy6CnE"}
|
package/dist/tools.js
CHANGED
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
*
|
|
33
33
|
* stdout is the MCP protocol channel for stdio — nothing here may write to it.
|
|
34
34
|
*/
|
|
35
|
-
import { agentEvidenceSchema, importManifestSchema, workspacePatchSchema } from '@extenshi/contracts';
|
|
35
|
+
import { agentCreateProjectSchema, agentEvidenceSchema, importManifestSchema, proposeDecisionSchema, workspacePatchSchema, } from '@extenshi/contracts';
|
|
36
36
|
import { UserError } from 'fastmcp';
|
|
37
37
|
import { z } from 'zod';
|
|
38
38
|
import { zodToJsonSchema } from 'zod-to-json-schema';
|
|
@@ -44,7 +44,8 @@ import { hostedLandingNextSteps, landingFormFromArgs, renderGenerateLandingPage
|
|
|
44
44
|
import { renderLocalizeWorkflow } from './localize-workflow.js';
|
|
45
45
|
import { PAY_OPERATIONS, paySchemas } from './pay.js';
|
|
46
46
|
import { describePrivacyAiUpdate } from './privacy-ai-outcome.js';
|
|
47
|
-
import {
|
|
47
|
+
import { checkInlineImage, PROJECT_MEDIA_MAX_BYTES, PROJECT_MEDIA_MIME_TYPES, ProjectMediaInputError, readWorkspaceImage, } from './project-media.js';
|
|
48
|
+
import { amoCreateAllowed, PublishSetupError, publishArtifact, storeCredentialsFor, validateStoreCredentials, } from './publish.js';
|
|
48
49
|
import { checkPublishAccess } from './publish-access.js';
|
|
49
50
|
import { ScanError, scanArtifact } from './scan.js';
|
|
50
51
|
import { describeStoreConstraints, validateSearchFilters } from './search-filters.js';
|
|
@@ -90,7 +91,10 @@ export const SERVER_INSTRUCTIONS = 'Extenshi helps develop and operate browser e
|
|
|
90
91
|
'plan from scope and research through code, assets, privacy, CI, store release and maintenance. ' +
|
|
91
92
|
'Keep a checklist covering the whole requested lifecycle. For standalone Pay, start with list_pay_apps; create_pay_app needs no development project or repository. Request explicit pay.read/pay.write scopes, use get_pay_readiness, and leave agreement acceptance and KYC to the author in the browser. Only the publishable SDK key and public verification key belong in extension code. Use search_docs (free) for current ' +
|
|
92
93
|
'product details and exact CLI flags. With identity, call list_my_projects then get_project_state ' +
|
|
93
|
-
'to reuse the existing project and repository
|
|
94
|
+
'to reuse the existing project and repository; for a new extension, create_project makes one (idempotent). ' +
|
|
95
|
+
'Read get_decisions early: the AMO add-on id, license, seller identity and pricing are owner decisions — ' +
|
|
96
|
+
'propose defaults with propose_decision; the owner decides them in Dojo, and release readiness blocks on them. ' +
|
|
97
|
+
'Use list_extension_templates before the manifest, ' +
|
|
94
98
|
'and get_project_scaffold for a new project. Preserve existing source. For an existing extension, read get_project_workspace then preview and apply import_manifest to fill Dojo from its real manifest and default-locale messages before configuring services. Review the integration diff and preserve local edits; write integration.file ' +
|
|
95
99
|
'verbatim to integration.path, check integration.unwired and re-read state after cabinet edits. ' +
|
|
96
100
|
'Check get_credit_balance before metered work. get_risk_by_store_ids covers up to 40 store IDs ' +
|
|
@@ -444,6 +448,26 @@ const TOOL_ANNOTATIONS = {
|
|
|
444
448
|
idempotentHint: true,
|
|
445
449
|
openWorldHint: false,
|
|
446
450
|
},
|
|
451
|
+
create_project: {
|
|
452
|
+
title: 'Create an extension project',
|
|
453
|
+
readOnlyHint: false,
|
|
454
|
+
idempotentHint: true,
|
|
455
|
+
destructiveHint: false,
|
|
456
|
+
openWorldHint: true,
|
|
457
|
+
},
|
|
458
|
+
get_decisions: {
|
|
459
|
+
title: 'Read owner decisions',
|
|
460
|
+
readOnlyHint: true,
|
|
461
|
+
idempotentHint: true,
|
|
462
|
+
openWorldHint: true,
|
|
463
|
+
},
|
|
464
|
+
propose_decision: {
|
|
465
|
+
title: 'Propose an owner decision',
|
|
466
|
+
readOnlyHint: false,
|
|
467
|
+
idempotentHint: true,
|
|
468
|
+
destructiveHint: false,
|
|
469
|
+
openWorldHint: true,
|
|
470
|
+
},
|
|
447
471
|
list_my_projects: {
|
|
448
472
|
title: 'List my extension projects',
|
|
449
473
|
readOnlyHint: true,
|
|
@@ -567,6 +591,14 @@ const TOOL_ANNOTATIONS = {
|
|
|
567
591
|
destructiveHint: true,
|
|
568
592
|
openWorldHint: true,
|
|
569
593
|
},
|
|
594
|
+
upload_project_media: {
|
|
595
|
+
title: 'Upload a public image for hosted pages',
|
|
596
|
+
readOnlyHint: false,
|
|
597
|
+
// Content-addressed: the same bytes always return the same URL.
|
|
598
|
+
idempotentHint: true,
|
|
599
|
+
destructiveHint: false,
|
|
600
|
+
openWorldHint: true,
|
|
601
|
+
},
|
|
570
602
|
remove_hosted_page: {
|
|
571
603
|
title: 'Remove a hosted page registration',
|
|
572
604
|
readOnlyHint: false,
|
|
@@ -742,6 +774,63 @@ export function registerTools(server, deps) {
|
|
|
742
774
|
}
|
|
743
775
|
},
|
|
744
776
|
});
|
|
777
|
+
add({
|
|
778
|
+
name: 'create_project',
|
|
779
|
+
description: 'Create a new extension project (a Dojo workspace) owned by this identity, through the same service ' +
|
|
780
|
+
'the Dojo project wizard uses, with the same ownership and limits. Returns JSON {projectId, dojoUrl, ' +
|
|
781
|
+
'project, pendingDecisions, nextSteps}: the next steps cover binding the repository and the starter ' +
|
|
782
|
+
'files. Idempotent: a repeated request with the same idempotencyKey returns the project it already ' +
|
|
783
|
+
'created (replayed: true); the same key with different input is rejected. Requires project.write.',
|
|
784
|
+
parameters: agentCreateProjectSchema,
|
|
785
|
+
execute: async (args, context) => {
|
|
786
|
+
try {
|
|
787
|
+
return JSON.stringify(await bff(context).createProject(args), null, 2);
|
|
788
|
+
}
|
|
789
|
+
catch (err) {
|
|
790
|
+
return readError(err, missingKeyMessage);
|
|
791
|
+
}
|
|
792
|
+
},
|
|
793
|
+
});
|
|
794
|
+
add({
|
|
795
|
+
name: 'get_decisions',
|
|
796
|
+
description: 'Owner decisions for one project: the AMO add-on id, license, seller public name, support contact ' +
|
|
797
|
+
'and terms, pricing, target browsers and target locales. Each entry reports its status (undecided, ' +
|
|
798
|
+
'proposed or decided), the value, a suggested default where one is derivable (a stable {GUID} add-on ' +
|
|
799
|
+
'id or the id already in the Firefox manifest, the project browsers), who proposed or decided it and ' +
|
|
800
|
+
'when, and which releases it blocks (blocksBrowsers, blocksPayment). `pending` lists the keys the ' +
|
|
801
|
+
'owner has not decided. FREE.',
|
|
802
|
+
annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: true },
|
|
803
|
+
parameters: z.object({ projectId: z.string().uuid().describe('Project id from list_my_projects.') }),
|
|
804
|
+
execute: async (args, context) => {
|
|
805
|
+
try {
|
|
806
|
+
return JSON.stringify(await bff(context).getDecisions(args), null, 2);
|
|
807
|
+
}
|
|
808
|
+
catch (err) {
|
|
809
|
+
return readError(err, missingKeyMessage);
|
|
810
|
+
}
|
|
811
|
+
},
|
|
812
|
+
});
|
|
813
|
+
add({
|
|
814
|
+
name: 'propose_decision',
|
|
815
|
+
description: 'Propose a value for one owner decision. The proposal is stored with its rationale, proposer and ' +
|
|
816
|
+
'time; the owner accepts or edits it on the Dojo project page, which is the only place a decision ' +
|
|
817
|
+
'becomes decided. A key the owner already decided is refused (DECISION_ALREADY_DECIDED). Value ' +
|
|
818
|
+
'formats: amo.addonId {GUID} or name@domain; license an SPDX id such as MIT, or all-rights-reserved; ' +
|
|
819
|
+
'seller.publicName text; seller.supportContact an email or HTTPS URL; seller.terms an HTTPS URL; ' +
|
|
820
|
+
'pricing {model: free|paid|donations, trialDays?, plans?: subscription|lifetime|one_time}; ' +
|
|
821
|
+
'targetBrowsers an array of chrome/firefox/edge; targetLocales an array of locale codes. Idempotent ' +
|
|
822
|
+
'per idempotencyKey. Requires project.write.',
|
|
823
|
+
annotations: { readOnlyHint: false, idempotentHint: true, destructiveHint: false, openWorldHint: true },
|
|
824
|
+
parameters: proposeDecisionSchema,
|
|
825
|
+
execute: async (args, context) => {
|
|
826
|
+
try {
|
|
827
|
+
return JSON.stringify(await bff(context).proposeDecision(args), null, 2);
|
|
828
|
+
}
|
|
829
|
+
catch (err) {
|
|
830
|
+
return readError(err, missingKeyMessage);
|
|
831
|
+
}
|
|
832
|
+
},
|
|
833
|
+
});
|
|
745
834
|
const reads = [
|
|
746
835
|
[
|
|
747
836
|
'get_project_workspace',
|
|
@@ -753,7 +842,11 @@ export function registerTools(server, deps) {
|
|
|
753
842
|
'Explain readiness for the recorded browser and artifact by locale. Local or agent reports are not treated as CI attestations. Stale evidence does not pass. Requires a Pro project. ' +
|
|
754
843
|
'Readiness is measured against the release recorded in the workspace: until apply_project_patch sets patch.release ' +
|
|
755
844
|
'(browser, version, artifactDigest, manifestDigest, locales, paymentRequired, and commit or dirtyTreeDigest) it reports ' +
|
|
756
|
-
'RELEASE_NOT_RECORDED; after that, evidence counts only when it matches that release artifactDigest.'
|
|
845
|
+
'RELEASE_NOT_RECORDED; after that, evidence counts only when it matches that release artifactDigest. ' +
|
|
846
|
+
"When the project has a linked Pay application, the payment check also carries `platform`: what Extenshi's own " +
|
|
847
|
+
'payment ledger proves (checkout, license, installation activation, recovery, refund). A live-mode purchase through ' +
|
|
848
|
+
"those stages passes the check with source 'platform'; test-mode purchases are listed without passing it. Clients cannot " +
|
|
849
|
+
"record source 'platform'.",
|
|
757
850
|
'getReleaseReadiness',
|
|
758
851
|
],
|
|
759
852
|
];
|
|
@@ -901,7 +994,8 @@ export function registerTools(server, deps) {
|
|
|
901
994
|
'active custom domain. The code is permanent: republishing creates a new version at the same URL. ' +
|
|
902
995
|
'By default the URL is also registered as the project homepage, which feeds HOMEPAGE_URL. Hosted ' +
|
|
903
996
|
'images are limited to store screenshot URLs (from get_extension) and images uploaded in the Dojo ' +
|
|
904
|
-
'Page generator
|
|
997
|
+
'Page generator or with upload_project_media (use its url for local screenshots or a logo); the logo ' +
|
|
998
|
+
'may also be an inline SVG or a raster data: URL. Returns JSON {url, publicCode, ' +
|
|
905
999
|
'versionNumber, contentHash, bytes, warnings, homepage, nextSteps}. Requires hosted.write. ' +
|
|
906
1000
|
`API reference: ${HOSTED_PAGES_DOCS}`,
|
|
907
1001
|
parameters: z.object({
|
|
@@ -956,6 +1050,72 @@ export function registerTools(server, deps) {
|
|
|
956
1050
|
}
|
|
957
1051
|
},
|
|
958
1052
|
});
|
|
1053
|
+
// A local filesystem exists only where local artifacts do (stdio).
|
|
1054
|
+
const localFiles = caps.has('scan');
|
|
1055
|
+
add({
|
|
1056
|
+
name: 'upload_project_media',
|
|
1057
|
+
description: "Upload a logo or screenshot (PNG, JPEG or WebP, up to 2 MB) to the project's PUBLIC media store — " +
|
|
1058
|
+
'the same store the Dojo Page generator uploads into — and get a stable https URL that ' +
|
|
1059
|
+
'publish_landing_page accepts as screenshots[].url or logoUrl. The server checks the file by content ' +
|
|
1060
|
+
'(magic bytes), strips EXIF/XMP/text metadata and anything after the image end marker, bounds the ' +
|
|
1061
|
+
'dimensions (16–4096 px) and enforces a per-project quota (100 files / 50 MB, Dojo uploads included); ' +
|
|
1062
|
+
'identical bytes return the same URL without using quota. SVG is refused: rasterize it first ' +
|
|
1063
|
+
'(CLI: extenshi icon store-assets) or pass an inline logo as logoSvg. ' +
|
|
1064
|
+
(localFiles
|
|
1065
|
+
? 'Pass filePath (a file inside the workspace) or dataBase64 + mime. '
|
|
1066
|
+
: 'Pass dataBase64 + mime (this connection has no access to local files). ') +
|
|
1067
|
+
'Store screenshots come from the CLI: extenshi screenshots. Returns JSON {url, sha256, mime, bytes, ' +
|
|
1068
|
+
'width, height, strippedBytes, deduplicated, quota}. Requires hosted.write. ' +
|
|
1069
|
+
`CLI: extenshi media upload <file> --project <id>. API reference: ${HOSTED_PAGES_DOCS}`,
|
|
1070
|
+
parameters: z.object({
|
|
1071
|
+
projectId: z.string().uuid(),
|
|
1072
|
+
filePath: z
|
|
1073
|
+
.string()
|
|
1074
|
+
.min(1)
|
|
1075
|
+
.max(4096)
|
|
1076
|
+
.optional()
|
|
1077
|
+
.describe('Image file inside the workspace (local stdio server only).'),
|
|
1078
|
+
dataBase64: z
|
|
1079
|
+
.string()
|
|
1080
|
+
.min(1)
|
|
1081
|
+
.max(Math.ceil(PROJECT_MEDIA_MAX_BYTES / 3) * 4 + 16)
|
|
1082
|
+
.optional()
|
|
1083
|
+
.describe('The raw image, base64-encoded (no data: prefix). Use with mime.'),
|
|
1084
|
+
mime: z.enum(PROJECT_MEDIA_MIME_TYPES).optional().describe('Required with dataBase64.'),
|
|
1085
|
+
}),
|
|
1086
|
+
execute: async (args, context) => {
|
|
1087
|
+
let payload;
|
|
1088
|
+
try {
|
|
1089
|
+
if (args.filePath && args.dataBase64)
|
|
1090
|
+
throw new ProjectMediaInputError('Pass filePath OR dataBase64, not both.');
|
|
1091
|
+
if (args.filePath) {
|
|
1092
|
+
if (!localFiles)
|
|
1093
|
+
throw new ProjectMediaInputError('filePath works only with the local stdio server; send dataBase64 + mime instead.');
|
|
1094
|
+
const read = await readWorkspaceImage(args.filePath);
|
|
1095
|
+
payload = { mime: read.mime, dataBase64: read.dataBase64 };
|
|
1096
|
+
}
|
|
1097
|
+
else if (args.dataBase64) {
|
|
1098
|
+
if (!args.mime)
|
|
1099
|
+
throw new ProjectMediaInputError('mime is required with dataBase64.');
|
|
1100
|
+
checkInlineImage(args.dataBase64, args.mime);
|
|
1101
|
+
payload = { mime: args.mime, dataBase64: args.dataBase64 };
|
|
1102
|
+
}
|
|
1103
|
+
else
|
|
1104
|
+
throw new ProjectMediaInputError('Pass filePath or dataBase64 + mime.');
|
|
1105
|
+
}
|
|
1106
|
+
catch (err) {
|
|
1107
|
+
if (err instanceof ProjectMediaInputError)
|
|
1108
|
+
throw new UserError(err.message);
|
|
1109
|
+
throw err;
|
|
1110
|
+
}
|
|
1111
|
+
try {
|
|
1112
|
+
return JSON.stringify(await bff(context).uploadProjectMedia({ projectId: args.projectId, ...payload }));
|
|
1113
|
+
}
|
|
1114
|
+
catch (err) {
|
|
1115
|
+
return readError(err, missingKeyMessage);
|
|
1116
|
+
}
|
|
1117
|
+
},
|
|
1118
|
+
});
|
|
959
1119
|
add({
|
|
960
1120
|
name: 'list_hosted_pages',
|
|
961
1121
|
description: 'List the project registered hosted pages (homepage/support) with their verification status, content hash and last check time.',
|
|
@@ -1517,13 +1677,14 @@ export function registerTools(server, deps) {
|
|
|
1517
1677
|
description: 'For extension-development tasks: returns the complete tool inventory for THIS connection, ' +
|
|
1518
1678
|
'the Extenshi service directory with access requirements and docs links, GitHub/code placement ' +
|
|
1519
1679
|
'guidance, and the ordered workflow from idea and repository through implementation, assets, ' +
|
|
1520
|
-
'privacy, tests/CI, store submission and maintenance
|
|
1521
|
-
'CLI
|
|
1680
|
+
'privacy, tests/CI, store submission and maintenance, plus store media: the scenes.json format for ' +
|
|
1681
|
+
'CLI screenshots (per-locale store screenshots) and listing artwork sizes per store. Distinguishes ' +
|
|
1682
|
+
'MCP tools from cabinet, CLI and external steps. Free; no key, account lookup or network request.',
|
|
1522
1683
|
parameters: z.object({
|
|
1523
1684
|
sections: z
|
|
1524
1685
|
.array(z.enum(['all', ...GUIDE_SECTIONS]))
|
|
1525
1686
|
.optional()
|
|
1526
|
-
.describe('Full guide sections to include: tools, localActions, services, repository, workflow, handoff, or all. ' +
|
|
1687
|
+
.describe('Full guide sections to include: tools, localActions, services, repository, workflow, handoff, storeMedia, or all. ' +
|
|
1527
1688
|
'Omitted: a compact overview with tool names, workflow stages and a table of contents.'),
|
|
1528
1689
|
}),
|
|
1529
1690
|
execute: async (args) => JSON.stringify(buildDevelopmentGuide(registeredTools, args?.sections), null, 2),
|
|
@@ -1759,8 +1920,12 @@ export function registerTools(server, deps) {
|
|
|
1759
1920
|
'CHROME_REFRESH_TOKEN, FIREFOX_ADDON_GUID/FIREFOX_JWT_ISSUER/FIREFOX_JWT_SECRET, ' +
|
|
1760
1921
|
'EDGE_PRODUCT_ID/EDGE_CLIENT_ID/EDGE_CLIENT_SECRET/EDGE_TENANT_ID). The upload itself is local, but ' +
|
|
1761
1922
|
'publishing is in an active testing phase: a quick Extenshi access check runs first (it identifies your ' +
|
|
1762
|
-
'account by EXTENSHI_API_KEY). Edge submissions are polled to a terminal status.
|
|
1763
|
-
'
|
|
1923
|
+
'account by EXTENSHI_API_KEY). Edge submissions are polled to a terminal status. For Firefox, ' +
|
|
1924
|
+
'listing_path turns the upload into a listed AMO submission with metadata: first-time add-on creation ' +
|
|
1925
|
+
'(gated by allow_new_addon or the project decision), per-locale name/summary/description, categories, ' +
|
|
1926
|
+
'license, homepage, support email and URL, privacy policy, release and reviewer notes, reviewer source ' +
|
|
1927
|
+
'(source_path) and previews (screenshots_dir); the result lists each step. The artifact is not ' +
|
|
1928
|
+
'security-scanned by this tool (scanning is scan_extension).',
|
|
1764
1929
|
parameters: z.object({
|
|
1765
1930
|
artifact_path: z
|
|
1766
1931
|
.string()
|
|
@@ -1774,6 +1939,42 @@ export function registerTools(server, deps) {
|
|
|
1774
1939
|
.optional()
|
|
1775
1940
|
.describe('Separate Firefox artifact (.xpi); defaults to artifact_path.'),
|
|
1776
1941
|
release_notes: z.string().optional().describe('Release notes for stores that accept them.'),
|
|
1942
|
+
listing_path: z
|
|
1943
|
+
.string()
|
|
1944
|
+
.optional()
|
|
1945
|
+
.describe('Firefox: AMO listing file (JSON with per-locale fields, or the AMO.md that generate-listing --store ' +
|
|
1946
|
+
'firefox writes, placeholders filled). Makes the Firefox submission a listed one with metadata: ' +
|
|
1947
|
+
'the add-on is created on first submission (see allow_new_addon) or its listing is edited, then ' +
|
|
1948
|
+
'privacy policy, release notes, reviewer notes, source and previews are applied.'),
|
|
1949
|
+
source_path: z
|
|
1950
|
+
.string()
|
|
1951
|
+
.optional()
|
|
1952
|
+
.describe('Firefox: reviewer source archive (.zip/.tar.gz/.tgz/.tar.bz2) for the new version.'),
|
|
1953
|
+
screenshots_dir: z
|
|
1954
|
+
.string()
|
|
1955
|
+
.optional()
|
|
1956
|
+
.describe('Firefox: AMO previews in file-name order: a directory of .png/.jpg/.gif files, or the extenshi ' +
|
|
1957
|
+
'screenshots output directory (its firefox/<locale>/ set, default locale first).'),
|
|
1958
|
+
allow_new_addon: z
|
|
1959
|
+
.boolean()
|
|
1960
|
+
.optional()
|
|
1961
|
+
.describe('Firefox: permits creating a NEW AMO add-on, whose id becomes permanent. With project_id the ' +
|
|
1962
|
+
"project's decided amo.addonId governs creation instead."),
|
|
1963
|
+
addon_id: z
|
|
1964
|
+
.string()
|
|
1965
|
+
.max(255)
|
|
1966
|
+
.optional()
|
|
1967
|
+
.describe('Firefox: the AMO add-on id ({GUID} or name@domain), stated explicitly. Needed with allow_new_addon ' +
|
|
1968
|
+
'when there is no project_id; fills FIREFOX_ADDON_GUID when the environment has none.'),
|
|
1969
|
+
replace_screenshots: z
|
|
1970
|
+
.boolean()
|
|
1971
|
+
.optional()
|
|
1972
|
+
.describe('Firefox: replaces the previews of an existing AMO add-on with screenshots_dir.'),
|
|
1973
|
+
project_id: z
|
|
1974
|
+
.string()
|
|
1975
|
+
.uuid()
|
|
1976
|
+
.optional()
|
|
1977
|
+
.describe('Dojo project id. Its owner-decided amo.addonId gates first-time AMO creation and has to equal FIREFOX_ADDON_GUID.'),
|
|
1777
1978
|
extension_id: z
|
|
1778
1979
|
.number()
|
|
1779
1980
|
.optional()
|
|
@@ -1793,7 +1994,7 @@ export function registerTools(server, deps) {
|
|
|
1793
1994
|
// preflight evaluates the `publish-access` PostHog flag for this developer
|
|
1794
1995
|
// / extension. Fails open on any transport error — only a definitive
|
|
1795
1996
|
// server "no" blocks here (see checkPublishAccess).
|
|
1796
|
-
const creds =
|
|
1997
|
+
const creds = storeCredentialsFor(args.addon_id);
|
|
1797
1998
|
const storeIds = {};
|
|
1798
1999
|
if (creds.chrome)
|
|
1799
2000
|
storeIds.chrome = creds.chrome.appId;
|
|
@@ -1811,12 +2012,37 @@ export function registerTools(server, deps) {
|
|
|
1811
2012
|
throw new UserError(access.message ??
|
|
1812
2013
|
"Publishing is in an active testing phase and isn't available for your account yet.");
|
|
1813
2014
|
}
|
|
2015
|
+
let firefoxListing;
|
|
2016
|
+
if (args.listing_path || args.source_path || args.screenshots_dir) {
|
|
2017
|
+
if (!args.listing_path)
|
|
2018
|
+
throw new UserError('source_path and screenshots_dir need listing_path, the AMO listing they belong to.');
|
|
2019
|
+
let decision = null;
|
|
2020
|
+
if (args.project_id) {
|
|
2021
|
+
const view = (await bff(context).getDecisions({ projectId: args.project_id }));
|
|
2022
|
+
decision = view.decisions?.find((d) => d.key === 'amo.addonId') ?? null;
|
|
2023
|
+
}
|
|
2024
|
+
firefoxListing = {
|
|
2025
|
+
listingPath: args.listing_path,
|
|
2026
|
+
sourcePath: args.source_path,
|
|
2027
|
+
screenshotsDir: args.screenshots_dir,
|
|
2028
|
+
replaceScreenshots: args.replace_screenshots,
|
|
2029
|
+
allowCreate: amoCreateAllowed({
|
|
2030
|
+
addonGuid: creds.firefox?.addonGuid ?? '',
|
|
2031
|
+
allowNewAddon: args.allow_new_addon,
|
|
2032
|
+
addonId: args.addon_id,
|
|
2033
|
+
projectId: args.project_id,
|
|
2034
|
+
decision,
|
|
2035
|
+
}),
|
|
2036
|
+
};
|
|
2037
|
+
}
|
|
1814
2038
|
void context.reportProgress({ progress: 0, total: 1 });
|
|
1815
2039
|
const result = await publishArtifact({
|
|
1816
2040
|
artifactPath: args.artifact_path,
|
|
1817
2041
|
stores: args.stores,
|
|
1818
2042
|
firefoxArtifactPath: args.firefox_artifact_path,
|
|
1819
2043
|
releaseNotes: args.release_notes,
|
|
2044
|
+
addonId: args.addon_id,
|
|
2045
|
+
firefoxListing,
|
|
1820
2046
|
});
|
|
1821
2047
|
void context.reportProgress({ progress: 1, total: 1 });
|
|
1822
2048
|
return JSON.stringify(result, null, 2);
|