@clawsaga/cli 0.1.26 → 0.1.27
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 +7 -0
- package/README.md +1 -1
- package/bin/clawsaga.mjs +331 -214
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
Changes to this CLI and skill, newest first. Game, rule and API changes shared with MCP are in `clawsaga changelog`.
|
|
4
4
|
|
|
5
|
+
## 0.1.27
|
|
6
|
+
|
|
7
|
+
- Updated the response format to v3.18. Older CLIs reject responses from the current server. World quests replace `reward_tiers`, `your_tier` and `next_tier_points` with `reward_per_stage` and `reward_point_cap`.
|
|
8
|
+
- When the server reports a newer CLI release, the CLI prints the command's result and then updates itself once. A failed update is reported on stderr and does not change the result.
|
|
9
|
+
- `travel --to <id>,<id>,...` walks several locations one step at a time and stops at an ambush or a step it cannot confirm. The top-level `repetition` lists `requested_locations`, `arrived_locations` and `stopped_reason`; `data.last_result` is the last step only.
|
|
10
|
+
- Added `raids` to read the running raid boss and the last one that ended. Fight it with `fight --enemy <enemy_id>` at its location.
|
|
11
|
+
|
|
5
12
|
## 0.1.26
|
|
6
13
|
|
|
7
14
|
- Updated the response format to v3.17. Older CLIs reject responses from the current server. World quests replace `reward_per_point`, `points_per_reputation` and `stage_reward` with `reward_tiers`, and `goal-deliver` no longer reports `delivered.gold` or `delivered.experience`.
|
package/README.md
CHANGED
|
@@ -51,7 +51,7 @@ Keep the shell tool's process ID, running/exit status and output. Collect the sa
|
|
|
51
51
|
|
|
52
52
|
The game serves current rules through `resume` and `guide`; command help comes from the installed CLI. `hello` reports the latest server update without querying npm or GitHub. Run `clawsaga update` to install the latest CLI once with npm. Updating replaces only an npm global installation; a source checkout or a CLI installed another way reports an error and must be updated the way it was installed.
|
|
53
53
|
|
|
54
|
-
When a response requires an update, the CLI automatically updates and verifies a read-only request, waiting 60 seconds between attempts for up to five minutes. It does not replay the original operation: check its outcome before another change. If updating fails, stop and try again later.
|
|
54
|
+
When the server reports a newer CLI release, the CLI prints the command's result and then updates itself once before exiting. A failed update is reported on stderr and does not change the result. When a response requires an update, the CLI automatically updates and verifies a read-only request, waiting 60 seconds between attempts for up to five minutes. It does not replay the original operation: check its outcome before another change. If updating fails, stop and try again later.
|
|
55
55
|
|
|
56
56
|
CLI-only updates do not require a skill update or matching skill version. If the server changelog explicitly requests a skill update, run `npx skills update clawsaga` and reload it. Response `hints` suggest commands but do not run them.
|
|
57
57
|
|
package/bin/clawsaga.mjs
CHANGED
|
@@ -2621,9 +2621,9 @@ var DualOptions = class {
|
|
|
2621
2621
|
* @returns {boolean}
|
|
2622
2622
|
*/
|
|
2623
2623
|
valueFromOption(value, option) {
|
|
2624
|
-
const
|
|
2625
|
-
if (!this.dualOptions.has(
|
|
2626
|
-
const preset = this.negativeOptions.get(
|
|
2624
|
+
const optionKey = option.attributeName();
|
|
2625
|
+
if (!this.dualOptions.has(optionKey)) return true;
|
|
2626
|
+
const preset = this.negativeOptions.get(optionKey).presetArg;
|
|
2627
2627
|
const negativeValue = preset !== void 0 ? preset : false;
|
|
2628
2628
|
return option.negate === (negativeValue === value);
|
|
2629
2629
|
}
|
|
@@ -4152,11 +4152,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
4152
4152
|
*/
|
|
4153
4153
|
_checkForConflictingLocalOptions() {
|
|
4154
4154
|
const definedNonDefaultOptions = this.options.filter((option) => {
|
|
4155
|
-
const
|
|
4156
|
-
if (this.getOptionValue(
|
|
4155
|
+
const optionKey = option.attributeName();
|
|
4156
|
+
if (this.getOptionValue(optionKey) === void 0) {
|
|
4157
4157
|
return false;
|
|
4158
4158
|
}
|
|
4159
|
-
return this.getOptionValueSource(
|
|
4159
|
+
return this.getOptionValueSource(optionKey) !== "default";
|
|
4160
4160
|
});
|
|
4161
4161
|
const optionsWithConflicting = definedNonDefaultOptions.filter(
|
|
4162
4162
|
(option) => option.conflictsWith.length > 0
|
|
@@ -4354,9 +4354,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
4354
4354
|
_parseOptionsEnv() {
|
|
4355
4355
|
this.options.forEach((option) => {
|
|
4356
4356
|
if (option.envVar && option.envVar in process2.env) {
|
|
4357
|
-
const
|
|
4358
|
-
if (this.getOptionValue(
|
|
4359
|
-
this.getOptionValueSource(
|
|
4357
|
+
const optionKey = option.attributeName();
|
|
4358
|
+
if (this.getOptionValue(optionKey) === void 0 || ["default", "config", "env"].includes(
|
|
4359
|
+
this.getOptionValueSource(optionKey)
|
|
4360
4360
|
)) {
|
|
4361
4361
|
if (option.required || option.optional) {
|
|
4362
4362
|
this.emit(`optionEnv:${option.name()}`, process2.env[option.envVar]);
|
|
@@ -4374,8 +4374,8 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
4374
4374
|
*/
|
|
4375
4375
|
_parseOptionsImplied() {
|
|
4376
4376
|
const dualHelper = new DualOptions(this.options);
|
|
4377
|
-
const hasCustomOptionValue = (
|
|
4378
|
-
return this.getOptionValue(
|
|
4377
|
+
const hasCustomOptionValue = (optionKey) => {
|
|
4378
|
+
return this.getOptionValue(optionKey) !== void 0 && !["default", "implied"].includes(this.getOptionValueSource(optionKey));
|
|
4379
4379
|
};
|
|
4380
4380
|
this.options.filter(
|
|
4381
4381
|
(option) => option.implied !== void 0 && hasCustomOptionValue(option.attributeName()) && dualHelper.valueFromOption(
|
|
@@ -4431,13 +4431,13 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
4431
4431
|
*/
|
|
4432
4432
|
_conflictingOption(option, conflictingOption) {
|
|
4433
4433
|
const findBestOptionFromValue = (option2) => {
|
|
4434
|
-
const
|
|
4435
|
-
const optionValue = this.getOptionValue(
|
|
4434
|
+
const optionKey = option2.attributeName();
|
|
4435
|
+
const optionValue = this.getOptionValue(optionKey);
|
|
4436
4436
|
const negativeOption = this.options.find(
|
|
4437
|
-
(target2) => target2.negate &&
|
|
4437
|
+
(target2) => target2.negate && optionKey === target2.attributeName()
|
|
4438
4438
|
);
|
|
4439
4439
|
const positiveOption = this.options.find(
|
|
4440
|
-
(target2) => !target2.negate &&
|
|
4440
|
+
(target2) => !target2.negate && optionKey === target2.attributeName()
|
|
4441
4441
|
);
|
|
4442
4442
|
if (negativeOption && (negativeOption.presetArg === void 0 && optionValue === false || negativeOption.presetArg !== void 0 && optionValue === negativeOption.presetArg)) {
|
|
4443
4443
|
return negativeOption;
|
|
@@ -4446,8 +4446,8 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
4446
4446
|
};
|
|
4447
4447
|
const getErrorMessage = (option2) => {
|
|
4448
4448
|
const bestOption = findBestOptionFromValue(option2);
|
|
4449
|
-
const
|
|
4450
|
-
const source = this.getOptionValueSource(
|
|
4449
|
+
const optionKey = bestOption.attributeName();
|
|
4450
|
+
const source = this.getOptionValueSource(optionKey);
|
|
4451
4451
|
if (source === "env") {
|
|
4452
4452
|
return `environment variable '${bestOption.envVar}'`;
|
|
4453
4453
|
}
|
|
@@ -14073,8 +14073,8 @@ function ko_default() {
|
|
|
14073
14073
|
var capitalizeFirstCharacter = (text2) => {
|
|
14074
14074
|
return text2.charAt(0).toUpperCase() + text2.slice(1);
|
|
14075
14075
|
};
|
|
14076
|
-
function getUnitTypeFromNumber(
|
|
14077
|
-
const abs = Math.abs(
|
|
14076
|
+
function getUnitTypeFromNumber(number4) {
|
|
14077
|
+
const abs = Math.abs(number4);
|
|
14078
14078
|
const last = abs % 10;
|
|
14079
14079
|
const last2 = abs % 100;
|
|
14080
14080
|
if (last2 >= 11 && last2 <= 19 || last === 0)
|
|
@@ -23944,6 +23944,7 @@ var agentLastResultSchema = external_exports.looseObject({
|
|
|
23944
23944
|
status: external_exports.string().optional(),
|
|
23945
23945
|
end_reason: external_exports.string().optional(),
|
|
23946
23946
|
output: external_exports.looseObject({ item_id: external_exports.string(), quantity: external_exports.number() }).optional(),
|
|
23947
|
+
to: external_exports.looseObject({ id: external_exports.string() }).optional(),
|
|
23947
23948
|
ambush: external_exports.looseObject({ activity_id: external_exports.number() }).optional()
|
|
23948
23949
|
});
|
|
23949
23950
|
|
|
@@ -23962,10 +23963,12 @@ var agentResumeResponseSchema = external_exports.looseObject({
|
|
|
23962
23963
|
var changelogResponseSchema = external_exports.looseObject({
|
|
23963
23964
|
changelog: external_exports.looseObject({})
|
|
23964
23965
|
});
|
|
23965
|
-
var agentSchemaVersion = "3.
|
|
23966
|
+
var agentSchemaVersion = "3.18";
|
|
23966
23967
|
var agentGameResponseSchema = external_exports.looseObject({
|
|
23967
23968
|
ok: external_exports.boolean(),
|
|
23968
|
-
|
|
23969
|
+
// The client rejects a newer version before parsing. An older server's
|
|
23970
|
+
// response is read when it still matches this CLI's format.
|
|
23971
|
+
schema_version: external_exports.string(),
|
|
23969
23972
|
server_time: external_exports.string(),
|
|
23970
23973
|
next_poll_after_seconds: external_exports.number().optional(),
|
|
23971
23974
|
hints: external_exports.array(agentHintSchema).optional(),
|
|
@@ -24092,7 +24095,7 @@ var tacticConditionSchema = external_exports.discriminatedUnion("kind", [
|
|
|
24092
24095
|
kind: external_exports.literal("potions_below"),
|
|
24093
24096
|
count: external_exports.number().int().min(1)
|
|
24094
24097
|
}).strict().describe(
|
|
24095
|
-
"Matches when usable
|
|
24098
|
+
"Matches when usable potions remaining in this battle are strictly below count."
|
|
24096
24099
|
),
|
|
24097
24100
|
external_exports.object({ kind: external_exports.literal("enemy_weak_to"), damage_type: damageTypeSchema }).strict().describe("Matches when the enemy resistance for damage_type is negative."),
|
|
24098
24101
|
external_exports.object({
|
|
@@ -24121,6 +24124,10 @@ var tacticActionSchema = external_exports.discriminatedUnion("kind", [
|
|
|
24121
24124
|
"Uses the ability when it is unlocked, off cooldown, affordable in MP and its effect is currently applicable."
|
|
24122
24125
|
)
|
|
24123
24126
|
]);
|
|
24127
|
+
var combatPotionIdSchema = external_exports.enum([
|
|
24128
|
+
"healing_potion",
|
|
24129
|
+
"manastone_potion"
|
|
24130
|
+
]);
|
|
24124
24131
|
var tacticSchema = external_exports.object({
|
|
24125
24132
|
rules: external_exports.array(
|
|
24126
24133
|
external_exports.object({
|
|
@@ -24133,7 +24140,13 @@ var tacticSchema = external_exports.object({
|
|
|
24133
24140
|
"Evaluated from top to bottom each tick. The first matching, usable action runs; otherwise use a basic attack."
|
|
24134
24141
|
),
|
|
24135
24142
|
potion_limit: external_exports.number().int().min(0).describe(
|
|
24136
|
-
"
|
|
24143
|
+
"Most potions one battle may use in total, capped by the bag at start. Each is consumed when used; zero disables potions."
|
|
24144
|
+
),
|
|
24145
|
+
potion_items: external_exports.array(combatPotionIdSchema).min(1).refine(
|
|
24146
|
+
(itemIds) => new Set(itemIds).size === itemIds.length,
|
|
24147
|
+
"potion_items must not repeat"
|
|
24148
|
+
).optional().describe(
|
|
24149
|
+
"Potions in drinking order. Defaults to healing_potion, then manastone_potion."
|
|
24137
24150
|
)
|
|
24138
24151
|
}).strict().meta({ id: "Tactic" });
|
|
24139
24152
|
var presetIdSchema = external_exports.enum(["safe", "aggressive"]);
|
|
@@ -24164,6 +24177,7 @@ var getCombatReportSchema = external_exports.object({
|
|
|
24164
24177
|
include: external_exports.array(combatReportIncludeSchema).optional()
|
|
24165
24178
|
}).strict();
|
|
24166
24179
|
var getEncountersSchema = external_exports.object(characterTarget).strict();
|
|
24180
|
+
var getRaidsSchema = external_exports.object(characterTarget).strict();
|
|
24167
24181
|
var getLostItemsSchema = external_exports.object(characterTarget).strict();
|
|
24168
24182
|
var recoverLostItemsSchema = external_exports.object({ ...characterTarget, drop_id: dropIdSchema }).strict();
|
|
24169
24183
|
|
|
@@ -24178,7 +24192,7 @@ var questNumber = external_exports.number().int().min(1);
|
|
|
24178
24192
|
var acceptQuestSchema = external_exports.object({
|
|
24179
24193
|
...characterTarget,
|
|
24180
24194
|
offer_id: uuidSchema.optional(),
|
|
24181
|
-
fixed_quest_id:
|
|
24195
|
+
fixed_quest_id: combatIdSchema.optional(),
|
|
24182
24196
|
goal_id: questNumber.optional()
|
|
24183
24197
|
}).strict().refine(
|
|
24184
24198
|
(input2) => [input2.offer_id, input2.fixed_quest_id, input2.goal_id].filter(
|
|
@@ -24325,12 +24339,7 @@ var depositItemsSchema = external_exports.object({
|
|
|
24325
24339
|
request_id: uuidSchema,
|
|
24326
24340
|
items: storageTransferItemsSchema
|
|
24327
24341
|
}).strict();
|
|
24328
|
-
var withdrawItemsSchema =
|
|
24329
|
-
...characterTarget,
|
|
24330
|
-
town_id: locationIdSchema,
|
|
24331
|
-
request_id: uuidSchema,
|
|
24332
|
-
items: storageTransferItemsSchema
|
|
24333
|
-
}).strict();
|
|
24342
|
+
var withdrawItemsSchema = depositItemsSchema;
|
|
24334
24343
|
|
|
24335
24344
|
// src/protocol/gift.ts
|
|
24336
24345
|
var sendGiftSchema = external_exports.object({
|
|
@@ -24349,9 +24358,7 @@ var getGiftsSchema = external_exports.object({
|
|
|
24349
24358
|
// src/protocol/market.ts
|
|
24350
24359
|
var change = { ...characterTarget, request_id: uuidSchema };
|
|
24351
24360
|
var marketQualitySchema = external_exports.enum(["standard", "fine", "superior"]);
|
|
24352
|
-
var
|
|
24353
|
-
var quantity = external_exports.number().int().positive();
|
|
24354
|
-
var number4 = external_exports.number().int().positive();
|
|
24361
|
+
var positiveInteger = external_exports.number().int().positive();
|
|
24355
24362
|
var marketSourceSchema = external_exports.enum(["carried", "storage"]);
|
|
24356
24363
|
var marketSectionSchema = external_exports.enum(["orders", "listings", "trades"]);
|
|
24357
24364
|
var getMarketSchema = external_exports.object({
|
|
@@ -24361,7 +24368,7 @@ var getMarketSchema = external_exports.object({
|
|
|
24361
24368
|
quality: marketQualitySchema.optional(),
|
|
24362
24369
|
levels: external_exports.number().int().min(1).optional(),
|
|
24363
24370
|
cursor: external_exports.number().int().positive().optional(),
|
|
24364
|
-
max_price:
|
|
24371
|
+
max_price: positiveInteger.optional(),
|
|
24365
24372
|
minimum_durability: external_exports.number().int().nonnegative().optional()
|
|
24366
24373
|
}).strict();
|
|
24367
24374
|
var getMyMarketSchema = external_exports.object({
|
|
@@ -24373,32 +24380,32 @@ var placeMarketSellOrderSchema = external_exports.object({
|
|
|
24373
24380
|
...change,
|
|
24374
24381
|
item_id: itemIdSchema,
|
|
24375
24382
|
quality: marketQualitySchema,
|
|
24376
|
-
quantity,
|
|
24377
|
-
unit_price:
|
|
24383
|
+
quantity: positiveInteger,
|
|
24384
|
+
unit_price: positiveInteger,
|
|
24378
24385
|
source: marketSourceSchema
|
|
24379
24386
|
}).strict();
|
|
24380
24387
|
var placeMarketBuyOrderSchema = external_exports.object({
|
|
24381
24388
|
...change,
|
|
24382
24389
|
item_id: itemIdSchema,
|
|
24383
24390
|
quality: marketQualitySchema,
|
|
24384
|
-
quantity,
|
|
24385
|
-
unit_price:
|
|
24391
|
+
quantity: positiveInteger,
|
|
24392
|
+
unit_price: positiveInteger
|
|
24386
24393
|
}).strict();
|
|
24387
|
-
var cancelMarketOrderSchema = external_exports.object({ ...change, order_id:
|
|
24394
|
+
var cancelMarketOrderSchema = external_exports.object({ ...change, order_id: positiveInteger }).strict();
|
|
24388
24395
|
var claimMarketOrderSchema = cancelMarketOrderSchema;
|
|
24389
24396
|
var createMarketListingSchema = external_exports.object({
|
|
24390
24397
|
...change,
|
|
24391
24398
|
instance_id: instanceIdSchema,
|
|
24392
|
-
price,
|
|
24399
|
+
price: positiveInteger,
|
|
24393
24400
|
source: marketSourceSchema
|
|
24394
24401
|
}).strict();
|
|
24395
24402
|
var buyMarketListingSchema = external_exports.object({
|
|
24396
24403
|
...change,
|
|
24397
|
-
listing_id:
|
|
24398
|
-
max_price:
|
|
24404
|
+
listing_id: positiveInteger,
|
|
24405
|
+
max_price: positiveInteger,
|
|
24399
24406
|
minimum_durability: external_exports.number().int().nonnegative().optional()
|
|
24400
24407
|
}).strict();
|
|
24401
|
-
var cancelMarketListingSchema = external_exports.object({ ...change, listing_id:
|
|
24408
|
+
var cancelMarketListingSchema = external_exports.object({ ...change, listing_id: positiveInteger }).strict();
|
|
24402
24409
|
var claimMarketListingSchema = cancelMarketListingSchema;
|
|
24403
24410
|
|
|
24404
24411
|
// src/credentials.ts
|
|
@@ -24427,6 +24434,7 @@ var cliErrorMessages = {
|
|
|
24427
24434
|
INVALID_RESPONSE: "The server returned a response this CLI could not read.",
|
|
24428
24435
|
AUTH_START_FAILED: "Could not start authorization. Try again later.",
|
|
24429
24436
|
AUTH_NOT_COMPLETED: "Authorization was not completed.",
|
|
24437
|
+
CREDENTIAL_STORAGE_FAILED: "Could not read or save ~/.clawsaga/credentials.json. Check the file and its directory permissions.",
|
|
24430
24438
|
INVALID_SERVER: "The server origin is invalid.",
|
|
24431
24439
|
INVALID_AUTH_SERVER: "The authorization server origin does not match the game server.",
|
|
24432
24440
|
INVALID_ARGUMENTS: "The command arguments are invalid.",
|
|
@@ -24554,6 +24562,61 @@ var CredentialStore = class {
|
|
|
24554
24562
|
}
|
|
24555
24563
|
};
|
|
24556
24564
|
|
|
24565
|
+
// package.json
|
|
24566
|
+
var package_default = {
|
|
24567
|
+
name: "@clawsaga/cli",
|
|
24568
|
+
version: "0.1.27",
|
|
24569
|
+
homepage: "https://clawsaga.net",
|
|
24570
|
+
repository: {
|
|
24571
|
+
type: "git",
|
|
24572
|
+
url: "git+https://github.com/palon7/clawsaga.git"
|
|
24573
|
+
},
|
|
24574
|
+
license: "MIT",
|
|
24575
|
+
author: "Palon (Ryota Uno) <palon@palon.org>",
|
|
24576
|
+
bin: {
|
|
24577
|
+
clawsaga: "bin/clawsaga.mjs"
|
|
24578
|
+
},
|
|
24579
|
+
files: [
|
|
24580
|
+
"bin/",
|
|
24581
|
+
"THIRD-PARTY-LICENSES.txt",
|
|
24582
|
+
"CHANGELOG.md"
|
|
24583
|
+
],
|
|
24584
|
+
publishConfig: {
|
|
24585
|
+
access: "public"
|
|
24586
|
+
},
|
|
24587
|
+
type: "module",
|
|
24588
|
+
packageManager: "pnpm@12.3.4",
|
|
24589
|
+
engines: {
|
|
24590
|
+
node: ">=22.12.0"
|
|
24591
|
+
},
|
|
24592
|
+
scripts: {
|
|
24593
|
+
build: "node build.mjs",
|
|
24594
|
+
typecheck: "tsc --noEmit",
|
|
24595
|
+
test: "vitest run",
|
|
24596
|
+
format: "prettier --write .",
|
|
24597
|
+
lint: "eslint .",
|
|
24598
|
+
check: "prettier --check . && pnpm lint && pnpm typecheck && pnpm build && pnpm test && pnpm test:package",
|
|
24599
|
+
"test:package": "node scripts/test-package.mjs"
|
|
24600
|
+
},
|
|
24601
|
+
devDependencies: {
|
|
24602
|
+
"@eslint-community/eslint-plugin-eslint-comments": "4.8.1",
|
|
24603
|
+
"@eslint/js": "10.0.1",
|
|
24604
|
+
"@stylistic/eslint-plugin": "5.10.0",
|
|
24605
|
+
"@types/node": "22.20.4",
|
|
24606
|
+
"@types/proper-lockfile": "4.1.4",
|
|
24607
|
+
commander: "15.0.0",
|
|
24608
|
+
esbuild: "0.28.2",
|
|
24609
|
+
eslint: "10.11.0",
|
|
24610
|
+
"eslint-config-prettier": "10.1.8",
|
|
24611
|
+
prettier: "3.9.6",
|
|
24612
|
+
"proper-lockfile": "4.1.2",
|
|
24613
|
+
typescript: "6.0.3",
|
|
24614
|
+
"typescript-eslint": "8.71.0",
|
|
24615
|
+
vitest: "5.0.0",
|
|
24616
|
+
zod: "4.5.4"
|
|
24617
|
+
}
|
|
24618
|
+
};
|
|
24619
|
+
|
|
24557
24620
|
// src/client.ts
|
|
24558
24621
|
var tokensSchema = external_exports.object({
|
|
24559
24622
|
access_token: external_exports.string(),
|
|
@@ -24602,6 +24665,16 @@ function needsUpdate(body) {
|
|
|
24602
24665
|
const [major = 0, minor = 0] = parsed.data.schema_version.split(".").map(Number);
|
|
24603
24666
|
return major > supportedSchemaMajor || major === supportedSchemaMajor && minor > supportedSchemaMinor;
|
|
24604
24667
|
}
|
|
24668
|
+
var announcedCli;
|
|
24669
|
+
function noteAnnouncedCli(response) {
|
|
24670
|
+
const version2 = response.headers.get("ClawSaga-CLI-Version");
|
|
24671
|
+
if (version2 && /^\d+\.\d+\.\d+$/.test(version2) && version2.localeCompare(package_default.version, "en", { numeric: true }) > 0) {
|
|
24672
|
+
announcedCli = version2;
|
|
24673
|
+
}
|
|
24674
|
+
}
|
|
24675
|
+
function announcedCliUpdate() {
|
|
24676
|
+
return announcedCli;
|
|
24677
|
+
}
|
|
24605
24678
|
function serverOrigin(input2) {
|
|
24606
24679
|
const url2 = URL.parse(input2);
|
|
24607
24680
|
if (!url2 || url2.username || url2.password || url2.pathname !== "/" || url2.search || url2.hash || url2.protocol !== "https:" && !(url2.protocol === "http:" && ["localhost", "127.0.0.1", "[::1]"].includes(url2.hostname))) {
|
|
@@ -24657,7 +24730,7 @@ var GameClient = class {
|
|
|
24657
24730
|
const response = await this.oauth("/device/code", {
|
|
24658
24731
|
client_id: "clawsaga-cli",
|
|
24659
24732
|
scope: "game:read game:play offline_access",
|
|
24660
|
-
resource: `${this.origin}
|
|
24733
|
+
resource: `${this.origin}/`
|
|
24661
24734
|
});
|
|
24662
24735
|
if (!response.ok) throw new CliError("AUTH_START_FAILED");
|
|
24663
24736
|
const parsed = deviceSchema.safeParse(await readBody(response));
|
|
@@ -24748,6 +24821,7 @@ var GameClient = class {
|
|
|
24748
24821
|
},
|
|
24749
24822
|
body: JSON.stringify(input2)
|
|
24750
24823
|
});
|
|
24824
|
+
noteAnnouncedCli(response);
|
|
24751
24825
|
const body = await readBody(response);
|
|
24752
24826
|
const message = serverMessage(body);
|
|
24753
24827
|
if (response.status === 401) {
|
|
@@ -24766,17 +24840,17 @@ var GameClient = class {
|
|
|
24766
24840
|
http_status: response.status
|
|
24767
24841
|
});
|
|
24768
24842
|
}
|
|
24843
|
+
if (needsUpdate(body)) {
|
|
24844
|
+
throw new CliError("UPDATE_REQUIRED", {
|
|
24845
|
+
operation: path2,
|
|
24846
|
+
http_status: response.status,
|
|
24847
|
+
update_required: true,
|
|
24848
|
+
// The automatic update verifies a read against this server.
|
|
24849
|
+
server: this.origin
|
|
24850
|
+
});
|
|
24851
|
+
}
|
|
24769
24852
|
const parsed = agentGameResponseSchema.safeParse(body);
|
|
24770
24853
|
if (!parsed.success) {
|
|
24771
|
-
if (needsUpdate(body)) {
|
|
24772
|
-
throw new CliError("UPDATE_REQUIRED", {
|
|
24773
|
-
operation: path2,
|
|
24774
|
-
http_status: response.status,
|
|
24775
|
-
update_required: true,
|
|
24776
|
-
// The automatic update verifies a read against this server.
|
|
24777
|
-
server: this.origin
|
|
24778
|
-
});
|
|
24779
|
-
}
|
|
24780
24854
|
throw new CliError("INVALID_RESPONSE", {
|
|
24781
24855
|
message: `The server response did not match this CLI's expected format. ${checkOutcome}`,
|
|
24782
24856
|
operation: path2,
|
|
@@ -24836,6 +24910,21 @@ function activityCommand(activityId, character) {
|
|
|
24836
24910
|
function repetitionOf(response) {
|
|
24837
24911
|
return response.repetition;
|
|
24838
24912
|
}
|
|
24913
|
+
function stoppedEarlyNote(repetition) {
|
|
24914
|
+
const failedRead = repetition.stopped_reason === "activity_failed";
|
|
24915
|
+
if ("requested_locations" in repetition) {
|
|
24916
|
+
const arrived = repetition.arrived_locations.length;
|
|
24917
|
+
const requested = repetition.requested_locations.length;
|
|
24918
|
+
if (arrived >= requested) return void 0;
|
|
24919
|
+
const unconfirmed2 = failedRead ? " The last step may also have arrived. Check your current or latest activity before continuing." : "";
|
|
24920
|
+
return `Stopped after arriving at ${arrived} of ${requested} locations. No further steps were sent.${unconfirmed2}`;
|
|
24921
|
+
}
|
|
24922
|
+
if (repetition.completed_count >= repetition.requested_count) {
|
|
24923
|
+
return void 0;
|
|
24924
|
+
}
|
|
24925
|
+
const unconfirmed = failedRead ? " The last attempt may also have succeeded. Check your current or latest activity before continuing." : "";
|
|
24926
|
+
return `Stopped with ${repetition.completed_count} of ${repetition.requested_count} attempts completed. You keep their results.${unconfirmed}`;
|
|
24927
|
+
}
|
|
24839
24928
|
function ambushNotes(response, character) {
|
|
24840
24929
|
const notes = [];
|
|
24841
24930
|
const lastResult = response.data.last_result;
|
|
@@ -24863,11 +24952,9 @@ function stateNotes(response, character, wait) {
|
|
|
24863
24952
|
const lastResult = response.data.last_result;
|
|
24864
24953
|
const activity = response.data.activity ?? void 0;
|
|
24865
24954
|
const repetition = repetitionOf(response);
|
|
24866
|
-
|
|
24867
|
-
|
|
24868
|
-
notes.push(
|
|
24869
|
-
`Stopped with ${repetition.completed_count} of ${repetition.requested_count} attempts completed. You keep their results.${unconfirmed}`
|
|
24870
|
-
);
|
|
24955
|
+
const stopped = repetition && stoppedEarlyNote(repetition);
|
|
24956
|
+
if (stopped) {
|
|
24957
|
+
notes.push(stopped);
|
|
24871
24958
|
} else if (!wait && response.ok) {
|
|
24872
24959
|
if (lastResult) {
|
|
24873
24960
|
notes.push(
|
|
@@ -25052,6 +25139,20 @@ async function updateCli(server) {
|
|
|
25052
25139
|
}
|
|
25053
25140
|
throw new CliError("UPDATE_FAILED");
|
|
25054
25141
|
}
|
|
25142
|
+
async function updateAnnouncedCli(version2, notify) {
|
|
25143
|
+
if (process.env.CLAWSAGA_AUTO_UPDATE === "0") return;
|
|
25144
|
+
notify(
|
|
25145
|
+
`Updating the CLI to ${version2}. The result above is final; wait for this command to finish.`
|
|
25146
|
+
);
|
|
25147
|
+
try {
|
|
25148
|
+
notify(`The CLI was updated to ${await updateCli()}.`);
|
|
25149
|
+
} catch (error61) {
|
|
25150
|
+
const reason = cliFailure(error61).error.message;
|
|
25151
|
+
notify(
|
|
25152
|
+
`The CLI could not be updated automatically: ${reason} Run clawsaga update later.`
|
|
25153
|
+
);
|
|
25154
|
+
}
|
|
25155
|
+
}
|
|
25055
25156
|
async function recoverUpdate(error61, notify) {
|
|
25056
25157
|
if (!(error61 instanceof CliError) || error61.code !== "UPDATE_REQUIRED" || // Set for the verification read, which must not start an update of its own.
|
|
25057
25158
|
process.env.CLAWSAGA_AUTO_UPDATE === "0") {
|
|
@@ -25079,61 +25180,6 @@ async function recoverUpdate(error61, notify) {
|
|
|
25079
25180
|
}
|
|
25080
25181
|
}
|
|
25081
25182
|
|
|
25082
|
-
// package.json
|
|
25083
|
-
var package_default = {
|
|
25084
|
-
name: "@clawsaga/cli",
|
|
25085
|
-
version: "0.1.26",
|
|
25086
|
-
homepage: "https://clawsaga.net",
|
|
25087
|
-
repository: {
|
|
25088
|
-
type: "git",
|
|
25089
|
-
url: "git+https://github.com/palon7/clawsaga.git"
|
|
25090
|
-
},
|
|
25091
|
-
license: "MIT",
|
|
25092
|
-
author: "Palon (Ryota Uno) <palon@palon.org>",
|
|
25093
|
-
bin: {
|
|
25094
|
-
clawsaga: "bin/clawsaga.mjs"
|
|
25095
|
-
},
|
|
25096
|
-
files: [
|
|
25097
|
-
"bin/",
|
|
25098
|
-
"THIRD-PARTY-LICENSES.txt",
|
|
25099
|
-
"CHANGELOG.md"
|
|
25100
|
-
],
|
|
25101
|
-
publishConfig: {
|
|
25102
|
-
access: "public"
|
|
25103
|
-
},
|
|
25104
|
-
type: "module",
|
|
25105
|
-
packageManager: "pnpm@12.3.4",
|
|
25106
|
-
engines: {
|
|
25107
|
-
node: ">=22.12.0"
|
|
25108
|
-
},
|
|
25109
|
-
scripts: {
|
|
25110
|
-
build: "node build.mjs",
|
|
25111
|
-
typecheck: "tsc --noEmit",
|
|
25112
|
-
test: "vitest run",
|
|
25113
|
-
format: "prettier --write .",
|
|
25114
|
-
lint: "eslint .",
|
|
25115
|
-
check: "prettier --check . && pnpm lint && pnpm typecheck && pnpm build && pnpm test && pnpm test:package",
|
|
25116
|
-
"test:package": "node scripts/test-package.mjs"
|
|
25117
|
-
},
|
|
25118
|
-
devDependencies: {
|
|
25119
|
-
"@eslint-community/eslint-plugin-eslint-comments": "4.8.1",
|
|
25120
|
-
"@eslint/js": "10.0.1",
|
|
25121
|
-
"@stylistic/eslint-plugin": "5.10.0",
|
|
25122
|
-
"@types/node": "22.20.4",
|
|
25123
|
-
"@types/proper-lockfile": "4.1.4",
|
|
25124
|
-
commander: "15.0.0",
|
|
25125
|
-
esbuild: "0.28.2",
|
|
25126
|
-
eslint: "10.11.0",
|
|
25127
|
-
"eslint-config-prettier": "10.1.8",
|
|
25128
|
-
prettier: "3.9.6",
|
|
25129
|
-
"proper-lockfile": "4.1.2",
|
|
25130
|
-
typescript: "6.0.3",
|
|
25131
|
-
"typescript-eslint": "8.71.0",
|
|
25132
|
-
vitest: "5.0.0",
|
|
25133
|
-
zod: "4.5.4"
|
|
25134
|
-
}
|
|
25135
|
-
};
|
|
25136
|
-
|
|
25137
25183
|
// src/activity-wait.ts
|
|
25138
25184
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
25139
25185
|
import { setTimeout as sleep2 } from "node:timers/promises";
|
|
@@ -25230,6 +25276,67 @@ async function repeatActivity(client, path2, input2, values, count, options) {
|
|
|
25230
25276
|
}
|
|
25231
25277
|
throw new CliError("INVALID_ARGUMENTS", { fields: ["count"] });
|
|
25232
25278
|
}
|
|
25279
|
+
async function walkRoute(client, path2, input2, values, route, notify) {
|
|
25280
|
+
const arrived = [];
|
|
25281
|
+
const summary = (stoppedReason) => ({
|
|
25282
|
+
requested_locations: [...route],
|
|
25283
|
+
arrived_locations: [...arrived],
|
|
25284
|
+
stopped_reason: stoppedReason
|
|
25285
|
+
});
|
|
25286
|
+
const incomplete = (response, stoppedReason) => ({
|
|
25287
|
+
...response,
|
|
25288
|
+
ok: false,
|
|
25289
|
+
error: { message: "The travel stopped before reaching every location." },
|
|
25290
|
+
repetition: summary(stoppedReason)
|
|
25291
|
+
});
|
|
25292
|
+
const step = async (to) => {
|
|
25293
|
+
const started = await client.invoke(path2, { ...input2, to });
|
|
25294
|
+
if (!started.ok) {
|
|
25295
|
+
return { ...started, repetition: summary("start_rejected") };
|
|
25296
|
+
}
|
|
25297
|
+
const completed = await waitForActivity(client, values, started, notify);
|
|
25298
|
+
if (!completed.ok) {
|
|
25299
|
+
return { ...completed, repetition: summary("activity_failed") };
|
|
25300
|
+
}
|
|
25301
|
+
const result = endedTravel(completed, to);
|
|
25302
|
+
if (result.end_reason !== "COMPLETED") {
|
|
25303
|
+
return incomplete(completed, "activity_stopped");
|
|
25304
|
+
}
|
|
25305
|
+
arrived.push(to);
|
|
25306
|
+
const last = arrived.length === route.length;
|
|
25307
|
+
if (result.ambush) {
|
|
25308
|
+
return last ? { ...completed, repetition: summary("ambush") } : incomplete(completed, "ambush");
|
|
25309
|
+
}
|
|
25310
|
+
if (last) return { ...completed, repetition: summary("route_completed") };
|
|
25311
|
+
notify?.({ event: "activity_result", last_result: result });
|
|
25312
|
+
return void 0;
|
|
25313
|
+
};
|
|
25314
|
+
for (const to of route) {
|
|
25315
|
+
try {
|
|
25316
|
+
const final = await step(to);
|
|
25317
|
+
if (final) return final;
|
|
25318
|
+
} catch (error61) {
|
|
25319
|
+
if (error61 instanceof CliError) {
|
|
25320
|
+
throw new CliError(error61.code, {
|
|
25321
|
+
...error61.detail,
|
|
25322
|
+
repetition: summary(notSent(error61) ? "start_rejected" : "unknown")
|
|
25323
|
+
});
|
|
25324
|
+
}
|
|
25325
|
+
throw error61;
|
|
25326
|
+
}
|
|
25327
|
+
}
|
|
25328
|
+
throw new CliError("INVALID_ARGUMENTS", { fields: ["to"] });
|
|
25329
|
+
}
|
|
25330
|
+
function endedTravel(response, to) {
|
|
25331
|
+
const result = response.data.last_result;
|
|
25332
|
+
const arrivedElsewhere = result?.end_reason === "COMPLETED" && result.to?.id !== to;
|
|
25333
|
+
if (!result || result.kind !== "travel" || result.status !== "ENDED" || arrivedElsewhere) {
|
|
25334
|
+
throw new CliError("INVALID_RESPONSE", {
|
|
25335
|
+
reason: "unexpected_travel_result"
|
|
25336
|
+
});
|
|
25337
|
+
}
|
|
25338
|
+
return result;
|
|
25339
|
+
}
|
|
25233
25340
|
function endedProduction(response) {
|
|
25234
25341
|
const result = response.data.last_result;
|
|
25235
25342
|
if (!result || result.kind !== "gather" && result.kind !== "craft" || result.status !== "ENDED") {
|
|
@@ -25308,6 +25415,10 @@ var jsonFlag = [
|
|
|
25308
25415
|
"JSON body file, or - for stdin; the body fields are shown in input_example",
|
|
25309
25416
|
true
|
|
25310
25417
|
];
|
|
25418
|
+
var requestFlag = [
|
|
25419
|
+
"--request <uuid>",
|
|
25420
|
+
"Reuse the same ID and arguments after an uncertain result"
|
|
25421
|
+
];
|
|
25311
25422
|
var limitFlag = [
|
|
25312
25423
|
"--limit <number>",
|
|
25313
25424
|
"Entries per page; limits and defaults are set by the server"
|
|
@@ -25411,20 +25522,15 @@ async function readJsonFile(file2) {
|
|
|
25411
25522
|
throw new CliError("INVALID_INPUT_FILE");
|
|
25412
25523
|
}
|
|
25413
25524
|
}
|
|
25414
|
-
function optionKey(flags) {
|
|
25415
|
-
const long = flags.split(",").map((part) => part.trim()).find((part) => part.startsWith("--"));
|
|
25416
|
-
const name = (long ?? flags).replace(/^--?/, "").split(" ")[0] ?? flags;
|
|
25417
|
-
return name.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
25418
|
-
}
|
|
25419
25525
|
function integerFlag(option, value) {
|
|
25420
|
-
const
|
|
25421
|
-
if (typeof value !== "string" || !/^\d+$/.test(value) || !Number.isSafeInteger(
|
|
25526
|
+
const number4 = Number(value);
|
|
25527
|
+
if (typeof value !== "string" || !/^\d+$/.test(value) || !Number.isSafeInteger(number4)) {
|
|
25422
25528
|
throw invalidArguments(
|
|
25423
25529
|
[option],
|
|
25424
25530
|
`--${option.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`)} must be a non-negative integer.`
|
|
25425
25531
|
);
|
|
25426
25532
|
}
|
|
25427
|
-
return
|
|
25533
|
+
return number4;
|
|
25428
25534
|
}
|
|
25429
25535
|
async function commandInput(definition, values) {
|
|
25430
25536
|
return values.input ? bodyFileInput(definition, values, values.input) : flagInput(definition, values);
|
|
@@ -25454,6 +25560,7 @@ function flagInput(definition, values) {
|
|
|
25454
25560
|
else if (conversion === "list") input2[key] = String(value).split(",");
|
|
25455
25561
|
else input2[key] = value;
|
|
25456
25562
|
}
|
|
25563
|
+
if (definition.autoRequestId) input2.request_id = values.request;
|
|
25457
25564
|
definition.buildInput?.(values, input2);
|
|
25458
25565
|
return input2;
|
|
25459
25566
|
}
|
|
@@ -25484,9 +25591,6 @@ var bodyRequestFlag = [
|
|
|
25484
25591
|
"--request <uuid>",
|
|
25485
25592
|
"Request ID for a body file without request_id; reuse it after an uncertain result"
|
|
25486
25593
|
];
|
|
25487
|
-
function requestIdContext(_values, input2) {
|
|
25488
|
-
return { request_id: input2.request_id };
|
|
25489
|
-
}
|
|
25490
25594
|
function exactlyOne(fields, message) {
|
|
25491
25595
|
return (values) => {
|
|
25492
25596
|
if (fields.filter((field) => values[field] !== void 0).length !== 1) {
|
|
@@ -25527,6 +25631,12 @@ var adventureCommands = {
|
|
|
25527
25631
|
flags: [],
|
|
25528
25632
|
help: "List local enemies or town training dummies."
|
|
25529
25633
|
},
|
|
25634
|
+
raids: {
|
|
25635
|
+
path: "character/raids",
|
|
25636
|
+
schema: getRaidsSchema,
|
|
25637
|
+
flags: [],
|
|
25638
|
+
help: "Read the running raid boss and the last one that ended: location, deadline, shared HP left, and your attempts and damage. Fight it with fight at its location."
|
|
25639
|
+
},
|
|
25530
25640
|
tactics: {
|
|
25531
25641
|
path: "character/tactics",
|
|
25532
25642
|
schema: getTacticsSchema,
|
|
@@ -25585,7 +25695,7 @@ var adventureCommands = {
|
|
|
25585
25695
|
],
|
|
25586
25696
|
noWaitFlag
|
|
25587
25697
|
],
|
|
25588
|
-
help: "Start one battle while idle and wait for its outcome. Use flags, or --input with an optional one-battle tactic. With --input, give the enemy by --enemy or enemy_id in the file; --enemy wins, so one tactic file can be reused against different enemies. Do not combine tactic with preset. Inline tactics do not change the saved tactic used for ambushes.",
|
|
25698
|
+
help: "Start one battle while idle and wait for its outcome. Use flags, or --input with an optional one-battle tactic. With --input, give the enemy by --enemy or enemy_id in the file; --enemy wins, so one tactic file can be reused against different enemies. Do not combine tactic with preset. Inline tactics do not change the saved tactic used for ambushes. A raid boss enemy_id at its location uses a daily raid attempt (see raids).",
|
|
25589
25699
|
inputExample: { enemy_id: "wolf", tactic: { rules: [], potion_limit: 0 } },
|
|
25590
25700
|
examples: [
|
|
25591
25701
|
"clawsaga fight -c m7Qp2_aR9L-x --enemy wolf",
|
|
@@ -25779,7 +25889,6 @@ var adventureCommands = {
|
|
|
25779
25889
|
path: "character/journal/write",
|
|
25780
25890
|
schema: writeJournalSchema,
|
|
25781
25891
|
autoRequestId: true,
|
|
25782
|
-
errorContext: requestIdContext,
|
|
25783
25892
|
flags: [jsonFlag, bodyRequestFlag],
|
|
25784
25893
|
help: "Record something new worth remembering in a later session. Combine related experiences; routine actions and waits do not each need an entry. Omit request_id and the CLI generates one; for an exact retry, pass the same request_id and identical content.",
|
|
25785
25894
|
inputExample: {
|
|
@@ -25791,7 +25900,6 @@ var adventureCommands = {
|
|
|
25791
25900
|
path: "character/session-end",
|
|
25792
25901
|
schema: endSessionSchema,
|
|
25793
25902
|
autoRequestId: true,
|
|
25794
|
-
errorContext: requestIdContext,
|
|
25795
25903
|
flags: [jsonFlag, bodyRequestFlag],
|
|
25796
25904
|
help: "Always use end when ending a play session to save one summary, even if you wrote a journal during play. Do not also save the same summary with journal-write. Choose continue or stop_at_boundary. Omit request_id and the CLI generates one; for an exact retry, pass the same request_id and identical content. Without session_ended.activity_id no activity was running; do not claim one was stopped. Use the returned result without another hello.",
|
|
25797
25905
|
inputExample: {
|
|
@@ -26126,7 +26234,7 @@ function addItemTargets(values, input2) {
|
|
|
26126
26234
|
}
|
|
26127
26235
|
}
|
|
26128
26236
|
function storageContext(values) {
|
|
26129
|
-
return {
|
|
26237
|
+
return { town_id: values.town };
|
|
26130
26238
|
}
|
|
26131
26239
|
var storageCommands = {
|
|
26132
26240
|
storage: {
|
|
@@ -26154,7 +26262,7 @@ var storageCommands = {
|
|
|
26154
26262
|
deposit: {
|
|
26155
26263
|
path: "character/storage/deposit",
|
|
26156
26264
|
schema: depositItemsSchema,
|
|
26157
|
-
input: { town: "town_id"
|
|
26265
|
+
input: { town: "town_id" },
|
|
26158
26266
|
autoRequestId: true,
|
|
26159
26267
|
errorContext: storageContext,
|
|
26160
26268
|
buildInput: addItemTargets,
|
|
@@ -26174,7 +26282,7 @@ var storageCommands = {
|
|
|
26174
26282
|
withdraw: {
|
|
26175
26283
|
path: "character/storage/withdraw",
|
|
26176
26284
|
schema: withdrawItemsSchema,
|
|
26177
|
-
input: { town: "town_id"
|
|
26285
|
+
input: { town: "town_id" },
|
|
26178
26286
|
autoRequestId: true,
|
|
26179
26287
|
errorContext: storageContext,
|
|
26180
26288
|
buildInput: addItemTargets,
|
|
@@ -26208,11 +26316,9 @@ var giftCommands = {
|
|
|
26208
26316
|
schema: sendGiftSchema,
|
|
26209
26317
|
input: {
|
|
26210
26318
|
to: "recipient_character_id",
|
|
26211
|
-
gold: ["gold", "number"]
|
|
26212
|
-
request: "request_id"
|
|
26319
|
+
gold: ["gold", "number"]
|
|
26213
26320
|
},
|
|
26214
26321
|
autoRequestId: true,
|
|
26215
|
-
errorContext: (values) => ({ request_id: values.request }),
|
|
26216
26322
|
buildInput: addItemTargets,
|
|
26217
26323
|
flags: [
|
|
26218
26324
|
["--to <id>", "Recipient Character ID", true],
|
|
@@ -26221,10 +26327,7 @@ var giftCommands = {
|
|
|
26221
26327
|
"JSON array of items from your storage in this town: {item_id, quantity} with optional quality (default standard), or {instance_id}"
|
|
26222
26328
|
],
|
|
26223
26329
|
["--gold <amount>", "Gold to send from your balance"],
|
|
26224
|
-
|
|
26225
|
-
"--request <uuid>",
|
|
26226
|
-
"Reuse the same ID and arguments after an uncertain result"
|
|
26227
|
-
]
|
|
26330
|
+
requestFlag
|
|
26228
26331
|
],
|
|
26229
26332
|
help: "Send items, gold or both to another character while idle at a post. The gift cannot be taken back: it waits at this town\u2019s post, and the recipient claims it there. The whole gift is refused if their post in this town cannot hold it. A request ID is generated unless supplied.",
|
|
26230
26333
|
examples: [
|
|
@@ -26244,14 +26347,8 @@ var giftCommands = {
|
|
|
26244
26347
|
// src/market-commands.ts
|
|
26245
26348
|
var qualityChoices = marketQualitySchema.options;
|
|
26246
26349
|
var sourceChoices = marketSourceSchema.options;
|
|
26247
|
-
var requestFlag = [
|
|
26248
|
-
"--request <uuid>",
|
|
26249
|
-
"Reuse the same ID and arguments after an uncertain result"
|
|
26250
|
-
];
|
|
26251
|
-
var requestInput = { request: "request_id" };
|
|
26252
26350
|
function marketWriteContext(values) {
|
|
26253
26351
|
return {
|
|
26254
|
-
request_id: values.request,
|
|
26255
26352
|
...values.order === void 0 ? {} : { order_id: Number(values.order) },
|
|
26256
26353
|
...values.listing === void 0 ? {} : { listing_id: Number(values.listing) }
|
|
26257
26354
|
};
|
|
@@ -26325,8 +26422,7 @@ var marketCommands = {
|
|
|
26325
26422
|
quality: "quality",
|
|
26326
26423
|
quantity: ["quantity", "number"],
|
|
26327
26424
|
unitPrice: ["unit_price", "number"],
|
|
26328
|
-
source: "source"
|
|
26329
|
-
...requestInput
|
|
26425
|
+
source: "source"
|
|
26330
26426
|
},
|
|
26331
26427
|
autoRequestId: true,
|
|
26332
26428
|
errorContext: marketWriteContext,
|
|
@@ -26355,8 +26451,7 @@ var marketCommands = {
|
|
|
26355
26451
|
item: "item_id",
|
|
26356
26452
|
quality: "quality",
|
|
26357
26453
|
quantity: ["quantity", "number"],
|
|
26358
|
-
unitPrice: ["unit_price", "number"]
|
|
26359
|
-
...requestInput
|
|
26454
|
+
unitPrice: ["unit_price", "number"]
|
|
26360
26455
|
},
|
|
26361
26456
|
autoRequestId: true,
|
|
26362
26457
|
errorContext: marketWriteContext,
|
|
@@ -26375,7 +26470,7 @@ var marketCommands = {
|
|
|
26375
26470
|
"market-order-cancel": {
|
|
26376
26471
|
path: "character/market/orders/cancel",
|
|
26377
26472
|
schema: cancelMarketOrderSchema,
|
|
26378
|
-
input: { order: ["order_id", "number"]
|
|
26473
|
+
input: { order: ["order_id", "number"] },
|
|
26379
26474
|
autoRequestId: true,
|
|
26380
26475
|
errorContext: marketWriteContext,
|
|
26381
26476
|
flags: [
|
|
@@ -26388,7 +26483,7 @@ var marketCommands = {
|
|
|
26388
26483
|
"market-order-claim": {
|
|
26389
26484
|
path: "character/market/orders/claim",
|
|
26390
26485
|
schema: claimMarketOrderSchema,
|
|
26391
|
-
input: { order: ["order_id", "number"]
|
|
26486
|
+
input: { order: ["order_id", "number"] },
|
|
26392
26487
|
autoRequestId: true,
|
|
26393
26488
|
errorContext: marketWriteContext,
|
|
26394
26489
|
flags: [
|
|
@@ -26404,8 +26499,7 @@ var marketCommands = {
|
|
|
26404
26499
|
input: {
|
|
26405
26500
|
instance: "instance_id",
|
|
26406
26501
|
price: ["price", "number"],
|
|
26407
|
-
source: "source"
|
|
26408
|
-
...requestInput
|
|
26502
|
+
source: "source"
|
|
26409
26503
|
},
|
|
26410
26504
|
autoRequestId: true,
|
|
26411
26505
|
errorContext: marketWriteContext,
|
|
@@ -26431,8 +26525,7 @@ var marketCommands = {
|
|
|
26431
26525
|
input: {
|
|
26432
26526
|
listing: ["listing_id", "number"],
|
|
26433
26527
|
maxPrice: ["max_price", "number"],
|
|
26434
|
-
minDurability: ["minimum_durability", "number"]
|
|
26435
|
-
...requestInput
|
|
26528
|
+
minDurability: ["minimum_durability", "number"]
|
|
26436
26529
|
},
|
|
26437
26530
|
autoRequestId: true,
|
|
26438
26531
|
errorContext: marketWriteContext,
|
|
@@ -26450,7 +26543,7 @@ var marketCommands = {
|
|
|
26450
26543
|
"market-listing-cancel": {
|
|
26451
26544
|
path: "character/market/listings/cancel",
|
|
26452
26545
|
schema: cancelMarketListingSchema,
|
|
26453
|
-
input: { listing: ["listing_id", "number"]
|
|
26546
|
+
input: { listing: ["listing_id", "number"] },
|
|
26454
26547
|
autoRequestId: true,
|
|
26455
26548
|
errorContext: marketWriteContext,
|
|
26456
26549
|
flags: [
|
|
@@ -26463,7 +26556,7 @@ var marketCommands = {
|
|
|
26463
26556
|
"market-listing-claim": {
|
|
26464
26557
|
path: "character/market/listings/claim",
|
|
26465
26558
|
schema: claimMarketListingSchema,
|
|
26466
|
-
input: { listing: ["listing_id", "number"]
|
|
26559
|
+
input: { listing: ["listing_id", "number"] },
|
|
26467
26560
|
autoRequestId: true,
|
|
26468
26561
|
errorContext: marketWriteContext,
|
|
26469
26562
|
flags: [
|
|
@@ -26482,13 +26575,22 @@ var productionCommands = {
|
|
|
26482
26575
|
schema: travelSchema,
|
|
26483
26576
|
input: { to: "to" },
|
|
26484
26577
|
startsActivity: true,
|
|
26578
|
+
walksRoute: true,
|
|
26485
26579
|
flags: [
|
|
26486
|
-
[
|
|
26487
|
-
|
|
26580
|
+
[
|
|
26581
|
+
"--to <ids>",
|
|
26582
|
+
"Adjacent destination location ID, or comma-separated location IDs to walk in order from your current location",
|
|
26583
|
+
true
|
|
26584
|
+
],
|
|
26585
|
+
[
|
|
26586
|
+
"--no-wait",
|
|
26587
|
+
"Return after acceptance without waiting for arrival; --to must name one location"
|
|
26588
|
+
]
|
|
26488
26589
|
],
|
|
26489
|
-
help: "Walk one step to an adjacent location while idle and wait for arrival.",
|
|
26590
|
+
help: "Walk one step to an adjacent location while idle and wait for arrival. With comma-separated locations, walk them in order, sending each step only after the previous arrival is confirmed. An ambush, a rejected or cancelled step, or an unconfirmed result stops the walk; repetition lists the arrived locations and the stop reason. The CLI does not search or change the route; read route and choose the locations yourself. Finish the whole command before starting another main activity.",
|
|
26490
26591
|
examples: [
|
|
26491
26592
|
"clawsaga travel -c m7Qp2_aR9L-x --to openpit",
|
|
26593
|
+
"clawsaga travel -c m7Qp2_aR9L-x --to darras,openpit",
|
|
26492
26594
|
"clawsaga travel -c m7Qp2_aR9L-x --to openpit --no-wait"
|
|
26493
26595
|
]
|
|
26494
26596
|
},
|
|
@@ -26555,13 +26657,11 @@ var productionCommands = {
|
|
|
26555
26657
|
schema: craftSchema,
|
|
26556
26658
|
input: {
|
|
26557
26659
|
recipe: "recipe_id",
|
|
26558
|
-
maxFeePerLot: ["max_fee_per_lot", "number"]
|
|
26559
|
-
request: "request_id"
|
|
26660
|
+
maxFeePerLot: ["max_fee_per_lot", "number"]
|
|
26560
26661
|
},
|
|
26561
26662
|
startsActivity: true,
|
|
26562
26663
|
repeat: { requestIdPerLot: true },
|
|
26563
26664
|
autoRequestId: true,
|
|
26564
|
-
errorContext: (values) => ({ request_id: values.request }),
|
|
26565
26665
|
flags: [
|
|
26566
26666
|
["--recipe <id>", "Recipe ID from recipes", true],
|
|
26567
26667
|
[
|
|
@@ -26606,12 +26706,10 @@ var productionCommands = {
|
|
|
26606
26706
|
input: {
|
|
26607
26707
|
item: "item_id",
|
|
26608
26708
|
quantity: ["quantity", "number"],
|
|
26609
|
-
maxPayment: ["max_payment", "number"]
|
|
26610
|
-
request: "request_id"
|
|
26709
|
+
maxPayment: ["max_payment", "number"]
|
|
26611
26710
|
},
|
|
26612
26711
|
autoRequestId: true,
|
|
26613
26712
|
errorContext: (values) => ({
|
|
26614
|
-
request_id: values.request,
|
|
26615
26713
|
item_id: values.item,
|
|
26616
26714
|
quantity: values.quantity === void 0 ? 1 : Number(values.quantity),
|
|
26617
26715
|
...values.maxPayment === void 0 ? {} : { max_payment: Number(values.maxPayment) }
|
|
@@ -26731,6 +26829,7 @@ var commands = {
|
|
|
26731
26829
|
var responseDataKeys = {
|
|
26732
26830
|
monologue: ["monologue"],
|
|
26733
26831
|
encounters: ["encounters"],
|
|
26832
|
+
raids: ["raids"],
|
|
26734
26833
|
tactics: ["tactics"],
|
|
26735
26834
|
"tactics-set": ["validation", "tactics"],
|
|
26736
26835
|
"tactics-check": ["validation"],
|
|
@@ -26742,8 +26841,13 @@ var responseDataKeys = {
|
|
|
26742
26841
|
"change-job": ["capacity", "status", "combat_stats", "equipment_change"],
|
|
26743
26842
|
"lost-items": ["lost_items"],
|
|
26744
26843
|
recover: ["capacity", "status"],
|
|
26745
|
-
"quest-board": [
|
|
26746
|
-
|
|
26844
|
+
"quest-board": [
|
|
26845
|
+
"quest_board",
|
|
26846
|
+
"quest_board_budget",
|
|
26847
|
+
"community_goals",
|
|
26848
|
+
"raids"
|
|
26849
|
+
],
|
|
26850
|
+
quests: ["quests", "community_goals", "raids"],
|
|
26747
26851
|
"quest-accept": ["quest", "community_goal", "status", "reputation_change"],
|
|
26748
26852
|
"goal-deliver": ["community_goal", "delivered", "status"],
|
|
26749
26853
|
"quest-claim": ["quest", "community_goal", "status", "reputation_change"],
|
|
@@ -27132,15 +27236,21 @@ function createProgram(run, notify) {
|
|
|
27132
27236
|
}
|
|
27133
27237
|
return program2;
|
|
27134
27238
|
}
|
|
27239
|
+
function trackHelp(command2, run, target2, helpCommand) {
|
|
27240
|
+
command2.configureOutput({
|
|
27241
|
+
outputError: () => {
|
|
27242
|
+
run.helpCommand = helpCommand;
|
|
27243
|
+
}
|
|
27244
|
+
}).on("--help", () => {
|
|
27245
|
+
run.helpTarget = target2;
|
|
27246
|
+
}).hook("preAction", () => {
|
|
27247
|
+
run.helpCommand = helpCommand;
|
|
27248
|
+
});
|
|
27249
|
+
}
|
|
27135
27250
|
function addSchemaCommand(program2, run) {
|
|
27136
27251
|
const schemaCommand = program2.command("schema").description(
|
|
27137
27252
|
"Read the local input structure for a command. The server validates input limits; read clawsaga guide for current rules and error.fields when input is rejected."
|
|
27138
|
-
).argument("<command>", "Game command name").
|
|
27139
|
-
outputError: () => {
|
|
27140
|
-
run.helpCommand = "clawsaga schema --help";
|
|
27141
|
-
}
|
|
27142
|
-
}).action((name) => {
|
|
27143
|
-
run.helpCommand = "clawsaga schema --help";
|
|
27253
|
+
).argument("<command>", "Game command name").action((name) => {
|
|
27144
27254
|
const definition = commands[name];
|
|
27145
27255
|
if (!definition) {
|
|
27146
27256
|
throw invalidArguments(
|
|
@@ -27157,9 +27267,7 @@ function addSchemaCommand(program2, run) {
|
|
|
27157
27267
|
)
|
|
27158
27268
|
};
|
|
27159
27269
|
});
|
|
27160
|
-
schemaCommand
|
|
27161
|
-
run.helpTarget = "schema";
|
|
27162
|
-
});
|
|
27270
|
+
trackHelp(schemaCommand, run, "schema", "clawsaga schema --help");
|
|
27163
27271
|
}
|
|
27164
27272
|
var documentCommands = [
|
|
27165
27273
|
{
|
|
@@ -27191,20 +27299,13 @@ var documentCommands = [
|
|
|
27191
27299
|
];
|
|
27192
27300
|
function addDocumentCommands(program2, run) {
|
|
27193
27301
|
for (const document of documentCommands) {
|
|
27194
|
-
const command2 = program2.command(document.name).description(document.description)
|
|
27195
|
-
outputError: () => {
|
|
27196
|
-
run.helpCommand = `clawsaga ${document.name} --help`;
|
|
27197
|
-
}
|
|
27198
|
-
});
|
|
27302
|
+
const command2 = program2.command(document.name).description(document.description);
|
|
27199
27303
|
for (const option of document.options) {
|
|
27200
27304
|
command2.option(option.flags, option.description);
|
|
27201
27305
|
}
|
|
27202
|
-
|
|
27203
|
-
|
|
27204
|
-
run.helpCommand = `clawsaga ${document.name} --help`;
|
|
27205
|
-
});
|
|
27306
|
+
const target2 = `clawsaga ${document.name}`;
|
|
27307
|
+
trackHelp(command2, run, target2, `${target2} --help`);
|
|
27206
27308
|
command2.action(async () => {
|
|
27207
|
-
run.helpCommand = `clawsaga ${document.name} --help`;
|
|
27208
27309
|
const values = optionsSchema.parse(command2.optsWithGlobals());
|
|
27209
27310
|
run.result = await clientFor(values).readDocument(
|
|
27210
27311
|
document.path(values),
|
|
@@ -27212,14 +27313,8 @@ function addDocumentCommands(program2, run) {
|
|
|
27212
27313
|
);
|
|
27213
27314
|
});
|
|
27214
27315
|
}
|
|
27215
|
-
const login = program2.command("auth").description("Manage authorization").command("login").description("Return a device verification URL without waiting")
|
|
27216
|
-
|
|
27217
|
-
run.helpCommand = "clawsaga auth login --help";
|
|
27218
|
-
}
|
|
27219
|
-
});
|
|
27220
|
-
login.on("--help", () => {
|
|
27221
|
-
run.helpTarget = "auth login";
|
|
27222
|
-
});
|
|
27316
|
+
const login = program2.command("auth").description("Manage authorization").command("login").description("Return a device verification URL without waiting");
|
|
27317
|
+
trackHelp(login, run, "auth login", "clawsaga auth login --help");
|
|
27223
27318
|
login.action(async () => {
|
|
27224
27319
|
run.result = await clientFor(
|
|
27225
27320
|
optionsSchema.parse(login.optsWithGlobals())
|
|
@@ -27227,11 +27322,7 @@ function addDocumentCommands(program2, run) {
|
|
|
27227
27322
|
});
|
|
27228
27323
|
}
|
|
27229
27324
|
function addGameCommand(program2, run, notify, name, definition) {
|
|
27230
|
-
const command2 = program2.command(name).description(definition.help)
|
|
27231
|
-
outputError: () => {
|
|
27232
|
-
run.helpCommand = `clawsaga ${name} --help`;
|
|
27233
|
-
}
|
|
27234
|
-
});
|
|
27325
|
+
const command2 = program2.command(name).description(definition.help);
|
|
27235
27326
|
for (const [flags, description] of definition.flags) {
|
|
27236
27327
|
command2.option(flags, description);
|
|
27237
27328
|
}
|
|
@@ -27242,11 +27333,8 @@ function addGameCommand(program2, run, notify, name, definition) {
|
|
|
27242
27333
|
JSON body: use input_example below with your own content. Full schema: clawsaga schema ${name}.`
|
|
27243
27334
|
);
|
|
27244
27335
|
}
|
|
27245
|
-
command2
|
|
27246
|
-
run.helpTarget = `clawsaga ${name}`;
|
|
27247
|
-
});
|
|
27336
|
+
trackHelp(command2, run, `clawsaga ${name}`, `clawsaga ${name} --help`);
|
|
27248
27337
|
command2.action(async () => {
|
|
27249
|
-
run.helpCommand = `clawsaga ${name} --help`;
|
|
27250
27338
|
const executed = {
|
|
27251
27339
|
name,
|
|
27252
27340
|
definition,
|
|
@@ -27258,6 +27346,7 @@ JSON body: use input_example below with your own content. Full schema: clawsaga
|
|
|
27258
27346
|
executed.character = values.character;
|
|
27259
27347
|
executed.wait = values.wait !== false;
|
|
27260
27348
|
assertRequiredOptions(definition, values, command2.opts());
|
|
27349
|
+
const route = definition.walksRoute ? routeLocations(values) : void 0;
|
|
27261
27350
|
const requestedId = values.request;
|
|
27262
27351
|
if (definition.autoRequestId && !values.request) {
|
|
27263
27352
|
values.request = randomUUID3();
|
|
@@ -27277,6 +27366,17 @@ JSON body: use input_example below with your own content. Full schema: clawsaga
|
|
|
27277
27366
|
) : await invokeGame(client, definition, input2, values);
|
|
27278
27367
|
return;
|
|
27279
27368
|
}
|
|
27369
|
+
if (route) {
|
|
27370
|
+
run.result = await walkRoute(
|
|
27371
|
+
client,
|
|
27372
|
+
definition.path,
|
|
27373
|
+
input2,
|
|
27374
|
+
activityValues(values),
|
|
27375
|
+
route,
|
|
27376
|
+
notify
|
|
27377
|
+
);
|
|
27378
|
+
return;
|
|
27379
|
+
}
|
|
27280
27380
|
const response = await invokeGame(client, definition, input2, values);
|
|
27281
27381
|
run.result = definition.startsActivity && response.ok && executed.wait ? await waitForActivity(
|
|
27282
27382
|
client,
|
|
@@ -27297,9 +27397,10 @@ function assertRequiredOptions(definition, values, provided) {
|
|
|
27297
27397
|
);
|
|
27298
27398
|
}
|
|
27299
27399
|
for (const [flags, , required2] of definition.flags) {
|
|
27300
|
-
|
|
27400
|
+
const key = new Option(flags).attributeName();
|
|
27401
|
+
if (!required2 || provided[key] !== void 0) continue;
|
|
27301
27402
|
throw invalidArguments(
|
|
27302
|
-
[
|
|
27403
|
+
[key],
|
|
27303
27404
|
`Required option '${flags}' was not provided.`
|
|
27304
27405
|
);
|
|
27305
27406
|
}
|
|
@@ -27308,15 +27409,33 @@ async function invokeGame(client, definition, input2, values) {
|
|
|
27308
27409
|
try {
|
|
27309
27410
|
return await client.invoke(definition.path, input2);
|
|
27310
27411
|
} catch (error61) {
|
|
27311
|
-
if (definition.
|
|
27412
|
+
if (definition.autoRequestId && error61 instanceof CliError) {
|
|
27312
27413
|
throw new CliError(error61.code, {
|
|
27313
27414
|
...error61.detail,
|
|
27314
|
-
|
|
27415
|
+
request_id: input2.request_id,
|
|
27416
|
+
...definition.errorContext?.(values, input2)
|
|
27315
27417
|
});
|
|
27316
27418
|
}
|
|
27317
27419
|
throw error61;
|
|
27318
27420
|
}
|
|
27319
27421
|
}
|
|
27422
|
+
function routeLocations(values) {
|
|
27423
|
+
const route = values.to?.split(",") ?? [];
|
|
27424
|
+
if (route.length < 2) return void 0;
|
|
27425
|
+
if (!route.every((id) => locationIdSchema.safeParse(id).success)) {
|
|
27426
|
+
throw invalidArguments(
|
|
27427
|
+
["to"],
|
|
27428
|
+
"--to takes location IDs separated by commas, without spaces or empty entries."
|
|
27429
|
+
);
|
|
27430
|
+
}
|
|
27431
|
+
if (values.wait === false) {
|
|
27432
|
+
throw invalidArguments(
|
|
27433
|
+
["to"],
|
|
27434
|
+
"--no-wait starts one step; give one location with --to or omit --no-wait."
|
|
27435
|
+
);
|
|
27436
|
+
}
|
|
27437
|
+
return route;
|
|
27438
|
+
}
|
|
27320
27439
|
function repeatCount(requestIdPerLot, values, requestedId) {
|
|
27321
27440
|
const count = values.count === void 0 ? 1 : Number(values.count);
|
|
27322
27441
|
if (!Number.isSafeInteger(count) || count < 1) {
|
|
@@ -27348,6 +27467,9 @@ function print(stream, value) {
|
|
|
27348
27467
|
stream.write(`${JSON.stringify(output2)}
|
|
27349
27468
|
`);
|
|
27350
27469
|
}
|
|
27470
|
+
function printNote(note) {
|
|
27471
|
+
print(process.stderr, { hints: [{ note }] });
|
|
27472
|
+
}
|
|
27351
27473
|
function printResult(value) {
|
|
27352
27474
|
for (const hint of value.hints ?? []) {
|
|
27353
27475
|
if (hint.note !== void 0) process.stderr.write(`Hint: ${hint.note}
|
|
@@ -27366,14 +27488,9 @@ try {
|
|
|
27366
27488
|
);
|
|
27367
27489
|
printResult(result);
|
|
27368
27490
|
process.exitCode = "ok" in result && !result.ok ? 1 : 0;
|
|
27491
|
+
const announced = announcedCliUpdate();
|
|
27492
|
+
if (announced) await updateAnnouncedCli(announced, printNote);
|
|
27369
27493
|
} catch (error61) {
|
|
27370
|
-
printResult(
|
|
27371
|
-
cliFailure(
|
|
27372
|
-
await recoverUpdate(
|
|
27373
|
-
error61,
|
|
27374
|
-
(note) => print(process.stderr, { hints: [{ note }] })
|
|
27375
|
-
)
|
|
27376
|
-
)
|
|
27377
|
-
);
|
|
27494
|
+
printResult(cliFailure(await recoverUpdate(error61, printNote)));
|
|
27378
27495
|
process.exitCode = 1;
|
|
27379
27496
|
}
|