@maka/maka-cli 5.143.1 → 5.145.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 +93 -1
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@maka/maka-cli",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.145.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
|
|
@@ -2,6 +2,89 @@ import fs from 'fs';
|
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import { Command } from '../../command.js';
|
|
4
4
|
import { UsageError } from '../../error.js';
|
|
5
|
+
/**
|
|
6
|
+
* `maka play:backlog:mcp` -- an MCP server exposing the game-backlog
|
|
7
|
+
* admin actions as tools, so an AI agent can drive backlog resolution
|
|
8
|
+
* directly (list items, read one, attach evidence, advance status,
|
|
9
|
+
* request an AI-drafted bench) with a human approving the consequential
|
|
10
|
+
* calls through the MCP client's own tool-permission UI.
|
|
11
|
+
*
|
|
12
|
+
* SCOPED HERE, NOT AT THE CLI'S TOP LEVEL (user ruling 2026-09-08). A
|
|
13
|
+
* command whose only job is game-backlog administration does not belong
|
|
14
|
+
* as a generic top-level command just because an unrelated, unbuilt stub
|
|
15
|
+
* (`maka ai:mcp`) already claimed that shape in .claude/mcp.json -- that
|
|
16
|
+
* stub is left alone. This lives under the feature it actually serves,
|
|
17
|
+
* registered as a CHILD of `play:backlog` (see registerBacklogMcp below
|
|
18
|
+
* and its call site in sideQuest-backlog.sub.cmd.ts).
|
|
19
|
+
*
|
|
20
|
+
* RUNS AS THE M2M SERVICE ACCOUNT, NEVER A HUMAN'S SESSION. Every tool
|
|
21
|
+
* below is a thin wrapper over the exact same REST routes
|
|
22
|
+
* game-backlog-v1-rest-api.ts already exposes to the web board and the
|
|
23
|
+
* human CLI -- so every role check, evidence gate and audit log line
|
|
24
|
+
* those routes already enforce applies here unchanged. Nothing is
|
|
25
|
+
* bypassed or reimplemented; this command only adds a way to call them.
|
|
26
|
+
*
|
|
27
|
+
* STDOUT IS THE PROTOCOL, NOT A LOG (the one hard constraint worth
|
|
28
|
+
* repeating). StdioServerTransport owns process.stdout for the MCP
|
|
29
|
+
* JSON-RPC stream once connected -- anything else written there
|
|
30
|
+
* (including Log.* from this codebase's own logger, which writes via
|
|
31
|
+
* console.log) corrupts every message after it. Diagnostics in this
|
|
32
|
+
* file go to console.error (stderr) only, and Log is not imported here
|
|
33
|
+
* at all, on purpose.
|
|
34
|
+
*
|
|
35
|
+
* SECRETS COME FROM THE MAKA-CLI.COM PROJECT'S OWN CONFIG.
|
|
36
|
+
*
|
|
37
|
+
* `--site <path>` IS THE REAL ANSWER, NOT `cwd` (corrected 2026-09-08,
|
|
38
|
+
* after `cwd` alone shipped broken). The first cut relied entirely on
|
|
39
|
+
* `this.cfg.getAppConfigPath(env)` against `process.cwd()` -- the same
|
|
40
|
+
* mechanism `maka env:get` uses -- on the theory that an MCP client's
|
|
41
|
+
* server config setting `cwd` to a maka-cli.com checkout would make
|
|
42
|
+
* that resolve correctly. It does not, at least not for a server
|
|
43
|
+
* registered in Claude Code's GLOBAL config (~/.claude.json): the
|
|
44
|
+
* process spawns with the session's own working directory regardless
|
|
45
|
+
* of a `cwd` field there, `mustBeInMakaProject` fails immediately
|
|
46
|
+
* ("No maka project config file found"), and the process exits before
|
|
47
|
+
* the MCP handshake completes -- which surfaces to the client as a
|
|
48
|
+
* bare "Connection closed", not a readable error. `--site` sidesteps
|
|
49
|
+
* the whole question of what a given MCP client's `cwd` support
|
|
50
|
+
* actually is: the checkout path is a literal argument, not inferred
|
|
51
|
+
* from where the process happened to start.
|
|
52
|
+
*
|
|
53
|
+
* `cwd` STILL WORKS AS A CONVENIENCE, for a terminal or a client that
|
|
54
|
+
* does set it correctly (a project-scoped `.claude/mcp.json`, say):
|
|
55
|
+
* omitting `--site` falls back to the original cwd-based resolution.
|
|
56
|
+
* `mustBeInMakaProject` is OFF at the framework level either way --
|
|
57
|
+
* this command does its own check so both paths get the same clear
|
|
58
|
+
* error instead of the framework's for one and a hand-rolled one for
|
|
59
|
+
* the other.
|
|
60
|
+
*
|
|
61
|
+
* AUTHZERO_SECRET never leaves this lookup either way: it is used
|
|
62
|
+
* once, in-process, to mint an Auth0 token, and is never logged or
|
|
63
|
+
* forwarded anywhere.
|
|
64
|
+
*/
|
|
65
|
+
/**
|
|
66
|
+
* WHAT A CONNECTING SESSION IS TOLD, surfaced at MCP connection time.
|
|
67
|
+
* This is the loop as it actually runs, corrected in-session against
|
|
68
|
+
* real friction on the first item worked through it (2026-09-08/09) --
|
|
69
|
+
* not a policy written in advance of ever using the tool.
|
|
70
|
+
*/
|
|
71
|
+
const MCP_SERVER_INSTRUCTIONS = `This server exposes the game-backlog admin actions as tools. Every tool is a thin wrapper over the same REST routes the human web board and CLI already use -- role checks, evidence gates, and audit logging all apply exactly as they do for a human admin. Nothing here bypasses them.
|
|
72
|
+
|
|
73
|
+
THE LOOP IS NEARLY AUTOMATED BY DESIGN -- that is the whole reason this server exists instead of a human doing this work by hand. For each item: read it in full (backlog_get), find the root cause in the relevant repo (maka-cli-src for the CLI/game engine, maka-cli.com for the site/backend -- see sources-1/CLAUDE.md for which repo owns what), fix it, write/run tests, build, lint, typecheck -- then commit, version-bump (maka-cli-src releases go through the full chain: push -> build -> publish -> GitHub release + site pin -> the pin auto-deploys the site; maka-cli.com-only changes need either the next pin or a manual "gh workflow run deploy.yml"), and once the fix is committed AND actually deployed live, call backlog_advance with the commit sha(s) to move the item to "ready-for-bench".
|
|
74
|
+
|
|
75
|
+
DO NOT PAUSE TO ASK PERMISSION for a routine step in that loop -- committing a clean, tested, single-purpose change, bumping a version, pushing, or letting the release chain run. That is exactly the friction this tooling was built to remove. Reserve a real stop for a production-only action with no easy rollback, or a failure that genuinely needs human judgment to interpret.
|
|
76
|
+
|
|
77
|
+
DESIGN DECISIONS THAT COME UP WHILE FIXING ARE NOT A STOP EITHER. Make the call, then record the decision and its reasoning as a backlog_comment (kind: "note") on the item itself -- that comment is the durable record a later reviewer or the reporter can read; a live question to the human is the thing this loop exists to avoid. Only escalate a design question directly to the human when the choice changes externally-visible behavior in a way nobody could reconstruct from the code and the note.
|
|
78
|
+
|
|
79
|
+
SR5 CANON FIDELITY IS NOT OPTIONAL for anything in the side-quest game (see maka-cli-src/CLAUDE.md, "ALWAYS FOLLOW THE SHADOWRUN RULES"): a deviation from the rules is a defect, full stop -- check the shadowrun-rag MCP tool (ask_shadowrun_rules) rather than reasoning from memory, including when this item's own vetting text claims to summarize the rules; it has been wrong before. "The excerpt didn't mention X" is not "X doesn't exist."
|
|
80
|
+
|
|
81
|
+
SWEEP THE FAMILY. If a root cause affects more than one open item (the same clamp, the same missing check, the same divergent code path), fix all of them in one pass and add a backlog_comment cross-referencing the shared cause on every affected item -- fixing one twin and leaving the other broken reproduces the same report one layer down.
|
|
82
|
+
|
|
83
|
+
"ready-for-bench" MEANS COMMITTED *AND* DEPLOYED, not just committed -- a bench built against undeployed code would replay the old bug and report the fix as failed. Don't advance to ready-for-bench before confirming the deploy actually succeeded.
|
|
84
|
+
|
|
85
|
+
WHAT THIS SERVER DELIBERATELY DOES NOT EXPOSE, and why: signoff/reject/close are the reporter's own verbs -- only the person who hit the bug can confirm it is actually gone in play, and an AI closing its own fix would be exactly the self-certification this project's design already rejects for human admins. grant/revoke/delete/top-priority are rarer, higher-blast-radius actions left to a human directly.
|
|
86
|
+
|
|
87
|
+
A "failed" vetting state means the automated vetting pipeline itself errored (no lore-search hits, or the model call failed) -- it is NOT a judgment that the item lacks merit. Treat those items as needing your own diagnosis from scratch, same as any other open item.`;
|
|
5
88
|
export function registerBacklogMcp(parent) {
|
|
6
89
|
return Command.create({
|
|
7
90
|
name: 'mcp',
|
|
@@ -117,7 +200,16 @@ export function registerBacklogMcp(parent) {
|
|
|
117
200
|
isError: value.outcome !== 'ok',
|
|
118
201
|
};
|
|
119
202
|
}
|
|
120
|
-
|
|
203
|
+
// SERVER INSTRUCTIONS -- surfaced by MCP clients at connection time
|
|
204
|
+
// as priority context, which is the point: this ships the workflow
|
|
205
|
+
// WITH the tool, for whichever Claude session connects, rather than
|
|
206
|
+
// depending on one session's own accumulated memory of how this is
|
|
207
|
+
// supposed to run. Written and revised in-session (2026-09-08/09)
|
|
208
|
+
// after the first real item exposed exactly the friction it warns
|
|
209
|
+
// against -- see MCP_SERVER_INSTRUCTIONS's own history if this ever
|
|
210
|
+
// needs updating again: keep it a record of what actually went
|
|
211
|
+
// wrong, not a wishlist.
|
|
212
|
+
const server = new McpServer({ name: 'maka-play-backlog', version: '1.0.0' }, { instructions: MCP_SERVER_INSTRUCTIONS });
|
|
121
213
|
server.registerTool('backlog_list', {
|
|
122
214
|
title: 'List backlog items',
|
|
123
215
|
description: 'List game-backlog items, optionally filtered by status. Closed (complete) items are excluded unless a status is given explicitly.',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@maka/maka-cli",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.145.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.",
|