@clawops/cli 2.1.0 → 2.1.2

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/README.md CHANGED
@@ -162,6 +162,21 @@ the correct absolute binary path.
162
162
 
163
163
  To add the entry manually instead, paste this into your editor's MCP config:
164
164
 
165
+ ```json
166
+ {
167
+ "mcpServers": {
168
+ "clawops": {
169
+ "command": "npx",
170
+ "args": ["-y", "@clawops/cli", "mcp", "serve", "--read-only"]
171
+ }
172
+ }
173
+ }
174
+ ```
175
+
176
+ That form needs nothing on `$PATH` and is what a directory or an installer will copy. If you
177
+ would rather point at the binary you already have, use its absolute path — the output of
178
+ `which clawops` — with the same arguments:
179
+
165
180
  ```json
166
181
  {
167
182
  "mcpServers": {
@@ -173,7 +188,11 @@ To add the entry manually instead, paste this into your editor's MCP config:
173
188
  }
174
189
  ```
175
190
 
176
- Replace `/path/to/clawops` with the output of `which clawops`. Config file locations:
191
+ Either way, pass the arguments. `mcp serve` is what speaks the protocol, and an explicit config
192
+ is one that still reads clearly a year later. clawops does not strand a client that omits them:
193
+ run with no command at all and a pipe on stdin — how every MCP client starts a server — and it
194
+ starts `mcp serve`, saying so on stderr. Typed at a terminal, `clawops` still prints help.
195
+ Config file locations:
177
196
 
178
197
  | App | Path |
179
198
  |---|---|
