@acedatacloud/skills 2026.726.10 → 2026.726.11

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@acedatacloud/skills",
3
- "version": "2026.726.10",
3
+ "version": "2026.726.11",
4
4
  "description": "Agent Skills for AceDataCloud AI services — music, image, video generation, LLM chat, web search. Compatible with Claude Code, GitHub Copilot, Gemini CLI, OpenAI Codex, and 30+ AI coding agents.",
5
5
  "keywords": [
6
6
  "agent-skills",
@@ -334,17 +334,23 @@ class _ImgFinder(_HTMLParser):
334
334
  text = self.get_starttag_text() or ""
335
335
  line, col = self.getpos()
336
336
  start = self._line_starts[line - 1] + col
337
+ # If the computed offset doesn't land on the tag we were handed, the
338
+ # line mapping is wrong and splicing would corrupt the article. Refuse
339
+ # rather than write a mangled body.
340
+ if self._html[start:start + len(text)] != text:
341
+ raise ValueError(f"offset mismatch at line {line} col {col}")
337
342
  self.spans.append((start, start + len(text), attrs))
338
343
 
339
344
  handle_starttag = _record
340
345
  handle_startendtag = _record
341
346
 
342
347
  def find(self, html):
343
- # getpos() is (line, col); precompute line offsets to map to an index.
344
- self._line_starts, pos = [0], 0
345
- for ln in html.splitlines(keepends=True):on \r, \v, \f, \x1c-\x1e, \x85, 
, 
, and every
346
- pos += len(ln)
347
- self._line_starts.append(pos)
348
+ # getpos() is (line, col); map that to an index. HTMLParser counts
349
+ # lines with rawdata.count("\n"), so index on "\n" ONLY — str.splitlines
350
+ # also breaks on \r, \v, \f, \x1c-\x1e, \x85, 
, 
, and every
351
+ # such character would shift every subsequent offset.
352
+ self._html = html
353
+ self._line_starts = [0] + [mt.end() for mt in re.finditer("\n", html)]
348
354
  self.feed(html)
349
355
  self.close()
350
356
  return self.spans
@@ -490,6 +496,22 @@ def rehost_images(jar, html, drop_failed=False):
490
496
  failures.append(f"{src[:80]} ({e})")
491
497
  out.append(html[cursor:])
492
498
  result = "".join(out)
499
+ # Backstop: the tokenizer silently sees nothing inside an unterminated tag
500
+ # or an unterminated <script>/<style>/<textarea>/<title>, so an external
501
+ # <img> there would ship verbatim and 头条 rejects the whole article (7115).
502
+ # Our own rewrites all carry web_uri=, so any other <img left in the output
503
+ # is one we never processed. Fatal even under drop_failed — a tag the
504
+ # parser cannot see is also one we cannot remove.
505
+ unseen = [seg[:120] for seg in re.split(r"(?i)(?=<img\b)", result)[1:]
506
+ if 'web_uri="' not in seg.split(">", 1)[0][:2000]]
507
+ if unseen:
508
+ die("the article contains an <img> tag this skill could not parse, so "
509
+ "it can neither be uploaded to 头条 nor safely removed — and 头条 "
510
+ "rejects any article with an external image. Nothing was "
511
+ "published:\n - " + "\n - ".join(unseen)
512
+ + "\nUsually an unterminated tag, or an unclosed <script>/<style> "
513
+ "earlier in the body hiding it from the parser. "
514
+ "--drop-failed-images does NOT bypass this.")
493
515
  if failures and not drop_failed:
494
516
  die("could not upload these images to 头条, and 头条 rejects any article "
495
517
  "with an external image, so nothing was published:\n - "