@maka/maka-cli 5.143.0 → 5.144.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/bundle/typescript/package.json +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/factories/scene-chunks.js +6 -4
- package/bundle/typescript/src/commands/game/sideQuest/factories/scene-seed-generator.js +13 -6
- package/bundle/typescript/src/commands/game/sideQuest/utilities/affordances.js +40 -0
- package/bundle/typescript/src/commands/game/sideQuest-backlog-mcp.sub.cmd.js +35 -14
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@maka/maka-cli",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.144.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"summary": "A command line tool for scaffolding Meteor 3.x applications using either React.",
|
|
6
6
|
"description": "A command line tool for scaffolding Meteor 3.x applications using React.",
|
|
@@ -3,6 +3,7 @@ import { spreadStationedNpcs } from './npc-spread.js';
|
|
|
3
3
|
import { Logger } from '../utilities/logger.js';
|
|
4
4
|
import { catalogAugmentations } from '../utilities/catalog.js';
|
|
5
5
|
import { isOutdoorsPlace } from '../utilities/outdoors.js';
|
|
6
|
+
import { clampDeviceKind } from '../utilities/affordances.js';
|
|
6
7
|
/**
|
|
7
8
|
* CHUNKED scene generation (see SceneSeedGenerator.generate for the
|
|
8
9
|
* pipeline that drives this module). One monolithic whole-scene completion
|
|
@@ -2176,10 +2177,11 @@ export function assembleScene(skeleton, details, playerName) {
|
|
|
2176
2177
|
? detail.guardsExit.toLowerCase()
|
|
2177
2178
|
: undefined;
|
|
2178
2179
|
const footprint = guardsExit && detail?.footprint && VALID_FOOTPRINTS.has(detail.footprint) ? detail.footprint : undefined;
|
|
2179
|
-
// KIND CLAMPS, never throws
|
|
2180
|
-
//
|
|
2181
|
-
//
|
|
2182
|
-
|
|
2180
|
+
// KIND CLAMPS, never throws -- see clampDeviceKind's own doc for
|
|
2181
|
+
// why, and for the incident (a "tunnel grate" clamped to `panel`
|
|
2182
|
+
// and rendered hack-only) that put a name/description-aware
|
|
2183
|
+
// fallback here instead of a blind default to `panel`.
|
|
2184
|
+
const kind = clampDeviceKind(device.kind, device.name, detail?.description ?? device.concept);
|
|
2183
2185
|
// A CODE ONLY BELONGS ON A PANEL -- enforced here as well as in the
|
|
2184
2186
|
// prompt, because the prompt is advice and this is not. You cannot
|
|
2185
2187
|
// talk at a mechanical lock.
|
|
@@ -4,6 +4,7 @@ import { AI } from '../../../../tools/ai/ai.class.js';
|
|
|
4
4
|
import { Player } from '../models/player.js';
|
|
5
5
|
import { Room } from '../models/room.js';
|
|
6
6
|
import { Logger } from '../utilities/logger.js';
|
|
7
|
+
import { clampDeviceKind } from '../utilities/affordances.js';
|
|
7
8
|
import { GenerationCapture } from '../utilities/generation-capture.js';
|
|
8
9
|
import { fetchCanonContext } from '../utilities/canon-lore.js';
|
|
9
10
|
import { SceneSynthesizer } from './scene-factory.js';
|
|
@@ -681,17 +682,23 @@ export class SceneSeedGenerator {
|
|
|
681
682
|
* This used to throw on an unrecognised bypassType. A kind we cannot
|
|
682
683
|
* read is still a device, and rejecting a whole draft -- 20-40s of
|
|
683
684
|
* generation -- over one misspelled word is a worse outcome than a
|
|
684
|
-
*
|
|
685
|
-
* same clamp
|
|
685
|
+
* guess where the model meant something else. assembleScene does the
|
|
686
|
+
* same clamp (via the same clampDeviceKind helper, so the two cannot
|
|
687
|
+
* drift); this one catches a seed that reached us another way.
|
|
688
|
+
*
|
|
689
|
+
* THE GUESS IS NAME/DESCRIPTION-AWARE, not a blind "panel" (fixed
|
|
690
|
+
* 2026-09-08, backlog 2uNPnc4L6jHaYEtnN / tuku6Z5XTtmNemkzd): a
|
|
691
|
+
* "tunnel grate" clamped to `panel` rendered as a hack-only "sealed
|
|
692
|
+
* SYSTEM", which is backwards for a physical mechanism.
|
|
686
693
|
*/
|
|
687
694
|
static clampDeviceKinds(candidate) {
|
|
688
|
-
const allowed = new Set(['lock', 'panel', 'ward']);
|
|
689
695
|
for (const room of candidate.rooms ?? []) {
|
|
690
696
|
for (const device of room.devices ?? []) {
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
device.kind
|
|
697
|
+
const clamped = clampDeviceKind(device.kind, device.name, device.description);
|
|
698
|
+
if (device.kind && device.kind !== clamped) {
|
|
699
|
+
Logger.getInstance().write(`scene-seed-generator: device "${device.name}" had kind "${device.kind}"; clamped to "${clamped}".`);
|
|
694
700
|
}
|
|
701
|
+
device.kind = clamped;
|
|
695
702
|
}
|
|
696
703
|
}
|
|
697
704
|
}
|
|
@@ -33,4 +33,44 @@ export const AFFORDANCE_FLAVOR = {
|
|
|
33
33
|
export function verbsFor(kind) {
|
|
34
34
|
return AFFORDANCE_FLAVOR[kind]?.verbs ?? [];
|
|
35
35
|
}
|
|
36
|
+
/** WARD-SOUNDING NAMES, checked first: a magical barrier is rare and
|
|
37
|
+
* specific enough here that missing one costs less than a false
|
|
38
|
+
* positive stealing a genuine lock from `lock`. */
|
|
39
|
+
const WARD_HINTS = ['ward', 'seal', 'rune', 'glyph', 'weave', 'astral', 'spell', 'enchant', 'mystic'];
|
|
40
|
+
/** PHYSICAL-MECHANISM NAMES, checked second -- the actual fix
|
|
41
|
+
* (backlog 2uNPnc4L6jHaYEtnN / tuku6Z5XTtmNemkzd, 2026-09-08). A
|
|
42
|
+
* device that reads as a mechanism now falls back to `lock`
|
|
43
|
+
* (pick/breach) instead of `panel` (hack): defaulting a "tunnel
|
|
44
|
+
* grate" to panel had the game insist a metal grate was "a sealed
|
|
45
|
+
* SYSTEM", which is exactly backwards for a physical object. */
|
|
46
|
+
const LOCK_HINTS = [
|
|
47
|
+
'grate', 'gate', 'hatch', 'grille', 'grill', 'padlock', 'deadbolt',
|
|
48
|
+
'bolt', 'latch', 'mechanism', 'portcullis', 'chain', 'valve', 'hinge',
|
|
49
|
+
'tumbler', 'maglock', 'lock', 'vault', 'safe', 'cage', 'shutter',
|
|
50
|
+
'manhole', 'trapdoor', 'hasp',
|
|
51
|
+
];
|
|
52
|
+
/**
|
|
53
|
+
* THE ONE KIND CLAMP, shared by both scene-chunks.ts's assembleScene and
|
|
54
|
+
* scene-seed-generator.ts's clampDeviceKinds so the fallback cannot
|
|
55
|
+
* drift between them the way a bare "default to panel" already had.
|
|
56
|
+
*
|
|
57
|
+
* NEVER THROWS -- deliberately, and for the reason both call sites'
|
|
58
|
+
* own comments already gave before this existed: a kind the model got
|
|
59
|
+
* wrong is still a device, and rejecting a whole generated scene over
|
|
60
|
+
* one word costs the player a 20-40s regeneration for a mistake this
|
|
61
|
+
* heuristic can approximate better. This only changes WHAT the
|
|
62
|
+
* fallback guesses when the raw kind isn't one of the three real
|
|
63
|
+
* ones -- from a blind `panel` to a look at the device's own name and
|
|
64
|
+
* description first.
|
|
65
|
+
*/
|
|
66
|
+
export function clampDeviceKind(rawKind, name, description) {
|
|
67
|
+
if (rawKind === 'lock' || rawKind === 'panel' || rawKind === 'ward')
|
|
68
|
+
return rawKind;
|
|
69
|
+
const text = `${name} ${description ?? ''}`.toLowerCase();
|
|
70
|
+
if (WARD_HINTS.some(hint => text.includes(hint)))
|
|
71
|
+
return 'ward';
|
|
72
|
+
if (LOCK_HINTS.some(hint => text.includes(hint)))
|
|
73
|
+
return 'lock';
|
|
74
|
+
return 'panel';
|
|
75
|
+
}
|
|
36
76
|
//# sourceMappingURL=affordances.js.map
|
|
@@ -1,10 +1,17 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
1
2
|
import path from 'path';
|
|
2
3
|
import { Command } from '../../command.js';
|
|
4
|
+
import { UsageError } from '../../error.js';
|
|
3
5
|
export function registerBacklogMcp(parent) {
|
|
4
6
|
return Command.create({
|
|
5
7
|
name: 'mcp',
|
|
6
|
-
usage: 'maka play:backlog:mcp [--env <env>]',
|
|
7
|
-
|
|
8
|
+
usage: 'maka play:backlog:mcp [--env <env>] [--site <path>]',
|
|
9
|
+
// OFF, DELIBERATELY -- see the file header. The framework's own
|
|
10
|
+
// check fires before this handler runs at all and only knows how
|
|
11
|
+
// to look at process.cwd(); --site is this command's own way to
|
|
12
|
+
// satisfy the same requirement, so it needs the chance to try that
|
|
13
|
+
// first rather than being refused upstream of ever seeing it.
|
|
14
|
+
mustBeInMakaProject: false,
|
|
8
15
|
// NO maxArgLength HERE, DELIBERATELY. Command's own arg-length check
|
|
9
16
|
// is `args.length >= maxArgLength` (command.ts), so `maxArgLength: 0`
|
|
10
17
|
// refuses EVERY invocation regardless of what was typed -- an
|
|
@@ -17,29 +24,43 @@ export function registerBacklogMcp(parent) {
|
|
|
17
24
|
name: 'env',
|
|
18
25
|
description: 'Which maka-cli.com config/<env>/process.env supplies the Auth0 M2M credentials (default: production).',
|
|
19
26
|
},
|
|
27
|
+
{
|
|
28
|
+
name: 'site',
|
|
29
|
+
description: 'Path to a maka-cli.com checkout. Defaults to resolving one from the current working directory if omitted -- pass this explicitly when the launching MCP client does not set cwd reliably.',
|
|
30
|
+
},
|
|
20
31
|
],
|
|
21
32
|
shortDesc: 'Run an MCP server exposing game-backlog admin tools, authenticated as the M2M service account.',
|
|
22
33
|
description: `Starts a local MCP server (stdio transport) with tools for listing and reading
|
|
23
34
|
backlog items, attaching evidence and advancing status, drafting an AI bench, and posting
|
|
24
35
|
admin notes -- all against maka-cli.com's existing game-backlog REST API, authenticated as
|
|
25
36
|
the claude-agent@maka-cli.com service account via the Auth0 M2M token exchange
|
|
26
|
-
(api/v1/auth/m2m-login).
|
|
27
|
-
|
|
28
|
-
|
|
37
|
+
(api/v1/auth/m2m-login). Needs a maka-cli.com checkout to read AUTHZERO_DOMAIN /
|
|
38
|
+
AUTHZERO_CLIENT_ID / AUTHZERO_SECRET / AUTHZERO_AUDIENCE from config/<env>/process.env --
|
|
39
|
+
pass --site explicitly, or run with cwd already set to one.`,
|
|
29
40
|
examples: [
|
|
30
|
-
'maka play:backlog:mcp',
|
|
31
|
-
'maka play:backlog:mcp --env local',
|
|
41
|
+
'maka play:backlog:mcp --site C:\\path\\to\\maka-cli.com',
|
|
42
|
+
'maka play:backlog:mcp --env local --site C:\\path\\to\\maka-cli.com',
|
|
32
43
|
],
|
|
33
44
|
}, async function (_args, opts) {
|
|
34
45
|
const env = opts.env ?? 'production';
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
46
|
+
let processEnvPath;
|
|
47
|
+
if (opts.site) {
|
|
48
|
+
const siteConfigDir = path.join(path.resolve(opts.site), 'config', env);
|
|
49
|
+
processEnvPath = path.join(siteConfigDir, 'process.env');
|
|
50
|
+
if (!fs.existsSync(processEnvPath)) {
|
|
51
|
+
throw new UsageError(`No config/${env}/process.env under --site ${opts.site} (looked for ${processEnvPath}).`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
if (!this.cfg.checkConfigExists(env)) {
|
|
56
|
+
// Pre-handshake failure -- nothing has touched stdout as MCP
|
|
57
|
+
// protocol yet, so a plain thrown Error (which Command's own
|
|
58
|
+
// wrapper reports via Log.error) is fine here.
|
|
59
|
+
throw new UsageError(`Not in a maka-cli.com checkout and no --site given (looked for config/${env} under ${process.cwd()}).`);
|
|
60
|
+
}
|
|
61
|
+
const configPath = this.cfg.getAppConfigPath(env);
|
|
62
|
+
processEnvPath = path.join(configPath, 'process.env');
|
|
40
63
|
}
|
|
41
|
-
const configPath = this.cfg.getAppConfigPath(env);
|
|
42
|
-
const processEnvPath = path.join(configPath, 'process.env');
|
|
43
64
|
const [domain, clientId, clientSecret, audience] = await Promise.all([
|
|
44
65
|
this.dotenvx.get('AUTHZERO_DOMAIN', processEnvPath),
|
|
45
66
|
this.dotenvx.get('AUTHZERO_CLIENT_ID', processEnvPath),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@maka/maka-cli",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.144.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"summary": "A command line tool for scaffolding Meteor 3.x applications using either React.",
|
|
6
6
|
"description": "A command line tool for scaffolding Meteor 3.x applications using React.",
|