@opvs-ai/cli 0.14.0 → 0.15.1

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.
@@ -84,6 +84,40 @@ export function registerFileCommands(program) {
84
84
  process.exit(1);
85
85
  }
86
86
  });
87
+ // `attachFileFromUrl` (POST /tasks/{id}/files/fetch-url) had an MCP method
88
+ // and no CLI command (ASP-85). Distinct from `attach-url`, which stores a
89
+ // LINK: this stores the BYTES. `FileService.fetch_url_to_attachment` defaults
90
+ // file_type to attachment (verbatim); `image` runs `process_cover_image`.
91
+ files
92
+ .command("fetch-url <taskId> <url>")
93
+ .description("Download the file at a public http(s) URL onto a card, server-side. Stores the BYTES in your brand's file " +
94
+ "storage (up to 50 MB), so it survives the source going away — unlike attach-url, which keeps only a link. " +
95
+ "Internal, loopback and cloud-metadata addresses are refused.")
96
+ .option("--filename <name>", "Stored filename (default: the URL's last path segment)")
97
+ .option("--description <desc>", "Attachment description")
98
+ .option("--type <type>", "attachment (default: the original bytes, verbatim) | result | input | document | data | other | image. " +
99
+ "'image' RESIZES and center-crops to a 1200x675 JPEG and does not keep the original.")
100
+ .action(async (taskId, url, opts) => {
101
+ const wsSlug = program.opts().workspace;
102
+ try {
103
+ const client = createClient(wsSlug);
104
+ const body = { url };
105
+ if (opts.filename)
106
+ body.filename = opts.filename;
107
+ if (opts.description)
108
+ body.description = opts.description;
109
+ if (opts.type)
110
+ body.file_type = opts.type;
111
+ const res = await client.post(`/api/v1/board/tasks/${taskId}/files/fetch-url`, body);
112
+ const data = await res.json();
113
+ printJson(data);
114
+ }
115
+ catch (err) {
116
+ const e = err;
117
+ console.error(`Error: ${e.detail || "Failed to fetch URL onto the task"}`);
118
+ process.exit(1);
119
+ }
120
+ });
87
121
  files
88
122
  .command("download <fileId>")
89
123
  .description("Download a file")
