@integrity-labs/agt-cli 0.28.466 → 0.28.467

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin/agt.js CHANGED
@@ -40,7 +40,7 @@ import {
40
40
  success,
41
41
  table,
42
42
  warn
43
- } from "../chunk-CL24G4D3.js";
43
+ } from "../chunk-P5NFIZI4.js";
44
44
  import {
45
45
  AnchorSessionClient,
46
46
  CHANNEL_REGISTRY,
@@ -4830,7 +4830,7 @@ import { execFileSync, execSync } from "child_process";
4830
4830
  import { existsSync as existsSync10, realpathSync as realpathSync2 } from "fs";
4831
4831
  import chalk18 from "chalk";
4832
4832
  import ora16 from "ora";
4833
- var cliVersion = true ? "0.28.466" : "dev";
4833
+ var cliVersion = true ? "0.28.467" : "dev";
4834
4834
  async function fetchLatestVersion() {
4835
4835
  const host2 = getHost();
4836
4836
  if (!host2) return null;
@@ -6002,7 +6002,7 @@ function handleError(err) {
6002
6002
  }
6003
6003
 
6004
6004
  // src/bin/agt.ts
6005
- var cliVersion2 = true ? "0.28.466" : "dev";
6005
+ var cliVersion2 = true ? "0.28.467" : "dev";
6006
6006
  var program = new Command();
6007
6007
  program.name("agt").description("Augmented CLI \u2014 agent provisioning and management").version(cliVersion2).option("--json", "Emit machine-readable JSON output (suppress spinners and colors)").option("--skip-update-check", "Skip the automatic update check on startup");
6008
6008
  program.hook("preAction", async (thisCommand, actionCommand) => {
@@ -4911,7 +4911,7 @@ function requireHost() {
4911
4911
  }
4912
4912
 
4913
4913
  // src/lib/api-client.ts
4914
- var agtCliVersion = true ? "0.28.466" : "dev";
4914
+ var agtCliVersion = true ? "0.28.467" : "dev";
4915
4915
  var lastConfigHash = null;
4916
4916
  function setConfigHash(hash) {
4917
4917
  lastConfigHash = hash && hash.length > 0 ? hash : null;
@@ -7595,4 +7595,4 @@ export {
7595
7595
  managerInstallSystemUnitCommand,
7596
7596
  managerUninstallSystemUnitCommand
7597
7597
  };
7598
- //# sourceMappingURL=chunk-CL24G4D3.js.map
7598
+ //# sourceMappingURL=chunk-P5NFIZI4.js.map
@@ -42,7 +42,7 @@ import {
42
42
  resolveEffectivePinRaw,
43
43
  safeWriteJsonAtomic,
44
44
  setConfigHash
45
- } from "../chunk-CL24G4D3.js";
45
+ } from "../chunk-P5NFIZI4.js";
46
46
  import {
47
47
  getProjectDir as getProjectDir2,
48
48
  getReadyTasks,
@@ -9976,7 +9976,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
9976
9976
  var lastVersionCheckAt = 0;
9977
9977
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
9978
9978
  var lastResponsivenessProbeAt = 0;
9979
- var agtCliVersion = true ? "0.28.466" : "dev";
9979
+ var agtCliVersion = true ? "0.28.467" : "dev";
9980
9980
  function resolveBrewPath(execFileSync2) {
9981
9981
  try {
9982
9982
  const out = execFileSync2("which", ["brew"], { timeout: 5e3 }).toString().trim();
package/dist/mcp/index.js CHANGED
@@ -21057,6 +21057,9 @@ function kanbanStatusLabel(status) {
21057
21057
  function kanbanPriorityLabel(priority) {
21058
21058
  return priority === 1 ? "HIGH" : priority === 3 ? "LOW" : "MED";
21059
21059
  }
21060
+ function isHumanAssigned(item) {
21061
+ return item.assignee_type !== void 0 && item.assignee_type !== "agent";
21062
+ }
21060
21063
  function groupKanbanByStatus(items) {
21061
21064
  const groups = {};
21062
21065
  for (const item of items) {
@@ -21064,9 +21067,18 @@ function groupKanbanByStatus(items) {
21064
21067
  }
21065
21068
  return groups;
21066
21069
  }
21070
+ function renderKanbanItemLine(item) {
21071
+ const pri = kanbanPriorityLabel(item.priority);
21072
+ const est = item.estimated_minutes ? ` ~${item.estimated_minutes}min` : "";
21073
+ const del = item.deliverable ? ` \u2192 ${item.deliverable}` : "";
21074
+ const res = item.result ? ` \u2713 ${item.result}` : "";
21075
+ return `- [${pri}] ${item.title}${est}${del}${res} (id: ${item.id})`;
21076
+ }
21067
21077
  function renderKanbanList(items) {
21068
21078
  if (!items.length) return "Board is empty.";
21069
- const grouped = groupKanbanByStatus(items);
21079
+ const humanAssigned = items.filter(isHumanAssigned);
21080
+ const mine = items.filter((i) => !isHumanAssigned(i));
21081
+ const grouped = groupKanbanByStatus(mine);
21070
21082
  const lines = [];
21071
21083
  const known = new Set(KANBAN_LIST_DISPLAY_ORDER);
21072
21084
  const unknown2 = Object.keys(grouped).filter((s) => !known.has(s));
@@ -21076,16 +21088,92 @@ function renderKanbanList(items) {
21076
21088
  if (!group?.length) continue;
21077
21089
  lines.push(`
21078
21090
  ## ${kanbanStatusLabel(status)} (${group.length})`);
21079
- for (const item of group) {
21080
- const pri = kanbanPriorityLabel(item.priority);
21081
- const est = item.estimated_minutes ? ` ~${item.estimated_minutes}min` : "";
21082
- const del = item.deliverable ? ` \u2192 ${item.deliverable}` : "";
21083
- const res = item.result ? ` \u2713 ${item.result}` : "";
21084
- lines.push(`- [${pri}] ${item.title}${est}${del}${res} (id: ${item.id})`);
21091
+ for (const item of group) lines.push(renderKanbanItemLine(item));
21092
+ }
21093
+ if (humanAssigned.length) {
21094
+ lines.push(`
21095
+ ## ${HUMAN_ASSIGNED_SECTION_HEADING} (${humanAssigned.length})`);
21096
+ lines.push(HUMAN_ASSIGNED_SECTION_NOTE);
21097
+ for (const item of humanAssigned) {
21098
+ const who = item.assignee_name ? ` [with ${item.assignee_name}]` : "";
21099
+ lines.push(`${renderKanbanItemLine(item)}${who}`);
21085
21100
  }
21086
21101
  }
21087
21102
  return lines.join("\n");
21088
21103
  }
21104
+ var HUMAN_ASSIGNED_SECTION_HEADING = "Assigned to a person (not yours to action)";
21105
+ var HUMAN_ASSIGNED_SECTION_NOTE = "_These belong to a person, not to you. You cannot move, note or complete them \u2014 every kanban write is refused. If the work is finished (or was never really theirs), use `kanban_recall` to pull the card back onto your board, then close it as normal._";
21106
+
21107
+ // src/kanban-write-outcome.ts
21108
+ function describeKanbanWriteFailure(failure, label) {
21109
+ if (!failure) return null;
21110
+ switch (failure.reason) {
21111
+ case "assigned_to_human": {
21112
+ const who = failure.assignee_name ? ` (${failure.assignee_name})` : "";
21113
+ return `Can't touch "${label}" \u2014 that card is assigned to a person${who}, not to you, so every kanban write to it is refused. It still shows on your board for visibility. If the work is done (or should come back to you), call kanban_recall with this id first, then move or complete it as normal.`;
21114
+ }
21115
+ case "ambiguous_match": {
21116
+ const candidates = failure.candidates ?? [];
21117
+ if (candidates.length === 0) {
21118
+ return `"${label}" matched more than one card. Retry with the card's id.`;
21119
+ }
21120
+ const listed = candidates.map((c) => ` - ${c.title} [${c.status}] (id: ${c.id})`).join("\n");
21121
+ return `"${label}" matched ${candidates.length} cards. Retry with one of these ids:
21122
+ ${listed}`;
21123
+ }
21124
+ case "invalid_transition":
21125
+ return `Can't move "${label}" from ${failure.from ?? "its current status"} to ${failure.to ?? "that status"} \u2014 closed cards are not reopened this way. Add a new card if the work has genuinely restarted.`;
21126
+ case "not_found":
21127
+ return null;
21128
+ // The caller's existing "not found" message is correct here.
21129
+ default:
21130
+ return `Couldn't update "${label}": ${failure.reason}.`;
21131
+ }
21132
+ }
21133
+ function selectKanbanFailure(data, match) {
21134
+ const failures = data?.failed_updates ?? [];
21135
+ if (failures.length === 0) return void 0;
21136
+ const exact = failures.find(
21137
+ (f) => match.id !== void 0 && f.id === match.id || match.title !== void 0 && f.title === match.title
21138
+ );
21139
+ if (exact) return exact;
21140
+ return failures.length === 1 ? failures[0] : void 0;
21141
+ }
21142
+ function describeKanbanWriteOutcome(data, match, label, onSuccess) {
21143
+ if ((data?.updated ?? 0) > 0) return { text: onSuccess(), isError: false };
21144
+ const explained = describeKanbanWriteFailure(selectKanbanFailure(data, match), label);
21145
+ return { text: explained ?? `Item "${label}" not found.`, isError: true };
21146
+ }
21147
+ function describeKanbanRecallResult(data, requestedId) {
21148
+ if (!data) {
21149
+ return {
21150
+ text: `Recall of ${requestedId} returned nothing. The card is still with the person it was assigned to.`,
21151
+ isError: true
21152
+ };
21153
+ }
21154
+ if (data.ok !== true) {
21155
+ if (data.reason === "not_found") {
21156
+ return {
21157
+ text: `No card with id ${requestedId} on your board. You can only recall a card you assigned yourself - check the id against kanban_list.`,
21158
+ isError: true
21159
+ };
21160
+ }
21161
+ return {
21162
+ text: `Recall of ${requestedId} was refused${data.reason ? `: ${data.reason}` : ""}. The card is still with the person it was assigned to.`,
21163
+ isError: true
21164
+ };
21165
+ }
21166
+ if (data.reason === "already_agent_assigned") {
21167
+ return {
21168
+ text: `"${data.title ?? requestedId}" is already on your board - nothing to recall. You can act on it directly.`,
21169
+ isError: false
21170
+ };
21171
+ }
21172
+ return {
21173
+ text: `Recalled "${data.title ?? requestedId}" onto your board (status: ${data.status ?? "unchanged"}). It is yours to act on now - close it with kanban_done and a result if the work is finished.`,
21174
+ isError: false
21175
+ };
21176
+ }
21089
21177
 
21090
21178
  // src/token-refresh-selection.ts
21091
21179
  var REFRESH_WINDOW_MS = 10 * 6e4;
@@ -21479,9 +21567,13 @@ function buildKanbanLogUpdate(params) {
21479
21567
  if (params.title) update.title = params.title;
21480
21568
  return { update };
21481
21569
  }
21482
- function formatKanbanLogResult(label, data) {
21570
+ function formatKanbanLogResult(label, data, match = {}) {
21483
21571
  if (data.updated < 1) {
21484
- return { text: `Item "${label}" not found.`, isError: true };
21572
+ const explained = describeKanbanWriteFailure(
21573
+ selectKanbanFailure(data, match),
21574
+ label ?? ""
21575
+ );
21576
+ return { text: explained ?? `Item "${label}" not found.`, isError: true };
21485
21577
  }
21486
21578
  const trimmed = data.updated_items?.some((i) => i.notes_truncated) ?? false;
21487
21579
  return {
@@ -21922,14 +22014,16 @@ server.tool(
21922
22014
  }
21923
22015
  ]
21924
22016
  });
21925
- const label = params.id ?? params.title;
22017
+ const label = params.id ?? params.title ?? "";
22018
+ const outcome = describeKanbanWriteOutcome(
22019
+ data,
22020
+ { id: params.id, title: params.title },
22021
+ label,
22022
+ () => `Moved "${label}" \u2192 ${params.status}.`
22023
+ );
21926
22024
  return {
21927
- content: [
21928
- {
21929
- type: "text",
21930
- text: data.updated > 0 ? `Moved "${label}" \u2192 ${params.status}.` : `Item "${label}" not found.`
21931
- }
21932
- ]
22025
+ content: [{ type: "text", text: outcome.text }],
22026
+ ...outcome.isError ? { isError: true } : {}
21933
22027
  };
21934
22028
  }
21935
22029
  );
@@ -21963,6 +22057,18 @@ server.tool(
21963
22057
  isError: true
21964
22058
  };
21965
22059
  }
22060
+ if (isHumanAssigned(match)) {
22061
+ const who = match.assignee_name ? ` (${match.assignee_name})` : "";
22062
+ return {
22063
+ content: [
22064
+ {
22065
+ type: "text",
22066
+ text: `Can't update "${match.title}" \u2014 that card is assigned to a person${who}, not to you. Call kanban_recall with id ${match.id} to bring it back onto your board first.`
22067
+ }
22068
+ ],
22069
+ isError: true
22070
+ };
22071
+ }
21966
22072
  const data = await apiPost("/host/kanban", {
21967
22073
  agent_id: AGT_AGENT_ID,
21968
22074
  update: [
@@ -21974,13 +22080,15 @@ server.tool(
21974
22080
  }
21975
22081
  ]
21976
22082
  });
22083
+ const outcome = describeKanbanWriteOutcome(
22084
+ data,
22085
+ { id: match.id },
22086
+ match.title,
22087
+ () => `Updated "${match.title}".`
22088
+ );
21977
22089
  return {
21978
- content: [
21979
- {
21980
- type: "text",
21981
- text: data.updated > 0 ? `Updated "${match.title}".` : "Update failed."
21982
- }
21983
- ]
22090
+ content: [{ type: "text", text: outcome.text }],
22091
+ ...outcome.isError ? { isError: true } : {}
21984
22092
  };
21985
22093
  }
21986
22094
  );
@@ -22008,7 +22116,10 @@ server.tool(
22008
22116
  );
22009
22117
  const { text, isError } = formatKanbanLogResult(
22010
22118
  params.id ?? params.title,
22011
- data
22119
+ data,
22120
+ // ENG-8281: pass the match so a refusal can be attributed and explained
22121
+ // (e.g. "assigned to a person — recall it first") instead of "not found".
22122
+ { id: params.id, title: params.title }
22012
22123
  );
22013
22124
  return { content: [{ type: "text", text }], ...isError ? { isError: true } : {} };
22014
22125
  }
@@ -22040,14 +22151,16 @@ server.tool(
22040
22151
  }
22041
22152
  ]
22042
22153
  });
22043
- const label = params.id ?? params.title;
22154
+ const label = params.id ?? params.title ?? "";
22155
+ const outcome = describeKanbanWriteOutcome(
22156
+ data,
22157
+ { id: params.id, title: params.title },
22158
+ label,
22159
+ () => params.step.trim().length > 0 ? `Progress on "${label}": ${params.step}` : `Cleared progress step on "${label}".`
22160
+ );
22044
22161
  return {
22045
- content: [
22046
- {
22047
- type: "text",
22048
- text: data.updated > 0 ? params.step.trim().length > 0 ? `Progress on "${label}": ${params.step}` : `Cleared progress step on "${label}".` : `Item "${label}" not found.`
22049
- }
22050
- ]
22162
+ content: [{ type: "text", text: outcome.text }],
22163
+ ...outcome.isError ? { isError: true } : {}
22051
22164
  };
22052
22165
  }
