@neta-art/neta-search-cli 0.2.45 → 0.2.47

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/README.md CHANGED
@@ -29,7 +29,7 @@ Use `@latest` (or an exact version): with a range such as `@0.2`, npx keeps runn
29
29
 
30
30
  `submit` publishes one of your skills and works inside a Cohub sandbox only, from a chat started by the space owner: it runs the static check first (see `lint`), sends this version, and waits for the result: published (with its digest) or why not. Nothing is shared until you submit: `use` only runs a skill. `submit --withdraw <name>` takes it down again; deleting the directory does not.
31
31
 
32
- `lint [name-or-dir]` checks a skill folder locally and sends nothing. **Errors** are what the skills site would reject (a missing frontmatter or description, a SKILL.md saved with Windows line endings or a byte-order mark, size limits, a SKILL.md or skill folder that is a symbolic link, anything that looks like a secret, a folder installed from someone else); `submit` stops on them. **Warnings** are suggestions and never block: other symbolic links (skipped when publishing), paths the skill mentions that are not in it, hard-coded `/workspace/...` paths (use paths relative to the skill folder or the current folder), missing or incomplete test declarations (`evals/matrix.json`), common writing problems (no rule that replies follow the user's language, no hand-off card, no `--work-title`, no out-of-scope section, non-English text hard-coded in the deliverable), ready-made non-English words for the agent to say to users, instructions not written in English (recommended, not required), and the optional `listing.json` (your skill's name and description in `en` / `zh` and up to 6 showcase Works for Studio; only Works made in Studio and shared publicly are shown, not links to other sites). It is a static check, not a review: passing it says nothing about how well the skill works. `--json` for agents.
32
+ `lint [name-or-dir]` checks a skill folder locally and sends nothing. **Errors** are what the skills site would reject (a missing frontmatter or description, a SKILL.md saved with Windows line endings or a byte-order mark, size limits, a SKILL.md or skill folder that is a symbolic link, anything that looks like a secret, a folder installed from someone else); `submit` stops on them. **Warnings** are suggestions and never block: other symbolic links (skipped when publishing), paths the skill mentions that are not in it, hard-coded `/workspace/...` paths (use paths relative to the skill folder or the current folder), missing or incomplete test declarations (`evals/matrix.json`), common writing problems (no rule that replies follow the user's language, no hand-off card, no `--work-title`, no out-of-scope section, non-English text hard-coded in the deliverable), ready-made non-English words for the agent to say to users, instructions not written in English (recommended, not required), and the optional `listing.json` (your skill's name and description in `en` / `zh` and up to 6 showcase Works for Studio; only Works made in Studio and shared publicly are shown, not links to other sites; refer to a Work by its id or its `https://neta.art/w/<id>` link). After `submit`, the result says which languages of the name and description were read and which showcase Works can be shown, and why not. It is a static check, not a review: passing it says nothing about how well the skill works. `--json` for agents.
33
33
 
34
34
  `feedback [name]` reads Neta's review feedback on your own skills (Neta reviews skills it nominates; when one needs changes, the feedback says what, where in the files, and how to fix it). Like `submit`, it works only inside a Cohub sandbox, in a chat the space owner started in that space: the server checks that you are the author before showing anything. `skills list` also marks your own skills that have feedback (it does the same check while it looks for updates; if it cannot check, it just shows the list). Without a name, `feedback` lists your skills that have feedback; with a name it saves the latest feedback to `.neta-search/skill-feedback/<name>/<version>/` (`fix-pack.json` for agents, `feedback.md` for people) and prints it. `--digest` picks a version.
35
35
 
package/neta-search.mjs CHANGED
@@ -29381,13 +29381,14 @@ var MAX_LISTING_NAME = 80;
29381
29381
  var MAX_LISTING_DESC = 300;
29382
29382
  var MAX_LISTING_WORKS = 6;
29383
29383
  var WORK_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
