@follenfang/fupload 0.0.22 → 0.0.24

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/fupload/SKILL.md CHANGED
@@ -2,7 +2,7 @@
2
2
  name: fupload
3
3
  description: Explicit author-publishing workflow for World of Warcraft plugins, configuration shares, and WA/strings on NewBeeBox, NetEase DD, CurseForge, Heybox Workshop, and ModUs.Creator, including local Creator login reuse and plugin ZIP publishing. Use only when the user explicitly invokes `$fupload`, explicitly asks to use the Fupload Skill, or loads this Skill by path. Do not trigger from ordinary mentions of publishing, NewBeeBox, DD, CurseForge, Heybox, ModUs, plugins, configurations, or WA.
4
4
  metadata:
5
- version: "0.0.22"
5
+ version: "0.0.24"
6
6
  ---
7
7
 
8
8
  # Fupload
@@ -22,7 +22,7 @@ Map natural language consistently:
22
22
 
23
23
  - `create`: create the main record. If first content is a separate platform action, plan it as a following atomic step.
24
24
  - `update`: publish a plugin version, change selected configuration-backup content, or publish a WA/string version.
25
- - `edit`: change fields allowed by the target platform's action allowlist. For DD plugins, this includes `description`, `html_desc`, and existing-record commercial, association, room/channel, and creation-statement settings; other first-publication metadata, categories, media, and version fields are create/update-only. Description edits read both detail and author-list projections; either may confirm the value, but if neither matches, report verification-required.
25
+ - `edit`: change fields allowed by the target platform's action allowlist. For DD plugins, this includes `description`, `html_desc`, `update_desc`, and existing-record commercial, association, room/channel, and creation-statement settings; other first-publication metadata, categories, media, and version fields are create/update-only. Announcement edits preserve the published version and package; this edits the current plugin announcement, not an arbitrary historical version. Edits read both detail and author-list projections; either may confirm the value, but if neither matches, report verification-required.
26
26
  - `delete`: delete one main record only. It never deletes an individual version, media object, or associated record.
27
27
 
28
28
  Never offer bulk delete, drafts, guides, messages, or GUI control automation. Heybox supports individual version deletion with asynchronous readback; whole-module deletion is not supported. The DD task-session command may close verified official GUI processes only after the consent flow below.
@@ -73,7 +73,7 @@ A published version's `update_desc` cannot be corrected through the CLI: `plugin
73
73
 
74
74
  Every path in `detail_img_files` must exist as a regular local file. Validation reports the exact indexed path, such as `$.detail_img_files[0]`, before any upload or mutation.
75
75
 
76
- `game_type` and the outer free/paid state are create-only. `plugin update` requires `sn`, `game_versions`, `version`, and `update_desc`; optional `file`, `detail_url`, and `release_type` publish a new version. `plugin edit` requires `sn` and accepts `description`, `html_desc`, plus the official existing-record commercial and association controls (`scope`, payment/lifetime/VIP fields, room/channel linkage, `creation_statement`, and associated content). Other first-publication metadata (`addon_type`, `name`, logo, detail images, and categories) and version fields are not edit fields. The CLI verifies description edits through both detail and author-list readback; if DD accepts the request but leaves the remote value unchanged, it reports a verification-required error rather than false success.
76
+ `game_type` and the outer free/paid state are create-only. `plugin update` requires `sn`, `game_versions`, `version`, and `update_desc`; optional `file`, `detail_url`, and `release_type` publish a new version. `plugin edit` requires `sn` and accepts `description`, `html_desc`, `update_desc`, plus the official existing-record commercial and association controls (`scope`, payment/lifetime/VIP fields, room/channel linkage, `creation_statement`, and associated content). Other first-publication metadata (`addon_type`, `name`, logo, detail images, and categories) and package/version fields are not edit fields. To repair the current announcement, supply only `sn` and HTML `update_desc` (at most 1000 characters including tags) to `plugin edit`; the existing published version and package URL are preserved. This does not edit arbitrary rows in version history. The CLI verifies description edits through both detail and author-list readback; if DD accepts the request but leaves the remote value unchanged, it reports a verification-required error rather than false success.
77
77
 