@@ -523,7 +542,7 @@ pnpm dev doctor # verify toolchain
523
542
  ```bash
524
543
  pnpm dev # run CLI from src/ via tsx
525
544
  pnpm build # tsup → dist/
526
- pnpm test # vitest (1855 tests, ~13s)
545
+ pnpm test # vitest (1897 tests, ~13s)
527
546
  pnpm test:changed # vitest --changed (fast edit loop)
528
547
  pnpm test:integration # Docker-based SSH integration tests
529
548
  pnpm typecheck # tsc --noEmit
@@ -584,6 +603,7 @@ Use `pnpm changeset` to record a release note before merging a `feat` or `fix`.
584
603
  ## What's new in 2.1
585
604
 
586
605
  Private networking, hardening on every cloud, and two fixes to commands that could not start.
606
+ 2.1.1 follows with the fixes below it.
587
607
 
588
608
  ### Reach a stack over your tailnet
589
609
 
@@ -626,6 +646,25 @@ Private networking, hardening on every cloud, and two fixes to commands that cou
626
646
  - The published package carries its license, keywords and issue tracker, so it is findable on npm
627
647
  and its listing is complete.
628
648
 
649
+ ### 2.1.1
650
+
651
+ - **`clawops` started with no command and a pipe on stdin serves MCP** instead of printing help.
652
+ That is how every MCP client starts a server, and how directories that infer a run command
653
+ start one; several were getting the help text and reporting the server as broken. Typed at a
654
+ terminal, `clawops` still prints help, and so does `clawops | less`.
655
+ - The MCP config example is `npx -y @clawops/cli mcp serve`, which runs as written. It used to
656
+ say `/path/to/clawops`, which nothing could run and no directory could copy.
657
+ - The description is inside the MCP registry's 100-character limit. The one 2.1.0 shipped was
658
+ 110, and the registry refused it with a 422 after npm had already published — so 2.1.0 reached
659
+ npm and not the registry.
660
+ - `clawops harden` says a stack is not deployed, or that its state could not be read, instead of
661
+ passing along `code: -2` and a subprocess dump.
662
+ - The MCP registry backfill registers the version that was released rather than the one the
663
+ release tooling is preparing, so an entry that falls behind can actually be repaired.
664
+ - The Docker image builds. It had never been built, and did not: `npm pack --pack-destination`
665
+ does not create its destination. `pnpm verify:docker` builds it and speaks MCP to the running
666
+ container, both through its entrypoint and as a bare binary, in CI.
667
+
629
668
  ---
630
669
 
631
670
  ## What's new in 2.0.1
@@ -71,7 +71,7 @@ async function generatePlan(intent, _opts) {
71
71
  "plan/apply is not supported for the local provider. Use `clawops up` directly."
72
72
  );
73
73
  }
74
- const { version } = await import("./package-JWDMWPV3.js");
74
+ const { version } = await import("./package-JFVGCNKU.js");
75
75
  const config = getConfig();
76
76
  const instanceType = await resolveInstanceType(intent);
77
77
  const { guardOpenclawVersion, defaultOpenclawVersion } = await import("./version-guard-XVYW5WFJ.js");
@@ -12,7 +12,7 @@ import {
12
12
  } from "./chunk-2I7KCMXZ.js";
13
13
  import {
14
14
  generatePlan
15
- } from "./chunk-A2DS5SB7.js";
15
+ } from "./chunk-IQQTB7ER.js";
16
16
  import {
17
17
  validatePlan
18
18
  } from "./chunk-XFN3YDZE.js";
@@ -143,6 +143,7 @@ import { z } from "zod";
143
143
  var clawops_statusSchema = z.object({
144
144
  stackName: z.string().optional()
145
145
  });
146
+ var clawops_statusDescription = "Get what is deployed for a clawops-managed stack: public IP, gateway URL,\nSSH user, or that nothing is deployed yet. Reads stack outputs; does not\ncontact the host.\n\nUse when: the user asks what exists for a stack, or where to reach it.\n\nDo NOT use when: the user asks whether the gateway is actually WORKING \u2014\nthat needs the host, so use clawops_doctor. Also not for live logs (use\nclawops_logs_tail) or config values (use clawops_config_get).";
146
147
  var clawops_statusAnnotations = {
147
148
  title: "Get Stack Status",
148
149
  readOnlyHint: true,
@@ -155,6 +156,7 @@ var clawops_doctorSchema = z.object({
155
156
  stackName: z.string().optional(),
156
157
  failuresOnly: z.boolean().optional().default(false)
157
158
  });
159
+ var clawops_doctorDescription = "Run clawops's diagnostics and return the report: Node and Pulumi runtime, config,\nSSH key and known_hosts, cloud credentials per configured provider, and the\nsupported OpenClaw range. With stackName, also contacts the host for container\nstate, the deployed OpenClaw version, a real gateway health probe, whether the\nport is published to the internet, disk usage on the state directory, log\nrotation, and hardening drift.\n\nUse when: something is not working and you do not yet know what; before any\ndeploy, upgrade or migration; or to find out which OpenClaw version a gateway is\nactually running.\n\nDo NOT use when: you already know the problem and want to fix it. This tool only\nreports \u2014 it changes nothing, and never runs `openclaw doctor --fix`. No tool\nrepairs a gateway: `clawops gateway update` is CLI-only, so tell the user to run\nit themselves, after `clawops backup create`.\n\nEvery check carries a status: fail (something is wrong that clawops can name),\nwarn (worth knowing, not broken), info (did not apply). `ok` is false only when\nsomething failed \u2014 a fresh machine with no stacks is full of warnings and healthy.";
158
160
  var clawops_doctorAnnotations = {
159
161
  title: "Run Diagnostics",
160
162
  readOnlyHint: true,
@@ -168,6 +170,7 @@ var clawops_logs_tailSchema = z.object({
168
170
  tailLines: z.number().int().optional().default(100),
169
171
  sinceMin: z.number().int().optional()
170
172
  });
173
+ var clawops_logs_tailDescription = "Tail recent gateway logs from a clawops-managed instance.\n\nUse when: the user wants to investigate recent activity or errors, or\nasks \"what's been happening\" on the gateway.\n\nDo NOT use when: the user wants real-time streaming logs (those are not\nwell-suited to tool calls; suggest the user run `clawops logs -f` directly\nin their terminal). Do NOT use for instance-level system logs: no tool runs\narbitrary remote commands, so tell the user to run `clawops ssh --command\n'journalctl ...'` themselves.";
171
174
  var clawops_logs_tailAnnotations = {
172
175
  title: "Tail Gateway Logs",
173
176
  readOnlyHint: true,
@@ -180,6 +183,7 @@ var clawops_monitorSchema = z.object({
180
183
  stackName: z.string().optional(),
181
184
  tailLines: z.number().int().optional().default(5)
182
185
  });
186
+ var clawops_monitorDescription = "Take a live snapshot of a running clawops stack: gateway health, container\nstatus, resource usage (CPU, memory, disk), and recent log lines.\n\nUse when: the user wants to know if the gateway is running, how much\nmemory or CPU it is using, what recent log activity looks like, or\nwants a quick health overview richer than clawops_status.\n\nDo NOT use when: the user wants real-time streaming logs (use\nclawops_logs_tail or suggest `clawops logs -f`). Do NOT use for\nconfiguration queries (use clawops_config_get).";
183
187
  var clawops_monitorAnnotations = {
184
188
  title: "Monitor Stack Health",
185
189
  readOnlyHint: true,
@@ -189,6 +193,7 @@ var clawops_monitorAnnotations = {
189
193
  toolsets: ["cli", "read"]
190
194
  };
191
195
  var clawops_stacks_listSchema = z.object({});
196
+ var clawops_stacks_listDescription = 'List all clawops-managed stacks across all configured providers.\n\nUse when: the user wants an overview of their deployments, asks "what\nstacks do I have", or wants to compare stacks before an operation.\n\nDo NOT use when: the user named a specific stack \u2014 use clawops_status\ndirectly with that name.';
192
197
  var clawops_stacks_listAnnotations = {
193
198
  title: "List Stacks",
194
199
  readOnlyHint: true,
@@ -201,6 +206,7 @@ var clawops_config_getSchema = z.object({
201
206
  stackName: z.string().optional(),
202
207
  key: z.string().optional()
203
208
  });
209
+ var clawops_config_getDescription = "Read a configuration value from the remote OpenClaw gateway.\n\nUse when: the user wants to inspect current OpenClaw config (e.g., which\nmodel provider is active, which channels are enabled).\n\nDo NOT use when: the user wants to change the config \u2014 use\nclawops_config_set instead.";
204
210
  var clawops_config_getAnnotations = {
205
211
  title: "Get OpenClaw Config Value",
206
212
  readOnlyHint: true,
@@ -212,6 +218,7 @@ var clawops_config_getAnnotations = {
212
218
  var clawops_agents_listSchema = z.object({
213
219
  stackName: z.string().optional()
214
220
  });
221
+ var clawops_agents_listDescription = "List agents currently registered on the remote OpenClaw gateway.\n\nUse when: the user wants to see which agents are running, debug agent\nrouting, or count active workspaces.\n\nDo NOT use when: the user wants one agent's logs \u2014 no tool exposes those; tell\nthe user to run `clawops agents logs <name>`.";
215
222
  var clawops_agents_listAnnotations = {
216
223
  title: "List OpenClaw Agents",
217
224
  readOnlyHint: true,
@@ -231,6 +238,7 @@ var clawops_upSchema = z.object({
231
238
  openclawVersion: z.string().optional(),
232
239
  dryRun: z.boolean().optional().default(false)
233
240
  });
241
+ var clawops_upDescription = 'Provision and deploy a clawops stack. Idempotent \u2014 re-running with no spec\nchange produces no diff. Long-running (median 3min, p99 8min) so emits\nprogress notifications per R12.\n\nUse when: the user explicitly asks to deploy, provision, create, or "spin\nup" a stack. Always after the user has reviewed a plan\n(clawops_plan first when in doubt).\n\nDo NOT use when: the user has not yet generated a plan and is in\nexploratory/discovery mode \u2014 use clawops_plan first. Do NOT use for an\nexisting stack you only need to update; refresh first.';
234
242
  var clawops_upAnnotations = {
235
243
  title: "Provision and Deploy Stack",
236
244
  readOnlyHint: false,
@@ -243,6 +251,7 @@ var clawops_destroySchema = z.object({
243
251
  stackName: z.string(),
244
252
  yes: z.boolean().optional().default(false)
245
253
  });
254
+ var clawops_destroyDescription = "Destroy a clawops stack. Removes ALL provisioned resources. Triggers\nelicitation confirmation showing the resource diff before execution\n(R19). Cannot be undone.\n\nUse when: the user explicitly asks to destroy, tear down, delete, or\nremove a stack. Always confirm the stack name.\n\nDo NOT use when: the user wants to stop the gateway temporarily \u2014 that is not\na destroy, and no tool stops a gateway; clawops_gateway_restart is the only\ngateway tool. Do NOT use when in doubt about which stack; list first with\nclawops_stacks_list.";
246
255
  var clawops_destroyAnnotations = {
247
256
  title: "Destroy Stack (DESTRUCTIVE)",
248
257
  readOnlyHint: false,
@@ -255,6 +264,7 @@ var clawops_applySchema = z.object({
255
264
  planPath: z.string(),
256
265
  yes: z.boolean().optional().default(false)
257
266
  });
267
+ var clawops_applyDescription = "Apply a previously-generated Maker plan (deploy-plan.schema.json).\nDeterministic \u2014 the plan describes exactly what will be created.\n\nUse when: the user has a plan file path and wants to apply it. This is\nthe agent-friendly path for any deploy/destroy operation.\n\nDo NOT use when: there's no plan file \u2014 generate one first with\nclawops_plan.";
258
268
  var clawops_applyAnnotations = {
259
269
  title: "Apply Maker Plan",
260
270
  readOnlyHint: false,
@@ -275,6 +285,7 @@ var clawops_planSchema = z.object({
275
285
  privateOnly: z.boolean().optional(),
276
286
  outPath: z.string().optional()
277
287
  });
288
+ var clawops_planDescription = "Generate a Maker deploy plan (does NOT apply). Plan is JSON conforming to\ndeploy-plan.schema.json \u2014 review before applying.\n\nUse when: the user wants to see what would be created before committing,\nor you (the agent) need a reviewable artifact for the user to approve.\n\nDo NOT use when: the user has explicitly asked to deploy and you already\nhave their approval \u2014 go directly to clawops_up.";
278
289
  var clawops_planAnnotations = {
279
290
  title: "Generate Deploy Plan",
280
291
  readOnlyHint: true,
@@ -289,6 +300,7 @@ var clawops_config_setSchema = z.object({
289
300
  value: z.string(),
290
301
  restart: z.boolean().optional().default(false)
291
302
  });
303
+ var clawops_config_setDescription = "Set a configuration value on the remote OpenClaw gateway. Optionally\nrestarts the gateway after.\n\nUse when: the user wants to change OpenClaw configuration (model\nprovider, channel auth, gateway port).\n\nDo NOT use when: the user is reading config \u2014 use clawops_config_get.\nDo NOT bulk-edit; one key at a time so changes are auditable (R21).";
292
304
  var clawops_config_setAnnotations = {
293
305
  title: "Set OpenClaw Config Value",
294
306
  readOnlyHint: false,
@@ -302,6 +314,7 @@ var clawops_config_unsetSchema = z.object({
302
314
  key: z.string(),
303
315
  restart: z.boolean().optional().default(false)
304
316
  });
317
+ var clawops_config_unsetDescription = "Remove a configuration key from the remote OpenClaw gateway config, reverting\nit to the OpenClaw default.\n\nUse when: the user wants to delete a config key entirely (e.g., remove a\nchannel, clear an override).\n\nDo NOT use when: the user wants to set the key to a new value \u2014 use\nclawops_config_set instead.";
305
318
  var clawops_config_unsetAnnotations = {
306
319
  title: "Unset OpenClaw Config Key",
307
320
  readOnlyHint: false,
@@ -313,6 +326,7 @@ var clawops_config_unsetAnnotations = {
313
326
  var clawops_config_validateSchema = z.object({
314
327
  stackName: z.string().optional()
315
328
  });
329
+ var clawops_config_validateDescription = "Validate the remote OpenClaw gateway config against the known schema. Checks\nfor structural errors (wrong types, unknown top-level keys) that would cause\nOpenClaw to fail on startup.\n\nUse when: the user wants to verify config before restarting the gateway, or\nafter editing openclaw.json manually.\n\nDo NOT use when: the user wants to change config \u2014 use clawops_config_set.";
316
330
  var clawops_config_validateAnnotations = {
317
331
  title: "Validate OpenClaw Config",
318
332
  readOnlyHint: true,
@@ -324,6 +338,7 @@ var clawops_config_validateAnnotations = {
324
338
  var clawops_gateway_restartSchema = z.object({
325
339
  stackName: z.string().optional()
326
340
  });
341
+ var clawops_gateway_restartDescription = "Restart the OpenClaw gateway daemon on the remote instance.\n\nUse when: a gateway-wide config change requires reload, or the gateway is\nreported as unresponsive.\n\nNote: OpenClaw 2.0 removed per-agent restart; `gateway restart` is the only\nrestart it offers, and it affects every agent on the host. Brief downtime (~10s).";
327
342
  var clawops_gateway_restartAnnotations = {
328
343
  title: "Restart Gateway Daemon",
329
344
  readOnlyHint: false,
@@ -340,6 +355,7 @@ var clawops_hardenSchema = z.object({
340
355
  tailscaleRevert: z.boolean().optional().default(false),
341
356
  yes: z.boolean().optional().default(false)
342
357
  });
358
+ var clawops_hardenDescription = "Apply security hardening to a deployed stack: SSH, UFW, fail2ban,\nunattended-upgrades, the Docker socket, and per-cloud checks. Optionally join\nthe stack to a Tailscale network and reach it there instead of over the public\ninternet.\n\nUse when: the user asks to harden, secure, or lock down a stack; asks what the\nhardening report says (with dryRun: true, which changes nothing); or asks to put\na stack on their tailnet.\n\ntailscale: true installs Tailscale, joins the tailnet as clawops-<stack>, and\nthen moves clawops onto that address \u2014 but only after opening an SSH session to\nit, against host keys pinned over the connection already trusted. If that fails,\nnothing is recorded and the public address stays in use. The auth key comes from\n`clawops secret set TAILSCALE_AUTH_KEY` and is never passed through this tool\n(R6).\n\ntailscaleRevert: true takes the host back off the tailnet, over its public\naddress. On a private-only stack it refuses and names the plan/apply commands\nthat reopen SSH first \u2014 relay them rather than trying to work around it.\n\nTo close the public ports afterwards, plan with privateOnly: true and apply that\nplan; this tool does not change firewall rules.\n\nDo NOT use when: the user wants to know whether a stack is healthy \u2014 that is\nclawops_doctor. Do NOT pass tailscale and tailscaleRevert together.";
343
359
  var clawops_hardenAnnotations = {
344
360
  title: "Harden Stack",
345
361
  readOnlyHint: false,
@@ -354,6 +370,7 @@ var clawops_workflow_deploy_appSchema = z.object({
354
370
  stackName: z.string().optional().default("default"),
355
371
  instanceType: z.enum(["micro", "small", "medium", "large", "gpu"]).optional().default("small")
356
372
  });
373
+ var clawops_workflow_deploy_appDescription = 'Single-tool workflow that takes a user from "I want to deploy OpenClaw\nto <provider>" to a verified, healthy gateway. Internally: plan \u2192 user\nconfirms (elicitation) \u2192 up \u2192 wait for healthy \u2192 return URL.\n\nUse when: the user expresses end-to-end deployment intent ("deploy to\nAWS", "spin up an OpenClaw on GCP for me").\n\nDo NOT use when: the user is mid-deployment and only needs one step\n(e.g., they already have a plan; use clawops_apply). Do NOT use for\ndestroying or updating \u2014 separate workflows.';
357
374
  var clawops_workflow_deploy_appAnnotations = {
358
375
  title: "Deploy OpenClaw (End-to-End Workflow)",
359
376
  readOnlyHint: false,
@@ -365,6 +382,15 @@ var clawops_workflow_deploy_appAnnotations = {
365
382
  var clawops_workflow_recoverSchema = z.object({
366
383
  stackName: z.string().optional()
367
384
  });
385
+ var clawops_workflow_recoverDescription = `Diagnostic workflow for an unhealthy stack. Internally: status check \u2192
386
+ gateway logs \u2192 agent logs \u2192 systemd service status \u2192 produces a structured
387
+ diagnostic report with suggested remediation.
388
+
389
+ Use when: the user reports any "not working" symptom and you don't know
390
+ where to start. Best entry point for troubleshooting.
391
+
392
+ Do NOT use when: the user has already identified the problem and asks for
393
+ a specific fix.`;
368
394
  var clawops_workflow_recoverAnnotations = {
369
395
  title: "Recover/Diagnose Stack",
370
396
  readOnlyHint: true,
@@ -376,6 +402,7 @@ var clawops_workflow_recoverAnnotations = {
376
402
  var clawops_task_statusSchema = z.object({
377
403
  taskId: z.string()
378
404
  });
405
+ var clawops_task_statusDescription = "Poll the status of a long-running clawops task (returned by clawops_up,\nclawops_destroy, clawops_apply, etc.). Per R12 streaming model.\n\nUse when: the user is waiting on a long-running deploy/destroy and wants\nprogress, OR you need to check whether a previously-started operation\nfinished.\n\nDo NOT use when: there is no active taskId \u2014 start the operation first.";
379
406
  var clawops_task_statusAnnotations = {
380
407
  title: "Get Task Status",
381
408
  readOnlyHint: true,
@@ -873,7 +900,7 @@ async function handleUp(input, server) {
873
900
  const progressToken = void 0;
874
901
  const emit = makeProgressEmitter(server, progressToken);
875
902
  startTask(taskId, `clawops_up stack=${ctx.stackName}`);
876
- const { generatePlan: generatePlan2 } = await import("./generate-YEM73KVB.js");
903
+ const { generatePlan: generatePlan2 } = await import("./generate-Q2BGVMH7.js");
877
904
  const { applyPlan: applyPlan2 } = await import("./apply-HJ5GAKHW.js");
878
905
  const { resolveNetworkFlags } = await import("./network-args-PYJRJBYO.js");
879
906
  const { detectEgressIp } = await import("./firewall-5VKZ4WBH.js");
@@ -1329,29 +1356,29 @@ Error: ${err instanceof Error ? err.message : String(err)}`);
1329
1356
  }