@@ -1 +1 @@
1
- {"version":3,"file":"files.js","sourceRoot":"","sources":["../../src/commands/files.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAErC,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AACjE,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAEtE,MAAM,UAAU,oBAAoB,CAAC,OAAgB;IACnD,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,WAAW,CAAC,uBAAuB,CAAC,CAAC;IAE5E,KAAK;SACF,OAAO,CAAC,eAAe,CAAC;SACxB,WAAW,CAAC,+BAA+B,CAAC;SAC5C,MAAM,CAAC,KAAK,EAAE,MAAc,EAAE,EAAE;QAC/B,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,SAAS,CAAC;QACxC,MAAM,GAAG,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;QACvC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;YACpC,MAAM,GAAG,GAAG,QAAQ,CAAC,uBAAuB,MAAM,QAAQ,EAAE,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;YACnF,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAClC,MAAM,aAAa,CAAC,GAAG,CAAC,CAAC;QAC3B,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,MAAM,CAAC,GAAG,GAA0B,CAAC;YACrC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,MAAM,IAAI,sBAAsB,EAAE,CAAC,CAAC;YAC9D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;IAEL,KAAK;SACF,OAAO,CAAC,wBAAwB,CAAC;SACjC,WAAW,CAAC,yBAAyB,CAAC;SACtC,MAAM,CAAC,eAAe,EAAE,2DAA2D,EAAE,YAAY,CAAC;SAClG,MAAM,CAAC,sBAAsB,EAAE,kBAAkB,CAAC;SAClD,MAAM,CAAC,KAAK,EAAE,MAAc,EAAE,QAAgB,EAAE,IAAI,EAAE,EAAE;QACvD,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,SAAS,CAAC;QACxC,MAAM,GAAG,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;QACvC,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;YACxC,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;YAEpC,qCAAqC;YACrC,MAAM,QAAQ,GAAG,WAAW,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;YACzC,MAAM,KAAK,GAAa,EAAE,CAAC;YAE3B,YAAY;YACZ,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,QAAQ,8DAA8D,QAAQ,qDAAqD,CAAC,CAAC,CAAC;YAClK,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACrB,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;YAEhC,iBAAiB;YACjB,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,QAAQ,+DAA+D,IAAI,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC;YAErH,mBAAmB;YACnB,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;gBACrB,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,QAAQ,iEAAiE,IAAI,CAAC,WAAW,MAAM,CAAC,CAAC,CAAC;YAChI,CAAC;YAED,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,QAAQ,QAAQ,CAAC,CAAC,CAAC;YAC/C,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAElC,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;YACpC,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,IAAI,CAC3B,uBAAuB,MAAM,QAAQ,EACrC,IAAI,EACJ,EAAE,cAAc,EAAE,iCAAiC,QAAQ,EAAE,EAAE,CAChE,CAAC;YACF,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;YAC9B,SAAS,CAAC,IAAI,CAAC,CAAC;QAClB,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,MAAM,CAAC,GAAG,GAA4C,CAAC;YACvD,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,OAAO,IAAI,uBAAuB,EAAE,CAAC,CAAC;YAC5E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;IAEL,KAAK;SACF,OAAO,CAAC,2BAA2B,CAAC;SACpC,WAAW,CACV,kHAAkH,CACnH;SACA,MAAM,CAAC,eAAe,EAAE,2DAA2D,EAAE,YAAY,CAAC;SAClG,MAAM,CAAC,sBAAsB,EAAE,wBAAwB,CAAC;SACxD,MAAM,CAAC,KAAK,EAAE,MAAc,EAAE,GAAW,EAAE,IAAI,EAAE,EAAE;QAClD,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,SAAS,CAAC;QACxC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;YACpC,MAAM,IAAI,GAA4B,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC;YACpE,IAAI,IAAI,CAAC,WAAW;gBAAE,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC;YAC1D,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,IAAI,CAC3B,uBAAuB,MAAM,YAAY,EACzC,IAAI,CACL,CAAC;YACF,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;YAC9B,SAAS,CAAC,IAAI,CAAC,CAAC;QAClB,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,MAAM,CAAC,GAAG,GAA0B,CAAC;YACrC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,MAAM,IAAI,sBAAsB,EAAE,CAAC,CAAC;YAC9D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;IAEL,KAAK;SACF,OAAO,CAAC,mBAAmB,CAAC;SAC5B,WAAW,CAAC,iBAAiB,CAAC;SAC9B,MAAM,CAAC,qBAAqB,EAAE,kBAAkB,CAAC;SACjD,MAAM,CAAC,KAAK,EAAE,MAAc,EAAE,IAAI,EAAE,EAAE;QACrC,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,SAAS,CAAC;QACxC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;YAEpC,0CAA0C;YAC1C,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,GAAG,CAAC,uBAAuB,MAAM,EAAE,CAAC,CAAC;YAClE,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,IAAI,EAAE,CAAC;YAClC,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,iBAAiB,IAAI,QAAQ,MAAM,EAAE,CAAC;YAE7E,oBAAoB;YACpB,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,GAAG,CAAC,uBAAuB,MAAM,WAAW,CAAC,CAAC;YACzE,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC;YACtD,aAAa,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;YAClC,OAAO,CAAC,GAAG,CAAC,iBAAiB,UAAU,KAAK,MAAM,CAAC,MAAM,SAAS,CAAC,CAAC;QACtE,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,MAAM,CAAC,GAAG,GAA0B,CAAC;YACrC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,MAAM,IAAI,yBAAyB,EAAE,CAAC,CAAC;YACjE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;IAEL,KAAK;SACF,OAAO,CAAC,iBAAiB,CAAC;SAC1B,WAAW,CAAC,0BAA0B,CAAC;SACvC,MAAM,CAAC,KAAK,EAAE,MAAc,EAAE,EAAE;QAC/B,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,SAAS,CAAC;QACxC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;YACpC,MAAM,MAAM,CAAC,MAAM,CAAC,uBAAuB,MAAM,EAAE,CAAC,CAAC;YACrD,OAAO,CAAC,GAAG,CAAC,gBAAgB,MAAM,EAAE,CAAC,CAAC;QACxC,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,MAAM,CAAC,GAAG,GAA0B,CAAC;YACrC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,MAAM,IAAI,uBAAuB,EAAE,CAAC,CAAC;YAC/D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
1
+ {"version":3,"file":"files.js","sourceRoot":"","sources":["../../src/commands/files.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAErC,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AACjE,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAEtE,MAAM,UAAU,oBAAoB,CAAC,OAAgB;IACnD,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,WAAW,CAAC,uBAAuB,CAAC,CAAC;IAE5E,KAAK;SACF,OAAO,CAAC,eAAe,CAAC;SACxB,WAAW,CAAC,+BAA+B,CAAC;SAC5C,MAAM,CAAC,KAAK,EAAE,MAAc,EAAE,EAAE;QAC/B,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,SAAS,CAAC;QACxC,MAAM,GAAG,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;QACvC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;YACpC,MAAM,GAAG,GAAG,QAAQ,CAAC,uBAAuB,MAAM,QAAQ,EAAE,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;YACnF,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAClC,MAAM,aAAa,CAAC,GAAG,CAAC,CAAC;QAC3B,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,MAAM,CAAC,GAAG,GAA0B,CAAC;YACrC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,MAAM,IAAI,sBAAsB,EAAE,CAAC,CAAC;YAC9D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;IAEL,KAAK;SACF,OAAO,CAAC,wBAAwB,CAAC;SACjC,WAAW,CAAC,yBAAyB,CAAC;SACtC,MAAM,CAAC,eAAe,EAAE,2DAA2D,EAAE,YAAY,CAAC;SAClG,MAAM,CAAC,sBAAsB,EAAE,kBAAkB,CAAC;SAClD,MAAM,CAAC,KAAK,EAAE,MAAc,EAAE,QAAgB,EAAE,IAAI,EAAE,EAAE;QACvD,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,SAAS,CAAC;QACxC,MAAM,GAAG,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;QACvC,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;YACxC,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;YAEpC,qCAAqC;YACrC,MAAM,QAAQ,GAAG,WAAW,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;YACzC,MAAM,KAAK,GAAa,EAAE,CAAC;YAE3B,YAAY;YACZ,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,QAAQ,8DAA8D,QAAQ,qDAAqD,CAAC,CAAC,CAAC;YAClK,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACrB,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;YAEhC,iBAAiB;YACjB,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,QAAQ,+DAA+D,IAAI,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC;YAErH,mBAAmB;YACnB,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;gBACrB,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,QAAQ,iEAAiE,IAAI,CAAC,WAAW,MAAM,CAAC,CAAC,CAAC;YAChI,CAAC;YAED,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,QAAQ,QAAQ,CAAC,CAAC,CAAC;YAC/C,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAElC,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;YACpC,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,IAAI,CAC3B,uBAAuB,MAAM,QAAQ,EACrC,IAAI,EACJ,EAAE,cAAc,EAAE,iCAAiC,QAAQ,EAAE,EAAE,CAChE,CAAC;YACF,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;YAC9B,SAAS,CAAC,IAAI,CAAC,CAAC;QAClB,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,MAAM,CAAC,GAAG,GAA4C,CAAC;YACvD,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,OAAO,IAAI,uBAAuB,EAAE,CAAC,CAAC;YAC5E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;IAEL,KAAK;SACF,OAAO,CAAC,2BAA2B,CAAC;SACpC,WAAW,CACV,kHAAkH,CACnH;SACA,MAAM,CAAC,eAAe,EAAE,2DAA2D,EAAE,YAAY,CAAC;SAClG,MAAM,CAAC,sBAAsB,EAAE,wBAAwB,CAAC;SACxD,MAAM,CAAC,KAAK,EAAE,MAAc,EAAE,GAAW,EAAE,IAAI,EAAE,EAAE;QAClD,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,SAAS,CAAC;QACxC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;YACpC,MAAM,IAAI,GAA4B,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC;YACpE,IAAI,IAAI,CAAC,WAAW;gBAAE,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC;YAC1D,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,IAAI,CAC3B,uBAAuB,MAAM,YAAY,EACzC,IAAI,CACL,CAAC;YACF,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;YAC9B,SAAS,CAAC,IAAI,CAAC,CAAC;QAClB,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,MAAM,CAAC,GAAG,GAA0B,CAAC;YACrC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,MAAM,IAAI,sBAAsB,EAAE,CAAC,CAAC;YAC9D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;IAEL,2EAA2E;IAC3E,0EAA0E;IAC1E,8EAA8E;IAC9E,0EAA0E;IAC1E,KAAK;SACF,OAAO,CAAC,0BAA0B,CAAC;SACnC,WAAW,CACV,4GAA4G;QAC1G,4GAA4G;QAC5G,8DAA8D,CACjE;SACA,MAAM,CAAC,mBAAmB,EAAE,wDAAwD,CAAC;SACrF,MAAM,CAAC,sBAAsB,EAAE,wBAAwB,CAAC;SACxD,MAAM,CACL,eAAe,EACf,yGAAyG;QACvG,qFAAqF,CACxF;SACA,MAAM,CAAC,KAAK,EAAE,MAAc,EAAE,GAAW,EAAE,IAAI,EAAE,EAAE;QAClD,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,SAAS,CAAC;QACxC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;YACpC,MAAM,IAAI,GAA4B,EAAE,GAAG,EAAE,CAAC;YAC9C,IAAI,IAAI,CAAC,QAAQ;gBAAE,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;YACjD,IAAI,IAAI,CAAC,WAAW;gBAAE,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC;YAC1D,IAAI,IAAI,CAAC,IAAI;gBAAE,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC;YAC1C,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,uBAAuB,MAAM,kBAAkB,EAAE,IAAI,CAAC,CAAC;YACrF,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;YAC9B,SAAS,CAAC,IAAI,CAAC,CAAC;QAClB,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,MAAM,CAAC,GAAG,GAA0B,CAAC;YACrC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,MAAM,IAAI,mCAAmC,EAAE,CAAC,CAAC;YAC3E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;IAEL,KAAK;SACF,OAAO,CAAC,mBAAmB,CAAC;SAC5B,WAAW,CAAC,iBAAiB,CAAC;SAC9B,MAAM,CAAC,qBAAqB,EAAE,kBAAkB,CAAC;SACjD,MAAM,CAAC,KAAK,EAAE,MAAc,EAAE,IAAI,EAAE,EAAE;QACrC,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,SAAS,CAAC;QACxC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;YAEpC,0CAA0C;YAC1C,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,GAAG,CAAC,uBAAuB,MAAM,EAAE,CAAC,CAAC;YAClE,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,IAAI,EAAE,CAAC;YAClC,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,iBAAiB,IAAI,QAAQ,MAAM,EAAE,CAAC;YAE7E,oBAAoB;YACpB,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,GAAG,CAAC,uBAAuB,MAAM,WAAW,CAAC,CAAC;YACzE,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC;YACtD,aAAa,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;YAClC,OAAO,CAAC,GAAG,CAAC,iBAAiB,UAAU,KAAK,MAAM,CAAC,MAAM,SAAS,CAAC,CAAC;QACtE,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,MAAM,CAAC,GAAG,GAA0B,CAAC;YACrC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,MAAM,IAAI,yBAAyB,EAAE,CAAC,CAAC;YACjE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;IAEL,KAAK;SACF,OAAO,CAAC,iBAAiB,CAAC;SAC1B,WAAW,CAAC,0BAA0B,CAAC;SACvC,MAAM,CAAC,KAAK,EAAE,MAAc,EAAE,EAAE;QAC/B,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,SAAS,CAAC;QACxC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;YACpC,MAAM,MAAM,CAAC,MAAM,CAAC,uBAAuB,MAAM,EAAE,CAAC,CAAC;YACrD,OAAO,CAAC,GAAG,CAAC,gBAAgB,MAAM,EAAE,CAAC,CAAC;QACxC,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,MAAM,CAAC,GAAG,GAA0B,CAAC;YACrC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,MAAM,IAAI,uBAAuB,EAAE,CAAC,CAAC;YAC/D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -3,6 +3,23 @@
3
3
  */
4
4
  import { getEffectiveConfig, createClient } from "@opvs-ai/core";
5
5
  import { buildUrl, printResponse, printJson } from "../lib/format.js";
6
+ import { boolFlag, oneOf } from "../lib/options.js";
7
+ /** `MarkerCreate.marker_type` pattern (agentboard `schemas/marker.py`). */
8
+ const MARKER_TYPES = ["milestone", "epic", "story", "checkpoint"];
9
+ // `marker_type` is read by nothing on the server but the marker service's own
10
+ // write — it is how the dashboard groups markers, not a behaviour.
11
+ const TYPE_HELP = `Kind of marker: ${MARKER_TYPES.join(" | ")}. Display grouping only — nothing on the server acts on it.`;
12
+ const TARGET_DATE_HELP = "Target date (YYYY-MM-DD). Informational: a missed date raises no alert and moves nothing.";
13
+ const BOARD_LINK_HELP = "UUID of a board-to-board link (`opvs board-links list`) this marker annotates on the board graph.";
14
+ const DESCRIPTION_HELP = "Marker description (max 1000 chars).";
15
+ /** `YYYY-MM-DD`, checked locally so a typo is one line rather than a pydantic 422. */
16
+ function isoDate(flag, raw) {
17
+ if (!/^\d{4}-\d{2}-\d{2}$/.test(raw)) {
18
+ console.error(`Error: ${flag} must be a date as YYYY-MM-DD (got '${raw}')`);
19
+ process.exit(1);
20
+ }
21
+ return raw;
22
+ }
6
23
  export function registerMarkerCommands(program) {
7
24
  const markers = program
8
25
  .command("markers")
@@ -31,8 +48,13 @@ export function registerMarkerCommands(program) {
31
48
  .requiredOption("-n, --name <name>", "Marker name")
32
49
  .option("--color <hex>", "Color hex (e.g. '#ff0000')")
33
50
  .option("--icon <icon>", "Icon name")
51
+ .option("--description <text>", DESCRIPTION_HELP)
52
+ .option("--type <type>", `${TYPE_HELP} Default: milestone.`)
53
+ .option("--target-date <date>", TARGET_DATE_HELP)
54
+ .option("--board-link <uuid>", BOARD_LINK_HELP)
34
55
  .action(async (opts) => {
35
56
  const wsSlug = program.opts().workspace;
57
+ const markerType = oneOf("--type", opts.type, MARKER_TYPES);
36
58
  try {
37
59
  const client = createClient(wsSlug);
38
60
  const body = { name: opts.name };
@@ -40,6 +62,14 @@ export function registerMarkerCommands(program) {
40
62
  body.color = opts.color;
41
63
  if (opts.icon)
42
64
  body.icon = opts.icon;
65
+ if (opts.description)
66
+ body.description = opts.description;
67
+ if (markerType)
68
+ body.marker_type = markerType;
69
+ if (opts.targetDate)
70
+ body.target_date = isoDate("--target-date", opts.targetDate);
71
+ if (opts.boardLink)
72
+ body.board_link_id = opts.boardLink;
43
73
  const res = await client.post("/api/v1/board/markers", body);
44
74
  const data = await res.json();
45
75
  printJson(data);
@@ -74,8 +104,18 @@ export function registerMarkerCommands(program) {
74
104
  .option("-n, --name <name>", "New name")
75
105
  .option("--color <hex>", "New color hex")
76
106
  .option("--icon <icon>", "New icon")
107
+ .option("--description <text>", `${DESCRIPTION_HELP} Pass '' to clear it.`)
108
+ .option("--type <type>", TYPE_HELP)
109
+ .option("--target-date <date>", `${TARGET_DATE_HELP} Pass 'none' to clear it.`)
110
+ .option("--board-link <uuid>", `${BOARD_LINK_HELP} Pass 'none' to detach it.`)
111
+ // `is_completed` is NOT NULL, so there is no clear verb — only true | false.
112
+ // `MarkerService.update` stamps completed_at on the false→true edge and
113
+ // clears it on true→false, so re-completing restarts the timestamp.
114
+ .option("--completed <bool>", "true | false. Marks the milestone done (stamps completed_at) or reopens it (clears completed_at, so a later " +
115
+ "completion records a NEW date).")
77
116
  .action(async (markerId, opts) => {
78
117
  const wsSlug = program.opts().workspace;
118
+ const markerType = oneOf("--type", opts.type, MARKER_TYPES);
79
119
  try {
80
120
  const client = createClient(wsSlug);
81
121
  const body = {};
@@ -85,8 +125,20 @@ export function registerMarkerCommands(program) {
85
125
  body.color = opts.color;
86
126
  if (opts.icon)
87
127
  body.icon = opts.icon;
128
+ if (opts.description !== undefined)
129
+ body.description = opts.description === "" ? null : opts.description;
130
+ if (markerType)
131
+ body.marker_type = markerType;
132
+ if (opts.targetDate !== undefined) {
133
+ body.target_date = opts.targetDate === "none" ? null : isoDate("--target-date", opts.targetDate);
134
+ }
135
+ if (opts.boardLink !== undefined)
136
+ body.board_link_id = opts.boardLink === "none" ? null : opts.boardLink;
137
+ const completed = boolFlag("--completed", opts.completed);
138
+ if (completed !== undefined)
139
+ body.is_completed = completed;
88
140
  if (Object.keys(body).length === 0) {
89
- console.error("Nothing to update. Provide --name, --color, or --icon");
141
+ console.error("Nothing to update. Provide --name, --color, --icon, --description, --type, --target-date, --board-link, or --completed");
90
142
  process.exit(1);
91
143
  }
92
144
  const res = await client.patch(`/api/v1/board/markers/${markerId}`, body);
@@ -1 +1 @@
1
- {"version":3,"file":"markers.js","sourceRoot":"","sources":["../../src/commands/markers.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AACjE,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAEtE,MAAM,UAAU,sBAAsB,CAAC,OAAgB;IACrD,MAAM,OAAO,GAAG,OAAO;SACpB,OAAO,CAAC,SAAS,CAAC;SAClB,WAAW,CAAC,yCAAyC,CAAC,CAAC;IAE1D,OAAO;SACJ,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,oCAAoC,CAAC;SACjD,MAAM,CAAC,KAAK,IAAI,EAAE;QACjB,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,SAAS,CAAC;QACxC,MAAM,GAAG,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;QACvC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;YACpC,MAAM,GAAG,GAAG,QAAQ,CAAC,uBAAuB,EAAE,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;YACrE,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAClC,MAAM,aAAa,CAAC,GAAG,CAAC,CAAC;QAC3B,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,MAAM,CAAC,GAAG,GAA0B,CAAC;YACrC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,MAAM,IAAI,wBAAwB,EAAE,CAAC,CAAC;YAChE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;IAEL,OAAO;SACJ,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CAAC,qBAAqB,CAAC;SAClC,cAAc,CAAC,mBAAmB,EAAE,aAAa,CAAC;SAClD,MAAM,CAAC,eAAe,EAAE,4BAA4B,CAAC;SACrD,MAAM,CAAC,eAAe,EAAE,WAAW,CAAC;SACpC,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;QACrB,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,SAAS,CAAC;QACxC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;YACpC,MAAM,IAAI,GAA4B,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC;YAC1D,IAAI,IAAI,CAAC,KAAK;gBAAE,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;YACxC,IAAI,IAAI,CAAC,IAAI;gBAAE,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;YACrC,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,uBAAuB,EAAE,IAAI,CAAC,CAAC;YAC7D,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;YAC9B,SAAS,CAAC,IAAI,CAAC,CAAC;QAClB,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,MAAM,CAAC,GAAG,GAA0B,CAAC;YACrC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,MAAM,IAAI,yBAAyB,EAAE,CAAC,CAAC;YACjE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;IAEL,OAAO;SACJ,OAAO,CAAC,gBAAgB,CAAC;SACzB,WAAW,CAAC,oBAAoB,CAAC;SACjC,MAAM,CAAC,KAAK,EAAE,QAAgB,EAAE,EAAE;QACjC,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,SAAS,CAAC;QACxC,MAAM,GAAG,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;QACvC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;YACpC,MAAM,GAAG,GAAG,QAAQ,CAAC,yBAAyB,QAAQ,EAAE,EAAE,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;YACjF,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAClC,MAAM,aAAa,CAAC,GAAG,CAAC,CAAC;QAC3B,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,MAAM,CAAC,GAAG,GAA0B,CAAC;YACrC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,MAAM,IAAI,sBAAsB,EAAE,CAAC,CAAC;YAC9D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;IAEL,OAAO;SACJ,OAAO,CAAC,mBAAmB,CAAC;SAC5B,WAAW,CAAC,iBAAiB,CAAC;SAC9B,MAAM,CAAC,mBAAmB,EAAE,UAAU,CAAC;SACvC,MAAM,CAAC,eAAe,EAAE,eAAe,CAAC;SACxC,MAAM,CAAC,eAAe,EAAE,UAAU,CAAC;SACnC,MAAM,CAAC,KAAK,EAAE,QAAgB,EAAE,IAAI,EAAE,EAAE;QACvC,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,SAAS,CAAC;QACxC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;YACpC,MAAM,IAAI,GAA4B,EAAE,CAAC;YACzC,IAAI,IAAI,CAAC,IAAI;gBAAE,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;YACrC,IAAI,IAAI,CAAC,KAAK;gBAAE,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;YACxC,IAAI,IAAI,CAAC,IAAI;gBAAE,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;YACrC,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACnC,OAAO,CAAC,KAAK,CAAC,uDAAuD,CAAC,CAAC;gBACvE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;YACD,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,yBAAyB,QAAQ,EAAE,EAAE,IAAI,CAAC,CAAC;YAC1E,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;YAC9B,SAAS,CAAC,IAAI,CAAC,CAAC;QAClB,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,MAAM,CAAC,GAAG,GAA0B,CAAC;YACrC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,MAAM,IAAI,yBAAyB,EAAE,CAAC,CAAC;YACjE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;IAEL,OAAO;SACJ,OAAO,CAAC,mBAAmB,CAAC;SAC5B,WAAW,CAAC,iBAAiB,CAAC;SAC9B,MAAM,CAAC,KAAK,EAAE,QAAgB,EAAE,EAAE;QACjC,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,SAAS,CAAC;QACxC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;YACpC,MAAM,MAAM,CAAC,MAAM,CAAC,yBAAyB,QAAQ,EAAE,CAAC,CAAC;YACzD,OAAO,CAAC,GAAG,CAAC,kBAAkB,QAAQ,EAAE,CAAC,CAAC;QAC5C,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,MAAM,CAAC,GAAG,GAA0B,CAAC;YACrC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,MAAM,IAAI,yBAAyB,EAAE,CAAC,CAAC;YACjE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;IAEL,OAAO;SACJ,OAAO,CAAC,mBAAmB,CAAC;SAC5B,WAAW,CAAC,mCAAmC,CAAC;SAChD,cAAc,CAAC,iBAAiB,EAAE,+BAA+B,CAAC;SAClE,MAAM,CAAC,KAAK,EAAE,QAAgB,EAAE,IAAI,EAAE,EAAE;QACvC,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,SAAS,CAAC;QACxC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;YACpC,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,yBAAyB,QAAQ,SAAS,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;YAClG,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;YAC9B,SAAS,CAAC,IAAI,CAAC,CAAC;QAClB,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,MAAM,CAAC,GAAG,GAA0B,CAAC;YACrC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,MAAM,IAAI,yBAAyB,EAAE,CAAC,CAAC;YACjE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
1
+ {"version":3,"file":"markers.js","sourceRoot":"","sources":["../../src/commands/markers.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,38 @@
1
1
  /**
2
2
  * opvs members — board member management
3
+ *
4
+ * ── Why this file was rewritten (ASP-85) ─────────────────────────────────────
5
+ * `members add` sent `{user_id, role}` and `members remove` called
6
+ * `/members/{userId}`. The route has always taken `{member_type, member_id}`
7
+ * (AgentBoard `AddBoardMemberRequest`) and deletes at
8
+ * `/members/{member_type}/{member_id}`, so BOTH commands failed on every call —
9
+ * a 422 and a 404 — for as long as they had existed.
10
+ *
11
+ * ── What a role does, and does not do ───────────────────────────────────────
12
+ * `member_role` is read in exactly ONE place: the gateway's
13
+ * `_guest_role_allows` (apps/api `board.py`), and only for a membership with
14
+ * `is_external = true`. A member of the board's own brand is never checked
15
+ * against it. So `--role` caps a GUEST and is inert for everyone else — which
16
+ * is why the help says so rather than calling it a permission.
17
+ *
18
+ * `is_external` has no flag on purpose (surface_parity_exclusions/cli_fields.yaml).
19
+ * Whether a user is a guest is a fact about the user's brand, which the
20
+ * `by-email` route looks up and this command cannot — so `members invite`
21
+ * is the door for a guest, and it decides guest-ness itself.
3
22
  */
4
23
  import { Command } from "commander";
24
+ /** `AddBoardMemberRequest.member_role` pattern (agentboard `schemas/board.py`). */
25
+ export declare const MEMBER_ROLES: readonly ["viewer", "commenter", "editor"];
26
+ /**
27
+ * Resolve `--user` / `--agent` to the `(member_type, member_id)` pair the route
28
+ * takes. Exactly one is required: two would be two members in one request the
29
+ * route cannot express, and none is the 422 this command used to send.
30
+ */
31
+ export declare function memberTarget(opts: {
32
+ user?: string;
33
+ agent?: string;
34
+ }): {
35
+ member_type: string;
36
+ member_id: string;
37
+ };
5
38
  export declare function registerMemberCommands(program: Command): void;
@@ -1,8 +1,59 @@
1
1
  /**
2
2
  * opvs members — board member management
3
+ *
4
+ * ── Why this file was rewritten (ASP-85) ─────────────────────────────────────
5
+ * `members add` sent `{user_id, role}` and `members remove` called
6
+ * `/members/{userId}`. The route has always taken `{member_type, member_id}`
7
+ * (AgentBoard `AddBoardMemberRequest`) and deletes at
8
+ * `/members/{member_type}/{member_id}`, so BOTH commands failed on every call —
9
+ * a 422 and a 404 — for as long as they had existed.
10
+ *
11
+ * ── What a role does, and does not do ───────────────────────────────────────
12
+ * `member_role` is read in exactly ONE place: the gateway's
13
+ * `_guest_role_allows` (apps/api `board.py`), and only for a membership with
14
+ * `is_external = true`. A member of the board's own brand is never checked
15
+ * against it. So `--role` caps a GUEST and is inert for everyone else — which
16
+ * is why the help says so rather than calling it a permission.
17
+ *
18
+ * `is_external` has no flag on purpose (surface_parity_exclusions/cli_fields.yaml).
19
+ * Whether a user is a guest is a fact about the user's brand, which the
20
+ * `by-email` route looks up and this command cannot — so `members invite`
21
+ * is the door for a guest, and it decides guest-ness itself.
3
22
  */
4
23
  import { getEffectiveConfig, createClient } from "@opvs-ai/core";
5
24
  import { buildUrl, printResponse, printJson } from "../lib/format.js";
25
+ import { oneOf } from "../lib/options.js";
26
+ import { isUuid } from "../lib/board-refs.js";
27
+ /** `AddBoardMemberRequest.member_role` pattern (agentboard `schemas/board.py`). */
28
+ export const MEMBER_ROLES = ["viewer", "commenter", "editor"];
29
+ /** `AddBoardMemberRequest.member_type` pattern. */
30
+ const MEMBER_TYPES = ["user", "agent"];
31
+ // `_guest_role_allows`: viewer → reads; commenter → reads + POST a task comment;
32
+ // editor → every method. None → treated as viewer.
33
+ const ROLE_HELP = "Guest permission tier: viewer (read only) | commenter (read + comment) | editor (every write, including adding " +
34
+ "members). It caps an EXTERNAL guest only — a member of your own brand is never checked against it and keeps " +
35
+ "full access whatever you pass.";
36
+ function requireUuid(flag, raw) {
37
+ if (!isUuid(raw)) {
38
+ console.error(`Error: ${flag} must be a full UUID (got '${raw}')`);
39
+ process.exit(1);
40
+ }
41
+ return raw;
42
+ }
43
+ /**
44
+ * Resolve `--user` / `--agent` to the `(member_type, member_id)` pair the route
45
+ * takes. Exactly one is required: two would be two members in one request the
46
+ * route cannot express, and none is the 422 this command used to send.
47
+ */
48
+ export function memberTarget(opts) {
49
+ if ((opts.user === undefined) === (opts.agent === undefined)) {
50
+ console.error("Error: pass exactly one of --user <uuid> or --agent <uuid>");
51
+ process.exit(1);
52
+ }
53
+ return opts.user !== undefined
54
+ ? { member_type: "user", member_id: requireUuid("--user", opts.user) }
55
+ : { member_type: "agent", member_id: requireUuid("--agent", opts.agent) };
56
+ }
6
57
  export function registerMemberCommands(program) {
7
58
  const members = program
8
59
  .command("members")
@@ -27,16 +78,20 @@ export function registerMemberCommands(program) {
27
78
  });
28
79
  members
29
80
  .command("add <boardId>")
30
- .description("Add a member to a board")
31
- .requiredOption("--user <userId>", "User UUID to add")
32
- .option("--role <role>", "Member role (member, admin)", "member")
81
+ .description("Add a user or agent of YOUR brand to a board by UUID. Grants that member access to the board, including a " +
82
+ "private one. To add someone outside your brand, use `opvs members invite`.")
83
+ .option("--user <uuid>", "User UUID to add (the id `opvs members list` shows for a user). Exactly one of --user / --agent.")
84
+ .option("--agent <uuid>", "Agent (persona) UUID to add. The gateway refuses (403) an agent of another brand. Exactly one of --user / --agent.")
85
+ .option("--role <tier>", ROLE_HELP)
33
86
  .action(async (boardId, opts) => {
34
87
  const wsSlug = program.opts().workspace;
88
+ const target = memberTarget(opts);
89
+ const role = oneOf("--role", opts.role, MEMBER_ROLES);
35
90
  try {
36
91
  const client = createClient(wsSlug);
37
- const body = { user_id: opts.user };
38
- if (opts.role)
39
- body.role = opts.role;
92
+ const body = { member_type: target.member_type, member_id: target.member_id };
93
+ if (role)
94
+ body.member_role = role;
40
95
  const res = await client.post(`/api/v1/board/boards/${boardId}/members`, body);
41
96
  const data = await res.json();
42
97
  printJson(data);
@@ -47,15 +102,45 @@ export function registerMemberCommands(program) {
47
102
  process.exit(1);
48
103
  }
49
104
  });
105
+ // Gateway-only route (`/boards/{id}/members/by-email`): it resolves the email
106
+ // against every OPVS user and sets the guest flag from brand membership.
107
+ members
108
+ .command("invite <boardId>")
109
+ .description("Add a person to a board by EMAIL. Someone outside your brand becomes an EXTERNAL GUEST of this one board, " +
110
+ "capped by --role; someone already in your brand is added as a normal member and --role is ignored. " +
111
+ "Only the brand that owns the board may invite.")
112
+ .requiredOption("--email <email>", "Email of an existing OPVS user (404 if nobody has it)")
113
+ .option("--role <tier>", `${ROLE_HELP} Default: viewer.`)
114
+ .action(async (boardId, opts) => {
115
+ const wsSlug = program.opts().workspace;
116
+ const role = oneOf("--role", opts.role, MEMBER_ROLES) ?? "viewer";
117
+ try {
118
+ const client = createClient(wsSlug);
119
+ const res = await client.post(`/api/v1/board/boards/${boardId}/members/by-email`, {
120
+ email: opts.email,
121
+ member_role: role,
122
+ });
123
+ const data = await res.json();
124
+ printJson(data);
125
+ }
126
+ catch (err) {
127
+ const e = err;
128
+ console.error(`Error: ${e.detail || "Failed to invite member"}`);
129
+ process.exit(1);
130
+ }
131
+ });
50
132
  members
51
- .command("remove <boardId> <userId>")
52
- .description("Remove a member from a board")
53
- .action(async (boardId, userId) => {
133
+ .command("remove <boardId> <memberId>")
134
+ .description("Remove a user or agent from a board. They lose access to it at once, a private board included.")
135
+ .option("--type <type>", "What <memberId> is: user | agent. Default: user.")
136
+ .action(async (boardId, memberId, opts) => {
54
137
  const wsSlug = program.opts().workspace;
138
+ const type = oneOf("--type", opts.type, MEMBER_TYPES) ?? "user";
139
+ requireUuid("<memberId>", memberId);
55
140
  try {
56
141
  const client = createClient(wsSlug);
57
- await client.delete(`/api/v1/board/boards/${boardId}/members/${userId}`);
58
- console.log(`Removed member ${userId} from board ${boardId}`);
142
+ await client.delete(`/api/v1/board/boards/${boardId}/members/${type}/${memberId}`);
143
+ console.log(`Removed ${type} ${memberId} from board ${boardId}`);
59
144
  }
60
145
  catch (err) {
61
146
  const e = err;
@@ -1 +1 @@
1
- {"version":3,"file":"members.js","sourceRoot":"","sources":["../../src/commands/members.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AACjE,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAEtE,MAAM,UAAU,sBAAsB,CAAC,OAAgB;IACrD,MAAM,OAAO,GAAG,OAAO;SACpB,OAAO,CAAC,SAAS,CAAC;SAClB,WAAW,CAAC,yBAAyB,CAAC,CAAC;IAE1C,OAAO;SACJ,OAAO,CAAC,gBAAgB,CAAC;SACzB,WAAW,CAAC,yBAAyB,CAAC;SACtC,MAAM,CAAC,KAAK,EAAE,OAAe,EAAE,EAAE;QAChC,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,SAAS,CAAC;QACxC,MAAM,GAAG,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;QACvC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;YACpC,MAAM,GAAG,GAAG,QAAQ,CAAC,wBAAwB,OAAO,UAAU,EAAE,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;YACvF,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAClC,MAAM,aAAa,CAAC,GAAG,CAAC,CAAC;QAC3B,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,MAAM,CAAC,GAAG,GAA0B,CAAC;YACrC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,MAAM,IAAI,wBAAwB,EAAE,CAAC,CAAC;YAChE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;IAEL,OAAO;SACJ,OAAO,CAAC,eAAe,CAAC;SACxB,WAAW,CAAC,yBAAyB,CAAC;SACtC,cAAc,CAAC,iBAAiB,EAAE,kBAAkB,CAAC;SACrD,MAAM,CAAC,eAAe,EAAE,6BAA6B,EAAE,QAAQ,CAAC;SAChE,MAAM,CAAC,KAAK,EAAE,OAAe,EAAE,IAAI,EAAE,EAAE;QACtC,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,SAAS,CAAC;QACxC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;YACpC,MAAM,IAAI,GAA4B,EAAE,OAAO,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC;YAC7D,IAAI,IAAI,CAAC,IAAI;gBAAE,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;YACrC,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,wBAAwB,OAAO,UAAU,EAAE,IAAI,CAAC,CAAC;YAC/E,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;YAC9B,SAAS,CAAC,IAAI,CAAC,CAAC;QAClB,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,MAAM,CAAC,GAAG,GAA0B,CAAC;YACrC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,MAAM,IAAI,sBAAsB,EAAE,CAAC,CAAC;YAC9D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;IAEL,OAAO;SACJ,OAAO,CAAC,2BAA2B,CAAC;SACpC,WAAW,CAAC,8BAA8B,CAAC;SAC3C,MAAM,CAAC,KAAK,EAAE,OAAe,EAAE,MAAc,EAAE,EAAE;QAChD,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,SAAS,CAAC;QACxC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;YACpC,MAAM,MAAM,CAAC,MAAM,CAAC,wBAAwB,OAAO,YAAY,MAAM,EAAE,CAAC,CAAC;YACzE,OAAO,CAAC,GAAG,CAAC,kBAAkB,MAAM,eAAe,OAAO,EAAE,CAAC,CAAC;QAChE,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,MAAM,CAAC,GAAG,GAA0B,CAAC;YACrC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,MAAM,IAAI,yBAAyB,EAAE,CAAC,CAAC;YACjE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
1
+ {"version":3,"file":"members.js","sourceRoot":"","sources":["../../src/commands/members.ts"],"names":[],"mappings":"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"}
@@ -16,4 +16,12 @@
16
16
  * server-side from the PAT — never passed here.
17
17
  */
18
18
  import { Command } from "commander";
19
+ /**
20
+ * Parse repeatable `--command-body name=path` / `--skill-body name=path` into the
21
+ * `{name: content}` map the bundle PATCH takes, reading each file.
22
+ *
23
+ * A path, not inline text: a body is a whole playbook or SKILL.md (up to 20,000
24
+ * chars, `BundleBodyText`), which no shell quotes comfortably.
25
+ */
26
+ export declare function readBodies(flag: string, items: string[]): Record<string, string>;
19
27
  export declare function registerProjectCommands(program: Command): void;
@@ -17,12 +17,54 @@
17
17
  */
18
18
  import { getEffectiveConfig, createClient } from "@opvs-ai/core";
19
19
  import { buildUrl, printResponse, printJson } from "../lib/format.js";
20
+ import { healthParams, renderHealthReport, withHealthOptions } from "../lib/health.js";
21
+ import { buildRoutingBody, withRoutingOptions } from "../lib/routing.js";
22
+ import { FACTORY_PROJECT_GATE, warnIfFactoryUnresolved } from "../lib/factory-gate.js";
23
+ import { readFileSync } from "node:fs";
20
24
  const BASE = "/api/v1/board/board-groups/projects";
21
25
  /** commander repeatable-option accumulator (same shape as `create --board`). */
22
26
  const collect = (val, acc) => {
23
27
  acc.push(val);
24
28
  return acc;
25
29
  };
30
+ /**
31
+ * Parse repeatable `--command-body name=path` / `--skill-body name=path` into the
32
+ * `{name: content}` map the bundle PATCH takes, reading each file.
33
+ *
34
+ * A path, not inline text: a body is a whole playbook or SKILL.md (up to 20,000
35
+ * chars, `BundleBodyText`), which no shell quotes comfortably.
36
+ */
37
+ export function readBodies(flag, items) {
38
+ const out = {};
39
+ for (const item of items) {
40
+ const eq = item.indexOf("=");
41
+ if (eq <= 0 || eq === item.length - 1) {
42
+ console.error(`Error: ${flag} expects <name>=<path> (got '${item}')`);
43
+ process.exit(1);
44
+ }
45
+ const name = item.slice(0, eq);
46
+ if (name in out) {
47
+ console.error(`Error: ${flag} names '${name}' twice`);
48
+ process.exit(1);
49
+ }
50
+ try {
51
+ out[name] = readFileSync(item.slice(eq + 1), "utf-8");
52
+ }
53
+ catch (err) {
54
+ console.error(`Error: ${flag} ${name}: cannot read '${item.slice(eq + 1)}' (${err.message})`);
55
+ process.exit(1);
56
+ }
57
+ }
58
+ return out;
59
+ }
60
+ /** Warn for every member board a project write may have left unresolved (ASP-113). */
61
+ async function warnMemberBoards(client, data) {
62
+ const boards = data?.member_boards ?? [];
63
+ for (const b of boards) {
64
+ if (b.board_type === "factory" && b.id)
65
+ await warnIfFactoryUnresolved(client, b.id);
66
+ }
67
+ }
26
68
  export function registerProjectCommands(program) {
27
69
  const projects = program
28
70
  .command("projects")
@@ -74,7 +116,8 @@ export function registerProjectCommands(program) {
74
116
  // repeated --board on create). Brand is injected by the proxy.
75
117
  projects
76
118
  .command("create")
77
- .description("Create an empty project container")
119
+ .description("Create an empty project container. With --board, each board joins it; a board already in another active " +
120
+ `project becomes ambiguous. ${FACTORY_PROJECT_GATE}`)
78
121
  .requiredOption("-n, --name <name>", "Project name")
79
122
  .option("-b, --board <id>", "Initial member board id, repeatable (full UUID only — board_ids is not on the gateway's ref allowlist)", collect, [])
80
123
  .action(async (opts) => {
@@ -87,6 +130,7 @@ export function registerProjectCommands(program) {
87
130
  const res = await client.post(BASE, body);
88
131
  const data = await res.json();
89
132
  printJson(data);
133
+ await warnMemberBoards(client, data);
90
134
  }
91
135
  catch (err) {
92
136
  const e = err;
@@ -120,6 +164,61 @@ export function registerProjectCommands(program) {
120
164
  process.exit(1);
121
165
  }
122
166
  });
167
+ // ── set-routing (ASP-25, plan §C / migration 062) ───────────────────
168
+ // A dedicated verb rather than more flags on `update`: a routing default
169
+ // reaches every board in the project, the widest blast radius of the three
170
+ // rungs, and it deserves a command whose name says so.
171
+ withRoutingOptions(projects
172
+ .command("set-routing <id>")
173
+ .description("Set the project's routing defaults (model / provider / harness / claimable-by) for all its boards. Only the flags you pass change."), "project").action(async (id, opts) => {
174
+ const wsSlug = program.opts().workspace;
175
+ try {
176
+ const body = buildRoutingBody(opts);
177
+ if (Object.keys(body).length === 0) {
178
+ console.error("Nothing to set. Provide --model, --provider, --harness, or --claimable-by");
179
+ process.exit(1);
180
+ }
181
+ const client = createClient(wsSlug);
182
+ const res = await client.patch(`${BASE}/${id}`, body);
183
+ const data = (await res.json());
184
+ printJson({
185
+ id: data.id,
186
+ name: data.name,
187
+ default_model: data.default_model ?? null,
188
+ default_provider: data.default_provider ?? null,
189
+ default_harness: data.default_harness ?? null,
190
+ default_claimable_by: data.default_claimable_by ?? null,
191
+ });
192
+ }
193
+ catch (err) {
194
+ const e = err;
195
+ console.error(`Error: ${e.detail || "Failed to set project routing"}`);
196
+ process.exit(1);
197
+ }
198
+ });
199
+ // ── health (ASP-25, plan §J4 / §J5) ────────────────────────────────
200
+ withHealthOptions(projects
201
+ .command("health <id>")
202
+ .description("Project audit: bundle non-empty, member boards present, no board claimed by two projects, and every member " +
203
+ "board's verdict. Thresholds are forwarded to each board; an unsupplied one prints NOT CHECKED and the " +
204
+ "verdict reads INCOMPLETE — a project never reads healthier than its boards.")).action(async (id, opts) => {
205
+ const wsSlug = program.opts().workspace;
206
+ try {
207
+ const client = createClient(wsSlug);
208
+ const url = buildUrl(`${BASE}/${id}/health`, healthParams(opts));
209
+ const res = await client.get(url);
210
+ const report = (await res.json());
211
+ if (opts.json)
212
+ printJson(report);
213
+ else
214
+ console.log(renderHealthReport(report));
215
+ }
216
+ catch (err) {
217
+ const e = err;
218
+ console.error(`Error: ${e.detail || "Failed to get project health"}`);
219
+ process.exit(1);
220
+ }
221
+ });
123
222
  // ── set-status (manual lifecycle transition) ───────────────────────
124
223
  // status ∈ active | on_hold | completed. On `completed` an optional
125
224
  // --handoff free-text is stored in settings.closing_handoff.
@@ -147,8 +246,10 @@ export function registerProjectCommands(program) {
147
246
  // ── archive / unarchive (container-only, orthogonal to status) ─────
148
247
  projects
149
248
  .command("archive <id>")
150
- .description("Archive a project (hide from default list, still reachable)")
151
- .option("--undo", "Unarchive instead (set is_archived=false)")
249
+ .description("Archive a project (hide from default list, still reachable). An archived project is not ACTIVE: its boards " +
250
+ "stop inheriting its bundle and routing defaults, and a board it was the only project of drops to none. " +
251
+ FACTORY_PROJECT_GATE)
252
+ .option("--undo", "Unarchive instead (set is_archived=false). A board that also joined another project meanwhile becomes ambiguous.")
152
253
  .action(async (id, opts) => {
153
254
  const wsSlug = program.opts().workspace;
154
255
  try {
@@ -158,6 +259,7 @@ export function registerProjectCommands(program) {
158
259
  });
159
260
  const data = await res.json();
160
261
  printJson(data);
262
+ await warnMemberBoards(client, data);
161
263
  }
162
264
  catch (err) {
163
265
  const e = err;
@@ -168,7 +270,9 @@ export function registerProjectCommands(program) {
168
270
  // ── add-board (many-to-many membership) ────────────────────────────
169
271
  projects
170
272
  .command("add-board <id> <board_id>")
171
- .description("Add a board to a project (a board can be in many projects)")
273
+ .description("Add a board to a project. Membership is many-to-many, but a board claimed by TWO active projects is " +
274
+ "ambiguous and inherits NEITHER project's bundle or routing defaults — check with `opvs boards projects <board>`. " +
275
+ FACTORY_PROJECT_GATE)
172
276
  .action(async (id, boardId) => {
173
277
  const wsSlug = program.opts().workspace;
174
278
  try {
@@ -178,6 +282,7 @@ export function registerProjectCommands(program) {
178
282
  });
179
283
  const data = await res.json();
180
284
  printJson(data);
285
+ await warnIfFactoryUnresolved(client, boardId);
181
286
  }
182
287
  catch (err) {
183
288
  const e = err;
@@ -188,13 +293,15 @@ export function registerProjectCommands(program) {
188
293
  // ── remove-board (membership only — board survives, O-P1) ──────────
189
294
  projects
190
295
  .command("remove-board <id> <board_id>")
191
- .description("Remove a board from a project (the board itself stays live)")
296
+ .description("Remove a board from a project (the board itself stays live). Its cards stop inheriting this project's bundle " +
297
+ `and routing defaults; removing its only project leaves it in none. ${FACTORY_PROJECT_GATE}`)
192
298
  .action(async (id, boardId) => {
193
299
  const wsSlug = program.opts().workspace;
194
300
  try {
195
301
  const client = createClient(wsSlug);
196
302
  const res = await client.delete(`${BASE}/${id}/boards/${boardId}`);
197
303
  await printResponse(res, true);
304
+ await warnIfFactoryUnresolved(client, boardId);
198
305
  }
199
306
  catch (err) {
200
307
  const e = err;
@@ -263,6 +370,16 @@ export function registerProjectCommands(program) {
263
370
  .option("--clear-commands", "Replace commands with an empty list")
264
371
  .option("--clear-skills", "Replace skills with an empty list")
265
372
  .option("--clear-rules", "Replace rules with an empty list")
373
+ // `ProjectBundleUpdate.command_bodies` / `skill_bodies`: omitted = left
374
+ // alone, passed = the map is REPLACED, and bodies for names not in the
375
+ // resulting list are pruned server-side (`_drop_orphan_bodies`).
376
+ .option("--command-body <name=path>", "Inline content for a listed command, read from a file (repeatable; max 20,000 chars). Installed on the desk " +
377
+ "at claim time instead of the repo image's file. Passing any REPLACES the whole map — a body you leave out " +
378
+ "is deleted — and a body whose name is not in the commands list is dropped.", collect, [])
379
+ .option("--skill-body <name=path>", "Inline SKILL.md for a listed skill, read from a file (repeatable; max 20,000 chars). Same REPLACE and drop " +
380
+ "rules as --command-body.", collect, [])
381
+ .option("--clear-command-bodies", "Replace the command bodies with an empty map (names fall back to the repo image)")
382
+ .option("--clear-skill-bodies", "Replace the skill bodies with an empty map")
266
383
  .action(async (id, opts) => {
267
384
  const wsSlug = program.opts().workspace;
268
385
  const body = {};
@@ -285,8 +402,23 @@ export function registerProjectCommands(program) {
285
402
  else if (values.length > 0)
286
403
  body[name] = values;
287
404
  }
405
+ const bodyMaps = [
406
+ ["command_bodies", "--command-body", opts.commandBody ?? [], !!opts.clearCommandBodies, "--clear-command-bodies"],
407
+ ["skill_bodies", "--skill-body", opts.skillBody ?? [], !!opts.clearSkillBodies, "--clear-skill-bodies"],
408
+ ];
409
+ for (const [name, flag, items, clear, clearFlag] of bodyMaps) {
410
+ if (clear && items.length > 0) {
411
+ console.error(`Cannot both set and clear ${name}. Drop ${clearFlag} or ${flag}.`);
412
+ process.exit(1);
413
+ return;
414
+ }
415
+ if (clear)
416
+ body[name] = {};
417
+ else if (items.length > 0)
418
+ body[name] = readBodies(flag, items);
419
+ }
288
420
  if (Object.keys(body).length === 0) {
289
- console.error("Nothing to update. Provide --command / --skill / --rule, or --clear-commands / --clear-skills / --clear-rules");
421
+ console.error("Nothing to update. Provide --command / --skill / --rule / --command-body / --skill-body, or a --clear-* flag");
290
422
  process.exit(1);
291
423
  return;
292
424
  }