meguro-mcp 0.2.1 → 0.2.3
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/CHANGELOG.md +17 -0
- package/README.md +6 -5
- package/package.json +1 -1
- package/src/server.mjs +1 -1
- package/src/tools.mjs +103 -19
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `meguro-mcp` are recorded here. Versions follow Semantic Versioning.
|
|
4
4
|
|
|
5
|
+
## 0.2.3 — 2026-08-01
|
|
6
|
+
|
|
7
|
+
- Adds `templates_list`, a read-only closed-world projection of the ordered practice-store template
|
|
8
|
+
catalog, so customers can discover supported templates without duplicating registry data.
|
|
9
|
+
- Preserves only the documented public template fields and excludes profiles, scenario presets,
|
|
10
|
+
credentials, and private route payload from MCP responses.
|
|
11
|
+
- Pins Console connection guidance to the exact `meguro-mcp@0.2.3` artifact.
|
|
12
|
+
|
|
13
|
+
## 0.2.2 — 2026-08-01
|
|
14
|
+
|
|
15
|
+
- Enforces each tool's declared top-level argument boundary before API transport, with bounded errors
|
|
16
|
+
that do not echo attacker-controlled property names.
|
|
17
|
+
- Rejects practice-store ids and oversized or malformed practice-run ids locally across run,
|
|
18
|
+
continuation, and Exam entry tools while preserving supported historical run-id shapes.
|
|
19
|
+
- Keeps well-formed missing and cross-workspace run ids on the same generic
|
|
20
|
+
`practice-run-unavailable` response so validation does not create an existence oracle.
|
|
21
|
+
|
|
5
22
|
## 0.2.1 — 2026-08-01
|
|
6
23
|
|
|
7
24
|
- Preserves the API's approved wrong/revoked workspace-key code and actionable Connection settings
|
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ Dependency-free, no build step: the server is plain Node ≥ 20.
|
|
|
14
14
|
Customer MCP clients run the exact public version directly from npm:
|
|
15
15
|
|
|
16
16
|
```bash
|
|
17
|
-
npx -y meguro-mcp@0.2.
|
|
17
|
+
npx -y meguro-mcp@0.2.3
|
|
18
18
|
```
|
|
19
19
|
|
|
20
20
|
Pin the version in client configuration. A pinned quickstart stays reproducible and never changes its
|
|
@@ -32,11 +32,12 @@ Console provides fast trusted proof and evidence inspection; the agency agent no
|
|
|
32
32
|
|
|
33
33
|
<!-- BEGIN GENERATED MCP TOOL TABLE -->
|
|
34
34
|
<!-- Run `npm run docs:tools --workspace meguro-mcp` to refresh this section from `tools/list`. -->
|
|
35
|
-
This table is generated from the server's live `tools/list` response (
|
|
35
|
+
This table is generated from the server's live `tools/list` response (44 tools).
|
|
36
36
|
|
|
37
37
|
| Tool | Title | Behavior annotations |
|
|
38
38
|
|---|---|---|
|
|
39
39
|
| `docs_read` | Read Meguro receipt and Gate documentation | read-only · non-destructive · idempotent · closed-world |
|
|
40
|
+
| `templates_list` | List practice-store templates | read-only · non-destructive · idempotent · closed-world |
|
|
40
41
|
| `stores_list` | List practice stores | read-only · non-destructive · idempotent · closed-world |
|
|
41
42
|
| `store_create` | Create a practice store | read-write · non-destructive · non-idempotent · closed-world |
|
|
42
43
|
| `store_delete` | Delete a practice store | read-write · destructive · non-idempotent · closed-world |
|
|
@@ -161,7 +162,7 @@ claude mcp add meguro \
|
|
|
161
162
|
-e MEGURO_API_BASE_URL=https://api-dev.meguro.io \
|
|
162
163
|
-e MEGURO_API_TOKEN=meg_sk_... \
|
|
163
164
|
-e MEGURO_DASHBOARD_URL=https://... \
|
|
164
|
-
-- npx -y meguro-mcp@0.2.
|
|
165
|
+
-- npx -y meguro-mcp@0.2.3
|
|
165
166
|
```
|
|
166
167
|
|
|
167
168
|
## Register — Cursor (`.cursor/mcp.json`)
|
|
@@ -171,7 +172,7 @@ claude mcp add meguro \
|
|
|
171
172
|
"mcpServers": {
|
|
172
173
|
"meguro": {
|
|
173
174
|
"command": "npx",
|
|
174
|
-
"args": ["-y", "meguro-mcp@0.2.
|
|
175
|
+
"args": ["-y", "meguro-mcp@0.2.3"],
|
|
175
176
|
"env": {
|
|
176
177
|
"MEGURO_API_BASE_URL": "https://api-dev.meguro.io",
|
|
177
178
|
"MEGURO_API_TOKEN": "meg_sk_...",
|
|
@@ -192,6 +193,6 @@ npm test --workspace meguro-mcp
|
|
|
192
193
|
```
|
|
193
194
|
|
|
194
195
|
The test suite packs the public artifact, installs it into a temporary clean-room project, starts the
|
|
195
|
-
installed binary, and requires `tools/list` to return exactly
|
|
196
|
+
installed binary, and requires `tools/list` to return exactly 44 tools without leaking supplied
|
|
196
197
|
credentials to stdout or stderr. Maintainers should follow [RELEASING.md](./RELEASING.md) for every
|
|
197
198
|
version; release notes are in [CHANGELOG.md](./CHANGELOG.md).
|
package/package.json
CHANGED
package/src/server.mjs
CHANGED
|
@@ -7,7 +7,7 @@ import { createInterface } from 'node:readline';
|
|
|
7
7
|
import { documentationResource, documentationResources } from './docs.mjs';
|
|
8
8
|
import { createTools, redactSecrets } from './tools.mjs';
|
|
9
9
|
|
|
10
|
-
const SERVER_INFO = { name: 'meguro', version: '0.2.
|
|
10
|
+
const SERVER_INFO = { name: 'meguro', version: '0.2.3' };
|
|
11
11
|
const PROTOCOL_VERSION = '2025-03-26';
|
|
12
12
|
|
|
13
13
|
const tools = createTools({
|
package/src/tools.mjs
CHANGED
|
@@ -11,18 +11,20 @@ const SECRET_HEADER = /\b(?:authorization|cookie|set-cookie|x-shopify-access-tok
|
|
|
11
11
|
const SECRET_KEY = /(?:authorization|cookie|password|secret|token|api[_-]?key|signedsnapshot)/iu;
|
|
12
12
|
const PRIVATE_RESPONSE_KEY = /^(?:raw|rawBody|rawBodyPreview|responsePayload|requestHeaders|responseHeaders|headers|cookies)$/iu;
|
|
13
13
|
const RESERVED_WORLD_IDS = new Set(['api', 'api-dev', 'www', 'dev', 'hooks', 'control']);
|
|
14
|
+
const PRACTICE_ATTEMPT_ID = /^pa-[a-z0-9][a-z0-9-]{0,124}$/u;
|
|
14
15
|
const AUTH_TEACHING = Object.freeze({
|
|
15
16
|
'workspace-api-key-invalid': 'This workspace API key is invalid or revoked. Create or replace it in Connection settings.',
|
|
16
17
|
'workspace-api-key-revoked': 'This workspace API key is revoked. Create or replace it in Connection settings.',
|
|
17
18
|
});
|
|
18
19
|
const FLEET_TOOL_NAMES = new Set([
|
|
19
|
-
'stores_list', 'store_create', 'store_delete', 'store_passport',
|
|
20
|
+
'templates_list', 'stores_list', 'store_create', 'store_delete', 'store_passport',
|
|
20
21
|
'workspaces_list', 'workspace_create', 'workspace_archive', 'workspace_unarchive',
|
|
21
22
|
'share_create', 'shares_list', 'share_status', 'share_publish', 'share_revoke',
|
|
22
23
|
'catalog_slice_read', 'catalog_slice_snapshot', 'catalog_slices_saved',
|
|
23
24
|
'store_claim_by_code', 'store_claim',
|
|
24
25
|
]);
|
|
25
26
|
const TOOL_PRESENTATION = Object.freeze({
|
|
27
|
+
templates_list: { title: 'List practice-store templates', readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
26
28
|
stores_list: { title: 'List practice stores', readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
27
29
|
store_create: { title: 'Create a practice store', readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false },
|
|
28
30
|
store_delete: { title: 'Delete a practice store', readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false },
|
|
@@ -152,6 +154,47 @@ function catalogSnapshotProjection(value) {
|
|
|
152
154
|
: safe;
|
|
153
155
|
}
|
|
154
156
|
|
|
157
|
+
const STORE_TEMPLATE_FIELDS = Object.freeze([
|
|
158
|
+
'key',
|
|
159
|
+
'label',
|
|
160
|
+
'category',
|
|
161
|
+
'recommended',
|
|
162
|
+
'bestFor',
|
|
163
|
+
'agentTypes',
|
|
164
|
+
'agentSees',
|
|
165
|
+
'recommendedRunDays',
|
|
166
|
+
'recommendedPaceMinutes',
|
|
167
|
+
'recommendedStepDays',
|
|
168
|
+
'eventWindowReason',
|
|
169
|
+
'shortDebugDays',
|
|
170
|
+
'extendedRunDays',
|
|
171
|
+
'whatAgentGets',
|
|
172
|
+
'supportedReads',
|
|
173
|
+
'liveRun',
|
|
174
|
+
'goodFirstAgents',
|
|
175
|
+
'supportedWrites',
|
|
176
|
+
'knownUnsupported',
|
|
177
|
+
'goodAgentShould',
|
|
178
|
+
'avoid',
|
|
179
|
+
'reportGrades',
|
|
180
|
+
]);
|
|
181
|
+
|
|
182
|
+
function storeTemplatesProjection(value) {
|
|
183
|
+
if (!Array.isArray(value?.storeTemplates)) {
|
|
184
|
+
throw new Error('Meguro template catalog response did not contain storeTemplates');
|
|
185
|
+
}
|
|
186
|
+
return {
|
|
187
|
+
storeTemplates: value.storeTemplates.map((template) => {
|
|
188
|
+
if (!template || typeof template !== 'object' || Array.isArray(template)) {
|
|
189
|
+
throw new Error('Meguro template catalog contained an invalid template entry');
|
|
190
|
+
}
|
|
191
|
+
return Object.fromEntries(STORE_TEMPLATE_FIELDS
|
|
192
|
+
.filter((field) => Object.hasOwn(template, field))
|
|
193
|
+
.map((field) => [field, secretSafe(template[field], 1)]));
|
|
194
|
+
}),
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
|
|
155
198
|
function practiceErrorResult(status, value, retryAfterSeconds) {
|
|
156
199
|
const authenticationError = authenticationErrorResult(status, value);
|
|
157
200
|
if (authenticationError) return authenticationError;
|
|
@@ -281,6 +324,14 @@ function requiredPracticeStoreId(args) {
|
|
|
281
324
|
return validatedStoreId(canonical, provided[0]);
|
|
282
325
|
}
|
|
283
326
|
|
|
327
|
+
function requiredPracticeAttemptId(args, key = 'attemptId') {
|
|
328
|
+
const attemptId = requiredString(args, key);
|
|
329
|
+
if (!PRACTICE_ATTEMPT_ID.test(attemptId)) {
|
|
330
|
+
throw new Error(`${key} must be the pa-... run identity returned by practice_run_start, not a practice-store id (storeId)`);
|
|
331
|
+
}
|
|
332
|
+
return attemptId;
|
|
333
|
+
}
|
|
334
|
+
|
|
284
335
|
function optionalPositiveInteger(args, key) {
|
|
285
336
|
const value = args?.[key];
|
|
286
337
|
if (value === undefined) return undefined;
|
|
@@ -1005,6 +1056,18 @@ export function createTools(config) {
|
|
|
1005
1056
|
required: ['topic', 'version'],
|
|
1006
1057
|
},
|
|
1007
1058
|
},
|
|
1059
|
+
{
|
|
1060
|
+
name: 'templates_list',
|
|
1061
|
+
description: 'List the ordered, public-safe practice-store template catalog available for creating a store. The response is a bounded projection of storeTemplates only: it excludes customer profiles, scenario presets, credentials, and private route payload. An OAuth grant may select an owned non-default workspace; an API key remains bound to its own workspace.',
|
|
1062
|
+
inputSchema: {
|
|
1063
|
+
type: 'object',
|
|
1064
|
+
additionalProperties: false,
|
|
1065
|
+
properties: {
|
|
1066
|
+
workspaceId: { type: 'string', minLength: 1, description: 'Optional OAuth selector for an account-owned non-default workspace. A workspace API key may omit it or repeat only its own binding.' },
|
|
1067
|
+
},
|
|
1068
|
+
required: [],
|
|
1069
|
+
},
|
|
1070
|
+
},
|
|
1008
1071
|
{
|
|
1009
1072
|
name: 'stores_list',
|
|
1010
1073
|
description: 'List one workspace\'s practice-store fleet with ids, names, templates, generated-history span, readiness, active-run state, and deletion context. An OAuth grant is account-bound: omit workspaceId for the default workspace or provide an owned non-default workspace id. An API key remains bound to its own workspace.',
|
|
@@ -1358,7 +1421,7 @@ export function createTools(config) {
|
|
|
1358
1421
|
inputSchema: {
|
|
1359
1422
|
type: 'object', additionalProperties: false,
|
|
1360
1423
|
properties: {
|
|
1361
|
-
attemptId: { type: 'string', minLength:
|
|
1424
|
+
attemptId: { type: 'string', minLength: 4, maxLength: 128, pattern: '^pa-[a-z0-9][a-z0-9-]{0,124}$', description: 'Completed practice-run attempt id carrying immutable Exam capture.' },
|
|
1362
1425
|
shopDomain: { type: 'string', pattern: '^[a-z0-9][a-z0-9-]*\\.myshopify\\.com$', description: 'Exact lowercase connected Shopify development-store domain.' },
|
|
1363
1426
|
},
|
|
1364
1427
|
required: ['attemptId', 'shopDomain'],
|
|
@@ -1370,7 +1433,7 @@ export function createTools(config) {
|
|
|
1370
1433
|
inputSchema: {
|
|
1371
1434
|
type: 'object', additionalProperties: false,
|
|
1372
1435
|
properties: {
|
|
1373
|
-
attemptId: { type: 'string', minLength:
|
|
1436
|
+
attemptId: { type: 'string', minLength: 4, maxLength: 128, pattern: '^pa-[a-z0-9][a-z0-9-]{0,124}$', description: 'Completed practice-run attempt id carrying immutable Exam capture.' },
|
|
1374
1437
|
shopDomain: { type: 'string', pattern: '^[a-z0-9][a-z0-9-]*\\.myshopify\\.com$', description: 'Exact lowercase connected Shopify development-store domain; this is the typed target confirmation.' },
|
|
1375
1438
|
},
|
|
1376
1439
|
required: ['attemptId', 'shopDomain'],
|
|
@@ -1403,7 +1466,7 @@ export function createTools(config) {
|
|
|
1403
1466
|
properties: {
|
|
1404
1467
|
storeId: { type: 'string', minLength: 1, description: 'Canonical Meguro practice-store id (tenant-owned), as returned by get_connection_details.' },
|
|
1405
1468
|
worldId: { type: 'string', minLength: 1, description: 'Legacy alias for storeId — the same practice-store id under its old name. Prefer storeId.' },
|
|
1406
|
-
continueFromAttemptId: { type: 'string', minLength:
|
|
1469
|
+
continueFromAttemptId: { type: 'string', minLength: 4, maxLength: 128, pattern: '^pa-[a-z0-9][a-z0-9-]{0,124}$', description: 'Completed prior segment to continue on the same aging practice store. Available only when the server tier policy allows continuation.' },
|
|
1407
1470
|
clock: { type: 'object', description: 'Existing hosted practice-run clock contract.' },
|
|
1408
1471
|
externalAgent: { type: 'object', description: 'Optional bounded external-agent identity metadata.' },
|
|
1409
1472
|
subject: {
|
|
@@ -1429,7 +1492,7 @@ export function createTools(config) {
|
|
|
1429
1492
|
description: 'Read the server-authoritative state of an external-agent practice run, including its announced run-conclusion deadlines and immutable conclusion receipt after any exit. Use Console for quick proof; the tested agent remains in the caller\'s environment.',
|
|
1430
1493
|
inputSchema: {
|
|
1431
1494
|
type: 'object', additionalProperties: false,
|
|
1432
|
-
properties: { attemptId: { type: 'string', minLength:
|
|
1495
|
+
properties: { attemptId: { type: 'string', minLength: 4, maxLength: 128, pattern: '^pa-[a-z0-9][a-z0-9-]{0,124}$', description: 'Run identity returned by practice_run_start — not the practice-store id (storeId).' } },
|
|
1433
1496
|
required: ['attemptId'],
|
|
1434
1497
|
},
|
|
1435
1498
|
},
|
|
@@ -1438,7 +1501,7 @@ export function createTools(config) {
|
|
|
1438
1501
|
description: 'Capture an immutable checkpoint for an external-agent practice run and return a bounded evidence summary. Console is quick proof; agent execution remains in the caller\'s environment.',
|
|
1439
1502
|
inputSchema: {
|
|
1440
1503
|
type: 'object', additionalProperties: false,
|
|
1441
|
-
properties: { attemptId: { type: 'string', minLength:
|
|
1504
|
+
properties: { attemptId: { type: 'string', minLength: 4, maxLength: 128, pattern: '^pa-[a-z0-9][a-z0-9-]{0,124}$', description: 'Run identity returned by practice_run_start — not the practice-store id (storeId).' } },
|
|
1442
1505
|
required: ['attemptId'],
|
|
1443
1506
|
},
|
|
1444
1507
|
},
|
|
@@ -1449,7 +1512,7 @@ export function createTools(config) {
|
|
|
1449
1512
|
type: 'object',
|
|
1450
1513
|
additionalProperties: false,
|
|
1451
1514
|
properties: {
|
|
1452
|
-
attemptId: { type: 'string', minLength:
|
|
1515
|
+
attemptId: { type: 'string', minLength: 4, maxLength: 128, pattern: '^pa-[a-z0-9][a-z0-9-]{0,124}$', description: 'Run identity returned by practice_run_start — not the practice-store id (storeId).' },
|
|
1453
1516
|
days: { type: 'integer', minimum: 1, description: 'Whole simulated days to advance.' },
|
|
1454
1517
|
until: { type: 'object', description: 'Existing meguro.practice-run-until.v1 event-gated request.' },
|
|
1455
1518
|
expectedDay: { type: 'integer', minimum: 0, description: 'Current practiceRun.time.watermarkDay.' },
|
|
@@ -1464,7 +1527,7 @@ export function createTools(config) {
|
|
|
1464
1527
|
description: 'Explicitly finish an external-agent practice run without inventing additional time or evidence. The response includes the immutable conclusion receipt and echoes the deadlines announced at start. Console is quick proof; agent execution remains in the caller\'s environment.',
|
|
1465
1528
|
inputSchema: {
|
|
1466
1529
|
type: 'object', additionalProperties: false,
|
|
1467
|
-
properties: { attemptId: { type: 'string', minLength:
|
|
1530
|
+
properties: { attemptId: { type: 'string', minLength: 4, maxLength: 128, pattern: '^pa-[a-z0-9][a-z0-9-]{0,124}$', description: 'Run identity returned by practice_run_start — not the practice-store id (storeId).' } },
|
|
1468
1531
|
required: ['attemptId'],
|
|
1469
1532
|
},
|
|
1470
1533
|
},
|
|
@@ -1473,7 +1536,7 @@ export function createTools(config) {
|
|
|
1473
1536
|
description: 'Read the run\'s receipt — a bounded receipt summary for a completed external-agent practice run. `report` is the protocol/route compatibility name for the receipt (the tool name and the `operation: "report"` field keep it for wire stability); user-facing language is "receipt". The payload includes an unguessable public receipt id, canonical unauthenticated fetch path, and SHA-256: gate a deploy by fetching that id and verifying the exact bytes before promotion. Raw private request and response payloads stay out of MCP; use Console for quick proof while the agent remains in the caller\'s environment. Receipts remain fetchable for 7 days on Free, 90 days on Solo, and 365 days on Builder; an expired response teaches the applicable upgrade or a fresh run.',
|
|
1474
1537
|
inputSchema: {
|
|
1475
1538
|
type: 'object', additionalProperties: false,
|
|
1476
|
-
properties: { attemptId: { type: 'string', minLength:
|
|
1539
|
+
properties: { attemptId: { type: 'string', minLength: 4, maxLength: 128, pattern: '^pa-[a-z0-9][a-z0-9-]{0,124}$', description: 'Run identity returned by practice_run_start — not the practice-store id (storeId).' } },
|
|
1477
1540
|
required: ['attemptId'],
|
|
1478
1541
|
},
|
|
1479
1542
|
},
|
|
@@ -1482,7 +1545,7 @@ export function createTools(config) {
|
|
|
1482
1545
|
description: 'Read the impact receipt for a completed external-agent practice run: the base year — the same store, same days, without your agent — compared with your agent\'s year, showing what changed because of your agent (orders, units, and revenue), a footprint of every write, and an integrity gate that reports a reason instead of numbers when the comparison is not clean. The payload includes an unguessable public receipt id, canonical unauthenticated fetch path, and SHA-256: gate a deploy by fetching that id and verifying the exact bytes before promotion. Read-only; never mutates the run and returns no credentials. Takes the run\'s attemptId (from practice_run_start), not the practice-store id (storeId). Receipts remain fetchable for 7 days on Free, 90 days on Solo, and 365 days on Builder; an expired response teaches the applicable upgrade or a fresh run.',
|
|
1483
1546
|
inputSchema: {
|
|
1484
1547
|
type: 'object', additionalProperties: false,
|
|
1485
|
-
properties: { attemptId: { type: 'string', minLength:
|
|
1548
|
+
properties: { attemptId: { type: 'string', minLength: 4, maxLength: 128, pattern: '^pa-[a-z0-9][a-z0-9-]{0,124}$', description: 'Run identity returned by practice_run_start — not the practice-store id (storeId).' } },
|
|
1486
1549
|
required: ['attemptId'],
|
|
1487
1550
|
},
|
|
1488
1551
|
},
|
|
@@ -1535,9 +1598,25 @@ export function createTools(config) {
|
|
|
1535
1598
|
const { title, ...annotations } = presentation;
|
|
1536
1599
|
return { ...definition, title, annotations };
|
|
1537
1600
|
});
|
|
1601
|
+
const definitionsByName = new Map(definitions.map((definition) => [definition.name, definition]));
|
|
1602
|
+
|
|
1603
|
+
function validateTopLevelArguments(name, args) {
|
|
1604
|
+
const definition = definitionsByName.get(name);
|
|
1605
|
+
if (!definition) return;
|
|
1606
|
+
if (!args || typeof args !== 'object' || Array.isArray(args)) {
|
|
1607
|
+
throw new Error(`${name} arguments must be an object`);
|
|
1608
|
+
}
|
|
1609
|
+
if (definition.inputSchema.additionalProperties !== false) return;
|
|
1610
|
+
const allowed = new Set(Object.keys(definition.inputSchema.properties ?? {}));
|
|
1611
|
+
const unexpected = Object.keys(args).filter((key) => !allowed.has(key)).sort();
|
|
1612
|
+
if (unexpected.length > 0) {
|
|
1613
|
+
throw new Error(`${name} arguments must match the declared top-level properties: ${[...allowed].join(', ') || '(none)'}`);
|
|
1614
|
+
}
|
|
1615
|
+
}
|
|
1538
1616
|
|
|
1539
1617
|
async function call(name, args = {}) {
|
|
1540
1618
|
try {
|
|
1619
|
+
validateTopLevelArguments(name, args);
|
|
1541
1620
|
switch (name) {
|
|
1542
1621
|
case 'docs_read': {
|
|
1543
1622
|
const topic = requiredString(args, 'topic');
|
|
@@ -1549,6 +1628,11 @@ export function createTools(config) {
|
|
|
1549
1628
|
}
|
|
1550
1629
|
return textResult(documentationByTopic(topic, args.version));
|
|
1551
1630
|
}
|
|
1631
|
+
case 'templates_list': {
|
|
1632
|
+
const workspaceId = optionalWorkspaceId(args);
|
|
1633
|
+
const response = await fleetRequest(name, 'GET', '/practice/profiles', undefined, { workspaceId });
|
|
1634
|
+
return 'error' in response ? response.error : textResult(storeTemplatesProjection(response.value));
|
|
1635
|
+
}
|
|
1552
1636
|
case 'stores_list': {
|
|
1553
1637
|
const workspaceId = optionalWorkspaceId(args);
|
|
1554
1638
|
const response = await fleetRequest(name, 'GET', '/practice/stores', undefined, { workspaceId });
|
|
@@ -1819,13 +1903,13 @@ export function createTools(config) {
|
|
|
1819
1903
|
)));
|
|
1820
1904
|
}
|
|
1821
1905
|
case 'exam_preflight': {
|
|
1822
|
-
const attemptId =
|
|
1906
|
+
const attemptId = requiredPracticeAttemptId(args);
|
|
1823
1907
|
const shopDomain = requiredShopifyDevDomain(args);
|
|
1824
1908
|
const response = await examRequest(name, 'POST', '/practice-exams/preflight', { attemptId, shopDomain }, attemptId);
|
|
1825
1909
|
return 'error' in response ? response.error : textResult(secretSafe(response.value));
|
|
1826
1910
|
}
|
|
1827
1911
|
case 'exam_start': {
|
|
1828
|
-
const attemptId =
|
|
1912
|
+
const attemptId = requiredPracticeAttemptId(args);
|
|
1829
1913
|
const shopDomain = requiredShopifyDevDomain(args);
|
|
1830
1914
|
const created = await examRequest(name, 'POST', '/practice-exams', { attemptId, shopDomain }, attemptId);
|
|
1831
1915
|
if ('error' in created) return created.error;
|
|
@@ -1910,7 +1994,7 @@ export function createTools(config) {
|
|
|
1910
1994
|
const storeId = requiredPracticeStoreId(args);
|
|
1911
1995
|
const body = {
|
|
1912
1996
|
purpose: 'external-agent',
|
|
1913
|
-
...(args.continueFromAttemptId !== undefined ? { continueFromAttemptId: args
|
|
1997
|
+
...(args.continueFromAttemptId !== undefined ? { continueFromAttemptId: requiredPracticeAttemptId(args, 'continueFromAttemptId') } : {}),
|
|
1914
1998
|
...(args.clock !== undefined ? { clock: args.clock } : {}),
|
|
1915
1999
|
...(args.externalAgent !== undefined ? { externalAgent: args.externalAgent } : {}),
|
|
1916
2000
|
...(args.subject !== undefined ? { subject: args.subject } : {}),
|
|
@@ -1934,7 +2018,7 @@ export function createTools(config) {
|
|
|
1934
2018
|
}));
|
|
1935
2019
|
}
|
|
1936
2020
|
case 'practice_run_status': {
|
|
1937
|
-
const attemptId =
|
|
2021
|
+
const attemptId = requiredPracticeAttemptId(args);
|
|
1938
2022
|
const response = await practiceApi('GET', `/practice/playbacks/${encodeURIComponent(attemptId)}/state`);
|
|
1939
2023
|
if (!response.ok) return practiceErrorResult(response.status, response.json, response.retryAfterSeconds);
|
|
1940
2024
|
const state = response.json ?? {};
|
|
@@ -1946,7 +2030,7 @@ export function createTools(config) {
|
|
|
1946
2030
|
}));
|
|
1947
2031
|
}
|
|
1948
2032
|
case 'practice_run_checkpoint': {
|
|
1949
|
-
const attemptId =
|
|
2033
|
+
const attemptId = requiredPracticeAttemptId(args);
|
|
1950
2034
|
const response = await practiceApi('POST', `/practice/playbacks/${encodeURIComponent(attemptId)}/checkpoint`, {});
|
|
1951
2035
|
if (!response.ok) return practiceErrorResult(response.status, response.json, response.retryAfterSeconds);
|
|
1952
2036
|
return textResult(secretSafe({
|
|
@@ -1958,7 +2042,7 @@ export function createTools(config) {
|
|
|
1958
2042
|
}));
|
|
1959
2043
|
}
|
|
1960
2044
|
case 'practice_run_advance': {
|
|
1961
|
-
const attemptId =
|
|
2045
|
+
const attemptId = requiredPracticeAttemptId(args);
|
|
1962
2046
|
const hasDays = args.days !== undefined;
|
|
1963
2047
|
const hasUntil = args.until !== undefined;
|
|
1964
2048
|
if (hasDays === hasUntil) throw new Error('practice_run_advance requires exactly one of days or until');
|
|
@@ -1983,7 +2067,7 @@ export function createTools(config) {
|
|
|
1983
2067
|
}));
|
|
1984
2068
|
}
|
|
1985
2069
|
case 'practice_run_finish': {
|
|
1986
|
-
const attemptId =
|
|
2070
|
+
const attemptId = requiredPracticeAttemptId(args);
|
|
1987
2071
|
const response = await practiceApi('POST', `/practice/playbacks/${encodeURIComponent(attemptId)}/finish`, {});
|
|
1988
2072
|
if (!response.ok) return practiceErrorResult(response.status, response.json, response.retryAfterSeconds);
|
|
1989
2073
|
return textResult(secretSafe({
|
|
@@ -1994,7 +2078,7 @@ export function createTools(config) {
|
|
|
1994
2078
|
}));
|
|
1995
2079
|
}
|
|
1996
2080
|
case 'practice_run_report': {
|
|
1997
|
-
const attemptId =
|
|
2081
|
+
const attemptId = requiredPracticeAttemptId(args);
|
|
1998
2082
|
const response = await practiceApi('GET', `/practice/playbacks/${encodeURIComponent(attemptId)}/report?v=2`);
|
|
1999
2083
|
if (!response.ok) return practiceErrorResult(response.status, response.json, response.retryAfterSeconds);
|
|
2000
2084
|
return textResult({
|
|
@@ -2004,7 +2088,7 @@ export function createTools(config) {
|
|
|
2004
2088
|
});
|
|
2005
2089
|
}
|
|
2006
2090
|
case 'practice_run_impact': {
|
|
2007
|
-
const attemptId =
|
|
2091
|
+
const attemptId = requiredPracticeAttemptId(args);
|
|
2008
2092
|
const response = await practiceApi('GET', `/practice/playbacks/${encodeURIComponent(attemptId)}/impact`);
|
|
2009
2093
|
if (!response.ok) return practiceErrorResult(response.status, response.json, response.retryAfterSeconds);
|
|
2010
2094
|
// T1 owns the shape and the API already ran the public-safe scan; pass it through verbatim
|