@idlekit/cli 0.3.0 → 0.3.1
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/dist/main.js +85 -21
- package/dist/main.js.map +7 -7
- package/package.json +2 -2
package/dist/main.js
CHANGED
|
@@ -147,7 +147,7 @@ var require_pad_end = __commonJS(function(exports, module) {
|
|
|
147
147
|
var require_package = __commonJS(function(exports, module) {
|
|
148
148
|
module.exports = {
|
|
149
149
|
name: "@idlekit/cli",
|
|
150
|
-
version: "0.3.
|
|
150
|
+
version: "0.3.1",
|
|
151
151
|
description: "Bun-first idk CLI for idle game scenario validation, simulation, tuning, and reporting.",
|
|
152
152
|
license: "MIT",
|
|
153
153
|
type: "module",
|
|
@@ -200,7 +200,7 @@ var require_package = __commonJS(function(exports, module) {
|
|
|
200
200
|
"@clack/prompts": "1.8.1",
|
|
201
201
|
"@gunshi/plugin-completion": "0.37.3",
|
|
202
202
|
"@gunshi/plugin-suggestion": "0.37.3",
|
|
203
|
-
"@idlekit/core": "0.3.
|
|
203
|
+
"@idlekit/core": "0.3.1",
|
|
204
204
|
ajv: "^8.20.0",
|
|
205
205
|
gunshi: "0.37.3",
|
|
206
206
|
yaml: "^2.9.1",
|
|
@@ -19292,7 +19292,8 @@ function parseMoney(E, input, opts) {
|
|
|
19292
19292
|
throw new Error(`Unknown suffix: ${suffixToken}`);
|
|
19293
19293
|
}
|
|
19294
19294
|
const exp3 = suffixIndex * 3;
|
|
19295
|
-
const
|
|
19295
|
+
const [mantissa, exponent = "0"] = numeric.split(/e/i);
|
|
19296
|
+
const scaled = E.from(exp3 > 0 ? `${mantissa}e${BigInt(exponent) + BigInt(exp3)}` : numeric);
|
|
19296
19297
|
const unit = opts.unit ?? (inlineUnit ? { code: inlineUnit } : undefined);
|
|
19297
19298
|
if (!unit) {
|
|
19298
19299
|
throw new Error("Unit is required. Provide opts.unit or unit in input string.");
|
|
@@ -21146,26 +21147,31 @@ function modelCreateParams(args) {
|
|
|
21146
21147
|
function assertScenarioPlanInputs(args) {
|
|
21147
21148
|
const startT = args.scenario.initial.t ?? 0;
|
|
21148
21149
|
const durationSec = args.scenario.clock.durationSec;
|
|
21149
|
-
|
|
21150
|
+
const stepSecs = args.stepSecs ?? [args.scenario.clock.stepSec];
|
|
21151
|
+
for (const stepSec of stepSecs) {
|
|
21150
21152
|
assertSimulationClock("scenario clock", { stepSec, durationSec, startT });
|
|
21151
|
-
const firstDt = durationSec !== undefined ? Math.min(stepSec, durationSec) : stepSec;
|
|
21152
|
-
if (firstDt > 0 && !(startT + firstDt > startT)) {
|
|
21153
|
-
throw new Error(`scenario clock tick did not advance state.t (start t: ${startT}, step: ${firstDt}); state.t is too large for stepSec ${stepSec}`);
|
|
21154
|
-
}
|
|
21155
21153
|
}
|
|
21156
|
-
|
|
21154
|
+
const unit = buildUnit({ scenario: args.scenario });
|
|
21155
|
+
const initial = buildInitialState({
|
|
21157
21156
|
E: args.E,
|
|
21158
21157
|
scenario: args.scenario,
|
|
21159
|
-
unit
|
|
21158
|
+
unit,
|
|
21160
21159
|
allowSuffixNotation: args.allowSuffixNotation ?? true
|
|
21161
21160
|
});
|
|
21162
|
-
compileUntilExpr({
|
|
21161
|
+
const until = compileUntilExpr({
|
|
21163
21162
|
expr: args.scenario.clock.untilExpr,
|
|
21164
21163
|
E: args.E,
|
|
21165
|
-
unit
|
|
21164
|
+
unit,
|
|
21166
21165
|
allowSuffixNotation: args.allowSuffixNotation ?? true,
|
|
21167
21166
|
allowUnsafe: false
|
|
21168
21167
|
});
|
|
21168
|
+
const untilMet = until?.(initial) ?? false;
|
|
21169
|
+
for (const stepSec of stepSecs) {
|
|
21170
|
+
const first = nextBoundary({ elapsedSec: 0, steps: 0, stepSec, durationSec, untilMet, hasUntil: !!until });
|
|
21171
|
+
if (first.kind === "step") {
|
|
21172
|
+
assertTickAdvanced("scenario clock", startT, startT + first.dt, first.dt, stepSec, startT);
|
|
21173
|
+
}
|
|
21174
|
+
}
|
|
21169
21175
|
}
|
|
21170
21176
|
function buildUnit(args) {
|
|
21171
21177
|
return args.unitFactory ? args.unitFactory(args.scenario.unit.code) : { code: args.scenario.unit.code, symbol: args.scenario.unit.symbol };
|
|
@@ -22137,13 +22143,16 @@ function resetSnapshot(ctx, state) {
|
|
|
22137
22143
|
count: state.prestige.count
|
|
22138
22144
|
};
|
|
22139
22145
|
}
|
|
22140
|
-
function wallNow(ctx, t) {
|
|
22146
|
+
function wallNow(ctx, t, explicitWallT) {
|
|
22141
22147
|
const clocks = ctx.clocks;
|
|
22142
|
-
|
|
22143
|
-
|
|
22144
|
-
|
|
22145
|
-
|
|
22146
|
-
|
|
22148
|
+
let wall = explicitWallT;
|
|
22149
|
+
if (wall === undefined) {
|
|
22150
|
+
if (!clocks || typeof clocks.wallT !== "number" || !Number.isFinite(clocks.wallT))
|
|
22151
|
+
return null;
|
|
22152
|
+
const offset = Number.isFinite(clocks.rewardT) ? Math.max(0, t - clocks.rewardT) : 0;
|
|
22153
|
+
wall = clocks.wallT + offset;
|
|
22154
|
+
}
|
|
22155
|
+
return clocks && Number.isFinite(clocks.wallEndT) ? Math.min(wall, clocks.wallEndT) : wall;
|
|
22147
22156
|
}
|
|
22148
22157
|
function applyDecisions(args) {
|
|
22149
22158
|
const { ctx, model, constraints } = args;
|
|
@@ -22304,7 +22313,7 @@ function applyDecisions(args) {
|
|
|
22304
22313
|
actionId: action.id,
|
|
22305
22314
|
kind: action.kind,
|
|
22306
22315
|
t: decisionT,
|
|
22307
|
-
wallT: args.wallT ??
|
|
22316
|
+
wallT: wallNow(ctx, decisionT, args.wallT ?? undefined),
|
|
22308
22317
|
cost: paid ? { unit: paid.unit.code, decimal: E.toString(paid.amount) } : null,
|
|
22309
22318
|
rewardDelta: E.toString(E.sub(next.prestige.points, pointsBefore)),
|
|
22310
22319
|
before,
|
|
@@ -28984,6 +28993,7 @@ function renderExperienceMarkdown(args) {
|
|
|
28984
28993
|
`- Scenario: \`${args.scenarioPath}\``,
|
|
28985
28994
|
`- Intent: ${args.intent ?? "unspecified"}`,
|
|
28986
28995
|
`- Mode: ${args.mode}`,
|
|
28996
|
+
...args.mode === "monte-carlo" ? ["- Snapshot scope: one recorded session (end state, growth, milestones, and perceived progression)"] : [],
|
|
28987
28997
|
`- Session pattern: \`${snapshot.session.pattern.id}\` for ${snapshot.session.pattern.days} day(s)`,
|
|
28988
28998
|
`- Active blocks: ${snapshot.session.activeBlocks}${snapshot.session.budgetStops > 0 ? ` (${snapshot.session.budgetStops} cut short by maxSteps)` : ""}`,
|
|
28989
28999
|
`- Active / offline: ${formatMetric(snapshot.session.totalActiveSec, 0)}s / ${formatMetric(snapshot.session.totalOfflineSec, 0)}s`,
|
|
@@ -29037,8 +29047,47 @@ function renderExperienceMarkdown(args) {
|
|
|
29037
29047
|
...snapshot.session.budgetStops > 0 ? ["- Active play was cut short by maxSteps; read these windows and progression rates with that time budget in mind."] : []
|
|
29038
29048
|
];
|
|
29039
29049
|
if (monteCarlo) {
|
|
29040
|
-
lines.push("", "## Monte Carlo", "", `- Draws: ${monteCarlo.draws}`, `- Seed: ${monteCarlo.seed}`, `- Net worth log10 mean: ${formatMetric(monteCarlo.endNetWorthLog10.mean, 3)}`, `- Visible changes / minute mean: ${formatMetric(monteCarlo.visibleChangesPerMinute.mean, 3)}`, `- No-reward gap mean: ${formatMetric(monteCarlo.maxNoRewardGapSec.mean, 2)}s`, `- First visible completion: ${monteCarlo.firstVisible.accounting.completionRate ?? "unavailable"}`, `- First visible population p95: ${monteCarlo.firstVisible.population.status === "observed" ? `${monteCarlo.firstVisible.population.value}s` : monteCarlo.firstVisible.population.status}`);
|
|
29050
|
+
lines.push("", "## Monte Carlo", "", `- Draws: ${monteCarlo.draws}`, `- Seed: ${monteCarlo.seed}`, `- Net worth log10 mean: ${formatMetric(monteCarlo.endNetWorthLog10.mean, 3)}`, `- Visible changes / minute mean: ${formatMetric(monteCarlo.visibleChangesPerMinute.mean, 3)}`, `- No-reward gap mean: ${formatMetric(monteCarlo.maxNoRewardGapSec.mean, 2)}s`, `- First visible completion: ${monteCarlo.firstVisible.accounting.completionRate ?? "unavailable"}`, `- First visible observed / right-censored / failed / unsupported: ${monteCarlo.firstVisible.accounting.observed} / ${monteCarlo.firstVisible.accounting.rightCensored} / ${monteCarlo.firstVisible.accounting.failed} / ${monteCarlo.firstVisible.accounting.unsupported}`, `- First visible population p95: ${monteCarlo.firstVisible.population.status === "observed" ? `${monteCarlo.firstVisible.population.value}s` : monteCarlo.firstVisible.population.status}`);
|
|
29051
|
+
}
|
|
29052
|
+
const checks = [
|
|
29053
|
+
"- Compare the same initial state, horizon, session pattern, and seed policy when attributing a change to a strategy."
|
|
29054
|
+
];
|
|
29055
|
+
if (args.mode === "monte-carlo") {
|
|
29056
|
+
checks.push("- The snapshot checks concern the recorded session. Use completion and population summaries when deciding about the draw population.");
|
|
29057
|
+
}
|
|
29058
|
+
if (snapshot.session.budgetStops > 0) {
|
|
29059
|
+
checks.push("- Increase the step budget and rerun the same horizon and session pattern before treating cut active blocks as complete play.");
|
|
29060
|
+
}
|
|
29061
|
+
if (coverage !== "complete") {
|
|
29062
|
+
checks.push("- Rerun with complete milestone observation before comparing exact milestone keys. Read any retained first-time summary separately from key coverage.");
|
|
29063
|
+
}
|
|
29064
|
+
if (snapshot.perceived.activeSeconds <= 0) {
|
|
29065
|
+
checks.push("- Collect an active-play observation window before judging visible progress or purchase feedback.");
|
|
29066
|
+
} else if (snapshot.perceived.visibleChangeCount === 0) {
|
|
29067
|
+
checks.push("- No visible change was observed in the active window. Check the feedback rules and rerun a matched longer window before interpreting the pace.");
|
|
29068
|
+
}
|
|
29069
|
+
if (snapshot.session.lostRewardSec > 0) {
|
|
29070
|
+
checks.push("- Compare matched offline runs with the cap or decay changed to measure the effect of lost reward credit.");
|
|
29071
|
+
}
|
|
29072
|
+
if (slowWindows.length > 0) {
|
|
29073
|
+
checks.push("- Inspect actions and income around the sampled stall or softcap windows, then compare a matched counterfactual to test the suspected cause.");
|
|
29074
|
+
}
|
|
29075
|
+
if (firstPrestige !== undefined) {
|
|
29076
|
+
checks.push("- Compare prestige with a matched run without that reset to estimate its net benefit.");
|
|
29077
|
+
}
|
|
29078
|
+
if (monteCarlo) {
|
|
29079
|
+
checks.push("- Check first-visible completion and right-censored, failed, and unsupported counts before reading conditional timing statistics.");
|
|
29080
|
+
if (monteCarlo.firstVisible.accounting.rightCensored > 0) {
|
|
29081
|
+
checks.push(`- ${monteCarlo.firstVisible.accounting.rightCensored} draw(s) had no visible change through the last active observation on the reward-time clock. This can differ from the wall horizon. Extend matched active observation to investigate those censored observations.`);
|
|
29082
|
+
}
|
|
29083
|
+
if (monteCarlo.firstVisible.population.status !== "observed") {
|
|
29084
|
+
checks.push("- The population p95 is unresolved. Conditional observed-change timings describe only the observations that completed.");
|
|
29085
|
+
}
|
|
29086
|
+
if (monteCarlo.firstVisible.accounting.failed > 0 || monteCarlo.firstVisible.accounting.unsupported > 0) {
|
|
29087
|
+
checks.push("- Resolve failed or unsupported draws before relying on timing statistics for the full cohort.");
|
|
29088
|
+
}
|
|
29041
29089
|
}
|
|
29090
|
+
lines.push("", "## Next checks", "", ...checks);
|
|
29042
29091
|
return `${lines.join(`
|
|
29043
29092
|
`)}
|
|
29044
29093
|
`;
|
|
@@ -33077,6 +33126,21 @@ function renderCompareMarkdown(args) {
|
|
|
33077
33126
|
if (args.results.some((result) => result.metric === "timeToMilestone")) {
|
|
33078
33127
|
lines.push("- Time-to-milestone scores can include an unreached penalty beyond the session horizon; that penalty is not an observed milestone time.");
|
|
33079
33128
|
}
|
|
33129
|
+
lines.push("", "## Choosing between scenarios", "");
|
|
33130
|
+
if (preferences.a.length && preferences.b.length) {
|
|
33131
|
+
lines.push("- The selected metrics prefer different scenarios. Choose the metric that matches the design intent and inspect the opposing cost before deciding.");
|
|
33132
|
+
} else if (preferences.a.length || preferences.b.length) {
|
|
33133
|
+
const side = preferences.a.length ? "A" : "B";
|
|
33134
|
+
lines.push(`- ${side} is preferred on the selected decisive metrics. Check unselected costs and benefits before choosing the full strategy.`);
|
|
33135
|
+
} else if (args.results.length && args.results.every((result) => result.better === "tie")) {
|
|
33136
|
+
lines.push("- All selected metrics tie. Use another intent-relevant measurement to distinguish the scenarios.");
|
|
33137
|
+
} else {
|
|
33138
|
+
lines.push("- Select intent-relevant metrics with available measurements and decisions before choosing a scenario.");
|
|
33139
|
+
}
|
|
33140
|
+
if (args.results.some((result) => result.better !== "a" && result.better !== "b" && result.better !== "tie")) {
|
|
33141
|
+
lines.push("- Resolve undetermined measurements or decisions before relying on those metrics.");
|
|
33142
|
+
}
|
|
33143
|
+
lines.push("- For a strategy comparison, use matching horizons, initial states, session patterns, and seed policies to interpret the measured differences.");
|
|
33080
33144
|
return `${lines.join(`
|
|
33081
33145
|
`)}
|
|
33082
33146
|
`;
|
|
@@ -38188,4 +38252,4 @@ export {
|
|
|
38188
38252
|
cli2 as cli
|
|
38189
38253
|
};
|
|
38190
38254
|
|
|
38191
|
-
//# debugId=
|
|
38255
|
+
//# debugId=1FC7442F0ACD246C64756E2164756E21
|