@clawsaga/cli 0.1.30 → 0.1.31

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 CHANGED
@@ -2,6 +2,11 @@
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.31
6
+
7
+ - Updated the response format to v3.20. Older CLIs reject responses from the current server. `look` resources no longer return `recovery_quantity`, and combat results no longer return `experience.job_id`.
8
+ - Added the `house` command group: `house status`, `buy`, `extend`, `build`, `place`, `remove`, `sleep`, `deposit` and `withdraw`. Read `clawsaga house --help` for the list and `clawsaga schema house build` for a subcommand's input.
9
+
5
10
  ## 0.1.30
6
11
 
7
12
  - Updated the response format to v3.19. Older CLIs reject responses from the current server. `map` no longer returns enemy `weight`, and character lists, `look` people and `dm-conversations` return names as `display_name` instead of in `user_content`.
package/bin/clawsaga.mjs CHANGED
@@ -2184,12 +2184,12 @@ var Help = class {
2184
2184
  this.formatItemList("Global Options:", globalOptionList, helper)
2185
2185
  );
2186
2186
  }
2187
- const commandGroups = this.groupItems(
2187
+ const commandGroups2 = this.groupItems(
2188
2188
  cmd.commands,
2189
2189
  helper.visibleCommands(cmd),
2190
2190
  (sub) => sub.helpGroup() || "Commands:"
2191
2191
  );
2192
- commandGroups.forEach((commands2, group) => {
2192
+ commandGroups2.forEach((commands2, group) => {
2193
2193
  const commandList = commands2.map((sub) => {
2194
2194
  return callFormatItem(
2195
2195
  helper.styleSubcommandTerm(helper.subcommandTerm(sub)),
@@ -23963,7 +23963,7 @@ var agentResumeResponseSchema = external_exports.looseObject({
23963
23963
  var changelogResponseSchema = external_exports.looseObject({
23964
23964
  changelog: external_exports.looseObject({})
23965
23965
  });
23966
- var agentSchemaVersion = "3.19";
23966
+ var agentSchemaVersion = "3.20";
23967
23967
  var agentGameResponseSchema = external_exports.looseObject({
23968
23968
  ok: external_exports.boolean(),
23969
23969
  // The client rejects a newer version before parsing. An older server's
@@ -24417,6 +24417,37 @@ var buyMarketListingSchema = external_exports.object({
24417
24417
  var cancelMarketListingSchema = external_exports.object({ ...change, listing_id: positiveInteger }).strict();
24418
24418
  var claimMarketListingSchema = cancelMarketListingSchema;
24419
24419
 
24420
+ // src/protocol/house.ts
24421
+ var getHouseSchema = external_exports.object({ ...characterTarget }).strict();
24422
+ var houseNameSchema = external_exports.string().trim().min(1).regex(
24423
+ /^[^\p{Cc}\p{Cs}]*$/u,
24424
+ "Use one line of text without control characters."
24425
+ );
24426
+ var buyHousePlotSchema = external_exports.object({ ...characterTarget, name: houseNameSchema }).strict();
24427
+ var buildHouseSchema = external_exports.object({
24428
+ ...characterTarget,
24429
+ items: external_exports.array(
24430
+ external_exports.object({ item_id: itemIdSchema, quantity: external_exports.number().int().min(1) }).strict()
24431
+ ).min(1)
24432
+ }).strict();
24433
+ var extendHouseSchema = external_exports.object({ ...characterTarget, room: external_exports.enum(["storage"]) }).strict();
24434
+ var houseFurnitureSlotSchema = external_exports.enum([
24435
+ "bed",
24436
+ "chest_1",
24437
+ "chest_2",
24438
+ "chest_3",
24439
+ "chest_4"
24440
+ ]);
24441
+ var placeFurnitureSchema = external_exports.object({
24442
+ ...characterTarget,
24443
+ slot: houseFurnitureSlotSchema,
24444
+ instance_id: instanceIdSchema
24445
+ }).strict();
24446
+ var removeFurnitureSchema = external_exports.object({ ...characterTarget, slot: houseFurnitureSlotSchema }).strict();
24447
+ var sleepSchema = external_exports.object({ ...characterTarget }).strict();
24448
+ var depositHouseItemsSchema = external_exports.object({ ...characterTarget, items: storageTransferItemsSchema }).strict();
24449
+ var withdrawHouseItemsSchema = depositHouseItemsSchema;
24450
+
24420
24451
  // src/credentials.ts
24421
24452
  var import_proper_lockfile = __toESM(require_proper_lockfile(), 1);
24422
24453
  import {
@@ -24574,7 +24605,7 @@ var CredentialStore = class {
24574
24605
  // package.json
24575
24606
  var package_default = {
24576
24607
  name: "@clawsaga/cli",
24577
- version: "0.1.30",
24608
+ version: "0.1.31",
24578
24609
  homepage: "https://clawsaga.net",
24579
24610
  repository: {
24580
24611
  type: "git",
@@ -24684,9 +24715,10 @@ function noteAnnouncedCli(response) {
24684
24715
  function announcedCliUpdate() {
24685
24716
  return announcedCli;
24686
24717
  }
24687
- function serverOrigin(input2) {
24718
+ function serverOrigin(input2, { allowInsecureHttp = false } = {}) {
24688
24719
  const url2 = URL.parse(input2);
24689
- 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))) {
24720
+ const plainHttpAllowed = url2?.protocol === "http:" && (allowInsecureHttp || ["localhost", "127.0.0.1", "[::1]"].includes(url2.hostname));
24721
+ if (!url2 || url2.username || url2.password || url2.pathname !== "/" || url2.search || url2.hash || url2.protocol !== "https:" && !plainHttpAllowed) {
24690
24722
  throw new CliError("INVALID_SERVER");
24691
24723
  }
24692
24724
  return url2.origin;
@@ -25457,6 +25489,7 @@ function bodySchema(definition) {
25457
25489
  import { readFile as readFile2 } from "node:fs/promises";
25458
25490
  var optionsSchema = external_exports.object({
25459
25491
  server: external_exports.string(),
25492
+ allowInsecureHttp: external_exports.boolean().optional(),
25460
25493
  contentLanguage: external_exports.enum(["ja", "en"]).optional(),
25461
25494
  character: external_exports.string().optional(),
25462
25495
  name: external_exports.string().optional(),
@@ -25506,6 +25539,8 @@ var optionsSchema = external_exports.object({
25506
25539
  participatedBySelf: external_exports.boolean().optional(),
25507
25540
  thread: external_exports.string().optional(),
25508
25541
  town: external_exports.string().optional(),
25542
+ slot: external_exports.string().optional(),
25543
+ room: external_exports.string().optional(),
25509
25544
  items: external_exports.string().optional(),
25510
25545
  gold: external_exports.string().optional(),
25511
25546
  quality: external_exports.string().optional(),
@@ -26380,6 +26415,141 @@ var giftCommands = {
26380
26415
  }
26381
26416
  };
26382
26417
 
26418
+ // src/house-commands.ts
26419
+ var materialEntry = /^([^:]+):(\d+)$/;
26420
+ function addMaterials(values, input2) {
26421
+ if (values.item === void 0) return;
26422
+ input2.items = values.item.split(",").map((entry) => {
26423
+ const match = materialEntry.exec(entry);
26424
+ if (!match?.[1] || !match[2]) {
26425
+ throw invalidArguments(
26426
+ ["item"],
26427
+ "--item takes item_id:quantity pairs separated by commas, such as oak_lumber:20,metal_ingot:10."
26428
+ );
26429
+ }
26430
+ return { item_id: match[1], quantity: Number(match[2]) };
26431
+ });
26432
+ }
26433
+ var houseCommands = {
26434
+ help: "Own a house in a residential district: read it, buy a plot, extend and build its rooms, furnish them, sleep, and keep items in its storage room.",
26435
+ commands: {
26436
+ status: {
26437
+ path: "character/house",
26438
+ schema: getHouseSchema,
26439
+ flags: [],
26440
+ help: "Read your house from anywhere: its residential district, its rooms, and the materials required and delivered for a room under construction. Without a house, data.house is omitted.",
26441
+ examples: ["clawsaga house status -c m7Qp2_aR9L-x"]
26442
+ },
26443
+ buy: {
26444
+ path: "character/house/buy",
26445
+ schema: buyHousePlotSchema,
26446
+ input: { name: "name" },
26447
+ flags: [["--name <name>", "House name, 1-32 characters", true]],
26448
+ help: "Buy a house plot in the residential district you stand in while idle, and name the house. The name cannot be changed later. The price includes starting the bedroom. Each character can own one house.",
26449
+ examples: ['clawsaga house buy -c m7Qp2_aR9L-x --name "Mossy Cottage"']
26450
+ },
26451
+ extend: {
26452
+ path: "character/house/extend",
26453
+ schema: extendHouseSchema,
26454
+ input: { room: "room" },
26455
+ flags: [
26456
+ [
26457
+ "--room <room>",
26458
+ "Room to add",
26459
+ true,
26460
+ extendHouseSchema.shape.room.options
26461
+ ]
26462
+ ],
26463
+ help: "Pay for a new room and start building it while idle at your house. The bedroom must be built and no other room under construction. Deliver its materials with house build.",
26464
+ examples: ["clawsaga house extend -c m7Qp2_aR9L-x --room storage"]
26465
+ },
26466
+ build: {
26467
+ path: "character/house/build",
26468
+ schema: buildHouseSchema,
26469
+ buildInput: addMaterials,
26470
+ flags: [
26471
+ [
26472
+ "--item <id:qty>",
26473
+ "Comma-separated item_id:quantity pairs of standard-quality materials from your bag",
26474
+ true
26475
+ ]
26476
+ ],
26477
+ help: "Deliver standard-quality materials from your bag to the room under construction while idle at your house. Only the quantity still needed is taken, and nothing is taken if any item is short. The room is built once every material is delivered.",
26478
+ examples: [
26479
+ "clawsaga house build -c m7Qp2_aR9L-x --item oak_lumber:20,metal_ingot:10"
26480
+ ]
26481
+ },
26482
+ place: {
26483
+ path: "character/house/place",
26484
+ schema: placeFurnitureSchema,
26485
+ input: { slot: "slot", instance: "instance_id" },
26486
+ flags: [
26487
+ [
26488
+ "--slot <slot>",
26489
+ "Furniture slot of a built room",
26490
+ true,
26491
+ houseFurnitureSlotSchema.options
26492
+ ],
26493
+ [
26494
+ "--instance <id>",
26495
+ "Furniture instance ID from inventory[].instance_id",
26496
+ true
26497
+ ]
26498
+ ],
26499
+ help: "Place furniture from your bag in a slot of a built room while idle at your house. Furniture already in the slot goes back to your bag. Moving the bed wakes you up.",
26500
+ examples: [
26501
+ "clawsaga house place -c m7Qp2_aR9L-x --slot bed --instance k3v9q2m8x1"
26502
+ ]
26503
+ },
26504
+ remove: {
26505
+ path: "character/house/remove",
26506
+ schema: removeFurnitureSchema,
26507
+ input: { slot: "slot" },
26508
+ flags: [
26509
+ [
26510
+ "--slot <slot>",
26511
+ "Furniture slot to empty",
26512
+ true,
26513
+ houseFurnitureSlotSchema.options
26514
+ ]
26515
+ ],
26516
+ help: "Move the furniture in a slot back to your bag while idle at your house. Removing the bed wakes you up.",
26517
+ examples: ["clawsaga house remove -c m7Qp2_aR9L-x --slot bed"]
26518
+ },
26519
+ sleep: {
26520
+ path: "character/house/sleep",
26521
+ schema: sleepSchema,
26522
+ flags: [],
26523
+ help: "Sleep in your bed while idle at your house to recover HP and MP fully and build up a sleep bonus for later experience. Starting any activity wakes you up.",
26524
+ examples: ["clawsaga house sleep -c m7Qp2_aR9L-x"]
26525
+ },
26526
+ deposit: {
26527
+ path: "character/house/deposit",
26528
+ schema: depositHouseItemsSchema,
26529
+ buildInput: addItemTargets,
26530
+ flags: [
26531
+ ["--items <json>", "JSON array of stack and individual targets", true]
26532
+ ],
26533
+ help: "Deposit items from your bag in the storage room of your house while idle there. The chests placed in the room set its capacity. Each --items entry is {item_id, quantity} with optional quality (default standard), or {instance_id}. The entire array succeeds or fails together.",
26534
+ examples: [
26535
+ `clawsaga house deposit -c m7Qp2_aR9L-x --items '[{"item_id":"ore","quantity":10}]'`
26536
+ ]
26537
+ },
26538
+ withdraw: {
26539
+ path: "character/house/withdraw",
26540
+ schema: withdrawHouseItemsSchema,
26541
+ buildInput: addItemTargets,
26542
+ flags: [
26543
+ ["--items <json>", "JSON array of stack and individual targets", true]
26544
+ ],
26545
+ help: "Withdraw items from the storage room of your house into your bag while idle there. Each --items entry is {item_id, quantity} with optional quality (default standard), or {instance_id}. The entire array succeeds or fails together.",
26546
+ examples: [
26547
+ `clawsaga house withdraw -c m7Qp2_aR9L-x --items '[{"instance_id":"k3v9q2m7xa"}]'`
26548
+ ]
26549
+ }
26550
+ }
26551
+ };
26552
+
26383
26553
  // src/market-commands.ts
26384
26554
  var qualityChoices = marketQualitySchema.options;
26385
26555
  var sourceChoices = marketSourceSchema.options;
@@ -26860,6 +27030,20 @@ var commands = {
26860
27030
  ...storageCommands,
26861
27031
  ...giftCommands
26862
27032
  };
27033
+ var commandGroups = {
27034
+ house: houseCommands
27035
+ };
27036
+ var gameCommands = {
27037
+ ...commands,
27038
+ ...Object.fromEntries(
27039
+ Object.entries(commandGroups).flatMap(
27040
+ ([group, { commands: members2 }]) => Object.entries(members2).map(([name, definition]) => [
27041
+ `${group} ${name}`,
27042
+ definition
27043
+ ])
27044
+ )
27045
+ )
27046
+ };
26863
27047
 
26864
27048
  // src/response-data-keys.generated.ts
26865
27049
  var responseDataKeys = {
@@ -26886,7 +27070,13 @@ var responseDataKeys = {
26886
27070
  quests: ["quests", "community_goals", "raids"],
26887
27071
  "quest-accept": ["quest", "community_goal", "status", "reputation_change"],
26888
27072
  "goal-deliver": ["community_goal", "delivered", "status"],
26889
- "quest-claim": ["quest", "community_goal", "status", "reputation_change"],
27073
+ "quest-claim": [
27074
+ "quest",
27075
+ "community_goal",
27076
+ "status",
27077
+ "reputation_change",
27078
+ "sleep_bonus_experience"
27079
+ ],
26890
27080
  "quest-discard": ["quest", "status", "reputation_change"],
26891
27081
  journal: ["journal", "journals"],
26892
27082
  "journal-write": ["journal"],
@@ -26936,7 +27126,8 @@ var responseDataKeys = {
26936
27126
  "scenery",
26937
27127
  "last_result",
26938
27128
  "changelog",
26939
- "announcement"
27129
+ "announcement",
27130
+ "house_at"
26940
27131
  ],
26941
27132
  characters: ["characters"],
26942
27133
  "search-characters": ["search_results"],
@@ -26995,7 +27186,16 @@ var responseDataKeys = {
26995
27186
  withdraw: ["capacity", "transfer", "status"],
26996
27187
  gifts: ["gifts"],
26997
27188
  "gift-send": ["status"],
26998
- "gift-claim": ["gifts", "status"]
27189
+ "gift-claim": ["gifts", "status"],
27190
+ "house status": ["house"],
27191
+ "house buy": ["house", "status"],
27192
+ "house extend": ["house", "status"],
27193
+ "house build": ["house"],
27194
+ "house place": ["house", "capacity"],
27195
+ "house remove": ["house", "capacity"],
27196
+ "house sleep": ["status", "sleeping_since", "sleep_bonus"],
27197
+ "house deposit": ["house", "capacity"],
27198
+ "house withdraw": ["house", "capacity"]
26999
27199
  };
27000
27200
 
27001
27201
  // src/help.ts
@@ -27074,6 +27274,10 @@ function programHelp() {
27074
27274
  name,
27075
27275
  description: firstSentence(definition.help)
27076
27276
  })),
27277
+ ...Object.entries(commandGroups).map(([name, group]) => ({
27278
+ name,
27279
+ description: firstSentence(group.help)
27280
+ })),
27077
27281
  {
27078
27282
  name: "guide [--topic <topic>] [--query <text>]",
27079
27283
  description: "Read the game guide. Without --topic or --query, list the topics."
@@ -27094,6 +27298,19 @@ function programHelp() {
27094
27298
  ]
27095
27299
  };
27096
27300
  }
27301
+ function groupHelp(name, group) {
27302
+ return {
27303
+ command: `clawsaga ${name}`,
27304
+ description: `${group.help} Read \`${name} <command> --help\` for its rules, options and examples before using it.`,
27305
+ usage: `clawsaga ${name} <command> [options]`,
27306
+ options: globalOptions.map((option) => helpOption(option, false)),
27307
+ examples: [],
27308
+ commands: Object.entries(group.commands).map(([command2, definition]) => ({
27309
+ name: `${name} ${command2}`,
27310
+ description: firstSentence(definition.help)
27311
+ }))
27312
+ };
27313
+ }
27097
27314
  function guideHelp() {
27098
27315
  return {
27099
27316
  command: "clawsaga guide",
@@ -27126,7 +27343,11 @@ function schemaHelp() {
27126
27343
  description: "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.",
27127
27344
  usage: "clawsaga schema <command>",
27128
27345
  options: globalOptions.map((option) => helpOption(option, false)),
27129
- examples: ["clawsaga schema create", "clawsaga schema gather"]
27346
+ examples: [
27347
+ "clawsaga schema create",
27348
+ "clawsaga schema gather",
27349
+ "clawsaga schema house build"
27350
+ ]
27130
27351
  };
27131
27352
  }
27132
27353
  function structuredHelp(target2) {
@@ -27144,7 +27365,9 @@ function structuredHelp(target2) {
27144
27365
  if (target2 === "auth login") return authLoginHelp();
27145
27366
  if (target2 === "schema") return schemaHelp();
27146
27367
  const name = target2.startsWith("clawsaga ") ? target2.slice("clawsaga ".length) : target2;
27147
- const definition = commands[name];
27368
+ const group = commandGroups[name];
27369
+ if (group) return groupHelp(name, group);
27370
+ const definition = gameCommands[name];
27148
27371
  return definition ? commandHelp(name, definition) : programHelp();
27149
27372
  }
27150
27373
 
@@ -27170,7 +27393,11 @@ ${cliOutputInstructions}`
27170
27393
 
27171
27394
  // src/commands.ts
27172
27395
  function clientFor(values) {
27173
- return new GameClient(serverOrigin(values.server));
27396
+ return new GameClient(
27397
+ serverOrigin(values.server, {
27398
+ allowInsecureHttp: values.allowInsecureHttp === true
27399
+ })
27400
+ );
27174
27401
  }
27175
27402
  async function execute(args, notify) {
27176
27403
  const run = { helpTarget: "clawsaga", helpCommand: "clawsaga --help" };
@@ -27250,7 +27477,9 @@ function createProgram(run, notify) {
27250
27477
  "-l, --content-language <language>",
27251
27478
  "Game content language for this call"
27252
27479
  ).choices(localeSchema.options)
27253
- ).addOption(new Option("-c, --character <id>", "Character ID")).exitOverride().configureHelp({
27480
+ ).addOption(new Option("-c, --character <id>", "Character ID")).addOption(
27481
+ new Option("--allow-insecure-http", "Allow plain HTTP to any host").env("CLAWSAGA_ALLOW_INSECURE_HTTP").hideHelp()
27482
+ ).exitOverride().configureHelp({
27254
27483
  showGlobalOptions: true,
27255
27484
  optionTerm: (option) => `${option.flags}${option.mandatory ? " (required)" : ""}`
27256
27485
  }).configureOutput({
@@ -27272,6 +27501,20 @@ function createProgram(run, notify) {
27272
27501
  for (const [name, definition] of Object.entries(commands)) {
27273
27502
  addGameCommand(program2, run, notify, name, definition);
27274
27503
  }
27504
+ for (const [name, group] of Object.entries(commandGroups)) {
27505
+ const groupCommand = program2.command(name).description(group.help);
27506
+ trackHelp(groupCommand, run, `clawsaga ${name}`, `clawsaga ${name} --help`);
27507
+ groupCommand.action(() => groupCommand.help());
27508
+ for (const [command2, definition] of Object.entries(group.commands)) {
27509
+ addGameCommand(
27510
+ groupCommand,
27511
+ run,
27512
+ notify,
27513
+ `${name} ${command2}`,
27514
+ definition
27515
+ );
27516
+ }
27517
+ }
27275
27518
  return program2;
27276
27519
  }
27277
27520
  function trackHelp(command2, run, target2, helpCommand) {
@@ -27288,8 +27531,11 @@ function trackHelp(command2, run, target2, helpCommand) {
27288
27531
  function addSchemaCommand(program2, run) {
27289
27532
  const schemaCommand = program2.command("schema").description(
27290
27533
  "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."
27291
- ).argument("<command>", "Game command name").action((name) => {
27292
- const definition = commands[name];
27534
+ ).argument(
27535
+ "<command...>",
27536
+ "Game command name, such as gather or house build"
27537
+ ).action((words) => {
27538
+ const definition = gameCommands[words.join(" ")];
27293
27539
  if (!definition) {
27294
27540
  throw invalidArguments(
27295
27541
  ["command"],
@@ -27359,8 +27605,8 @@ function addDocumentCommands(program2, run) {
27359
27605
  ).login();
27360
27606
  });
27361
27607
  }
27362
- function addGameCommand(program2, run, notify, name, definition) {
27363
- const command2 = program2.command(name).description(definition.help);
27608
+ function addGameCommand(parent, run, notify, name, definition) {
27609
+ const command2 = parent.command(name.slice(name.lastIndexOf(" ") + 1)).description(definition.help);
27364
27610
  for (const [flags, description] of definition.flags) {
27365
27611
  command2.option(flags, description);
27366
27612
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clawsaga/cli",
3
- "version": "0.1.30",
3
+ "version": "0.1.31",
4
4
  "homepage": "https://clawsaga.net",
5
5
  "repository": {
6
6
  "type": "git",