@nomac/cli 0.10.0 → 0.10.1
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 +1 -1
- package/src/hosted-sessions.mjs +6 -1
- package/src/mac-tools.mjs +1 -1
package/package.json
CHANGED
package/src/hosted-sessions.mjs
CHANGED
|
@@ -243,7 +243,12 @@ const clockUtc = ms => new Date(ms).toISOString().slice(11, 16) + " UTC";
|
|
|
243
243
|
/** One readable paragraph for nomac status. */
|
|
244
244
|
export function statusSummary(session, image) {
|
|
245
245
|
const lines = [`${session.id}: ${session.state}`];
|
|
246
|
-
if (image?.macos)
|
|
246
|
+
if (image?.macos) {
|
|
247
|
+
// An image with a second Xcode names it and its path, as the API's image line does.
|
|
248
|
+
const others = (image.xcodes ?? []).filter(x => !x.default);
|
|
249
|
+
const xcode = others.length ? `Xcode ${image.xcode} (default) and ${others.map(x => `Xcode ${x.version} (${x.path})`).join(" and ")}` : `Xcode ${image.xcode}`;
|
|
250
|
+
lines.push(`Mac: macOS ${image.macos.split(" ")[0]}, ${xcode}${(image.simulator_runtimes ?? []).map(r => `, ${r} Simulator`).join("")}`);
|
|
251
|
+
}
|
|
247
252
|
if (["ready", "provisioning", "queued"].includes(session.state)) lines.push(`Cost so far: ${usd(session.cost?.accrued_microunits)} ($0.80/hour, billed by the minute while ready). Credit left: nomac credits`);
|
|
248
253
|
const a = session.activity ?? {};
|
|
249
254
|
if (session.state === "ready") {
|
package/src/mac-tools.mjs
CHANGED
|
@@ -31,7 +31,7 @@ export const MAC_TOOLS = [
|
|
|
31
31
|
{ name: "send_to_testflight", description: "Send a signed .ipa on the Mac to TestFlight, with the App Store Connect key kept on NoMac's server: NoMac creates the upload at Apple and the Mac sends only the file. Apple then processes the build, usually for 5 to 15 minutes with no Mac needed, and NoMac sets the app's export-compliance answer and What to Test and puts it on TestFlight for the internal testers. Repeat the call with the returned request_key to follow it: sending, processing, on_testflight or failed. Once on_testflight, publish with the returned project_id and build_id submits it for App Review. Apple asks once per app whether it uses encryption beyond HTTPS and Apple's own: pass the person's answer as uses_non_exempt_encryption, never a guess. A build number Apple already has comes back with the next free one. A step only a person can take, such as creating the app in App Store Connect, comes back as needs_human with its link.", inputSchema: schema({ session_id: session, path: { type: "string", minLength: 1, maxLength: 1024, description: "The signed .ipa on the Mac, relative to the workspace or absolute" }, notes: { type: "string", minLength: 1, maxLength: 4000, description: "What to Test, shown to testers" }, uses_non_exempt_encryption: { type: "boolean", description: "The person's answer, asked once per app: does it use encryption beyond HTTPS and Apple's own?" }, issuer_id: { type: "string", maxLength: 64 }, request_key: { ...key, description: "Repeat with the request_key from the first answer to follow that send" }, wait_seconds: { type: "integer", minimum: 0, maximum: 50, description: "Wait up to this long for progress (50 while following)" } }, ["session_id", "path"]), handler: async ({ session_id, ...body }) => text(await api("POST", `${base({ session_id })}/testflight`, { body })) },
|
|
32
32
|
{ name: "notarize", description: "Notarize a Developer ID-signed Mac app, disk image or installer on the Mac (.app, .dmg, .pkg or .zip), with the App Store Connect key kept on NoMac's server: the Mac zips an .app and sends the file to Apple with temporary credentials for this one submission. Apple checks it, usually for a few minutes, then the Mac staples the ticket so it opens without a warning, even offline. Repeat the call with the returned request_key to follow it: preparing, uploading, in_progress, stapling, then accepted, invalid or rejected with Apple's issues. Sign first with the Developer ID Application certificate (the person uploads it at nomac.app/apple), the hardened runtime and a secure timestamp: codesign --force --options runtime --timestamp --sign \"Developer ID Application: …\". Keep the Mac running until it is stapled.", inputSchema: schema({ session_id: session, path: { type: "string", minLength: 1, maxLength: 1024, description: "The .app, .dmg, .pkg or .zip on the Mac, relative to the workspace or absolute" }, issuer_id: { type: "string", maxLength: 64 }, request_key: { ...key, description: "Repeat with the request_key from the first answer to follow that notarization" }, wait_seconds: { type: "integer", minimum: 0, maximum: 50, description: "Wait up to this long for progress (50 while following)" } }, ["session_id", "path"]), handler: async ({ session_id, ...body }) => text(await api("POST", `${base({ session_id })}/notarize`, { body })) },
|
|
33
33
|
{ name: "install_secrets", description: "Install the account's secrets and signing identities on a running Mac now: every-Mac secrets, the on-request secrets named in names, and what the Mac already has; a deleted secret is removed. Macs receive every-Mac secrets on their own when they become ready, so call this after the person adds or changes one.", inputSchema: schema({ session_id: session, names: { type: "array", items: { type: "string", minLength: 1, maxLength: 128 }, maxItems: 100 } }, ["session_id"]), handler: async ({ session_id, names = [] }) => text(await api("POST", `${base({ session_id })}/secrets`, { body: { names } })) },
|
|
34
|
-
{ name: "open_mac_desktop", description: "Open the Mac's full macOS desktop in the human's browser on this machine, with mouse and keyboard and nothing to install. Use it when the human wants to see or click something on the Mac, for example Xcode, the Simulator or a sign-in window. The session must be ready. If opened_in_browser is false, give the human the returned url; it opens after they sign in to nomac.app. The session stays busy while the desktop is open and the page disconnects after 15 minutes without input. To show the iOS Simulator there, boot a device with simctl, then run open
|
|
34
|
+
{ name: "open_mac_desktop", description: "Open the Mac's full macOS desktop in the human's browser on this machine, with mouse and keyboard and nothing to install. Use it when the human wants to see or click something on the Mac, for example Xcode, the Simulator or a sign-in window. The session must be ready. If opened_in_browser is false, give the human the returned url; it opens after they sign in to nomac.app. The session stays busy while the desktop is open and the page disconnects after 15 minutes without input. To show the iOS Simulator there, boot a device with simctl, then run open -a Simulator || open -a DeviceHub in a shell with exec_mac (Xcode 27 replaced Simulator.app with Device Hub; Xcode 26's Simulator.app, kept beside it, shows iOS 27 devices too). macOS has no RDP.", inputSchema: schema({ session_id: session, open: { type: "boolean", default: true, description: "Open the link in this machine's browser." } }, ["session_id"]), handler: async ({ session_id, open = true }) => {
|
|
35
35
|
const view = await api("GET", base({ session_id }));
|
|
36
36
|
if (view?.session?.state !== "ready") return text({ error: { code: "session_not_ready", message: "The Mac is not ready. Wait until get_mac_session shows ready, then call open_mac_desktop again." } });
|
|
37
37
|
const url = desktopUrl(session_id), opened = open ? openUrl(url) : false;
|