@sinoia/hubdoc-tools 1.10.0 → 1.11.0

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.
Files changed (3) hide show
  1. package/cli.js +111 -22
  2. package/docs/llm-usage.md +37 -11
  3. package/package.json +1 -1
package/cli.js CHANGED
@@ -95034,7 +95034,7 @@ var require_bignumber = __commonJS({
95034
95034
  "node_modules/bignumber.js/bignumber.js"(exports2, module2) {
95035
95035
  (function(globalObject) {
95036
95036
  "use strict";
95037
- var BigNumber, isNumeric = /^-?(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?$/i, mathceil = Math.ceil, mathfloor = Math.floor, bignumberError = "[BigNumber Error] ", tooManyDigits = bignumberError + "Number primitive has more than 15 significant digits: ", BASE4 = 1e14, LOG_BASE = 14, MAX_SAFE_INTEGER = 9007199254740991, POWS_TEN = [1, 10, 100, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13], SQRT_BASE = 1e7, MAX = 1e9;
95037
+ var BigNumber, isNumeric = /^-?(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?$/i, mathceil = Math.ceil, mathfloor = Math.floor, bignumberError = "[BigNumber Error] ", tooManyDigits = bignumberError + "Number primitive has more than 15 significant digits: ", BASE5 = 1e14, LOG_BASE = 14, MAX_SAFE_INTEGER = 9007199254740991, POWS_TEN = [1, 10, 100, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13], SQRT_BASE = 1e7, MAX = 1e9;
95038
95038
  function clone(configObject) {
95039
95039
  var div, convertBase, parseNumeric, P = BigNumber2.prototype = { constructor: BigNumber2, toString: null, valueOf: null }, ONE = new BigNumber2(1), DECIMAL_PLACES = 20, ROUNDING_MODE = 4, TO_EXP_NEG = -7, TO_EXP_POS = 21, MIN_EXP = -1e7, MAX_EXP = 1e7, CRYPTO = false, MODULO_MODE = 1, POW_PRECISION = 0, FORMAT = {
95040
95040
  prefix: "",
@@ -95286,7 +95286,7 @@ var require_bignumber = __commonJS({
95286
95286
  if (String(c3[0]).length == i3) {
95287
95287
  for (i3 = 0; i3 < c3.length; i3++) {
95288
95288
  n3 = c3[i3];
95289
- if (n3 < 0 || n3 >= BASE4 || n3 !== mathfloor(n3)) break out;
95289
+ if (n3 < 0 || n3 >= BASE5 || n3 !== mathfloor(n3)) break out;
95290
95290
  }
95291
95291
  if (n3 !== 0) return true;
95292
95292
  }
@@ -95503,7 +95503,7 @@ var require_bignumber = __commonJS({
95503
95503
  e3 = x3.e - y2.e;
95504
95504
  s3 = dp + e3 + 1;
95505
95505
  if (!base) {
95506
- base = BASE4;
95506
+ base = BASE5;
95507
95507
  e3 = bitFloor(x3.e / LOG_BASE) - bitFloor(y2.e / LOG_BASE);
95508
95508
  s3 = s3 / LOG_BASE | 0;
95509
95509
  }
@@ -95582,7 +95582,7 @@ var require_bignumber = __commonJS({
95582
95582
  more = rem[0] != null;
95583
95583
  if (!qc[0]) qc.splice(0, 1);
95584
95584
  }
95585
- if (base == BASE4) {
95585
+ if (base == BASE5) {
95586
95586
  for (i3 = 1, s3 = qc[0]; s3 >= 10; s3 /= 10, i3++) ;
95587
95587
  round(q3, dp + (q3.e = i3 + e3 * LOG_BASE - 1) + 1, rm, more);
95588
95588
  } else {
@@ -95741,12 +95741,12 @@ var require_bignumber = __commonJS({
95741
95741
  for (k3 = 1; j3 >= 10; j3 /= 10, k3++) ;
95742
95742
  if (i3 != k3) {
95743
95743
  x3.e++;
95744
- if (xc[0] == BASE4) xc[0] = 1;
95744
+ if (xc[0] == BASE5) xc[0] = 1;
95745
95745
  }
95746
95746
  break;
95747
95747
  } else {
95748
95748
  xc[ni] += k3;
95749
- if (xc[ni] != BASE4) break;
95749
+ if (xc[ni] != BASE5) break;
95750
95750
  xc[ni--] = 0;
95751
95751
  k3 = 1;
95752
95752
  }
@@ -95955,12 +95955,12 @@ var require_bignumber = __commonJS({
95955
95955
  }
95956
95956
  b3 = (j3 = yc.length) - (i3 = xc.length);
95957
95957
  if (b3 > 0) for (; b3--; xc[i3++] = 0) ;
95958
- b3 = BASE4 - 1;
95958
+ b3 = BASE5 - 1;
95959
95959
  for (; j3 > a3; ) {
95960
95960
  if (xc[--j3] < yc[j3]) {
95961
95961
  for (i3 = j3; i3 && !xc[--i3]; xc[i3] = b3) ;
95962
95962
  --xc[i3];
95963
- xc[j3] += BASE4;
95963
+ xc[j3] += BASE5;
95964
95964
  }
95965
95965
  xc[j3] -= yc[j3];
95966
95966
  }
@@ -96022,7 +96022,7 @@ var require_bignumber = __commonJS({
96022
96022
  ycL = i3;
96023
96023
  }
96024
96024
  for (i3 = xcL + ycL, zc = []; i3--; zc.push(0)) ;
96025
- base = BASE4;
96025
+ base = BASE5;
96026
96026
  sqrtBase = SQRT_BASE;
96027
96027
  for (i3 = ycL; --i3 >= 0; ) {
96028
96028
  c3 = 0;
@@ -96088,8 +96088,8 @@ var require_bignumber = __commonJS({
96088
96088
  b3 = a3;
96089
96089
  }
96090
96090
  for (a3 = 0; b3; ) {
96091
- a3 = (xc[--b3] = xc[b3] + yc[b3] + a3) / BASE4 | 0;
96092
- xc[b3] = BASE4 === xc[b3] ? 0 : xc[b3] % BASE4;
96091
+ a3 = (xc[--b3] = xc[b3] + yc[b3] + a3) / BASE5 | 0;
96092
+ xc[b3] = BASE5 === xc[b3] ? 0 : xc[b3] % BASE5;
96093
96093
  }
96094
96094
  if (a3) {
96095
96095
  xc = [a3].concat(xc);
@@ -733822,7 +733822,7 @@ var PERM_COLUMNS = [
733822
733822
  { header: "ID", key: "id" },
733823
733823
  { header: "Actor", key: "actor_type", format: (v6, row) => `${v6}:${row.actor?.display_name ?? row.actor_id?.substring(0, 8)}` },
733824
733824
  { header: "Level", key: "level" },
733825
- { header: "On", key: "permissible_type", format: (v6) => v6?.replace(/^Documents::/, "") ?? "" },
733825
+ { header: "On", key: "permissible_type", format: (v6) => v6?.replace(/^(Documents|Projects)::/, "") ?? "" },
733826
733826
  { header: "Resource ID", key: "permissible_id" },
733827
733827
  { header: "Updated", key: "updated_at" }
733828
733828
  ];
@@ -733831,7 +733831,8 @@ var PERMISSIBLE_ALIASES = {
733831
733831
  workspace: "Documents::Workspace",
733832
733832
  folder: "Documents::Folder",
733833
733833
  file: "Documents::File",
733834
- share_link: "Documents::ShareLink"
733834
+ share_link: "Documents::ShareLink",
733835
+ project: "Projects::Project"
733835
733836
  };
733836
733837
  var ACTOR_ALIASES = {
733837
733838
  user: "User",
@@ -733841,10 +733842,10 @@ var ACTOR_ALIASES = {
733841
733842
  function normalizePermissibleType(input, out) {
733842
733843
  const lower = input.toLowerCase();
733843
733844
  if (PERMISSIBLE_ALIASES[lower]) return PERMISSIBLE_ALIASES[lower];
733844
- if (input.startsWith("Documents::")) return input;
733845
+ if (input.startsWith("Documents::") || input.startsWith("Projects::")) return input;
733845
733846
  out.fail(
733846
733847
  new Error(
733847
- `Invalid --on-type: '${input}'. Use workspace/folder/file/share_link or a fully-qualified Documents::\u2026 class name.`
733848
+ `Invalid --on-type: '${input}'. Use workspace/folder/file/share_link/project or a fully-qualified Documents::\u2026 / Projects::\u2026 class name.`
733848
733849
  )
733849
733850
  );
733850
733851
  return "";
@@ -734334,7 +734335,7 @@ async function handleTicketsShow(id, opts) {
734334
734335
  out.fail(err);
734335
734336
  }
734336
734337
  }
734337
- function ticketBodyFromOpts(opts, includeAll) {
734338
+ function ticketBodyFromOpts(opts, out) {
734338
734339
  const body2 = {};
734339
734340
  if (opts.title !== void 0) body2.title = opts.title;
734340
734341
  if (opts.description !== void 0) body2.description = opts.description;
@@ -734355,14 +734356,21 @@ function ticketBodyFromOpts(opts, includeAll) {
734355
734356
  const labels = parseLabels(opts.labels);
734356
734357
  if (labels !== void 0) body2.labels = labels;
734357
734358
  if (opts.column !== void 0) body2.column_status = opts.column;
734358
- return includeAll ? body2 : body2;
734359
+ if (opts.agentConfig !== void 0) {
734360
+ try {
734361
+ body2.agent_config = JSON.parse(opts.agentConfig);
734362
+ } catch (err) {
734363
+ out.fail(new Error(`Invalid JSON for --agent-config: ${err.message}`));
734364
+ }
734365
+ }
734366
+ return body2;
734359
734367
  }
734360
734368
  async function handleTicketsCreate(opts) {
734361
734369
  const out = output(opts);
734362
734370
  requireProject2(opts, out);
734363
734371
  const ctx = await buildApiContext(out);
734364
734372
  if (!opts.title) out.fail(new Error("--title is required"));
734365
- const body2 = ticketBodyFromOpts(opts, true);
734373
+ const body2 = ticketBodyFromOpts(opts, out);
734366
734374
  try {
734367
734375
  const res = await ctx.axios.post(ticketsBase(opts.project), body2);
734368
734376
  const ticket = res.data?.ticket ?? res.data;
@@ -734375,7 +734383,7 @@ async function handleTicketsUpdate(id, opts) {
734375
734383
  const out = output(opts);
734376
734384
  requireProject2(opts, out);
734377
734385
  const ctx = await buildApiContext(out);
734378
- const body2 = ticketBodyFromOpts(opts, true);
734386
+ const body2 = ticketBodyFromOpts(opts, out);
734379
734387
  if (Object.keys(body2).length === 0) out.fail(new Error("No fields to update"));
734380
734388
  try {
734381
734389
  const res = await ctx.axios.patch(
@@ -734414,6 +734422,34 @@ async function handleTicketsDelete(id, opts) {
734414
734422
  out.fail(err);
734415
734423
  }
734416
734424
  }
734425
+ async function handleTicketsSetAgent(id, opts) {
734426
+ const out = output(opts);
734427
+ requireProject2(opts, out);
734428
+ const ctx = await buildApiContext(out);
734429
+ if (opts.agent === void 0) out.fail(new Error("--agent <agent-id|null> is required"));
734430
+ const body2 = {
734431
+ assignee_id: opts.agent === "null" ? null : opts.agent
734432
+ };
734433
+ if (opts.agentConfig !== void 0) {
734434
+ try {
734435
+ body2.agent_config = JSON.parse(opts.agentConfig);
734436
+ } catch (err) {
734437
+ out.fail(new Error(`Invalid JSON for --agent-config: ${err.message}`));
734438
+ }
734439
+ }
734440
+ try {
734441
+ const res = await ctx.axios.patch(
734442
+ `${ticketsBase(opts.project)}/${encodeURIComponent(id)}`,
734443
+ body2
734444
+ );
734445
+ out.ok(
734446
+ body2.assignee_id === null ? `Ticket ${id} agent cleared` : `Ticket ${id} agent set to ${body2.assignee_id}`,
734447
+ res.data?.ticket ?? res.data
734448
+ );
734449
+ } catch (err) {
734450
+ out.fail(err);
734451
+ }
734452
+ }
734417
734453
  async function handleTicketsAssign(id, opts) {
734418
734454
  const out = output(opts);
734419
734455
  requireProject2(opts, out);
@@ -734604,6 +734640,49 @@ async function handleTicketsDispatch(id, opts) {
734604
734640
  }
734605
734641
  }
734606
734642
 
734643
+ // apps/cli/cli/handlers/agent-handlers.ts
734644
+ var BASE4 = "/api/v1/agents";
734645
+ var AGENT_COLUMNS = [
734646
+ { header: "ID", key: "id" },
734647
+ { header: "Key", key: "key" },
734648
+ { header: "Name", key: "name", maxWidth: 30 },
734649
+ { header: "Type", key: "type", format: (v6) => v6?.replace(/^Agents::/, "") ?? "" },
734650
+ { header: "Active", key: "active", format: (v6) => v6 ? "\u2714" : "" }
734651
+ ];
734652
+ async function handleAgentsList(opts) {
734653
+ const out = output(opts);
734654
+ const ctx = await buildApiContext(out);
734655
+ const params = {};
734656
+ if (opts.active !== void 0) params.active = opts.active;
734657
+ if (opts.page) params.page = Number(opts.page);
734658
+ if (opts.perPage) params.per_page = Number(opts.perPage);
734659
+ try {
734660
+ const res = await ctx.axios.get(BASE4, { params });
734661
+ const items = Array.isArray(res.data) ? res.data : [];
734662
+ const pagination = extractPagination(res.headers, items.length);
734663
+ if (opts.json) {
734664
+ out.show({ items, pagination });
734665
+ return;
734666
+ }
734667
+ out.list(items, AGENT_COLUMNS);
734668
+ if (pagination.pages > 1) {
734669
+ out.note(`page ${pagination.page}/${pagination.pages} (${pagination.count} total)`);
734670
+ }
734671
+ } catch (err) {
734672
+ out.fail(err);
734673
+ }
734674
+ }
734675
+ async function handleAgentsShow(id, opts) {
734676
+ const out = output(opts);
734677
+ const ctx = await buildApiContext(out);
734678
+ try {
734679
+ const res = await ctx.axios.get(`${BASE4}/${encodeURIComponent(id)}`);
734680
+ out.show(res.data?.agent ?? res.data, { title: `Agent ${id}` });
734681
+ } catch (err) {
734682
+ out.fail(err);
734683
+ }
734684
+ }
734685
+
734607
734686
  // apps/cli/cli/handlers/task-handlers.ts
734608
734687
  var tasksBase = (pid, tid) => `/api/v1/projects/${encodeURIComponent(pid)}/tickets/${encodeURIComponent(tid)}/tasks`;
734609
734688
  var TASK_COLUMNS = [
@@ -734778,7 +734857,7 @@ async function handleTasksReorder(opts) {
734778
734857
  // apps/cli/cli.ts
734779
734858
  var getVersion = () => {
734780
734859
  try {
734781
- if (true) return "1.10.0";
734860
+ if (true) return "1.11.0";
734782
734861
  } catch {
734783
734862
  }
734784
734863
  for (const candidate of [
@@ -735123,10 +735202,10 @@ tickets.command("ls").alias("list").description("List tickets").requiredOption("
735123
735202
  tickets.command("show <id>").description("Show a ticket (with tasks, subtasks, deliverables)").requiredOption("--project <id>", "Parent project id").action(async (id, options) => {
735124
735203
  await handleTicketsShow(id, withGlobals(options));
735125
735204
  });
735126
- tickets.command("create").description("Create a ticket").requiredOption("--project <id>", "Parent project id").requiredOption("--title <text>").option("--description <text>").option("--type <ticket_type>", "task (default) | bug | story | epic | \u2026").option("--sprint <id>", "Attach to a sprint; omit to leave in backlog").option("--assignee <id>", "Assign to a user id").option("--priority <priority>", "lowest | low | medium | high | highest").option("--status <status>").option("--parent <id>", "Parent ticket id (for subtasks)").option("--due <YYYY-MM-DD>").option("--story-points <n>").option("--labels <a,b,c>", "Comma-separated labels").option("--column <column_status>").action(async (options) => {
735205
+ tickets.command("create").description("Create a ticket").requiredOption("--project <id>", "Parent project id").requiredOption("--title <text>").option("--description <text>").option("--type <ticket_type>", "task (default) | bug | story | epic | \u2026").option("--sprint <id>", "Attach to a sprint; omit to leave in backlog").option("--assignee <id>", "Assign to a user id").option("--priority <priority>", "lowest | low | medium | high | highest").option("--status <status>").option("--parent <id>", "Parent ticket id (for subtasks)").option("--due <YYYY-MM-DD>").option("--story-points <n>").option("--labels <a,b,c>", "Comma-separated labels").option("--column <column_status>").option("--agent-config <json>", "JSON payload written to the ticket agent_config (corex#591)").action(async (options) => {
735127
735206
  await handleTicketsCreate(withGlobals(options));
735128
735207
  });
735129
- tickets.command("update <id>").description("Update a ticket").requiredOption("--project <id>", "Parent project id").option("--title <text>").option("--description <text>").option("--type <ticket_type>").option("--sprint <id>", 'Move to a sprint; use "null" for backlog').option("--assignee <id>", 'Reassign; use "null" to unassign').option("--priority <priority>").option("--status <status>").option("--parent <id>").option("--due <YYYY-MM-DD>").option("--story-points <n>").option("--labels <a,b,c>").option("--column <column_status>").action(async (id, options) => {
735208
+ tickets.command("update <id>").description("Update a ticket").requiredOption("--project <id>", "Parent project id").option("--title <text>").option("--description <text>").option("--type <ticket_type>").option("--sprint <id>", 'Move to a sprint; use "null" for backlog').option("--assignee <id>", 'Reassign; use "null" to unassign').option("--priority <priority>").option("--status <status>").option("--parent <id>").option("--due <YYYY-MM-DD>").option("--story-points <n>").option("--labels <a,b,c>").option("--column <column_status>").option("--agent-config <json>", "JSON payload written to the ticket agent_config (corex#591)").action(async (id, options) => {
735130
735209
  await handleTicketsUpdate(id, withGlobals(options));
735131
735210
  });
735132
735211
  tickets.command("delete <id>").description("Delete a ticket (drops its tasks, deliverables, activities)").requiredOption("--project <id>", "Parent project id").option("--yes", "Skip the interactive confirmation").action(async (id, options) => {
@@ -735135,6 +735214,9 @@ tickets.command("delete <id>").description("Delete a ticket (drops its tasks, de
735135
735214
  tickets.command("assign <id>").description("Assign a ticket to a user; --to null to unassign").requiredOption("--project <id>", "Parent project id").requiredOption("--to <user-id|null>").action(async (id, options) => {
735136
735215
  await handleTicketsAssign(id, withGlobals(options));
735137
735216
  });
735217
+ tickets.command("set-agent <id>").description("Configure the ticket with an agent (assignee + agent_config in one PATCH) \u2014 needed before `dispatch` (corex#591)").requiredOption("--project <id>", "Parent project id").requiredOption("--agent <agent-id|null>", 'Agents::Agent UUID (use "null" to clear)').option("--agent-config <json>", "Optional JSON payload merged into agent_config").action(async (id, options) => {
735218
+ await handleTicketsSetAgent(id, withGlobals(options));
735219
+ });
735138
735220
  tickets.command("status <id>").description("Change a ticket status (optionally pin the kanban column with --column)").requiredOption("--project <id>", "Parent project id").requiredOption("--to <status>", "open | in_progress | done | blocked | awaiting_human | cancelled | failed").option("--column <column_status>", "Optionally set the kanban column at the same time").action(async (id, options) => {
735139
735221
  await handleTicketsStatus(id, withGlobals(options));
735140
735222
  });
@@ -735178,6 +735260,13 @@ tasks.command("complete <id>").description("Mark a task as completed (or re-open
735178
735260
  tasks.command("reorder").description("Reorder tasks under a ticket").requiredOption("--project <id>", "Parent project id").requiredOption("--ticket <id>", "Parent ticket id").requiredOption("--order <ids>", "Comma-separated task ids in the desired order").action(async (options) => {
735179
735261
  await handleTasksReorder(withGlobals(options));
735180
735262
  });
735263
+ var agents = program2.command("agents").description("List agents dispatchable on tickets (corex#591)");
735264
+ agents.command("ls").alias("list").description("List agents").option("--active", "Only agents whose config is active").option("--page <n>").option("--per-page <n>").action(async (options) => {
735265
+ await handleAgentsList(withGlobals(options));
735266
+ });
735267
+ agents.command("show <id>").description("Show an agent").action(async (id, options) => {
735268
+ await handleAgentsShow(id, withGlobals(options));
735269
+ });
735181
735270
  program2.parse();
735182
735271
  /*! Bundled license information:
735183
735272
 
package/docs/llm-usage.md CHANGED
@@ -377,16 +377,36 @@ themselves. All commands support `--json` for machine parsing.
377
377
  | start | complete`.
378
378
 
379
379
  `hubdoc tickets --project=<pid>` — `ls | show | create | update | delete
380
- | assign | status | move | activities | deliverable | dispatch |
381
- comment | comments`. Every verb requires `--project=<pid>`. `ls
382
- --backlog` (or `ls --sprint null`) lists the backlog. `assign --to null`
383
- unassigns. `status --to <state> [--column <col>]` uses the canonical
384
- statuses: `open | in_progress | done | blocked | awaiting_human |
385
- cancelled | failed` and optionally pins the kanban column at the same
386
- time. `comment <id> --body <text>` (or `--body-file <path>`) posts a
387
- message on the ticket's discussion thread (visible in Corex / Agoria,
388
- attributed to the token holder); `comments <id>` reads the thread
389
- oldest-first (paginated like `activities`).
380
+ | assign | set-agent | status | move | activities | deliverable |
381
+ dispatch | comment | comments`. Every verb requires `--project=<pid>`.
382
+ `ls --backlog` (or `ls --sprint null`) lists the backlog. `assign --to
383
+ null` unassigns. `status --to <state> [--column <col>]` uses the
384
+ canonical statuses: `open | in_progress | done | blocked |
385
+ awaiting_human | cancelled | failed` and optionally pins the kanban
386
+ column at the same time. `comment <id> --body <text>` (or `--body-file
387
+ <path>`) posts a message on the ticket's discussion thread (visible in
388
+ Corex / Agoria, attributed to the token holder); `comments <id>` reads
389
+ the thread oldest-first (paginated like `activities`).
390
+
391
+ **Agent configuration on tickets** (corex#591) : `create` and `update`
392
+ both accept `--agent-config <json>` — free-form jsonb persisted on the
393
+ ticket and read back by `dispatch_agent` / the agent runner (canonical
394
+ keys: `agent_role: planner|executor|…`, `instructions`). The convenience
395
+ verb `tickets set-agent <id> --project <pid> --agent <agent-id>
396
+ [--agent-config <json>]` PATCHes `assignee_id` and (optionally)
397
+ `agent_config` in one call — the shortest path from "empty ticket" to
398
+ "dispatchable". Use `hubdoc agents ls [--active]` to discover
399
+ dispatchable agent UUIDs (STI: `Agents::Planner`, `Agents::Executor`,
400
+ `Agents::Classifier`, `Agents::Conversational`, …).
401
+
402
+ **Project ACL** (hubdoc-tools#15) : the `permissions` verbs now accept
403
+ `--on-type project` (alias of `Projects::Project`) — the corex
404
+ `/api/v1/permissions` controller is polymorphic and `Projects::Project`
405
+ includes `HasPermissionsConcern`. This lets an agent share a **standalone
406
+ project** (no workspace attached) with a colleague or another agent
407
+ without going through a workspace-scoped ACL. Example:
408
+ `hubdoc permissions grant --to <user-id> --to-type user --on <project-id>
409
+ --on-type project --level admin`.
390
410
 
391
411
  `hubdoc tasks --project=<pid> --ticket=<tid>` — `ls | show | create |
392
412
  update | delete | complete | reorder`. Sub-tasks live under a ticket;
@@ -444,7 +464,13 @@ hubdoc tasks create --project "$PID" --ticket "$TID" \
444
464
  hubdoc tasks create --project "$PID" --ticket "$TID" \
445
465
  --title "Rédiger devis" --priority high --due 2026-07-16 --json
446
466
 
447
- # 5. Dispatch the agent already configured on the ticket.
467
+ # 5. Pick a dispatchable agent then set it on the ticket in one shot.
468
+ AGENT_ID=$(hubdoc agents ls --active --json | jq -r '.items[] | select(.key=="planner") | .id')
469
+ hubdoc tickets set-agent "$TID" --project "$PID" \
470
+ --agent "$AGENT_ID" \
471
+ --agent-config '{"agent_role":"planner","instructions":"Rédige un devis à partir des PJ."}' --json
472
+
473
+ # 5b. Now `dispatch` can actually fire (agent + agent_config both set).
448
474
  hubdoc tickets dispatch "$TID" --project "$PID" --json
449
475
 
450
476
  # 6. Later — post a follow-up on the ticket thread (visible to the human):
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sinoia/hubdoc-tools",
3
- "version": "1.10.0",
3
+ "version": "1.11.0",
4
4
  "description": "Professional command-line tool for HubDoc document management and bulk import/export",
5
5
  "main": "cli.js",
6
6
  "bin": {