29384
- var WORK_LINK = /^https:\/\/(?:www\.)?neta\.art\/w\/[^\s]+$/i;
29384
+ var WORK_LINK = /^https:\/\/(?:[a-z0-9-]+\.)?neta\.art\/w\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\/?$/i;
29385
+ var APP_LINK = /^https:\/\/(?:[a-z0-9-]+\.)?neta\.art\/w\/[^\s/]+\/[^\s/]+\/[^\s/]+\/?$/i;
29385
29386
  function checkListing(files, add) {
29386
29387
  const F = "listing.json";
29387
29388
  const w = (message, fix) => add({ level: "warn", check: "listing", file: F, line: 0, message, fix });
29388
29389
  const lf = files.find((f) => f.rel === F);
29389
29390
  if (!lf) {
29390
- w("no listing.json (optional): if the Neta team features this skill in Studio, the name, description and showcase you write here are used first.", 'Add {"en": {"name", "description"}, "zh": {...}, "media": {"works": ["<id or https://neta.art/w/... link of a Work made with this skill and shared publicly>"]}}. skill-creator can write it.');
29391
+ w("no listing.json (optional): if the Neta team features this skill in Studio, the name, description and showcase you write here are used first.", 'Add {"en": {"name", "description"}, "zh": {...}, "media": {"works": ["<id or https://neta.art/w/<id> link of a Work made with this skill and shared publicly>"]}}. skill-creator can write it.');
29391
29392
  return;
29392
29393
  }
29393
29394
  let j;
@@ -29423,13 +29424,17 @@ function checkListing(files, add) {
29423
29424
  if (j.media == null) return;
29424
29425
  const works = j.media?.works;
29425
29426
  if (!Array.isArray(works)) {
29426
- w('media.works must be a list of Works: ["<id or https://neta.art/w/... link>"].');
29427
+ w('media.works must be a list of Works: ["<id or https://neta.art/w/<id> link>"].');
29427
29428
  return;
29428
29429
  }
29429
29430
  if (works.length > MAX_LISTING_WORKS) w(`media.works has ${works.length} Works; at most ${MAX_LISTING_WORKS} (the Neta team picks one).`);
29430
29431
  for (const x of works) {
29431
29432
  if (typeof x === "string" && (WORK_ID.test(x) || WORK_LINK.test(x))) continue;
29432
- w(`media.works: "${String(x).slice(0, 80)}" is not a Studio Work. Only Works made in Studio are shown (not links to other sites): they show the skill works in Studio, and sharing them publicly is how you agree to have them shown.`, "Use the id or the https://neta.art/w/... link of a Work made with this skill and shared publicly.");
29433
+ if (typeof x === "string" && APP_LINK.test(x)) {
29434
+ w(`media.works: "${x.slice(0, 80)}" is the Work's page address; the skills site cannot match it to a Work.`, "Use the Work's id, or its https://neta.art/w/<id> link (from the share menu in Studio).");
29435
+ continue;
29436
+ }
29437
+ w(`media.works: "${String(x).slice(0, 80)}" is not a Studio Work. Only Works made in Studio are shown (not links to other sites): they show the skill works in Studio, and sharing them publicly is how you agree to have them shown.`, "Use the id or the https://neta.art/w/<id> link of a Work made with this skill and shared publicly.");
29433
29438
  }
29434
29439
  }
29435
29440
  function lintSkill(dir) {
@@ -29715,11 +29720,55 @@ function finish(opts, id, digest, name, s) {
29715
29720
  } else {
29716
29721
  lines.push("It appears on the public skills site and in find at the next publish (within a few minutes), marked as a community skill. Getting into Studio needs a review.");
29717
29722
  }
29723
+ lines.push(...listingLines(s.listing));
29718
29724
  lines.push(`To take it down later: neta-search skills submit --withdraw ${name} (deleting the directory does not withdraw it).`);
29719
- return done(opts, base, lines.join("\n"), 0);
29725
+ return done(opts, s.listing ? { ...base, listing: s.listing } : base, lines.join("\n"), 0);
29720
29726
  }
29721
29727
  }
29722
29728
  }
29729
+ function listingLines(l) {
29730
+ if (!l) return [];
29731
+ const out = [];
29732
+ const text = Object.entries(l.text ?? {});
29733
+ const okLangs = text.filter(([, c]) => c.ok).map(([lang]) => lang);
29734
+ const badLangs = text.filter(([, c]) => !c.ok);
29735
+ const works = l.works ?? [];
29736
+ const hidden = works.filter((w) => !w.shown);
29737
+ const noted = works.filter((w) => w.shown && w.note);
29738
+ out.push(`listing.json: ${okLangs.length ? `name and description read for ${okLangs.join(", ")}` : "no usable name and description"}${works.length ? `; ${works.length - hidden.length} of ${works.length} showcase Work(s) can be shown` : ""}. This does not affect publishing.`);
29739
+ for (const [lang, c] of badLangs) out.push(` - ${lang}: ${textProblem(c.reason)}`);
29740
+ for (const w of hidden) out.push(` - ${w.work}: ${workProblem(w.reason)}`);
29741
+ for (const w of noted) out.push(` - ${w.work}: ${workNote(w.note)}`);
29742
+ return out;
29743
+ }
29744
+ function textProblem(r) {
29745
+ switch (r) {
29746
+ case "too_long":
29747
+ return "too long (name at most 80 characters, description at most 300), not used";
29748
+ case "empty":
29749
+ return "name or description is empty, not used";
29750
+ case "invalid":
29751
+ return "not a name and a description (or has control characters), not used";
29752
+ default:
29753
+ return r || "not usable";
29754
+ }
29755
+ }
29756
+ function workProblem(r) {
29757
+ switch (r) {
29758
+ // 作品进作品表有大约一分钟的延迟;skill-creator 的流程正好是先分享、马上提交(PR #570 review)
29759
+ case "not_found":
29760
+ return "not shown: not found yet. A Work you just shared takes a few minutes to show up, so submit again later; refer to it by its id or its https://neta.art/w/<id> link";
29761
+ case "not_public":
29762
+ return "not shown: not shared publicly yet; choose Public in the Work's share menu in Studio";
29763
+ case "not_yours":
29764
+ return "not shown: it is someone else's Work";
29765
+ default:
29766
+ return `not shown${r ? `: ${r}` : ""}`;
29767
+ }
29768
+ }
29769
+ function workNote(n) {
29770
+ return n === "not_made_with_this_skill" ? "can be shown, but it does not look like it was made with this skill; the Neta team will check" : n || "";
29771
+ }
29723
29772
  function done(opts, json, text, code) {
29724
29773
  if (opts.json) console.log(JSON.stringify(json));
29725
29774
  else (code === 0 ? console.log : console.error)(text);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neta-art/neta-search-cli",
3
- "version": "0.2.45",
3
+ "version": "0.2.47",
4
4
  "description": "neta-search CLI — find, try and install skills from the Cohub / Neta skill registry",
5
5
  "type": "module",
6
6
  "bin": {