78
78
  When `assign_user_sn` is present, the official UI exposes only the public scope option. Python validates the final rebuilt form and rejects a private scope before upload or mutation.
79
79
 
@@ -131,12 +131,12 @@ PUT are separate stages.
131
131
  | `file_id` | `fileId` | positive integer | update/edit/delete required; upload allocates | `GET /game/data/author/project/fileId/{projectId}` | allocated ID is used by signature; create metadata omits it | update/delete/signature | `id`/`fileId` in release detail |
132
132
  | `version` | `version` | non-empty string, max 120 | create/upload required after ZIP preflight | ZIP `.toc` plus caller label | caller value preserved | metadata create/update | `version` |
133
133
  | `type` | `type` | non-empty string, max 40 | create/upload required | Creator release-type choices/API | must be a server-supported value | metadata create/update | `type` |
134
- | `supported_game_versions` | `supportedGameVersionsReqs[]` | non-empty object array | required; ZIP-derived | installed `.toc` `Interface` values and game config | each entry requires string `gameVersion` and `server`; explicit caller value must match ZIP | metadata create/update | `supportedGameVersionsReqs`/version compatibility rows |
134
+ | `supported_game_versions` | `supportedGameVersionsReqs[]` | non-empty object array | required; ZIP-derived | installed `.toc` `Interface` values and game config | each entry requires string `gameVersion` and `server`; explicit caller value must be a nonempty subset of ZIP and live `wow_builds` choices | metadata create/update | `supportedGameVersionsReqs`/version compatibility rows |
135
135
  | `md5` | `md5` | hex string, max 64 | derived from exact ZIP bytes | local ZIP preflight | must describe bytes later PUT | metadata create/update | `md5` |
136
136
  | `zip_size` | `zipSize` | non-negative integer | derived | local ZIP stat | must describe exact ZIP | metadata create/update | `zipSize` |
137
137
  | `unzip_size` | `unzipSize` | non-negative integer | derived | ZIP central directory | bounded by ZIP preflight | metadata create/update | `unzipSize` |
138
138
  | `path` | `path` | string, max 500 | metadata optional | Creator/object response | local path is never binary upload | metadata create/update | `path` |
139
- | `toc_version` | `tocVersion` | string, max 80 | derived | every ZIP `.toc` `Interface` | incompatible/missing/mixed values fail before write | metadata create/update | `tocVersion` |
139
+ | `toc_version` | `tocVersion` | string, max 80 | derived | each addon `.toc` `Interface`; TOCs under a `Libs` directory are ignored | recognized flavor TOCs form an addon union; missing values and conflicting independent addons fail before write | metadata create/update | `tocVersion` |
140
140
  | `changelog` | `changelog` | string/null, max 10000 | optional | free text | omitted/empty behavior is action-specific | metadata create/update | `changelog` |
141
141
  | `file` | not in JSON; raw bytes | local path | create/upload required | local filesystem | valid ZIP, max 200 MiB; bytes PUT only after metadata/signature | signed URL from `GET .../upload/signature/{projectId}/{fileId}`, then HTTP `PUT` | object upload status plus release detail hashes/sizes |
142
142
  | `transaction_log` | not sent | local path string | optional | caller | redacted durable stage record | local record only | transaction JSON |
@@ -147,9 +147,9 @@ binary upload stages that ran; failed records include `failed_stage`, a redacted
147
147
  error, and whether the ZIP was retained. The transaction record is established
148
148
  before file-ID allocation and ZIP preflight, so those early failures are also
149
149
  durable. Binary-upload errors expose only a query-free endpoint identifier,
150
- status when available, and a bounded redacted response summary. The provider parses every ZIP `.toc`
150
+ status when available, and a bounded redacted response summary. The provider parses each addon `.toc`
151
151
  `Interface` value to derive
