native macOS codings agent orchestrator
6
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge pull request #97 from onevcat/onevclaw/issue-96-cli-json-schema-defs

docs(cli): define v1 JSON Schemas for command outputs

authored by

Wei Wang and committed by
GitHub
43da56f6 f8cb3b5c

+702
+702
doc-onevcat/contracts/cli/schema.md
··· 1 + # Prowl CLI JSON Schema Definitions (v1) 2 + 3 + Status: draft truth source for #96. 4 + 5 + This file provides machine-validatable JSON Schema definitions for the v1 CLI output contracts described in: 6 + 7 + - `open.md` 8 + - `list.md` 9 + - `focus.md` 10 + - `send.md` 11 + - `key.md` 12 + - `read.md` 13 + 14 + ## Scope 15 + 16 + - JSON Schema dialect: **Draft 2020-12** 17 + - Commands covered: `open`, `list`, `focus`, `send`, `key`, `read` 18 + - Each command schema is represented as `oneOf(success, error)` 19 + - Shared objects are centralized in `$defs` and reused by command schemas 20 + 21 + ## Schema bundle 22 + 23 + ```json 24 + { 25 + "$schema": "https://json-schema.org/draft/2020-12/schema", 26 + "$id": "https://prowl.onev.cat/contracts/cli/v1/schema-bundle.json", 27 + "title": "Prowl CLI Output Contract Schemas (v1)", 28 + "description": "Bundle of output JSON schemas for prowl open/list/focus/send/key/read v1", 29 + "type": "object", 30 + "additionalProperties": false, 31 + "$defs": { 32 + "uuid": { 33 + "type": "string", 34 + "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$" 35 + }, 36 + "absolutePath": { 37 + "type": "string", 38 + "minLength": 1, 39 + "pattern": "^/.*" 40 + }, 41 + "worktreeKind": { 42 + "type": "string", 43 + "enum": ["git", "plain"] 44 + }, 45 + "worktree": { 46 + "type": "object", 47 + "additionalProperties": false, 48 + "required": ["id", "name", "path", "root_path", "kind"], 49 + "properties": { 50 + "id": { "type": "string", "minLength": 1 }, 51 + "name": { "type": "string", "minLength": 1 }, 52 + "path": { "$ref": "#/$defs/absolutePath" }, 53 + "root_path": { "$ref": "#/$defs/absolutePath" }, 54 + "kind": { "$ref": "#/$defs/worktreeKind" } 55 + } 56 + }, 57 + "tabBasic": { 58 + "type": "object", 59 + "additionalProperties": false, 60 + "required": ["id", "title"], 61 + "properties": { 62 + "id": { "$ref": "#/$defs/uuid" }, 63 + "title": { "type": "string" } 64 + } 65 + }, 66 + "paneBasic": { 67 + "type": "object", 68 + "additionalProperties": false, 69 + "required": ["id", "title", "cwd"], 70 + "properties": { 71 + "id": { "$ref": "#/$defs/uuid" }, 72 + "title": { "type": "string" }, 73 + "cwd": { 74 + "type": ["string", "null"], 75 + "pattern": "^/.*" 76 + } 77 + } 78 + }, 79 + "tabSelected": { 80 + "allOf": [ 81 + { "$ref": "#/$defs/tabBasic" }, 82 + { 83 + "type": "object", 84 + "additionalProperties": false, 85 + "required": ["selected"], 86 + "properties": { 87 + "selected": { "type": "boolean" } 88 + } 89 + } 90 + ] 91 + }, 92 + "paneFocused": { 93 + "allOf": [ 94 + { "$ref": "#/$defs/paneBasic" }, 95 + { 96 + "type": "object", 97 + "additionalProperties": false, 98 + "required": ["focused"], 99 + "properties": { 100 + "focused": { "type": "boolean" } 101 + } 102 + } 103 + ] 104 + }, 105 + "openTarget": { 106 + "type": "object", 107 + "additionalProperties": false, 108 + "required": ["worktree", "tab", "pane"], 109 + "properties": { 110 + "worktree": { "$ref": "#/$defs/worktree" }, 111 + "tab": { "$ref": "#/$defs/tabBasic" }, 112 + "pane": { "$ref": "#/$defs/paneBasic" } 113 + } 114 + }, 115 + "resolvedTarget": { 116 + "type": "object", 117 + "additionalProperties": false, 118 + "required": ["worktree", "tab", "pane"], 119 + "properties": { 120 + "worktree": { "$ref": "#/$defs/worktree" }, 121 + "tab": { "$ref": "#/$defs/tabSelected" }, 122 + "pane": { "$ref": "#/$defs/paneFocused" } 123 + } 124 + }, 125 + "errorDetails": { 126 + "type": "object", 127 + "additionalProperties": true 128 + }, 129 + 130 + "openSuccess": { 131 + "type": "object", 132 + "additionalProperties": false, 133 + "required": ["ok", "command", "schema_version", "data"], 134 + "properties": { 135 + "ok": { "const": true }, 136 + "command": { "const": "open" }, 137 + "schema_version": { "const": "prowl.cli.open.v1" }, 138 + "data": { 139 + "type": "object", 140 + "additionalProperties": false, 141 + "required": [ 142 + "invocation", 143 + "requested_path", 144 + "resolved_path", 145 + "resolution", 146 + "app_launched", 147 + "brought_to_front", 148 + "created_tab", 149 + "target" 150 + ], 151 + "properties": { 152 + "invocation": { 153 + "type": "string", 154 + "enum": ["bare", "implicit-open", "open-subcommand"] 155 + }, 156 + "requested_path": { 157 + "anyOf": [ 158 + { "$ref": "#/$defs/absolutePath" }, 159 + { "type": "null" } 160 + ] 161 + }, 162 + "resolved_path": { 163 + "anyOf": [ 164 + { "$ref": "#/$defs/absolutePath" }, 165 + { "type": "null" } 166 + ] 167 + }, 168 + "resolution": { 169 + "type": "string", 170 + "enum": ["no-argument", "exact-root", "inside-root", "new-root"] 171 + }, 172 + "app_launched": { "type": "boolean" }, 173 + "brought_to_front": { "type": "boolean" }, 174 + "created_tab": { "type": "boolean" }, 175 + "target": { "$ref": "#/$defs/openTarget" } 176 + }, 177 + "allOf": [ 178 + { 179 + "if": { 180 + "properties": { "requested_path": { "type": "null" } }, 181 + "required": ["requested_path"] 182 + }, 183 + "then": { 184 + "properties": { 185 + "resolved_path": { "type": "null" }, 186 + "resolution": { "const": "no-argument" } 187 + } 188 + } 189 + }, 190 + { 191 + "if": { 192 + "properties": { 193 + "invocation": { "const": "bare" } 194 + }, 195 + "required": ["invocation"] 196 + }, 197 + "then": { 198 + "properties": { 199 + "requested_path": { "type": "null" } 200 + } 201 + } 202 + } 203 + ] 204 + } 205 + } 206 + }, 207 + "openError": { 208 + "type": "object", 209 + "additionalProperties": false, 210 + "required": ["ok", "command", "schema_version", "error"], 211 + "properties": { 212 + "ok": { "const": false }, 213 + "command": { "const": "open" }, 214 + "schema_version": { "const": "prowl.cli.open.v1" }, 215 + "error": { 216 + "type": "object", 217 + "additionalProperties": false, 218 + "required": ["code", "message"], 219 + "properties": { 220 + "code": { 221 + "type": "string", 222 + "enum": [ 223 + "INVALID_ARGUMENT", 224 + "PATH_NOT_FOUND", 225 + "PATH_NOT_DIRECTORY", 226 + "PATH_NOT_ALLOWED", 227 + "LAUNCH_FAILED", 228 + "OPEN_FAILED" 229 + ] 230 + }, 231 + "message": { "type": "string", "minLength": 1 }, 232 + "details": { "$ref": "#/$defs/errorDetails" } 233 + } 234 + } 235 + } 236 + }, 237 + "openResponse": { 238 + "oneOf": [ 239 + { "$ref": "#/$defs/openSuccess" }, 240 + { "$ref": "#/$defs/openError" } 241 + ] 242 + }, 243 + 244 + "listSuccess": { 245 + "type": "object", 246 + "additionalProperties": false, 247 + "required": ["ok", "command", "schema_version", "data"], 248 + "properties": { 249 + "ok": { "const": true }, 250 + "command": { "const": "list" }, 251 + "schema_version": { "const": "prowl.cli.list.v1" }, 252 + "data": { 253 + "type": "object", 254 + "additionalProperties": false, 255 + "required": ["count", "items"], 256 + "properties": { 257 + "count": { "type": "integer", "minimum": 0 }, 258 + "items": { 259 + "type": "array", 260 + "items": { 261 + "type": "object", 262 + "additionalProperties": false, 263 + "required": ["worktree", "tab", "pane", "task"], 264 + "properties": { 265 + "worktree": { "$ref": "#/$defs/worktree" }, 266 + "tab": { "$ref": "#/$defs/tabSelected" }, 267 + "pane": { "$ref": "#/$defs/paneFocused" }, 268 + "task": { 269 + "type": "object", 270 + "additionalProperties": false, 271 + "required": ["status"], 272 + "properties": { 273 + "status": { 274 + "type": ["string", "null"], 275 + "enum": ["idle", "running", null] 276 + } 277 + } 278 + } 279 + } 280 + } 281 + } 282 + } 283 + } 284 + } 285 + }, 286 + "listError": { 287 + "type": "object", 288 + "additionalProperties": false, 289 + "required": ["ok", "command", "schema_version", "error"], 290 + "properties": { 291 + "ok": { "const": false }, 292 + "command": { "const": "list" }, 293 + "schema_version": { "const": "prowl.cli.list.v1" }, 294 + "error": { 295 + "type": "object", 296 + "additionalProperties": false, 297 + "required": ["code", "message"], 298 + "properties": { 299 + "code": { 300 + "type": "string", 301 + "enum": ["APP_NOT_RUNNING", "LIST_FAILED"] 302 + }, 303 + "message": { "type": "string", "minLength": 1 }, 304 + "details": { "$ref": "#/$defs/errorDetails" } 305 + } 306 + } 307 + } 308 + }, 309 + "listResponse": { 310 + "oneOf": [ 311 + { "$ref": "#/$defs/listSuccess" }, 312 + { "$ref": "#/$defs/listError" } 313 + ] 314 + }, 315 + 316 + "focusSuccess": { 317 + "type": "object", 318 + "additionalProperties": false, 319 + "required": ["ok", "command", "schema_version", "data"], 320 + "properties": { 321 + "ok": { "const": true }, 322 + "command": { "const": "focus" }, 323 + "schema_version": { "const": "prowl.cli.focus.v1" }, 324 + "data": { 325 + "type": "object", 326 + "additionalProperties": false, 327 + "required": ["requested", "resolved_via", "brought_to_front", "target"], 328 + "properties": { 329 + "requested": { 330 + "type": "object", 331 + "additionalProperties": false, 332 + "required": ["selector", "value"], 333 + "properties": { 334 + "selector": { 335 + "type": "string", 336 + "enum": ["worktree", "tab", "pane", "current"] 337 + }, 338 + "value": { 339 + "type": ["string", "null"] 340 + } 341 + }, 342 + "allOf": [ 343 + { 344 + "if": { 345 + "properties": { "selector": { "const": "current" } }, 346 + "required": ["selector"] 347 + }, 348 + "then": { 349 + "properties": { 350 + "value": { "type": "null" } 351 + } 352 + } 353 + } 354 + ] 355 + }, 356 + "resolved_via": { 357 + "type": "string", 358 + "enum": ["worktree", "tab", "pane"] 359 + }, 360 + "brought_to_front": { "type": "boolean" }, 361 + "target": { "$ref": "#/$defs/resolvedTarget" } 362 + } 363 + } 364 + } 365 + }, 366 + "focusError": { 367 + "type": "object", 368 + "additionalProperties": false, 369 + "required": ["ok", "command", "schema_version", "error"], 370 + "properties": { 371 + "ok": { "const": false }, 372 + "command": { "const": "focus" }, 373 + "schema_version": { "const": "prowl.cli.focus.v1" }, 374 + "error": { 375 + "type": "object", 376 + "additionalProperties": false, 377 + "required": ["code", "message"], 378 + "properties": { 379 + "code": { 380 + "type": "string", 381 + "enum": [ 382 + "APP_NOT_RUNNING", 383 + "INVALID_ARGUMENT", 384 + "TARGET_NOT_FOUND", 385 + "TARGET_NOT_UNIQUE", 386 + "FOCUS_FAILED" 387 + ] 388 + }, 389 + "message": { "type": "string", "minLength": 1 }, 390 + "details": { "$ref": "#/$defs/errorDetails" } 391 + } 392 + } 393 + } 394 + }, 395 + "focusResponse": { 396 + "oneOf": [ 397 + { "$ref": "#/$defs/focusSuccess" }, 398 + { "$ref": "#/$defs/focusError" } 399 + ] 400 + }, 401 + 402 + "sendSuccess": { 403 + "type": "object", 404 + "additionalProperties": false, 405 + "required": ["ok", "command", "schema_version", "data"], 406 + "properties": { 407 + "ok": { "const": true }, 408 + "command": { "const": "send" }, 409 + "schema_version": { "const": "prowl.cli.send.v1" }, 410 + "data": { 411 + "type": "object", 412 + "additionalProperties": false, 413 + "required": ["target", "input", "created_tab"], 414 + "properties": { 415 + "target": { "$ref": "#/$defs/resolvedTarget" }, 416 + "input": { 417 + "type": "object", 418 + "additionalProperties": false, 419 + "required": ["source", "characters", "bytes", "trailing_enter_sent"], 420 + "properties": { 421 + "source": { 422 + "type": "string", 423 + "enum": ["argv", "stdin"] 424 + }, 425 + "characters": { 426 + "type": "integer", 427 + "minimum": 1 428 + }, 429 + "bytes": { 430 + "type": "integer", 431 + "minimum": 1 432 + }, 433 + "trailing_enter_sent": { "type": "boolean" } 434 + } 435 + }, 436 + "created_tab": { "type": "boolean" } 437 + } 438 + } 439 + } 440 + }, 441 + "sendError": { 442 + "type": "object", 443 + "additionalProperties": false, 444 + "required": ["ok", "command", "schema_version", "error"], 445 + "properties": { 446 + "ok": { "const": false }, 447 + "command": { "const": "send" }, 448 + "schema_version": { "const": "prowl.cli.send.v1" }, 449 + "error": { 450 + "type": "object", 451 + "additionalProperties": false, 452 + "required": ["code", "message"], 453 + "properties": { 454 + "code": { 455 + "type": "string", 456 + "enum": [ 457 + "APP_NOT_RUNNING", 458 + "INVALID_ARGUMENT", 459 + "TARGET_NOT_FOUND", 460 + "TARGET_NOT_UNIQUE", 461 + "EMPTY_INPUT", 462 + "SEND_FAILED" 463 + ] 464 + }, 465 + "message": { "type": "string", "minLength": 1 }, 466 + "details": { "$ref": "#/$defs/errorDetails" } 467 + } 468 + } 469 + } 470 + }, 471 + "sendResponse": { 472 + "oneOf": [ 473 + { "$ref": "#/$defs/sendSuccess" }, 474 + { "$ref": "#/$defs/sendError" } 475 + ] 476 + }, 477 + 478 + "keySuccess": { 479 + "type": "object", 480 + "additionalProperties": false, 481 + "required": ["ok", "command", "schema_version", "data"], 482 + "properties": { 483 + "ok": { "const": true }, 484 + "command": { "const": "key" }, 485 + "schema_version": { "const": "prowl.cli.key.v1" }, 486 + "data": { 487 + "type": "object", 488 + "additionalProperties": false, 489 + "required": ["requested", "key", "delivery", "target"], 490 + "properties": { 491 + "requested": { 492 + "type": "object", 493 + "additionalProperties": false, 494 + "required": ["token", "repeat"], 495 + "properties": { 496 + "token": { "type": "string", "minLength": 1 }, 497 + "repeat": { "type": "integer", "minimum": 1, "maximum": 100 } 498 + } 499 + }, 500 + "key": { 501 + "type": "object", 502 + "additionalProperties": false, 503 + "required": ["normalized", "category"], 504 + "properties": { 505 + "normalized": { 506 + "type": "string", 507 + "enum": [ 508 + "enter", 509 + "esc", 510 + "tab", 511 + "backspace", 512 + "up", 513 + "down", 514 + "left", 515 + "right", 516 + "pageup", 517 + "pagedown", 518 + "home", 519 + "end", 520 + "ctrl-c", 521 + "ctrl-d", 522 + "ctrl-l" 523 + ] 524 + }, 525 + "category": { 526 + "type": "string", 527 + "enum": ["navigation", "editing", "control"] 528 + } 529 + } 530 + }, 531 + "delivery": { 532 + "type": "object", 533 + "additionalProperties": false, 534 + "required": ["attempted", "delivered", "mode"], 535 + "properties": { 536 + "attempted": { "type": "integer", "minimum": 1, "maximum": 100 }, 537 + "delivered": { "type": "integer", "minimum": 1, "maximum": 100 }, 538 + "mode": { "const": "keyDownUp" } 539 + } 540 + }, 541 + "target": { "$ref": "#/$defs/resolvedTarget" } 542 + } 543 + } 544 + } 545 + }, 546 + "keyError": { 547 + "type": "object", 548 + "additionalProperties": false, 549 + "required": ["ok", "command", "schema_version", "error"], 550 + "properties": { 551 + "ok": { "const": false }, 552 + "command": { "const": "key" }, 553 + "schema_version": { "const": "prowl.cli.key.v1" }, 554 + "error": { 555 + "type": "object", 556 + "additionalProperties": false, 557 + "required": ["code", "message"], 558 + "properties": { 559 + "code": { 560 + "type": "string", 561 + "enum": [ 562 + "APP_NOT_RUNNING", 563 + "INVALID_ARGUMENT", 564 + "INVALID_REPEAT", 565 + "TARGET_NOT_FOUND", 566 + "TARGET_NOT_UNIQUE", 567 + "NO_ACTIVE_PANE", 568 + "UNSUPPORTED_KEY", 569 + "KEY_DELIVERY_FAILED" 570 + ] 571 + }, 572 + "message": { "type": "string", "minLength": 1 }, 573 + "details": { "$ref": "#/$defs/errorDetails" } 574 + } 575 + } 576 + } 577 + }, 578 + "keyResponse": { 579 + "oneOf": [ 580 + { "$ref": "#/$defs/keySuccess" }, 581 + { "$ref": "#/$defs/keyError" } 582 + ] 583 + }, 584 + 585 + "readSuccess": { 586 + "type": "object", 587 + "additionalProperties": false, 588 + "required": ["ok", "command", "schema_version", "data"], 589 + "properties": { 590 + "ok": { "const": true }, 591 + "command": { "const": "read" }, 592 + "schema_version": { "const": "prowl.cli.read.v1" }, 593 + "data": { 594 + "type": "object", 595 + "additionalProperties": false, 596 + "required": [ 597 + "target", 598 + "mode", 599 + "last", 600 + "source", 601 + "truncated", 602 + "line_count", 603 + "text" 604 + ], 605 + "properties": { 606 + "target": { "$ref": "#/$defs/resolvedTarget" }, 607 + "mode": { 608 + "type": "string", 609 + "enum": ["snapshot", "last"] 610 + }, 611 + "last": { 612 + "type": ["integer", "null"], 613 + "minimum": 1 614 + }, 615 + "source": { 616 + "type": "string", 617 + "enum": ["screen", "scrollback", "mixed"] 618 + }, 619 + "truncated": { "type": "boolean" }, 620 + "line_count": { "type": "integer", "minimum": 0 }, 621 + "text": { "type": "string" } 622 + }, 623 + "allOf": [ 624 + { 625 + "if": { 626 + "properties": { "mode": { "const": "snapshot" } }, 627 + "required": ["mode"] 628 + }, 629 + "then": { 630 + "properties": { 631 + "last": { "type": "null" } 632 + } 633 + } 634 + }, 635 + { 636 + "if": { 637 + "properties": { "mode": { "const": "last" } }, 638 + "required": ["mode"] 639 + }, 640 + "then": { 641 + "properties": { 642 + "last": { "type": "integer", "minimum": 1 } 643 + } 644 + } 645 + } 646 + ] 647 + } 648 + } 649 + }, 650 + "readError": { 651 + "type": "object", 652 + "additionalProperties": false, 653 + "required": ["ok", "command", "schema_version", "error"], 654 + "properties": { 655 + "ok": { "const": false }, 656 + "command": { "const": "read" }, 657 + "schema_version": { "const": "prowl.cli.read.v1" }, 658 + "error": { 659 + "type": "object", 660 + "additionalProperties": false, 661 + "required": ["code", "message"], 662 + "properties": { 663 + "code": { 664 + "type": "string", 665 + "enum": [ 666 + "APP_NOT_RUNNING", 667 + "INVALID_ARGUMENT", 668 + "TARGET_NOT_FOUND", 669 + "TARGET_NOT_UNIQUE", 670 + "READ_FAILED" 671 + ] 672 + }, 673 + "message": { "type": "string", "minLength": 1 }, 674 + "details": { "$ref": "#/$defs/errorDetails" } 675 + } 676 + } 677 + } 678 + }, 679 + "readResponse": { 680 + "oneOf": [ 681 + { "$ref": "#/$defs/readSuccess" }, 682 + { "$ref": "#/$defs/readError" } 683 + ] 684 + } 685 + } 686 + } 687 + ``` 688 + 689 + ## Usage notes 690 + 691 + - Validate `prowl open --json` output against `#/$defs/openResponse` 692 + - Validate `prowl list --json` output against `#/$defs/listResponse` 693 + - Validate `prowl focus --json` output against `#/$defs/focusResponse` 694 + - Validate `prowl send --json` output against `#/$defs/sendResponse` 695 + - Validate `prowl key --json` output against `#/$defs/keyResponse` 696 + - Validate `prowl read --json` output against `#/$defs/readResponse` 697 + 698 + ## Non-goals (v1) 699 + 700 + - This file does **not** define CLI input argument parsing schemas. 701 + - This file does **not** guarantee order-sensitive invariants that require runtime state checks across array items (for example, uniqueness of focused pane across all rows in `list`). 702 + - This file does **not** attempt to encode transport-level details (stdout/stderr split, process exit code) beyond payload shape.