@nomac/cli 0.5.4 → 0.5.6
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/mac-credits.mjs +1 -0
- package/src/mac-tools.mjs +3 -3
package/package.json
CHANGED
package/src/mac-credits.mjs
CHANGED
|
@@ -9,6 +9,7 @@ const HELP = `nomac credits [--json]
|
|
|
9
9
|
nomac credits buy [--packs N] [--open] [--request-key KEY] [--json]
|
|
10
10
|
Get a payment link for the human. $10 packs, 1 to 10 per purchase;
|
|
11
11
|
each pack is 12.5 hours. $0.80 an hour, billed by the minute, never expires.
|
|
12
|
+
A first purchase of 1 pack ($10) is recommended and enough to get started.
|
|
12
13
|
Bigger purchases earn bonus credit: +5% from $30, +10% from $50, +20% at $100.
|
|
13
14
|
--open opens the link in this machine's browser (default when run by a person).
|
|
14
15
|
Reuse --request-key after a lost response; a new key is a new purchase.
|
package/src/mac-tools.mjs
CHANGED
|
@@ -7,17 +7,17 @@ const key = { type: "string", pattern: "^[A-Za-z0-9_.:-]{8,128}$" };
|
|
|
7
7
|
const schema = (properties, required = []) => ({ type: "object", properties, required, additionalProperties: false });
|
|
8
8
|
const base = args => `/api/v1/mac/sessions/${encodeURIComponent(args.session_id)}`;
|
|
9
9
|
export const MAC_TOOLS = [
|
|
10
|
-
{ name: "get_mac_checkout", description: "Get a payment link for Mac credit and open it in the human's browser on this machine. Credit is $0.80 an hour, billed by the minute, sold in $10 packs (12.5 hours each), 1 to 10 packs per purchase, and never expires. Bigger purchases earn bonus credit: +5% from 3 packs ($30), +10% from 5 ($50), +20% at 10 ($100 buys $120, 150 hours).
|
|
10
|
+
{ name: "get_mac_checkout", description: "Get a payment link for Mac credit and open it in the human's browser on this machine. Credit is $0.80 an hour, billed by the minute, sold in $10 packs (12.5 hours each), 1 to 10 packs per purchase, and never expires. Bigger purchases earn bonus credit: +5% from 3 packs ($30), +10% from 5 ($50), +20% at 10 ($100 buys $120, 150 hours). For a first purchase (get_mac_credits shows first_purchase: true), recommend 1 pack: $10 (12.5 hours) is enough to get started. For returning buyers who expect ongoing use, offer a choice, for example $10 or $50 (+10%, about 69 hours), and let them decide. Call this when get_mac_credits shows too little credit or start_mac returns insufficient_credit. Then tell the human a payment page opened (or give them the returned url if opened_in_browser is false) and ask them to pay. Never enter payment details yourself. Poll get_mac_credits until the balance appears, then start the Mac. Reuse request_key after a lost response; a new key is a new purchase.", inputSchema: schema({ packs: { type: "integer", minimum: 1, maximum: 10, default: 1, description: "Number of $10 packs, 1-10. Pick from the human's budget or expected hours; 3+ packs earn bonus credit." }, open: { type: "boolean", default: true, description: "Open the link in this machine's browser." }, request_key: key }, ["request_key"]), handler: async ({ packs = 1, open = true, request_key }) => {
|
|
11
11
|
const result = await api("POST", "/api/v1/mac/credits/checkout", { body: { packs }, idempotencyKey: request_key });
|
|
12
12
|
const opened = open && result.action === "open_checkout_url" && result.url ? openUrl(result.url) : false;
|
|
13
13
|
return text({ ...result, opened_in_browser: opened });
|
|
14
14
|
} },
|
|
15
|
-
{ name: "get_mac_credits", description: "Read the prepaid Mac credit balance: spendable dollars, spendable_seconds (how long a Mac can run on it), amounts held by a running session, pricing (including bonus_tiers for bigger purchases) and
|
|
15
|
+
{ name: "get_mac_credits", description: "Read the prepaid Mac credit balance: spendable dollars, spendable_seconds (how long a Mac can run on it), amounts held by a running session, pricing (including bonus_tiers for bigger purchases), recent purchases and first_purchase (true until the first paid top-up). Credit never expires. If spendable_seconds is below what the task needs, call get_mac_checkout.", inputSchema: schema({}), handler: async () => text(await api("GET", "/api/v1/mac/credits")) },
|
|
16
16
|
{ name: "start_mac", description: "Allocate a full cloud Mac VM, billed from prepaid credit at $0.80 an hour by the minute. If it returns insufficient_credit, call get_mac_checkout, have the human pay, then retry with the same request_key. Supply a stable request_key; SSH public_key is optional for HTTPS-only agents; reuse both after a lost response. Inspect the returned offer and limits. Poll get_mac_session until ready. No project pipeline is imposed; stop_mac deletes the VM and files.", inputSchema: schema({ public_key: { type: "string" }, request_key: key, limits: { type: "object", properties: { max_duration_seconds: { type: "integer", minimum: 60, maximum: 28800 }, idle_timeout_seconds: { type: "integer", minimum: 60, maximum: 3600 }, spend_cap_microunits: { type: "string", pattern: "^[1-9][0-9]{0,17}$" } }, additionalProperties: false } }, ["request_key"]), handler: async ({ request_key, ...body }) => text(await api("POST", "/api/v1/mac/sessions", { body, idempotencyKey: request_key })) },
|
|
17
17
|
{ name: "list_mac_sessions", description: "Find existing Mac sessions, including after losing a response. Shows state, cost, limits and cleanup.", inputSchema: schema({}), handler: async () => text(await api("GET", "/api/v1/mac/sessions")) },
|
|
18
18
|
{ name: "get_mac_session", description: "Read live Mac allocation state, cost, funded time and cleanup confirmation. queued/provisioning means wait; stopping is not yet confirmed cleanup.", inputSchema: schema({ session_id: session }, ["session_id"]), handler: async args => text(await api("GET", base(args))) },
|
|
19
19
|
{ name: "stop_mac", description: "Stop billing by shutting down the VM and deleting its files. Retrieve files first. Poll get_mac_session until cleanup_confirmed; stopping only acknowledges the request.", inputSchema: schema({ session_id: session }, ["session_id"]), handler: async args => text(await api("DELETE", base(args))) },
|
|
20
|
-
{ name: "exec_mac", description: "Run any argv command in your cloud Mac workspace. Returns a durable job ID; poll get_mac_job and read_mac_output. Reuse request_key and identical arguments after lost responses; never submit a new key blindly. Use bash -lc explicitly for shell syntax. timeout_seconds defaults to 300 and caps at 600; raise it for slow work such as a first simulator boot, which needs about 90 seconds.", inputSchema: schema({ session_id: session, request_key: key, argv: { type: "array", items: { type: "string" }, minItems: 1 }, timeout_seconds: { type: "integer", minimum: 1, maximum: 600 } }, ["session_id", "request_key", "argv"]), handler: async ({ session_id, request_key, ...body }) => text(await api("POST", `${base({ session_id })}/jobs`, { body, idempotencyKey: request_key })) },
|
|
20
|
+
{ name: "exec_mac", description: "Run any argv command in your cloud Mac workspace. Returns a durable job ID; poll get_mac_job and read_mac_output. Reuse request_key and identical arguments after lost responses; never submit a new key blindly. Use bash -lc explicitly for shell syntax. timeout_seconds defaults to 300 and caps at 600; raise it for slow work such as a first simulator boot, which needs about 90 seconds. A command (argv plus env) can be at most 64 KiB; to put larger files on the Mac, fetch them there (git clone, curl) or write them in parts of up to about 40 KiB (e.g. base64 -d >> file).", inputSchema: schema({ session_id: session, request_key: key, argv: { type: "array", items: { type: "string" }, minItems: 1 }, timeout_seconds: { type: "integer", minimum: 1, maximum: 600 } }, ["session_id", "request_key", "argv"]), handler: async ({ session_id, request_key, ...body }) => text(await api("POST", `${base({ session_id })}/jobs`, { body, idempotencyKey: request_key })) },
|
|
21
21
|
{ name: "get_mac_job", description: "Inspect the existing command without rerunning it. Retain its job ID until completion and retrieve output before stopping the VM.", inputSchema: schema({ session_id: session, job_id: job }, ["session_id", "job_id"]), handler: async args => text(await api("GET", `${base(args)}/jobs/${encodeURIComponent(args.job_id)}`)) },
|
|
22
22
|
{ name: "read_mac_output", description: "Read stdout/stderr as base64 chunks; resume from next_cursor. If truncated, the final response includes tail_base64 and its absolute tail_offset. Retrieve promptly: only recent completed jobs retain output. output_expired preserves the job receipt and never means rerun. Retrieve before stopping the VM.", inputSchema: schema({ session_id: session, job_id: job, cursor: { type: "integer", minimum: 0 }, stream: { type: "string", enum: ["stdout", "stderr"] } }, ["session_id", "job_id"]), handler: async args => text(await api("GET", `${base(args)}/jobs/${encodeURIComponent(args.job_id)}/output?${new URLSearchParams({ cursor: String(args.cursor ?? 0), stream: args.stream ?? "stdout" })}`)) },
|
|
23
23
|
];
|