@nomac/cli 0.17.0 → 0.18.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nomac/cli",
3
- "version": "0.17.0",
3
+ "version": "0.18.0",
4
4
  "description": "A real cloud Mac for AI agents: Xcode, the iOS Simulator, signing, TestFlight and App Store publishing, by the minute, over MCP, SSH and HTTPS.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",
package/skill/SKILL.md CHANGED
@@ -186,9 +186,9 @@ more than twice.
186
186
 
187
187
  ## Feedback
188
188
 
189
- When you stop a Mac, its answer asks for feedback. If anything got in your
190
- way, failed, was missing from the Mac or the tools, or would have saved you
191
- time, send it in a sentence or two: `report_issue` with `kind: "feedback"` and
192
- the `session_id`. Leave out code, secrets and personal data; skip it if nothing
193
- did. Send it once: a person at NoMac reads it and answers in that ticket
194
- (`report_issue` with no description shows the answer).
189
+ When you stop a Mac or a phone, its answer asks what got in your way, failed,
190
+ was missing or was slow. Answer in a sentence or two: `report_issue` with
191
+ `kind: "feedback"` and the `session_id`, or `nomac feedback "..."` after
192
+ `nomac stop`. Leave out code, secrets and personal data. Send it once: a person
193
+ at NoMac reads it and answers in that ticket (`report_issue` with no
194
+ description shows the answer).
package/src/cli.mjs CHANGED
@@ -9,6 +9,7 @@ Start:
9
9
  nomac start start a Mac, or reconnect to yours
10
10
  nomac attach use from this folder the Mac your agent started elsewhere (MCP, dashboard)
11
11
  nomac stop stop the Mac: deletes it and its files (not ~/drive), billing ends
12
+ nomac feedback "..." tell NoMac what got in your way, failed, was missing or was slow
12
13
 
13
14
  Use it:
14
15
  nomac exec -- ls run a command; prints its output, keeps its exit code
@@ -170,6 +171,20 @@ export async function main(argv) {
170
171
  console.log(describeApple(view));
171
172
  return view;
172
173
  }
174
+ case "feedback": {
175
+ // A note for NoMac, about this folder's last Mac when there is one (nomac stop asks for it).
176
+ const description = rest.join(" ").trim();
177
+ if (isHelp(rest) || description.length < 10) {
178
+ const usage = 'Usage: nomac feedback "what got in your way, failed, was missing or was slow"\n A person at NoMac reads it and answers. Leave out code, secrets and personal data.';
179
+ if (isHelp(rest)) return console.log(usage);
180
+ throw new CliError("feedback usage", usage);
181
+ }
182
+ const { sessionStore } = await import("./session-store.mjs");
183
+ const last = sessionStore().load();
184
+ const answer = await api("POST", "/api/v1/report-issue", { body: { description, kind: "feedback", ...(last?.mode === "hosted" && last.id ? { session_id: last.id } : {}) } });
185
+ console.log(answer.note ?? `Sent (${answer.ticket_id}).`);
186
+ return answer;
187
+ }
173
188
  case "whoami": {
174
189
  const [me, credit] = await Promise.all([api("GET", "/api/v1/me"), api("GET", "/api/v1/mac/credits").catch(() => null)]);
175
190
  const o = me.org ?? {}, c = credit?.credits ?? credit ?? {};
@@ -14,6 +14,8 @@ import { refreshSshConfig, sshConfigBlock, writeSshConfig } from "./ssh-config.m
14
14
  const WORKSPACE = "/Users/agent/workspace";
15
15
  /** How long the CLI keeps trying to put a project on the drive before it gives up for now. */
16
16
  const PLACE_BUDGET_MS = 120_000;
17
+ /** Stop's ask, as the API's feedback_request words it, with the CLI's way to answer (nomac feedback). */
18
+ const FEEDBACK_REQUEST = 'What got in your way, failed, was missing or was slow in this session? Tell NoMac in a sentence or two: nomac feedback "...". A person reads each one. Leave out code, secrets and personal data.';
17
19
 
18
20
  const HELP = `Nomac cloud Mac sessions
19
21
  nomac start [--wait 300] [--max-duration 7200] [--idle-timeout 600] [--max-cost 5] [--json]
@@ -385,7 +387,7 @@ export async function hostedSessionCommand(command, argv, { store = sessionStore
385
387
  : "Check: nomac status";
386
388
  // A ready Mac says what is on it, as nomac status does.
387
389
  const mac = result.session.state === "ready" && macLine(lastImage) ? `${macLine(lastImage)}\n` : "";
388
- print(`${result.attached ? `${result.attached}\n` : ""}${result.session.id}: ${result.session.state}\n${mac}${next}\n${usage}${result.warning ? `\n${result.warning}` : ""}`);
390
+ print(`${result.attached ? `${result.attached}\n` : ""}${result.session.id}: ${result.session.state}\n${mac}${next}\n${usage}${result.warning ? `\n${result.warning}` : ""}${result.feedback_request ? `\n\n${result.feedback_request}` : ""}`);
389
391
  return result;
390
392
  };
391
393
  const saveView = (local, view) => {
@@ -833,7 +835,7 @@ export async function hostedSessionCommand(command, argv, { store = sessionStore
833
835
  saveView(local, (await request("DELETE", `/api/v1/mac/sessions/${sessionId(local.id)}`)).session);
834
836
  const deadline = now() + wait * 1000;
835
837
  while (!["stopped", "failed"].includes(local.state) && now() < deadline) { await sleep(1000); await refresh(local); }
836
- return output({ session: local.snapshot });
838
+ return output({ session: local.snapshot, feedback_request: FEEDBACK_REQUEST });
837
839
  }
838
840
  await ready(local);
839
841
  if (command === "sync") {