@hasna/computer 0.1.9 → 0.1.11

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/dist/cli/index.js CHANGED
@@ -7696,9 +7696,15 @@ function print(value, json, text) {
7696
7696
  else
7697
7697
  console.log(text);
7698
7698
  }
7699
+ function hasJsonOption(options) {
7700
+ return Boolean(options?.json || options?.opts?.().json || options?.optsWithGlobals?.().json || options?.parent?.opts?.().json || options?.parent?.optsWithGlobals?.().json);
7701
+ }
7702
+ function wantsJson(actionOptions, command) {
7703
+ return hasJsonOption(actionOptions) || hasJsonOption(command);
7704
+ }
7699
7705
  function registerWebhookCommands(program2, options) {
7700
7706
  const webhooks = program2.command(options.webhooksCommandName ?? "webhooks").description("Manage Hasna event webhook subscriptions");
7701
- webhooks.command("add").description("Add or replace a webhook or command subscription").argument("<target>", "Webhook URL or command binary").requiredOption("--id <id>", "Subscription/channel identifier").option("--transport <kind>", "Transport kind: webhook or command", "webhook").option("--name <name>", "Display name").option("--type <pattern>", "Event type filter, e.g. todos.task.*").option("--source <pattern>", "Event source filter").option("--subject <pattern>", "Event subject filter").option("--severity <pattern>", "Event severity filter").option("--secret <secret>", "Webhook HMAC secret").option("--header <name=value...>", "Webhook header", collectValues, []).option("--arg <arg...>", "Command argument", collectValues, []).option("--timeout-ms <ms>", "Transport timeout in milliseconds", parseNumber).option("--retry-attempts <n>", "Maximum delivery attempts", parseNumber).option("--retry-backoff-ms <ms>", "Initial retry backoff in milliseconds", parseNumber).option("--redact <path...>", "Event field path to redact before delivery", collectValues, []).option("--disabled", "Create channel disabled", false).option("-j, --json", "Print JSON output", false).action(async (target, actionOptions) => {
7707
+ webhooks.command("add").description("Add or replace a webhook or command subscription").argument("<target>", "Webhook URL or command binary").requiredOption("--id <id>", "Subscription/channel identifier").option("--transport <kind>", "Transport kind: webhook or command", "webhook").option("--name <name>", "Display name").option("--type <pattern>", "Event type filter, e.g. todos.task.*").option("--source <pattern>", "Event source filter").option("--subject <pattern>", "Event subject filter").option("--severity <pattern>", "Event severity filter").option("--secret <secret>", "Webhook HMAC secret").option("--header <name=value...>", "Webhook header", collectValues, []).option("--arg <arg...>", "Command argument", collectValues, []).option("--timeout-ms <ms>", "Transport timeout in milliseconds", parseNumber).option("--retry-attempts <n>", "Maximum delivery attempts", parseNumber).option("--retry-backoff-ms <ms>", "Initial retry backoff in milliseconds", parseNumber).option("--redact <path...>", "Event field path to redact before delivery", collectValues, []).option("--disabled", "Create channel disabled", false).option("-j, --json", "Print JSON output", false).action(async (target, actionOptions, command) => {
7702
7708
  const timestamp = new Date().toISOString();
7703
7709
  const channel = {
7704
7710
  id: actionOptions.id,
@@ -7719,11 +7725,11 @@ function registerWebhookCommands(program2, options) {
7719
7725
  throw new Error(`Transport ${actionOptions.transport} is reserved for future use and cannot be added yet`);
7720
7726
  }
7721
7727
  const saved = await createClient(options).addChannel(channel);
7722
- print(sanitizeChannelForOutput(saved), Boolean(actionOptions.json), `Added ${saved.transport} channel ${saved.id}`);
7728
+ print(sanitizeChannelForOutput(saved), wantsJson(actionOptions, command), `Added ${saved.transport} channel ${saved.id}`);
7723
7729
  });
7724
- webhooks.command("list").description("List configured subscriptions").option("-j, --json", "Print JSON output", false).action(async (actionOptions) => {
7730
+ webhooks.command("list").description("List configured subscriptions").option("-j, --json", "Print JSON output", false).action(async (actionOptions, command) => {
7725
7731
  const channels = await createClient(options).listChannels();
7726
- if (actionOptions.json) {
7732
+ if (wantsJson(actionOptions, command)) {
7727
7733
  console.log(JSON.stringify(sanitizeChannelsForOutput(channels), null, 2));
7728
7734
  return;
7729
7735
  }
@@ -7735,11 +7741,11 @@ function registerWebhookCommands(program2, options) {
7735
7741
  console.log(`${channel.id} ${channel.enabled ? "enabled" : "disabled"} ${channel.transport} ${channel.webhook?.url ?? channel.command?.command ?? channel.transport}`);
7736
7742
  }
7737
7743
  });
7738
- webhooks.command("remove").description("Remove a subscription").argument("<id>", "Subscription/channel identifier").option("-j, --json", "Print JSON output", false).action(async (id, actionOptions) => {
7744
+ webhooks.command("remove").description("Remove a subscription").argument("<id>", "Subscription/channel identifier").option("-j, --json", "Print JSON output", false).action(async (id, actionOptions, command) => {
7739
7745
  const removed = await createClient(options).removeChannel(id);
7740
- print({ removed }, Boolean(actionOptions.json), removed ? `Removed ${id}` : `Channel not found: ${id}`);
7746
+ print({ removed }, wantsJson(actionOptions, command), removed ? `Removed ${id}` : `Channel not found: ${id}`);
7741
7747
  });
7742
- webhooks.command("test").description("Send a test event to one subscription").argument("<id>", "Subscription/channel identifier").option("--type <type>", "Event type", "events.test").option("--subject <subject>", "Event subject").option("--message <message>", "Event message", "Hasna events test delivery").option("--data <json>", "Event data JSON object").option("-j, --json", "Print JSON output", false).action(async (id, actionOptions) => {
7748
+ webhooks.command("test").description("Send a test event to one subscription").argument("<id>", "Subscription/channel identifier").option("--type <type>", "Event type", "events.test").option("--subject <subject>", "Event subject").option("--message <message>", "Event message", "Hasna events test delivery").option("--data <json>", "Event data JSON object").option("-j, --json", "Print JSON output", false).action(async (id, actionOptions, command) => {
7743
7749
  const result = await createClient(options).testChannel(id, {
7744
7750
  source: options.source,
7745
7751
  type: actionOptions.type,
@@ -7747,13 +7753,13 @@ function registerWebhookCommands(program2, options) {
7747
7753
  message: actionOptions.message,
7748
7754
  data: parseJsonObject(actionOptions.data, { test: true })
7749
7755
  });
7750
- print(result, Boolean(actionOptions.json), `${result.status}: ${result.channelId}`);
7756
+ print(result, wantsJson(actionOptions, command), `${result.status}: ${result.channelId}`);
7751
7757
  });
7752
7758
  return webhooks;
7753
7759
  }
7754
7760
  function registerEventCommands(program2, options) {
7755
7761
  const events = program2.command(options.eventsCommandName ?? "events").description("Emit, list, and replay Hasna events");
7756
- events.command("emit").description("Emit an event from this app").argument("<type>", "Event type").option("--source <source>", "Event source override").option("--subject <subject>", "Event subject").option("--severity <severity>", "Event severity", "info").option("--message <message>", "Event message").option("--dedupe-key <key>", "Dedupe key").option("--data <json>", "Event data JSON object").option("--metadata <json>", "Event metadata JSON object").option("--no-deliver", "Record without delivering").option("--no-dedupe", "Allow duplicate id/dedupeKey events").option("-j, --json", "Print JSON output", false).action(async (type, actionOptions) => {
7762
+ events.command("emit").description("Emit an event from this app").argument("<type>", "Event type").option("--source <source>", "Event source override").option("--subject <subject>", "Event subject").option("--severity <severity>", "Event severity", "info").option("--message <message>", "Event message").option("--dedupe-key <key>", "Dedupe key").option("--data <json>", "Event data JSON object").option("--metadata <json>", "Event metadata JSON object").option("--no-deliver", "Record without delivering").option("--no-dedupe", "Allow duplicate id/dedupeKey events").option("-j, --json", "Print JSON output", false).action(async (type, actionOptions, command) => {
7757
7763
  const result = await createClient(options).emit({
7758
7764
  source: actionOptions.source ?? options.source,
7759
7765
  type,
@@ -7764,9 +7770,9 @@ function registerEventCommands(program2, options) {
7764
7770
  data: parseJsonObject(actionOptions.data, {}),
7765
7771
  metadata: parseJsonObject(actionOptions.metadata, {})
7766
7772
  }, { deliver: actionOptions.deliver, dedupe: actionOptions.dedupe });
7767
- print(result, Boolean(actionOptions.json), `${result.deduped ? "Deduped" : "Emitted"} ${result.event.id} to ${result.deliveries.length} channel(s)`);
7773
+ print(result, wantsJson(actionOptions, command), `${result.deduped ? "Deduped" : "Emitted"} ${result.event.id} to ${result.deliveries.length} channel(s)`);
7768
7774
  });
7769
- events.command("list").description("List recorded events").option("--source <source>", "Filter by source").option("--type <type>", "Filter by type").option("--limit <n>", "Limit results", parseNumber).option("-j, --json", "Print JSON output", false).action(async (actionOptions) => {
7775
+ events.command("list").description("List recorded events").option("--source <source>", "Filter by source").option("--type <type>", "Filter by type").option("--limit <n>", "Limit results", parseNumber).option("-j, --json", "Print JSON output", false).action(async (actionOptions, command) => {
7770
7776
  let rows = await createClient(options).listEvents();
7771
7777
  if (actionOptions.source)
7772
7778
  rows = rows.filter((event) => event.source === actionOptions.source);
@@ -7774,7 +7780,7 @@ function registerEventCommands(program2, options) {
7774
7780
  rows = rows.filter((event) => event.type === actionOptions.type);
7775
7781
  if (actionOptions.limit)
7776
7782
  rows = rows.slice(-actionOptions.limit);
7777
- if (actionOptions.json) {
7783
+ if (wantsJson(actionOptions, command)) {
7778
7784
  console.log(JSON.stringify(rows, null, 2));
7779
7785
  return;
7780
7786
  }
@@ -7785,14 +7791,14 @@ function registerEventCommands(program2, options) {
7785
7791
  for (const event of rows)
7786
7792
  console.log(`${event.time} ${event.id} ${event.source} ${event.type} ${event.severity}`);
7787
7793
  });
7788
- events.command("replay").description("Replay recorded events").option("--id <id>", "Replay one event id").option("--source <source>", "Filter by source").option("--type <type>", "Filter by type").option("--dry-run", "Preview without delivery", false).option("-j, --json", "Print JSON output", false).action(async (actionOptions) => {
7794
+ events.command("replay").description("Replay recorded events").option("--id <id>", "Replay one event id").option("--source <source>", "Filter by source").option("--type <type>", "Filter by type").option("--dry-run", "Preview without delivery", false).option("-j, --json", "Print JSON output", false).action(async (actionOptions, command) => {
7789
7795
  const result = await createClient(options).replay({
7790
7796
  eventId: actionOptions.id,
7791
7797
  source: actionOptions.source,
7792
7798
  type: actionOptions.type,
7793
7799
  dryRun: actionOptions.dryRun
7794
7800
  });
7795
- print(result, Boolean(actionOptions.json), `Replayed ${result.events.length} event(s), ${result.deliveries.length} delivery result(s)`);
7801
+ print(result, wantsJson(actionOptions, command), `Replayed ${result.events.length} event(s), ${result.deliveries.length} delivery result(s)`);
7796
7802
  });
7797
7803
  return events;
7798
7804
  }
@@ -18456,7 +18462,7 @@ registerAppDriver(ghosttyDriver);
18456
18462
 
18457
18463
  // src/cli/index.ts
18458
18464
  var program2 = new Command;
18459
- program2.name("computer").description("Open-source computer use for AI agents \u2014 control your Mac with AI").version("0.1.0");
18465
+ program2.name("computer").description("Open-source computer use for AI agents \u2014 control your Mac with AI").version("0.1.10");
18460
18466
  program2.command("run").description("Run a computer use task").argument("<task>", "Natural language description of the task").option("-p, --provider <provider>", "AI provider (anthropic|openai)", "anthropic").option("-m, --model <model>", "Model to use").option("-s, --max-steps <n>", "Maximum number of steps", "50").option("--save-screenshots", "Save screenshots to disk", false).option("--screenshots-dir <dir>", "Directory to save screenshots").option("--system-prompt <prompt>", "Custom system prompt").option("--max-width <px>", "Max screenshot width for AI model (default: 1280)", "1280").option("--dry-run", "Plan actions without executing them", false).option("--no-preview", "Disable inline screenshot preview in terminal").option("--tag <tags...>", "Tag this session (can specify multiple)").option("--display <n>", "Display number to capture (1=main, 2=secondary)").action(async (task, opts) => {
18461
18467
  const cfg = loadConfig();
18462
18468
  const provider = opts.provider ?? cfg.provider;
package/dist/mcp/index.js CHANGED
@@ -19588,7 +19588,7 @@ function storageResult(value) {
19588
19588
  function buildServer() {
19589
19589
  const server = new McpServer({
19590
19590
  name: "computer",
19591
- version: "0.1.0"
19591
+ version: "0.1.10"
19592
19592
  });
19593
19593
  server.tool("computer_run_task", "Run a computer use task \u2014 the AI sees your screen and controls mouse/keyboard to complete it", {
19594
19594
  task: exports_external.string().describe("Natural language description of what to do"),
@@ -35498,7 +35498,7 @@ function storageResult(value) {
35498
35498
  function buildServer() {
35499
35499
  const server = new McpServer({
35500
35500
  name: "computer",
35501
- version: "0.1.0"
35501
+ version: "0.1.10"
35502
35502
  });
35503
35503
  server.tool("computer_run_task", "Run a computer use task \u2014 the AI sees your screen and controls mouse/keyboard to complete it", {
35504
35504
  task: exports_external.string().describe("Natural language description of what to do"),
@@ -35877,7 +35877,7 @@ var server = Bun.serve({
35877
35877
  return Response.json(getStats(), { headers: corsHeaders });
35878
35878
  }
35879
35879
  if (method === "GET" && (path === "/health" || path === "/")) {
35880
- return Response.json({ status: "ok", name: "computer", version: "0.1.0", port: PORT }, { headers: corsHeaders });
35880
+ return Response.json({ status: "ok", name: "computer", version: "0.1.10", port: PORT }, { headers: corsHeaders });
35881
35881
  }
35882
35882
  if (DASHBOARD_DIR && method === "GET" && (path.startsWith("/dashboard") || path === "/")) {
35883
35883
  if (path === "/" || path === "/dashboard" || path === "/dashboard/") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/computer",
3
- "version": "0.1.9",
3
+ "version": "0.1.11",
4
4
  "description": "Open-source computer use for AI agents — control your Mac with Anthropic or OpenAI. CLI + MCP server + REST API + Dashboard.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -74,7 +74,7 @@
74
74
  "license": "Apache-2.0",
75
75
  "dependencies": {
76
76
  "@anthropic-ai/sdk": "^0.39.0",
77
- "@hasna/events": "^0.1.3",
77
+ "@hasna/events": "^0.1.7",
78
78
  "@modelcontextprotocol/sdk": "^1.12.1",
79
79
  "chalk": "^5.4.1",
80
80
  "commander": "^13.1.0",