22053
22166
  );
@@ -22090,15 +22203,17 @@ server.tool(
22090
22203
  }
22091
22204
  ]
22092
22205
  });
22093
- const label = params.id ?? params.title;
22206
+ const label = params.id ?? params.title ?? "";
22094
22207
  const deliveryNote = params.suppress_delivery === true ? " Delivery suppressed (recorded on the card only)." : params.suppress_delivery === false ? " Delivery asserted." : "";
22208
+ const outcome = describeKanbanWriteOutcome(
22209
+ data,
22210
+ { id: params.id, title: params.title },
22211
+ label,
22212
+ () => `Marked "${label}" as done.${params.result ? ` Result: ${params.result}` : ""}${deliveryNote}`
22213
+ );
22095
22214
  return {
22096
- content: [
22097
- {
22098
- type: "text",
22099
- text: data.updated > 0 ? `Marked "${label}" as done.${params.result ? ` Result: ${params.result}` : ""}${deliveryNote}` : `Item "${label}" not found.`
22100
- }
22101
- ]
22215
+ content: [{ type: "text", text: outcome.text }],
22216
+ ...outcome.isError ? { isError: true } : {}
22102
22217
  };
22103
22218
  }
22104
22219
  );
@@ -22281,6 +22396,33 @@ server.tool(
22281
22396
  }
