@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 +21 -15
- package/dist/mcp/index.js +1 -1
- package/dist/server/index.js +2 -2
- package/package.json +2 -2
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),
|
|
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
|
|
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 },
|
|
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,
|
|
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,
|
|
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
|
|
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,
|
|
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.
|
|
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.
|
|
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"),
|
package/dist/server/index.js
CHANGED
|
@@ -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.
|
|
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.
|
|
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.
|
|
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.
|
|
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",
|