@maka/maka-cli 5.148.0 → 5.150.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/commands/backlog.js +25 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/look.js +15 -0
- package/bundle/typescript/src/commands/game/sideQuest/game.js +2 -27
- package/bundle/typescript/src/commands/game/sideQuest/utilities/draft-failure-note.js +66 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/web-character-generator.js +12 -0
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@maka/maka-cli",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.150.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.",
|
|
@@ -38,10 +38,11 @@ export class BacklogCommand extends Command {
|
|
|
38
38
|
static verb = "backlog";
|
|
39
39
|
// Writes to the player OWN board over their auth token -- never an NPC.
|
|
40
40
|
static humanOnly = true;
|
|
41
|
-
static description = 'File a play-tester item that somebody acts on -- it goes to maka-cli.com, keeps a link to this session, and comes back checked against the rulebooks. "backlog <what you noticed>" files one; "backlog list [status]" reads the board. For private scribbles, use "note".';
|
|
41
|
+
static description = 'File a play-tester item that somebody acts on -- it goes to maka-cli.com, keeps a link to this session, and comes back checked against the rulebooks. "backlog <what you noticed>" files one; "backlog list [status]" reads the board; "backlog web" opens the live board in your browser. For private scribbles, use "note".';
|
|
42
42
|
static subcommands = [
|
|
43
43
|
{ usage: 'backlog <text>', short: 'File an item against this session.' },
|
|
44
44
|
{ usage: 'backlog list', short: 'The whole board, what needs you last.' },
|
|
45
|
+
{ usage: 'backlog web', short: 'Open the live backlog board in your browser.' },
|
|
45
46
|
{ usage: 'backlog <n>', short: 'Read board item n in full.' },
|
|
46
47
|
{ usage: 'backlog repro <n>', short: 'Play the repro bench for board item n.' },
|
|
47
48
|
{ usage: 'backlog close <n> [why]', short: 'Close item n outright -- filed in error, duplicate, no longer real.' },
|
|
@@ -71,6 +72,12 @@ export class BacklogCommand extends Command {
|
|
|
71
72
|
if (args.length === 0 || sub === 'list') {
|
|
72
73
|
return this.list(args[1]);
|
|
73
74
|
}
|
|
75
|
+
// Claimed here, same reason "accept"/"reject"/"repro"/"close" are:
|
|
76
|
+
// every unclaimed word past this point is report text, and "backlog
|
|
77
|
+
// web" must open the board, not file an item whose text is "web".
|
|
78
|
+
if (sub === 'web') {
|
|
79
|
+
return this.webBoard();
|
|
80
|
+
}
|
|
74
81
|
// A BARE NUMBER READS THAT ROW OF THE BOARD, and it has to be caught
|
|
75
82
|
// here for the same reason `list` and `review` are: everything that
|
|
76
83
|
// reaches the bottom of this method FILES AN ITEM. Without this,
|
|
@@ -118,6 +125,23 @@ export class BacklogCommand extends Command {
|
|
|
118
125
|
}
|
|
119
126
|
return this.file(args.join(' '));
|
|
120
127
|
}
|
|
128
|
+
/**
|
|
129
|
+
* "backlog web" (user request, 2026-09-10): the same /cli-login
|
|
130
|
+
* handoff as "sheet web" (sheet.ts), landing on the shared board --
|
|
131
|
+
* /backlog, already on the NEXT_ALLOWLIST. The token is guaranteed
|
|
132
|
+
* present here: execute() already refused above if authToken() was
|
|
133
|
+
* empty, before any subcommand (this one included) could be reached.
|
|
134
|
+
*/
|
|
135
|
+
async webBoard() {
|
|
136
|
+
const { buildBacklogBoardUrl } = await import('../utilities/web-character-generator.js');
|
|
137
|
+
const url = buildBacklogBoardUrl(authToken());
|
|
138
|
+
const { openBrowser } = await import('../../../../tools/browser/open-browser.js');
|
|
139
|
+
openBrowser(url);
|
|
140
|
+
return [
|
|
141
|
+
`Your backlog board is opening in the browser -- the game keeps running right here.`,
|
|
142
|
+
` ${url}`,
|
|
143
|
+
].join('\n');
|
|
144
|
+
}
|
|
121
145
|
async file(text) {
|
|
122
146
|
const game = this.game;
|
|
123
147
|
// LAZY, and not for speed: shared-run.ts pulls in tools/version/
|
|
@@ -51,6 +51,21 @@ export class LookCommand extends Command {
|
|
|
51
51
|
return `${containerHit.description}\n Open. ${items.length === 0 ? 'Empty.'
|
|
52
52
|
: `Inside: ${items.map(i => i.quantity > 1 ? `${i.name} ×${i.quantity}` : i.name).join(', ')}.`}`;
|
|
53
53
|
}
|
|
54
|
+
// "look deck" (W7fzZRb6Asa7Qqjzg): a decker's cyberdeck is
|
|
55
|
+
// usually branded gear ("Sony CIY-720"), not literally named
|
|
56
|
+
// "deck" -- so the generic name-match below missed it entirely
|
|
57
|
+
// and "look deck" read "You cannot see deck" even carrying one.
|
|
58
|
+
// Resolved through the SAME lookup "deck" (deck.ts) already uses
|
|
59
|
+
// for the active/best-carried deck, then handed to the ordinary
|
|
60
|
+
// inspectItem by its real name so the two verbs describe one
|
|
61
|
+
// object identically.
|
|
62
|
+
if (target === 'deck') {
|
|
63
|
+
const carried = this.actor.getAnyCyberdeck();
|
|
64
|
+
if (carried) {
|
|
65
|
+
this.logger.write(`Looking at active deck '${carried.name}' in ${this.actor.name} inventory.`);
|
|
66
|
+
return this.inspectItem(carried.name, this.actor.inventory);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
54
69
|
if (this.actor.inventory.hasItem(target)) {
|
|
55
70
|
this.logger.write(`Looking at item '${target}' in ${this.actor.name} inventory.`);
|
|
56
71
|
return this.inspectItem(target, this.actor.inventory);
|
|
@@ -185,6 +185,7 @@ import { clockTime, worldNow } from './utilities/world-clock.js';
|
|
|
185
185
|
import { CommandFactory } from './factories/command-factory.js';
|
|
186
186
|
import { SceneSynthesizer } from './factories/scene-factory.js';
|
|
187
187
|
import { SceneSeedGenerator, FIXER_NAME, isFixerName } from './factories/scene-seed-generator.js';
|
|
188
|
+
import { draftFailureNote } from './utilities/draft-failure-note.js';
|
|
188
189
|
import { CALL_ICON, CALL_COLOR, END_CALL_SENTINEL } from './utilities/comm-style.js';
|
|
189
190
|
import { AI } from '../../../tools/ai/ai.class.js';
|
|
190
191
|
import { BULLET } from './utilities/log-style.js';
|
|
@@ -4147,33 +4148,7 @@ ${client.name} won't be remembering anything. Dead Johnsons pay nothing -- and t
|
|
|
4147
4148
|
// caller but the ask-for-data-work door passes.
|
|
4148
4149
|
const nextSeed = await SceneSeedGenerator.generate(this._logFilePath, nextTier, this.player, this.activeRumor, localCrew, undefined, runType);
|
|
4149
4150
|
if (!nextSeed) {
|
|
4150
|
-
|
|
4151
|
-
// six Krow calls into an out-of-credits key, indistinguishable
|
|
4152
|
-
// from flaky clients). Credit/auth failures are the player's to
|
|
4153
|
-
// fix -- say so, out of character, once per ping.
|
|
4154
|
-
const why = SceneSeedGenerator.lastFailure ?? '';
|
|
4155
|
-
// TELL THE TRUTH ABOUT WHOSE FAULT IT IS (playtest 2026-08-26).
|
|
4156
|
-
// The old test carried `invalid.*key`, meant for "invalid API
|
|
4157
|
-
// key" -- but `.*` spans the whole message, so a skeleton
|
|
4158
|
-
// validation error reading "Skeleton INVALID: ... locked doors
|
|
4159
|
-
// and KEY placements" matched, and a map-generation bug was
|
|
4160
|
-
// reported to the player as a billing problem. Sending someone to
|
|
4161
|
-
// rotate a working key is worse than saying nothing.
|
|
4162
|
-
//
|
|
4163
|
-
// Every pattern here is now anchored to the phrase it actually
|
|
4164
|
-
// means: a bare "invalid" or a stray "key" no longer counts, and
|
|
4165
|
-
// the status codes need word boundaries so they can't match
|
|
4166
|
-
// inside some other number.
|
|
4167
|
-
const providerDown = /credit balance|billing|quota|insufficient (?:credit|fund|quota|balance)|invalid[\s_-]*api[\s_-]*key|api[\s_-]*key (?:is )?(?:invalid|expired|missing|not)|unauthorized|authentication|\b(?:401|403|429)\b|Plans & Billing/i.test(why);
|
|
4168
|
-
// A structural failure is OURS, not the player's -- name it as
|
|
4169
|
-
// the generator's problem so nobody goes hunting their billing
|
|
4170
|
-
// page, and keep it short: the fiction already covers the beat.
|
|
4171
|
-
const structural = !providerDown && /^Skeleton invalid|validation failed|isn't placed|unreachable from the start/i.test(why);
|
|
4172
|
-
const opsNote = providerDown
|
|
4173
|
-
? `\n{yellow-fg}(Out of character: the AI provider refused -- "${why.slice(0, 120)}". Jobs can't generate until the API key/credits are fixed.){/yellow-fg}`
|
|
4174
|
-
: structural
|
|
4175
|
-
? `\n{yellow-fg}(Out of character: the job generator couldn't lay out a solvable map this time -- nothing wrong with your key or credits. Call again; the next draft usually takes.){/yellow-fg}`
|
|
4176
|
-
: '';
|
|
4151
|
+
const opsNote = draftFailureNote(SceneSeedGenerator.lastFailure ?? '');
|
|
4177
4152
|
return `Incoming call -- ${FIXER_NAME}: "Job fell through, chummer. Client got cold feet before the ink dried. Give me another call in a bit -- I'll shake something loose."${opsNote}`;
|
|
4178
4153
|
}
|
|
4179
4154
|
// HUB sessions: the draft lands as a MESSAGE, never a teleport (real
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* THE OUT-OF-CHARACTER NOTE ON A FAILED JOB DRAFT (game.ts's
|
|
3
|
+
* draftNextScene). SceneSeedGenerator.generate() gives up after three
|
|
4
|
+
* pipeline attempts and hands back a bare error string; Krow's "Job
|
|
5
|
+
* fell through" callback fires either way, and this decides what --
|
|
6
|
+
* if anything -- rides after it, so the player can tell "you did
|
|
7
|
+
* something wrong" from "this is on us" from "pure bad luck, try
|
|
8
|
+
* again."
|
|
9
|
+
*
|
|
10
|
+
* Extracted to its own module (2026-09-10) so the classification --
|
|
11
|
+
* pure string matching against known provider/generator error prose --
|
|
12
|
+
* can be pinned directly, without standing up a Game instance or
|
|
13
|
+
* mocking SceneSeedGenerator to reach it.
|
|
14
|
+
*
|
|
15
|
+
* TELL THE TRUTH ABOUT WHOSE FAULT IT IS (playtest 2026-08-26). The old
|
|
16
|
+
* test carried `invalid.*key`, meant for "invalid API key" -- but `.*`
|
|
17
|
+
* spans the whole message, so a skeleton validation error reading
|
|
18
|
+
* "Skeleton INVALID: ... locked doors and KEY placements" matched, and
|
|
19
|
+
* a map-generation bug was reported to the player as a billing problem.
|
|
20
|
+
* Sending someone to rotate a working key is worse than saying nothing.
|
|
21
|
+
* Every pattern here is anchored to the phrase it actually means: a
|
|
22
|
+
* bare "invalid" or a stray "key" no longer counts, and the status
|
|
23
|
+
* codes need word boundaries so they can't match inside some other
|
|
24
|
+
* number.
|
|
25
|
+
*/
|
|
26
|
+
export function draftFailureNote(why) {
|
|
27
|
+
// NAME THE CAUSE WHEN IT'S THE PROVIDER, NOT LUCK (real session: six
|
|
28
|
+
// Krow calls into an out-of-credits key, indistinguishable from flaky
|
|
29
|
+
// clients). Credit/auth failures are the player's to fix -- say so,
|
|
30
|
+
// out of character, once per ping.
|
|
31
|
+
// Widened 2026-09-10: the site's own current wording (ai-error-envelope.ts
|
|
32
|
+
// classifyUpstream's upstream_billing branch) reads "has run out of
|
|
33
|
+
// credit at its provider, or its key was rejected" -- neither phrase
|
|
34
|
+
// matched any pattern below, so the ORIGINAL motivating bug (the "six
|
|
35
|
+
// Krow calls into an out-of-credits key" session) would silently fall
|
|
36
|
+
// through to no note again today, on the site's real current message.
|
|
37
|
+
const providerDown = /credit balance|billing|quota|insufficient (?:credit|fund|quota|balance)|run out of credit|key was rejected|invalid[\s_-]*api[\s_-]*key|api[\s_-]*key (?:is )?(?:invalid|expired|missing|not)|unauthorized|authentication|\b(?:401|403|429)\b|Plans & Billing/i.test(why);
|
|
38
|
+
// TRANSIENT INFRASTRUCTURE, not billing and not a generation bug
|
|
39
|
+
// (real session, e8dLKM9j5P9yQn5yz's sibling report: a fresh
|
|
40
|
+
// character's very first homecoming draft, plus four manual "call
|
|
41
|
+
// Krow" retries, all failed in under half a second each against "The
|
|
42
|
+
// AI provider behind maka-cli.com is overloaded or down" --
|
|
43
|
+
// ai-error-envelope.ts's upstream_unavailable/rate_limited/
|
|
44
|
+
// upstream_timeout/upstream_error text, none of which this classifier
|
|
45
|
+
// recognized, so every one of those five calls read as the same
|
|
46
|
+
// unexplained "Job fell through" with nothing after it --
|
|
47
|
+
// indistinguishable from a broken loop rather than one outage. These
|
|
48
|
+
// are OURS and retryable, same tone as `structural` below, but a
|
|
49
|
+
// different truth: nothing was malformed, the provider just wasn't
|
|
50
|
+
// answering. Matched on the SITE'S OWN wording (ai-error-envelope.ts
|
|
51
|
+
// classifyUpstream/classifyTransportFailure) rather than status
|
|
52
|
+
// codes, since only the prose crosses the wire.
|
|
53
|
+
const providerOutage = !providerDown && /overloaded or down|rate-limited by its provider|took too long to answer|could not (?:complete that request|reach its ai provider)/i.test(why);
|
|
54
|
+
// A structural failure is OURS, not the player's -- name it as the
|
|
55
|
+
// generator's problem so nobody goes hunting their billing page, and
|
|
56
|
+
// keep it short: the fiction already covers the beat.
|
|
57
|
+
const structural = !providerDown && !providerOutage && /^Skeleton invalid|validation failed|isn't placed|unreachable from the start/i.test(why);
|
|
58
|
+
return providerDown
|
|
59
|
+
? `\n{yellow-fg}(Out of character: the AI provider refused -- "${why.slice(0, 120)}". Jobs can't generate until the API key/credits are fixed.){/yellow-fg}`
|
|
60
|
+
: providerOutage
|
|
61
|
+
? `\n{yellow-fg}(Out of character: the AI provider maka-cli.com talks to is overloaded, rate-limited, or unreachable right now -- nothing wrong with your account or your key. Give it a few minutes and call again.){/yellow-fg}`
|
|
62
|
+
: structural
|
|
63
|
+
? `\n{yellow-fg}(Out of character: the job generator couldn't lay out a solvable map this time -- nothing wrong with your key or credits. Call again; the next draft usually takes.){/yellow-fg}`
|
|
64
|
+
: '';
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=draft-failure-note.js.map
|
|
@@ -82,6 +82,18 @@ export function buildCharacterSheetUrl(resumeToken, slug) {
|
|
|
82
82
|
const next = `${CHARACTERS_PAGE}/${encodeURIComponent(slug)}`;
|
|
83
83
|
return `${cliLoginUrl()}?t=${Date.now()}#token=${encodeURIComponent(resumeToken)}&next=${next}`;
|
|
84
84
|
}
|
|
85
|
+
const BACKLOG_PAGE = '/backlog';
|
|
86
|
+
/**
|
|
87
|
+
* "backlog web" (user request, 2026-09-10): the same /cli-login handoff
|
|
88
|
+
* as the live sheet, landing on the shared backlog board -- /backlog,
|
|
89
|
+
* already on cli-login-next.ts's NEXT_ALLOWLIST as a bare path. Unlike
|
|
90
|
+
* buildCharacterSheetUrl/buildDossierUrl there is no per-item deep link
|
|
91
|
+
* to validate here: the board itself is the destination, not a row on
|
|
92
|
+
* it.
|
|
93
|
+
*/
|
|
94
|
+
export function buildBacklogBoardUrl(resumeToken) {
|
|
95
|
+
return `${cliLoginUrl()}?t=${Date.now()}#token=${encodeURIComponent(resumeToken)}&next=${BACKLOG_PAGE}`;
|
|
96
|
+
}
|
|
85
97
|
/**
|
|
86
98
|
* WHAT THE CLI SAYS ON ITS WAY OUT of the chargen handoff. Extracted
|
|
87
99
|
* from the command handler so the two things that matter about it are
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@maka/maka-cli",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.150.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.",
|