@zaisma/cli 0.2.0 → 0.3.0

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.
Files changed (3) hide show
  1. package/README.md +1 -1
  2. package/package.json +1 -1
  3. package/zaisma.mjs +70 -40
package/README.md CHANGED
@@ -11,4 +11,4 @@ Run it with `npx @zaisma/cli <command>`, or install it once with `npm install -g
11
11
 
12
12
  `zaisma versions <slug>` lists versions and their preview links; `zaisma publish` with an older version rolls back, and `--scheduled-publish-at "2026-11-01 17:00"` publishes later (`zaisma unschedule` cancels). Files over 95 MB are sent in parts automatically, up to 500 MB each.
13
13
 
14
- Found a bug in Zaisma, or missing something? `zaisma feedback send --kind bug --title "…" --text "…"` tells us, and answers with known issues that match. `zaisma feedback` lists yours and the known issues, `zaisma feedback <id>` shows one with our replies, and `zaisma feedback add <id> --text "…"` adds to it (`--reopen` if a fixed one is back). Posts say an AI wrote them unless you add `--by-me`. Everything here uses the [developer API](https://github.com/zaisma/zaisma/blob/main/docs/DEVELOPER-API.md).
14
+ Found a bug in Zaisma, or missing something? Search the developer forum first with `zaisma forum --search "too_big"`. `zaisma forum post --kind bug --title "…" --category mcp --text "…"` starts a public topic, and `zaisma forum message …` sends Zaisma a private one (logs, an unreleased game). `zaisma forum` lists your topics and messages, `zaisma forum <topic id>` shows one with its replies, and `zaisma forum reply <topic id> --text "…"` replies (`--reopen` if a fixed one is back). Posts say an AI wrote them unless you add `--by-me`. Everything here uses the [developer API](https://github.com/zaisma/zaisma/blob/main/docs/DEVELOPER-API.md).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zaisma/cli",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Upload and publish browser games on Zaisma from the command line.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://zaisma.com",
package/zaisma.mjs CHANGED
@@ -24,13 +24,17 @@ const HELP = `Usage:
24
24
  [--scheduled-publish-at "2026-11-01 17:00"] Publish later, at this time (your computer's time zone)
25
25
  zaisma unschedule <slug> <version> Cancel a publish-later
26
26
  zaisma show <slug> [--visibility listed|unlisted|private|draft]
27
- zaisma feedback [--search "words"] Your feedback to Zaisma, and the known issues
28
- zaisma feedback <id> One item with every post, or a known issue
29
- zaisma feedback send --kind bug|gap|feature|question --title "…" --text "…" [--game <slug>]
30
- Tell Zaisma about a bug, a gap, an idea or a question
31
- zaisma feedback add <id> --text "…" [--reopen]
32
- Add to an item, reopen it, or add your case to a known issue
27
+ zaisma forum [--search "words"] Your forum topics and messages to Zaisma, or search the forum
28
+ zaisma forum <topic id> A topic with every post you can see
29
+ zaisma forum post --kind bug|gap|feature|question|talk --title "…" --category <category> --text "…"
30
+ Start a public topic in the developer forum
31
+ zaisma forum message --kind bug|gap|feature|question --title "…" --text "…" [--category <category>] [--game <slug>]
32
+ A private message: only you and Zaisma see it
33
+ zaisma forum reply <topic id> --text "…" [--reopen]
34
+ Reply, or reopen your topic when something fixed is back
33
35
  [--by-me] Mark a post as written by you; otherwise it says your AI wrote it
36
+ Categories: publishing, scans, pages, rooms, servers, passes, sdk, saves, stats, mcp, api, cli,
37
+ accounts, dashboard, reports, rules, docs, other. Markdown works in --text, or pipe the text in.
34
38
 
35
39
  Set ZAISMA_KEY to an API key from https://zaisma.com/account (under Game developers).
36
40
  Without installing: npx @zaisma/cli <command>. Installed (npm i -g @zaisma/cli): zaisma <command>.`;
@@ -168,11 +172,11 @@ async function upload(folder, opts) {
168
172
  console.log(`Still scanning. Check later with: zaisma versions ${slug}`);
169
173
  }
170
174
 
171
- const day = (ms) => new Date(ms).toISOString().slice(0, 10);
175
+ const day = (at) => at.slice(0, 10);
172
176
 
173
- function printKnown(k) {
174
- console.log(`${k.id} ${k.status.padEnd(8)} ${k.title} (${k.developers} developer${k.developers === 1 ? "" : "s"}${k.roadmap ? `, roadmap: ${k.roadmap}` : ""})`);
175
- if (k.workaround) console.log(` Until it's fixed: ${k.workaround}`);
177
+ function printTopic(topic) {
178
+ const count = topic.is_known_issue ? `, ${topic.affected_developer_count} developer${topic.affected_developer_count === 1 ? "" : "s"} affected` : topic.vote_count ? `, ${topic.vote_count} vote${topic.vote_count === 1 ? "" : "s"}` : "";
179
+ console.log(`${topic.id} ${topic.topic_status.padEnd(13)} ${topic.is_unread ? "* " : " "}${topic.title} (${topic.is_known_issue ? "known issue" : topic.kind}${count})`);
176
180
  }
177
181
 
178
182
  /** Text from --text, or piped in. */
@@ -184,45 +188,70 @@ async function readText(opts) {
184
188
  return Buffer.concat(chunks).toString("utf8").trim();
185
189
  }
186
190
 
187
- /** Feedback to Zaisma. Posts say an AI wrote them unless --by-me says the developer did. */
188
- async function feedback(opts) {
191
+ /** The developer forum. Posts say an AI wrote them unless --by-me says the developer did. */
192
+ async function forum(opts) {
189
193
  const [sub, id] = opts._;
190
- const by = opts["by-me"] ? { author: "person" } : {};
191
- if (sub === "send") {
194
+ const by = opts["by-me"] ? { author_kind: "developer" } : {};
195
+ const sent = (out) => {
196
+ if (out.check_note) console.log(out.check_note);
197
+ if (out.removed_secret_count) console.log(`${out.removed_secret_count} secret${out.removed_secret_count === 1 ? " was" : "s were"} blanked before it was stored.`);
198
+ };
199
+ if (sub === "post" || sub === "message") {
192
200
  const text = await readText(opts);
193
- if (typeof opts.kind !== "string" || typeof opts.title !== "string" || !text) fail('usage: zaisma feedback send --kind bug|gap|feature|question --title "…" --text "…" [--game <slug>]');
194
- const out = await api("POST", "/feedback", { kind: opts.kind, title: opts.title, text, ...(typeof opts.game === "string" ? { game: opts.game } : {}), ...by });
195
- console.log(`Sent (${out.feedback.id}). Zaisma will reply here: zaisma feedback ${out.feedback.id}`);
196
- if (out.secrets_removed) console.log(`${out.secrets_removed} secret${out.secrets_removed === 1 ? " was" : "s were"} blanked before it was stored.`);
197
- if (out.matches.length) {
198
- console.log("\nKnown issues that look like the same problem:");
199
- for (const k of out.matches) printKnown(k);
201
+ const isMessage = sub === "message";
202
+ const usage = isMessage
203
+ ? 'usage: zaisma forum message --kind bug|gap|feature|question --title "…" --text "…" [--category <category>] [--game <slug>]'
204
+ : 'usage: zaisma forum post --kind bug|gap|feature|question|talk --title "…" --category <category> --text "…"';
205
+ if (typeof opts.kind !== "string" || typeof opts.title !== "string" || !text || (!isMessage && typeof opts.category !== "string")) fail(usage);
206
+ const out = await api("POST", "/forum", {
207
+ kind: opts.kind,
208
+ title: opts.title,
209
+ text_markdown: text,
210
+ ...(typeof opts.category === "string" ? { category: opts.category } : {}),
211
+ ...(isMessage ? { is_public: false, ...(typeof opts.game === "string" ? { game_slug: opts.game } : {}) } : {}),
212
+ ...by,
213
+ });
214
+ console.log(`${isMessage ? "Sent to Zaisma" : "Posted"} (${out.topic.id}). Replies show here: zaisma forum ${out.topic.id}`);
215
+ sent(out);
216
+ if (out.similar_topics.length) {
217
+ console.log("\nTopics that look like the same thing (vote or reply there if one is):");
218
+ for (const topic of out.similar_topics) printTopic(topic);
200
219
  }
201
220
  return;
202
221
  }
203
- if (sub === "add") {
222
+ if (sub === "reply") {
204
223
  const text = await readText(opts);
205
- if (!id || !text) fail('usage: zaisma feedback add <id> --text "…" [--reopen]');
206
- const out = await api("POST", `/feedback/${id}/posts`, { text, ...(opts.reopen ? { reopen: true } : {}), ...by });
207
- console.log(`Added to ${out.feedback.id} (${out.feedback.status}).`);
224
+ if (!id || !text) fail('usage: zaisma forum reply <topic id> --text "…" [--reopen]');
225
+ const out = await api("POST", `/forum/${id}/posts`, { text_markdown: text, ...(opts.reopen ? { reopen: true } : {}), ...by });
226
+ console.log(`Replied in ${id}.`);
227
+ sent(out);
208
228
  return;
209
229
  }
210
230
  if (sub) {
211
- const out = await api("GET", `/feedback/${sub}`);
212
- if (!out.feedback) return printKnown(out.known_issue);
213
- const f = out.feedback;
214
- console.log(`${f.title}\n${f.kind}, ${f.status}${f.game ? `, ${f.game}` : ""}`);
215
- if (f.known_issue) printKnown(f.known_issue);
216
- for (const p of f.posts) console.log(`\n${day(p.at)} ${p.by}${p.kind === "reopen" ? " (reopened)" : ""}:\n${p.text}${p.picture_url ? `\n[screenshot] ${p.picture_url}` : ""}`);
231
+ const { topic, posts } = await api("GET", `/forum/${sub}`);
232
+ console.log(`${topic.title}\n${topic.is_known_issue ? "known issue" : topic.kind}, ${topic.topic_status}${topic.is_public ? "" : ", a message to Zaisma"}${topic.game_slug ? `, ${topic.game_slug}` : ""}`);
233
+ if (topic.workaround) console.log(`Until it's fixed: ${topic.workaround}`);
234
+ if (topic.merged_into_topic) console.log(`Part of the known issue ${topic.merged_into_topic.id}: ${topic.merged_into_topic.title}`);
235
+ const names = { developer: "", ai: "'s AI", zaisma: "" };
236
+ for (const post of posts) {
237
+ const waiting = post.check_status === "pending" ? " (being checked)" : post.check_status === "held" ? " (waiting for a person at Zaisma)" : "";
238
+ console.log(`\n${day(post.created_at)} ${post.author.name}${names[post.author.kind]}${post.kind === "reopen" ? " (reopened)" : ""}${post.is_answer ? " (the answer)" : ""}${waiting}:\n${post.text_markdown}`);
239
+ for (const image of post.media) console.log(`[image] ${image.image_url}`);
240
+ }
241
+ return;
242
+ }
243
+ if (typeof opts.search === "string") {
244
+ const { topics } = await api("GET", `/forum?detail=brief&search_text=${encodeURIComponent(opts.search)}`);
245
+ if (!topics.length) console.log("Nothing matches that. Post it with: zaisma forum post");
246
+ for (const topic of topics) printTopic(topic);
217
247
  return;
218
248
  }
219
- const q = typeof opts.search === "string" ? `?q=${encodeURIComponent(opts.search)}` : "";
220
- const { mine, known_issues } = await api("GET", `/feedback${q}`);
221
- console.log(mine.length ? "Yours (* has a reply you haven't read):" : "You haven't sent any feedback yet.");
222
- for (const f of mine) console.log(`${f.id} ${f.status.padEnd(8)} ${f.news ? "* " : " "}${f.title}`);
223
- if (known_issues.length) {
224
- console.log("\nKnown issues:");
225
- for (const k of known_issues) printKnown(k);
249
+ const [yours, messages] = await Promise.all([api("GET", "/forum?detail=brief&tab=yours"), api("GET", "/forum?detail=brief&tab=messages")]);
250
+ console.log(yours.topics.length ? "Your topics (* has something new):" : "You haven't posted in the forum yet.");
251
+ for (const topic of yours.topics) printTopic(topic);
252
+ if (messages.topics.length) {
253
+ console.log("\nYour messages to Zaisma:");
254
+ for (const topic of messages.topics) printTopic(topic);
226
255
  }
227
256
  }
228
257
 
@@ -238,7 +267,7 @@ async function main() {
238
267
  const { games, unread_topic_count } = await api("GET", "/games");
239
268
  if (!games.length) return console.log('No games yet. Make one with: zaisma new "My Game"');
240
269
  for (const g of games) console.log(`${g.slug.padEnd(28)} ${g.visibility.padEnd(9)} ${g.review_status.padEnd(8)} ${g.title}`);
241
- if (unread_topic_count) console.log(`\nZaisma replied to ${unread_topic_count} of your forum topics. See them with: zaisma feedback`);
270
+ if (unread_topic_count) console.log(`\nZaisma replied to ${unread_topic_count} of your forum topics. See them with: zaisma forum`);
242
271
  return;
243
272
  }
244
273
  if (command === "new") {
@@ -283,7 +312,8 @@ async function main() {
283
312
  const { game } = await api("PATCH", `/games/${slug}`, { visibility: opts.visibility });
284
313
  return console.log(`${game.title} is now ${game.visibility}.`);
285
314
  }
286
- if (command === "feedback") return feedback(opts);
315
+ if (command === "forum") return forum(opts);
316
+ if (command === "feedback") fail("zaisma feedback is now zaisma forum: zaisma forum lists your topics, zaisma forum message sends Zaisma a private message.");
287
317
  fail(`unknown command "${command}". Run zaisma help.`);
288
318
  }
289
319