1330
1357
 
1331
1358
  // src/mcp/tools/registry.ts
1332
- function makeEntry(schema, annotations, handler) {
1333
- return { schema, annotations, handler };
1359
+ function makeEntry(schema, annotations, handler, description) {
1360
+ return { schema, annotations, handler, description };
1334
1361
  }
1335
1362
  var TOOL_REGISTRY = {
1336
- clawops_status: makeEntry(clawops_statusSchema, clawops_statusAnnotations, handleStatus),
1337
- clawops_doctor: makeEntry(clawops_doctorSchema, clawops_doctorAnnotations, handleDoctor),
1338
- clawops_logs_tail: makeEntry(clawops_logs_tailSchema, clawops_logs_tailAnnotations, handleLogsTail),
1339
- clawops_monitor: makeEntry(clawops_monitorSchema, clawops_monitorAnnotations, handleMonitor),
1340
- clawops_stacks_list: makeEntry(clawops_stacks_listSchema, clawops_stacks_listAnnotations, handleStacksList),
1341
- clawops_config_get: makeEntry(clawops_config_getSchema, clawops_config_getAnnotations, handleConfigGet),
1342
- clawops_agents_list: makeEntry(clawops_agents_listSchema, clawops_agents_listAnnotations, handleAgentsList),
1343
- clawops_up: makeEntry(clawops_upSchema, clawops_upAnnotations, handleUp),
1344
- clawops_destroy: makeEntry(clawops_destroySchema, clawops_destroyAnnotations, handleDestroy),
1345
- clawops_apply: makeEntry(clawops_applySchema, clawops_applyAnnotations, handleApply),
1346
- clawops_plan: makeEntry(clawops_planSchema, clawops_planAnnotations, handlePlan),
1347
- clawops_harden: makeEntry(clawops_hardenSchema, clawops_hardenAnnotations, handleHarden),
1348
- clawops_config_set: makeEntry(clawops_config_setSchema, clawops_config_setAnnotations, handleConfigSet),
1349
- clawops_config_unset: makeEntry(clawops_config_unsetSchema, clawops_config_unsetAnnotations, handleConfigUnset),
1350
- clawops_config_validate: makeEntry(clawops_config_validateSchema, clawops_config_validateAnnotations, handleConfigValidate),
1351
- clawops_gateway_restart: makeEntry(clawops_gateway_restartSchema, clawops_gateway_restartAnnotations, handleGatewayRestart),
1352
- clawops_workflow_deploy_app: makeEntry(clawops_workflow_deploy_appSchema, clawops_workflow_deploy_appAnnotations, handleWorkflowDeployApp),
1353
- clawops_workflow_recover: makeEntry(clawops_workflow_recoverSchema, clawops_workflow_recoverAnnotations, handleWorkflowRecover),
1354
- clawops_task_status: makeEntry(clawops_task_statusSchema, clawops_task_statusAnnotations, handleTaskStatus)
1363
+ clawops_status: makeEntry(clawops_statusSchema, clawops_statusAnnotations, handleStatus, clawops_statusDescription),
1364
+ clawops_doctor: makeEntry(clawops_doctorSchema, clawops_doctorAnnotations, handleDoctor, clawops_doctorDescription),
1365
+ clawops_logs_tail: makeEntry(clawops_logs_tailSchema, clawops_logs_tailAnnotations, handleLogsTail, clawops_logs_tailDescription),
1366
+ clawops_monitor: makeEntry(clawops_monitorSchema, clawops_monitorAnnotations, handleMonitor, clawops_monitorDescription),
1367
+ clawops_stacks_list: makeEntry(clawops_stacks_listSchema, clawops_stacks_listAnnotations, handleStacksList, clawops_stacks_listDescription),
1368
+ clawops_config_get: makeEntry(clawops_config_getSchema, clawops_config_getAnnotations, handleConfigGet, clawops_config_getDescription),
1369
+ clawops_agents_list: makeEntry(clawops_agents_listSchema, clawops_agents_listAnnotations, handleAgentsList, clawops_agents_listDescription),
1370
+ clawops_up: makeEntry(clawops_upSchema, clawops_upAnnotations, handleUp, clawops_upDescription),
1371
+ clawops_destroy: makeEntry(clawops_destroySchema, clawops_destroyAnnotations, handleDestroy, clawops_destroyDescription),
1372
+ clawops_apply: makeEntry(clawops_applySchema, clawops_applyAnnotations, handleApply, clawops_applyDescription),
1373
+ clawops_plan: makeEntry(clawops_planSchema, clawops_planAnnotations, handlePlan, clawops_planDescription),
1374
+ clawops_harden: makeEntry(clawops_hardenSchema, clawops_hardenAnnotations, handleHarden, clawops_hardenDescription),
1375
+ clawops_config_set: makeEntry(clawops_config_setSchema, clawops_config_setAnnotations, handleConfigSet, clawops_config_setDescription),
1376
+ clawops_config_unset: makeEntry(clawops_config_unsetSchema, clawops_config_unsetAnnotations, handleConfigUnset, clawops_config_unsetDescription),
1377
+ clawops_config_validate: makeEntry(clawops_config_validateSchema, clawops_config_validateAnnotations, handleConfigValidate, clawops_config_validateDescription),
1378
+ clawops_gateway_restart: makeEntry(clawops_gateway_restartSchema, clawops_gateway_restartAnnotations, handleGatewayRestart, clawops_gateway_restartDescription),
1379
+ clawops_workflow_deploy_app: makeEntry(clawops_workflow_deploy_appSchema, clawops_workflow_deploy_appAnnotations, handleWorkflowDeployApp, clawops_workflow_deploy_appDescription),
1380
+ clawops_workflow_recover: makeEntry(clawops_workflow_recoverSchema, clawops_workflow_recoverAnnotations, handleWorkflowRecover, clawops_workflow_recoverDescription),
1381
+ clawops_task_status: makeEntry(clawops_task_statusSchema, clawops_task_statusAnnotations, handleTaskStatus, clawops_task_statusDescription)
1355
1382
  };
1356
1383
  var TOOL_NAMES = Object.keys(TOOL_REGISTRY);
1357
1384
  function resolveEnabledTools(opts) {
@@ -1380,13 +1407,16 @@ function registerTools(server, opts) {
1380
1407
  for (const toolName of enabled) {
1381
1408
  const entry = TOOL_REGISTRY[toolName];
1382
1409
  if (!entry) continue;
1383
- const { schema, annotations, handler } = entry;
1410
+ const { schema, annotations, handler, description } = entry;
1384
1411
  const { title, readOnlyHint, destructiveHint, idempotentHint, openWorldHint } = annotations;
1385
1412
  const audited = withAudit(toolName, (input) => handler(input, server));
1386
1413
  server.registerTool(
1387
1414
  toolName,
1388
1415
  {
1389
1416
  title,
1417
+ // What a model reads when it picks a tool. Written per R3 to say when to use this one
1418
+ // and when to reach for another; omitted here, every client saw a nameless capability.
1419
+ description,
1390
1420
  inputSchema: schema,
1391
1421
  annotations: { title, readOnlyHint, destructiveHint, idempotentHint, openWorldHint }
1392
1422
  },
@@ -1646,7 +1676,7 @@ function bearerFrom(header) {
1646
1676
  return match?.[1]?.trim();
1647
1677
  }
1648
1678
  async function serveMcp(opts) {
1649
- const { version } = await import("./package-JWDMWPV3.js");
1679
+ const { version } = await import("./package-JFVGCNKU.js");
1650
1680
  const makeServer = () => {
1651
1681
  const server = new McpServer({ name: "clawops", version });
1652
1682
  registerTools(server, opts);
package/dist/cli.js CHANGED
@@ -392,7 +392,7 @@ var up_default = defineCommand2({
392
392
  }
393
393
  return;
394
394
  }
395
- const { generatePlan } = await import("./generate-YEM73KVB.js");
395
+ const { generatePlan } = await import("./generate-Q2BGVMH7.js");
396
396
  const { applyPlan } = await import("./apply-HJ5GAKHW.js");
397
397
  const { resolveNetworkFlags } = await import("./network-args-PYJRJBYO.js");
398
398
  const { detectEgressIp } = await import("./firewall-5VKZ4WBH.js");
@@ -688,7 +688,7 @@ var plan_default = defineCommand5({
688
688
  },
689
689
  async run({ args }) {
690
690
  const { buildContext } = await import("./context-7VI3R6EK.js");
691
- const { generatePlan } = await import("./generate-YEM73KVB.js");
691
+ const { generatePlan } = await import("./generate-Q2BGVMH7.js");
692
692
  const { resolveNetworkFlags } = await import("./network-args-PYJRJBYO.js");
693
693
  const { detectEgressIp } = await import("./firewall-5VKZ4WBH.js");
694
694
  const ctx = buildContext(args);
@@ -2375,7 +2375,7 @@ var serveCmd = defineCommand18({
2375
2375
  inspector: { type: "boolean", description: "Enable MCP inspector" }
2376
2376
  },
2377
2377
  async run({ args }) {
2378
- const { serveMcp } = await import("./server-ZJPXPRZT.js");
2378
+ const { serveMcp } = await import("./server-B7I6HBQH.js");
2379
2379
  await serveMcp({
2380
2380
  port: args.http ? Number(args.http) : void 0,
2381
2381
  bind: args.bind,
@@ -2456,8 +2456,8 @@ var wireCmd = defineCommand18({
2456
2456
  const { buildContext } = await import("./context-7VI3R6EK.js");
2457
2457
  const { acquireSession, drainPool } = await import("./pool-PIIKJ4L2.js");
2458
2458
  const { extractBaseOutputs } = await import("./outputs-DJHBY7EE.js");
2459
- const { wireGatewayMcp } = await import("./mcp-wire-TE2ZL6HD.js");
2460
- const { MCP_HTTP_PORT } = await import("./server-ZJPXPRZT.js");
2459
+ const { wireGatewayMcp } = await import("./mcp-wire-FQOMM7MK.js");
2460
+ const { MCP_HTTP_PORT } = await import("./server-B7I6HBQH.js");
2461
2461
  const ac = new AbortController();
2462
2462
  process20.on("SIGINT", () => {
2463
2463
  ac.abort();
@@ -3561,7 +3561,7 @@ async function maybeWireGatewayMcp(opts) {
3561
3561
  if (!wireGateway) return;
3562
3562
  const { connect } = await import("./ssh-VAI5DU5M.js");
3563
3563
  const { getConfigDir: getConfigDir2 } = await import("./store-OVB3DAJR.js");
3564
- const { wireGatewayMcp } = await import("./mcp-wire-TE2ZL6HD.js");
3564
+ const { wireGatewayMcp } = await import("./mcp-wire-FQOMM7MK.js");
3565
3565
  const knownHostsPath = path2.join(getConfigDir2(), "known_hosts");
3566
3566
  const spin = spinner("Wiring gateway MCP client...");
3567
3567
  const session = await connect({
@@ -4183,7 +4183,7 @@ import { accessSync, constants } from "fs";
4183
4183
  import { execSync as execSync2 } from "child_process";
4184
4184
  var ISSUES_URL = `${REPO_URL}/issues/new`;
4185
4185
  var BODY_CAP = 2e3;
4186
- var VERSION = true ? "2.1.0" : "dev";
4186
+ var VERSION = true ? "2.1.2" : "dev";
4187
4187
  async function collectContext() {
4188
4188
  const nodeVersion = process23.version;
4189
4189
  const os3 = `${process23.platform} ${process23.arch}`;
@@ -4463,8 +4463,14 @@ function handleError(err) {
4463
4463
  process25.exit(1);
4464
4464
  }
4465
4465
 
4466
+ // src/cli/default-command.ts
4467
+ function resolveArgv(argv2, stdinIsTty) {
4468
+ if (argv2.length === 0 && !stdinIsTty) return ["mcp", "serve"];
4469
+ return [...argv2];
4470
+ }
4471
+
4466
4472
  // src/cli/index.ts
4467
- var CLI_VERSION = true ? "2.1.0" : "dev";
4473
+ var CLI_VERSION = true ? "2.1.2" : "dev";
4468
4474
  var main = defineCommand24({
4469
4475
  meta: {
4470
4476
  name: "clawops",
@@ -4507,8 +4513,14 @@ var main = defineCommand24({
4507
4513
  harden: harden_default
4508
4514
  }
4509
4515
  });
4516
+ var argv = resolveArgv(process.argv.slice(2), Boolean(process.stdin.isTTY));
4517
+ if (argv.length === 2 && argv[0] === "mcp" && process.argv.length === 2) {
4518
+ process.stderr.write(
4519
+ "[clawops] no command given and stdin is not a terminal, so starting `clawops mcp serve`. Pass `mcp serve` explicitly to make this deliberate, or run clawops from a terminal for help.\n"
4520
+ );
4521
+ }
4510
4522
  try {
4511
- await runMain(main);
4523
+ await runMain(main, { rawArgs: argv });
4512
4524
  } catch (err) {
4513
4525
  handleError(err);
4514
4526
  }
@@ -5,7 +5,7 @@ import {
5
5
  isInstanceAlias,
6
6
  parseDiffForTest,
7
7
  planId
8
- } from "./chunk-A2DS5SB7.js";
8
+ } from "./chunk-IQQTB7ER.js";
9
9
  import "./chunk-XFN3YDZE.js";
10
10
  import "./chunk-QDNFADJI.js";
11
11
  import "./chunk-JW5A7E3X.js";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  MCP_HTTP_PORT
4
- } from "./chunk-AYUX4FOF.js";
4
+ } from "./chunk-T5XCMYAV.js";
5
5
  import "./chunk-R3DTA35B.js";
6
6
  import "./chunk-BOPSG2LI.js";
7
7
  import "./chunk-6ZFIFDBJ.js";
@@ -9,7 +9,7 @@ import "./chunk-3QJBNAHW.js";
9
9
  import "./chunk-2I7KCMXZ.js";
10
10
  import "./chunk-3Z5TDXCJ.js";
11
11
  import "./chunk-AEEMRFZV.js";
12
- import "./chunk-A2DS5SB7.js";
12
+ import "./chunk-IQQTB7ER.js";
13
13
  import "./chunk-XFN3YDZE.js";
14
14
  import "./chunk-2Z7J3ERQ.js";
15
15
  import "./chunk-E4NJSJ54.js";
@@ -2,8 +2,8 @@
2
2
 
3
3
  // package.json
4
4
  var name = "@clawops/cli";
5
- var version = "2.1.0";
6
- var description = "Deploy and operate self-hosted OpenClaw across AWS, GCP, Azure and local VMs \u2014 a CLI and an MCP server in one.";
5
+ var version = "2.1.2";
6
+ var description = "Deploy self-hosted OpenClaw to AWS, GCP, Azure or a local VM \u2014 a CLI and an MCP server in one.";
7
7
  var keywords = [
8
8
  "openclaw",
9
9
  "mcp",
@@ -5,7 +5,7 @@ import {
5
5
  bearerFrom,
6
6
  isLoopbackBind,
7
7
  serveMcp
8
- } from "./chunk-AYUX4FOF.js";
8
+ } from "./chunk-T5XCMYAV.js";
9
9
  import "./chunk-R3DTA35B.js";
10
10
  import "./chunk-BOPSG2LI.js";
11
11
  import "./chunk-6ZFIFDBJ.js";
@@ -13,7 +13,7 @@ import "./chunk-3QJBNAHW.js";
13
13
  import "./chunk-2I7KCMXZ.js";
14
14
  import "./chunk-3Z5TDXCJ.js";
15
15
  import "./chunk-AEEMRFZV.js";
16
- import "./chunk-A2DS5SB7.js";
16
+ import "./chunk-IQQTB7ER.js";
17
17
  import "./chunk-XFN3YDZE.js";
18
18
  import "./chunk-2Z7J3ERQ.js";
19
19
  import "./chunk-E4NJSJ54.js";
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@clawops/cli",
3
- "version": "2.1.0",
4
- "description": "Deploy and operate self-hosted OpenClaw across AWS, GCP, Azure and local VMs — a CLI and an MCP server in one.",
3
+ "version": "2.1.2",
4
+ "description": "Deploy self-hosted OpenClaw to AWS, GCP, Azure or a local VM — a CLI and an MCP server in one.",
5
5
  "keywords": [
6
6
  "openclaw",
7
7
  "mcp",