152
- `toc_version` and `supported_game_versions`; explicit caller values must match.
152
+ `toc_version` and `supported_game_versions`, and ignores TOCs under a `Libs` directory. Explicit `toc_version` must match. Known clients absent from live `wow_builds` are excluded from automatic selection; unknown Interface codes still fail. Explicit `supported_game_versions` may narrow selection to a product's supported scope, but must be a nonempty subset of both ZIP and live choices. Creator `plugin get/versions` uses the Creator session; main-client addon reads retain their separate session.
153
153
  The provider validates the ZIP, computes `md5`, `zip_size`, and `unzip_size`,
154
154
  registers metadata, obtains a signed URL, then uploads the ZIP bytes with HTTP
155
155
  `PUT` and `Content-Type: application/zip`. A local path is metadata only; it is
@@ -1,3 +1,3 @@
1
1
  """Fupload Python CLI."""
2
2
 
3
- __version__ = "0.0.22"
3
+ __version__ = "0.0.24"
@@ -400,7 +400,7 @@ def main(argv: Optional[Sequence[str]] = None) -> int:
400
400
  write_output(platform, operation, data)
401
401
  return 0
402
402
  modus_doctor = platform == "modus" and resource == "session" and action == "doctor"
403
- modus_main_session = resource in ("addon", "plugin", "config", "wa", "builds") or (
403
+ modus_main_session = resource in ("addon", "config", "wa", "builds") or (
404
404
  modus_doctor and getattr(args, "client", "creator") == "main"
405
405
  )
406
406
  provider = NewBee() if platform == "newbee" else (DD() if platform == "dd" else (Blackbox() if platform == "blackbox" else (CurseForge() if platform == "curseforge" else _modus_provider(authenticate=not modus_doctor, main_session=modus_main_session))))
@@ -1469,7 +1469,7 @@ PLUGIN_CREATE_DEFAULTS = {
1469
1469
  # exceptions and are verified by detail and author-list readback after every
1470
1470
  # edit. Other first-publication metadata remains create-only.
1471
1471
  PLUGIN_EDIT_FIELDS = (
1472
- "description", "html_desc",
1472
+ "description", "html_desc", "update_desc",
1473
1473
  "scope", "share_code_life_type", "need_buy", "price_fen", "buy_life_type",
1474
1474
  "jump_room", "room_id", "channel_id", "channel_type", "sync_room",
1475
1475
  "creation_statement", "with_associate", "associated_acts", "need_anchor_vip",
@@ -24,7 +24,7 @@ from typing import Any, Dict, Mapping, Optional
24
24
 
25
25
  from .errors import FuploadError, ValidationError, redact
26
26
  from .state_machine import COMPLETE, ProjectStateMachine
27
- from .modus_zip import parse_modus_zip
27
+ from .modus_zip import parse_modus_zip, select_game_versions
28
28
  from .transport import json_request, multipart_request
29
29
 
30
30
 
@@ -1289,14 +1289,17 @@ class ModUs:
1289
1289
  supplied_games = doc.get("supported_game_versions")
1290
1290
  if supplied_toc is not None and str(supplied_toc) != derived["toc_version"]:
1291
1291
  raise ValidationError("toc_version does not match the ZIP Interface field", path="$.toc_version")
1292
- if supplied_games is not None and _supported_game_versions(supplied_games) != derived["supported_game_versions"]:
1293
- raise ValidationError("supported_game_versions does not match the ZIP Interface field", path="$.supported_game_versions")
1292
+ selected_games = select_game_versions(
1293
+ derived["supported_game_versions"],
1294
+ self.options("game-versions", keys=["wow_builds"]),
1295
+ _supported_game_versions(supplied_games) if supplied_games is not None else None,
1296
+ )
1294
1297
  metadata.update({
1295
1298
  "md5": md5,
1296
1299
  "zip_size": size,
1297
1300
  "unzip_size": unzip_size,
1298
1301
  "toc_version": derived["toc_version"],
1299
- "supported_game_versions": derived["supported_game_versions"],
1302
+ "supported_game_versions": selected_games,
1300
1303
  "path": doc.get("path") or archive.name,
1301
1304
  })
1302
1305
  current_stage = "release_metadata_update" if update else "release_metadata"
@@ -14,6 +14,7 @@ of being silently classified.
14
14
  from __future__ import annotations
15
15
 
16
16
  import io
17
+ import json
17
18
  import os
18
19
  import re
19
20
  import zipfile
@@ -38,14 +39,33 @@ INTERFACE_GAME_VERSION_MAP: Mapping[str, Mapping[str, str]] = {
38
39
  "11507": {"gameVersion": "Classic Era", "server": "wow_classic_era"},
39
40
  "11508": {"gameVersion": "Classic Era", "server": "wow_classic_era"},
40
41
  "40401": {"gameVersion": "Cataclysm Classic", "server": "wow_classic_cata"},
41
- "40402": {"gameVersion": "Cataclysm Classic", "server": "wow_classic_cata"},
42
+ "11509": {"gameVersion": "1.15.9", "server": "wow_classic_era"},
43
+ "20506": {"gameVersion": "2.5.6", "server": "wow_anniversary"},
44
+ "38002": {"gameVersion": "3.80.2", "server": "wow_classic_titan"},
45
+ "40402": {"gameVersion": "4.4.2", "server": "wow_classic_cata"},
46
+ "50504": {"gameVersion": "5.5.4", "server": "wow_classic"},
42
47
  }
43
48
 
49
+ # Recognized WoW clients in universal ZIPs which currently have no Creator
50
+ # server mapping. Preserve their Interface codes, without inventing wire keys.
51
+ KNOWN_UNMAPPED_INTERFACES = {"16001", "30405"}
52
+
44
53
  _INTERFACE_RE = re.compile(r"^\s*##\s*Interface\s*:\s*(.*?)\s*$", re.IGNORECASE)
45
54
  _INTERFACE_VALUE_RE = re.compile(r"^\d+$")
46
55
  _SOURCE = Union[str, os.PathLike[str], bytes, bytearray, memoryview, BinaryIO]
47
56
 
48
57
 
58
+ def _is_library_toc(name: str) -> bool:
59
+ """Return whether ``name`` is an embedded library TOC.
60
+
61
+ Creator's release form reads the addon TOC. Libraries such as Ace3 and
62
+ LibDeflate live under a ``Libs`` directory and declare their own Interface
63
+ values, so treating them as addons rejects packages the Creator accepts.
64
+ """
65
+ parts = name.replace("\\", "/").split("/")
66
+ return any(part.casefold() == "libs" for part in parts[:-1])
67
+
68
+
49
69
  def _read_source(source: _SOURCE) -> Tuple[bytes, str]:
50
70
  """Read a path, byte buffer, or seekable stream without leaking content."""
51
71
  if isinstance(source, (bytes, bytearray, memoryview)):
@@ -127,27 +147,43 @@ def _zip_entries(raw: bytes, source_name: str) -> Iterable[Tuple[str, bytes]]:
127
147
  def parse_modus_zip(source: _SOURCE) -> Dict[str, Any]:
128
148
  """Return ModUs metadata inferred from ``source``.
129
149
 
130
- Every ``.toc`` in the archive must declare the same Interface set. This
131
- avoids choosing an arbitrary addon when a multi-addon archive contains
132
- incompatible game versions. Multiple Interface values in one TOC are
133
- supported and become a deterministic comma-separated ``toc_version``.
150
+ Each addon's base and recognized flavor TOCs form one Interface union.
151
+ Independent addons must declare the same union. This avoids
152
+ choosing an arbitrary addon when a multi-addon archive contains
153
+ incompatible game versions. TOCs under a ``Libs`` directory are ignored.
154
+ Multiple Interface values in one TOC are supported and become a
155
+ deterministic comma-separated ``toc_version``.
134
156
 
135
157
  Returned keys are JSON-ready and use the exact snake_case names accepted
136
158
  by the Fupload ModUs schema. ``interface_values`` and ``toc_files`` are
137
159
  diagnostic fields for callers and can be omitted from the wire request.
138
160
  """
139
161
  raw, source_name = _read_source(source)
162
+ addon_entries = [
163
+ (name, toc_raw)
164
+ for name, toc_raw in _zip_entries(raw, source_name)
165
+ if not _is_library_toc(name)
166
+ ]
167
+ if not addon_entries:
168
+ raise ValidationError("ZIP contains no addon .toc file outside a Libs directory", path="$.file")
140
169
  signatures: List[Tuple[str, Tuple[str, ...]]] = []
141
- for name, toc_raw in _zip_entries(raw, source_name):
170
+ for name, toc_raw in addon_entries:
142
171
  values = tuple(_interface_values(_decode_toc(toc_raw, name), name))
143
172
  signatures.append((name, values))
144
- expected = signatures[0][1]
145
- mismatches = [name for name, values in signatures[1:] if values != expected]
173
+ groups: Dict[str, set[str]] = {}
174
+ for name, values in signatures:
175
+ normalized = name.replace("\\", "/").casefold()
176
+ addon = re.sub(r"_(?:mainline|vanilla|classic|bcc|tbc|wrath|cata|mists)\.toc$", ".toc", normalized)
177
+ groups.setdefault(addon, set()).update(values)
178
+ first = next(iter(groups))
179
+ expected = tuple(sorted(groups[first], key=lambda item: (int(item), item)))
180
+ mismatches = [name for name, values in groups.items() if values != set(expected)]
146
181
  if mismatches:
147
- names = ", ".join([signatures[0][0], *mismatches])
182
+ names = ", ".join([first, *mismatches])
148
183
  raise ValidationError("addon TOC Interface values are ambiguous across files: %s" % names, path="$.file")
149
184
 
150
- unknown = [value for value in expected if value not in INTERFACE_GAME_VERSION_MAP]
185
+ unknown = [value for value in expected
186
+ if value not in INTERFACE_GAME_VERSION_MAP and value not in KNOWN_UNMAPPED_INTERFACES]
151
187
  if unknown:
152
188
  raise ValidationError(
153
189
  "unsupported addon TOC Interface value(s): %s" % ", ".join(unknown),
@@ -156,6 +192,8 @@ def parse_modus_zip(source: _SOURCE) -> Dict[str, Any]:
156
192
 
157
193
  games: List[Dict[str, str]] = []
158
194
  for interface in expected:
195
+ if interface in KNOWN_UNMAPPED_INTERFACES:
196
+ continue
159
197
  candidate = dict(INTERFACE_GAME_VERSION_MAP[interface])
160
198
  if candidate not in games:
161
199
  games.append(candidate)
@@ -164,6 +202,7 @@ def parse_modus_zip(source: _SOURCE) -> Dict[str, Any]:
164
202
  "supported_game_versions": games,
165
203
  "interface_values": list(expected),
166
204
  "toc_files": [name for name, _ in signatures],
205
+ "unmapped_interface_values": [value for value in expected if value in KNOWN_UNMAPPED_INTERFACES],
167
206
  }
168
207
 
169
208
 
@@ -172,4 +211,29 @@ def parse_modus_zip(source: _SOURCE) -> Dict[str, Any]:
172
211
  parse_zip_metadata = parse_modus_zip
173
212
 
174
213
 
175
- __all__ = ["INTERFACE_GAME_VERSION_MAP", "parse_modus_zip", "parse_zip_metadata"]
214
+ def select_game_versions(derived: Sequence[Mapping[str, str]], config: Any,
215
+ supplied: Any = None) -> List[Dict[str, str]]:
216
+ """Intersect known ZIP clients with live Creator choices and caller scope."""
217
+ rows = config if isinstance(config, list) else []
218
+ row = next((item for item in rows if isinstance(item, Mapping) and item.get("key") == "wow_builds"), None)
219
+ try:
220
+ builds = json.loads(row["value"]) if row and isinstance(row.get("value"), str) else None
221
+ except (ValueError, TypeError):
222
+ builds = None
223
+ if not isinstance(builds, Mapping) or not builds or any(
224
+ not isinstance(value, Mapping) or not isinstance(value.get("versions"), list)
225
+ or any(not isinstance(version, str) or not version.strip() for version in value["versions"])
226
+ for value in builds.values()
227
+ ):
228
+ raise ValidationError("live wow_builds config is missing or malformed", path="$.supported_game_versions")
229
+ available = [dict(item) for item in derived
230
+ if item["server"] in builds and item["gameVersion"] in builds[item["server"]]["versions"]]
231
+ selected = available if supplied is None else supplied
232
+ if not isinstance(selected, list) or not selected or any(item not in available for item in selected):
233
+ raise ValidationError("supported_game_versions must be a nonempty subset of ZIP and live Creator choices", path="$.supported_game_versions")
234
+ if len({(item["server"], item["gameVersion"]) for item in selected}) != len(selected):
235
+ raise ValidationError("supported_game_versions must not contain duplicates", path="$.supported_game_versions")
236
+ return [dict(item) for item in selected]
237
+
238
+
239
+ __all__ = ["INTERFACE_GAME_VERSION_MAP", "parse_modus_zip", "parse_zip_metadata", "select_game_versions"]
@@ -591,6 +591,9 @@ DD_PLUGIN_VERSION = {
591
591
  "version": f("string", nonempty=True, max_length=80),
592
592
  "update_desc": f("string", nonempty=True, max_length=1000),
593
593
  }
594
+ # The official existing-plugin editor includes the update announcement in
595
+ # its /addon/modify payload. Editing it does not require a new ZIP/version.
596
+ DD_PLUGIN_EDIT_META["update_desc"] = DD_PLUGIN_VERSION["update_desc"]
594
597
 
595
598
  DD_CONFIG_META = {
596
599
  "scope": DD_COMMERCIAL["scope"], "title": f("string", nonempty=True, max_length=40),
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "schema": "fupload.npm-skill-manifest.v1",
3
3
  "package_name": "@follenfang/fupload",
4
- "package_version": "0.0.22",
5
- "skill_version": "0.0.22",
6
- "tree_sha256": "fffd84093cea75f44ca8ad836f4cfb643e692cf121162201892ad130f23fbc5a",
4
+ "package_version": "0.0.24",
5
+ "skill_version": "0.0.24",
6
+ "tree_sha256": "53bc8cdcaab317ddace896026d8668614dfaeb19f421cf0195fe4846f6e9933c",
7
7
  "files": [
8
8
  {
9
9
  "path": "agents/openai.yaml",
@@ -87,13 +87,13 @@
87
87
  },
88
88
  {
89
89
  "path": "references/dd.md",
90
- "bytes": 20837,
91
- "sha256": "4a174fa9470a23aee5c607b85123575c157559570a2d3fd4caa9a0874f9ae934"
90
+ "bytes": 21111,
91
+ "sha256": "18895d95e5221b3c2243922bbfc6f2e826f9084a0d5d11c37c3eb923a9dd7547"
92
92
  },
93
93
  {
94
94
  "path": "references/modus.md",
95
- "bytes": 37142,
96
- "sha256": "84e1524bc3404de3c3bc0582d85651b884c616ff009b1d01839fb84e348917b3"
95
+ "bytes": 37716,
96
+ "sha256": "f462731d05d786cdfd290eceaea9104b0f28814c9a5bd793358e4dc1a7abcdce"
97
97
  },
98
98
  {
99
99
  "path": "references/newbee-official-cli.md",
@@ -113,7 +113,7 @@
113
113
  {
114
114
  "path": "scripts/fupload_cli/__init__.py",
115
115
  "bytes": 50,
116
- "sha256": "0cec28503481955d702020619b9cd9b3ec7032c4d20be0bbad2aa9f4f5dac6f8"
116
+ "sha256": "8903ed57cd646124d87b730c4c5923b97cacd906cef920de53c6b91acfb554f4"
117
117
  },
118
118
  {
119
119
  "path": "scripts/fupload_cli/blackbox_web.py",
@@ -127,8 +127,8 @@
127
127
  },
128
128
  {
129
129
  "path": "scripts/fupload_cli/cli.py",
130
- "bytes": 37420,
131
- "sha256": "3a052ec53c29ca95eafc9ba845d448ef45e4bd0231bf41ec1906e55281aa1650"
130
+ "bytes": 37410,
131
+ "sha256": "97ce8e53f916f619a16351c636d90b9ddf4a64ebb301a2cf28da81d65522863d"
132
132
  },
133
133
  {
134
134
  "path": "scripts/fupload_cli/curseforge.py",
@@ -147,8 +147,8 @@
147
147
  },
148
148
  {
149
149
  "path": "scripts/fupload_cli/dd.py",
150
- "bytes": 117372,
151
- "sha256": "19a303e84ce08dd3af9a905d04d24f7224c3302f83f0d62f899618cf45fe0433"
150
+ "bytes": 117387,
151
+ "sha256": "01051273f0e03010c88590305583f404de9588e60fc708999222aa80263ebb31"
152
152
  },
153
153
  {
154
154
  "path": "scripts/fupload_cli/errors.py",
@@ -162,13 +162,13 @@
162
162
  },
163
163
  {
164
164
  "path": "scripts/fupload_cli/modus_zip.py",
165
- "bytes": 7833,
166
- "sha256": "3b35b30266dd48874f679b40d12739534ede3dc58f0c34cdd35ac2deca4e07db"
165
+ "bytes": 11445,
166
+ "sha256": "ddf603cb24d5e9758be0428446f134e02aa1a44a8be39f697b8985ac34463e2f"
167
167
  },
168
168
  {
169
169
  "path": "scripts/fupload_cli/modus.py",
170
- "bytes": 74134,
171
- "sha256": "9841ce7188083b62c1c217d89436b3c3ddc3ecf726719d3c44c0b83027172fac"
170
+ "bytes": 74167,
171
+ "sha256": "f4ac5820476593f3db0a621faac61cbed319b0a046fb35945f9a684f292d0e5f"
172
172
  },
173
173
  {
174
174
  "path": "scripts/fupload_cli/newbee_auth.py",
@@ -182,8 +182,8 @@
182
182
  },
183
183
  {
184
184
  "path": "scripts/fupload_cli/schema.py",
185
- "bytes": 54911,
186
- "sha256": "bede6cc93de8a9d766e463cab0acb8725745da781aebabba73744394b594b93c"
185
+ "bytes": 55131,
186
+ "sha256": "b651963c504896cfef46f65b61d5fb638884aacb14a8e09593162526e239133f"
187
187
  },
188
188
  {
189
189
  "path": "scripts/fupload_cli/state_machine.py",
@@ -207,8 +207,8 @@
207
207
  },
208
208
  {
209
209
  "path": "SKILL.md",
210
- "bytes": 28582,
211
- "sha256": "925b6b480edae4272a6922200a7f046e95df96908edecd4660e1fc49bdb6688d"
210
+ "bytes": 28729,
211
+ "sha256": "9625fb102b1fcc347978d0b9fe73a51703ec8296d344550938e8a2dbe593565f"
212
212
  }
213
213
  ]
214
214
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@follenfang/fupload",
3
- "version": "0.0.22",
3
+ "version": "0.0.24",
4
4
  "description": "Install and run the Fuploader Agent Skill and Python CLI.",
5
5
  "type": "module",
6
6
  "bin": {