22282
22397
  }
22283
22398
  );
22399
+ server.tool(
22400
+ "kanban_recall",
22401
+ 'Pull a card you assigned to a HUMAN teammate back onto your own board. Use this when a card shows under "Assigned to a person" in kanban_list and you need to act on it - typically because the person finished the work (or it is no longer needed) and the card has to be closed. While a card is assigned to a person, every kanban write to it is refused; recall makes it yours again so kanban_move / kanban_done / kanban_log work. Recall does NOT complete the card - after recalling, close it yourself with kanban_done and a result. You can only recall a card you assigned.',
22402
+ {
22403
+ id: external_exports.string().describe('The card id, exactly as kanban_list shows it under "Assigned to a person".'),
22404
+ reason: external_exports.string().optional().describe(
22405
+ `Short note on why you are taking it back (e.g. "Brad confirmed the merge, closing it out"). Recorded in the audit trail - the card leaves a person's queue, so say why.`
22406
+ )
22407
+ },
22408
+ async (params) => {
22409
+ try {
22410
+ const data = await apiPost("/host/kanban/recall", {
22411
+ agent_id: AGT_AGENT_ID,
22412
+ id: params.id,
22413
+ reason: params.reason
22414
+ });
22415
+ const { text, isError } = describeKanbanRecallResult(data, params.id);
22416
+ return { content: [{ type: "text", text }], ...isError ? { isError: true } : {} };
22417
+ } catch (err) {
22418
+ const msg = err instanceof Error ? err.message : String(err);
22419
+ return {
22420
+ content: [{ type: "text", text: `Could not recall card ${params.id}: ${msg}` }],
22421
+ isError: true
22422
+ };
22423
+ }
22424
+ }
22425
+ );
22284
22426
  server.tool(
22285
22427
  "status_standup",
22286
22428
  "Submit a daily standup update with yesterday, today, and blockers.",
@@ -23709,6 +23851,9 @@ var LOCAL_TOOL_NAMES = /* @__PURE__ */ new Set([
23709
23851
  "kanban_assign",
23710
23852
  "kanban_reassign",
23711
23853
  "assign_kanban_to_human",
23854
+ // ENG-8281: the inverse of assign_kanban_to_human — take a human-assigned
23855
+ // card back so the agent can finally close it.
23856
+ "kanban_recall",
23712
23857
  // ENG-6953: agent + people directory lookup (always registered locally).
23713
23858
  "directory_lookup",
23714
23859
  "status_standup",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@integrity-labs/agt-cli",
3
- "version": "0.28.466",
3
+ "version": "0.28.467",
4
4
  "description": "Augmented Team CLI — agent provisioning and management",
5
5
  "type": "module",
6
6
  "engines": {