pipe-kan 0.17.0 → 0.18.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 (2) hide show
  1. package/dist/pipe-kan.js +89 -6
  2. package/package.json +1 -1
package/dist/pipe-kan.js CHANGED
@@ -10596,6 +10596,7 @@ class AcpSession {
10596
10596
  ready = Promise.withResolvers();
10597
10597
  textBuffer = "";
10598
10598
  detectToolCall = null;
10599
+ toolCalls = new Map;
10599
10600
  constructor(config) {
10600
10601
  this.config = config;
10601
10602
  this.id = crypto.randomUUID();
@@ -10610,6 +10611,17 @@ class AcpSession {
10610
10611
  setToolParser(parser) {
10611
10612
  this.detectToolCall = parser;
10612
10613
  }
10614
+ pendingToolCalls() {
10615
+ return this.toolCalls;
10616
+ }
10617
+ resolveToolCall(requestId, resultText) {
10618
+ const call = this.toolCalls.get(requestId);
10619
+ if (!call)
10620
+ return;
10621
+ this.toolCalls.delete(requestId);
10622
+ this.prompt(`Tool result for ${call.name}(${JSON.stringify(call.args)}):
10623
+ ${resultText}`);
10624
+ }
10613
10625
  approve(requestId, decision) {
10614
10626
  const entry = this.pendingPermissionResolvers.get(requestId);
10615
10627
  if (!entry)
@@ -10705,6 +10717,7 @@ class AcpSession {
10705
10717
  this.textBuffer += update.content.text;
10706
10718
  const tool = this.detectToolCall?.(this.textBuffer);
10707
10719
  if (tool) {
10720
+ this.toolCalls.set(tool.requestId, tool);
10708
10721
  this.push({ type: "tool_call", ...tool });
10709
10722
  return;
10710
10723
  }
@@ -10852,7 +10865,7 @@ function parseFrontMatter(text) {
10852
10865
  var TOOLS = [
10853
10866
  {
10854
10867
  name: "board_state",
10855
- description: "Read the current pipe-kan board state, columns, and cards.",
10868
+ description: "Read the current board columns and cards without changing anything.",
10856
10869
  parameters: {},
10857
10870
  mutates: false
10858
10871
  },
@@ -10890,6 +10903,52 @@ var TOOLS = [
10890
10903
  mutates: true
10891
10904
  }
10892
10905
  ];
10906
+ var EXECUTORS = {
10907
+ board_state(_, app) {
10908
+ const board = app.board();
10909
+ const columns = board.columns.map((c) => ({
10910
+ title: c.title,
10911
+ cards: c.cards.map((card) => ({ key: card.key, summary: card.summary, epic: card.epic }))
10912
+ }));
10913
+ return { ok: true, value: { columns } };
10914
+ },
10915
+ async issue_details(args, app) {
10916
+ const key = String(args.key ?? "");
10917
+ if (!key)
10918
+ return { ok: false, error: "Missing key parameter" };
10919
+ const result = await app.open(key);
10920
+ if (result.error)
10921
+ return { ok: false, error: result.error };
10922
+ return { ok: true, value: { url: result.url, fields: result.fields } };
10923
+ },
10924
+ async move_card(args, app) {
10925
+ const key = String(args.key ?? "");
10926
+ const status = String(args.status ?? "");
10927
+ if (!key || !status)
10928
+ return { ok: false, error: "Missing key or status" };
10929
+ const result = await app.move(key, status);
10930
+ if (result.error)
10931
+ return { ok: false, error: result.error };
10932
+ return { ok: true, value: { moved: key, to: status } };
10933
+ },
10934
+ async refresh_board(args, app) {
10935
+ const flags = typeof args.flags === "string" ? args.flags : undefined;
10936
+ await app.refresh(flags);
10937
+ return { ok: true, value: "Board refreshed" };
10938
+ },
10939
+ apply_preset(args) {
10940
+ const name = String(args.name ?? "");
10941
+ if (!name)
10942
+ return { ok: false, error: "Missing preset name" };
10943
+ return { ok: true, value: `Preset '${name}' would be applied by the UI when tool execution is wired there.` };
10944
+ },
10945
+ set_filter(args) {
10946
+ const filter = args.filter;
10947
+ if (!filter || typeof filter !== "object")
10948
+ return { ok: false, error: "Missing filter object" };
10949
+ return { ok: true, value: `Filter set to ${JSON.stringify(filter)}. UI should apply this filter.` };
10950
+ }
10951
+ };
10893
10952
  var SYSTEM_TEXT = `You can call tools by emitting a single JSON code block matching this schema:
10894
10953
 
10895
10954
  {"tool": "<name>", "args": {...}}
@@ -10926,6 +10985,16 @@ function createToolRegistry() {
10926
10985
  } catch {
10927
10986
  return;
10928
10987
  }
10988
+ },
10989
+ async execute(name, args, app) {
10990
+ const executor = EXECUTORS[name];
10991
+ if (!executor)
10992
+ return { ok: false, error: `Unknown tool: ${name}` };
10993
+ try {
10994
+ return await executor(args, app);
10995
+ } catch (err) {
10996
+ return { ok: false, error: String(err) };
10997
+ }
10929
10998
  }
10930
10999
  };
10931
11000
  }
@@ -10950,7 +11019,7 @@ function readBody2(req) {
10950
11019
  function pathOf2(req) {
10951
11020
  return new URL(req.url ?? "/", "http://127.0.0.1");
10952
11021
  }
10953
- function handleAgentApi(req, res) {
11022
+ function handleAgentApi(req, res, app) {
10954
11023
  const url = pathOf2(req);
10955
11024
  const method = (req.method ?? "GET").toUpperCase();
10956
11025
  if (url.pathname === "/api/agent/config" && method === "GET") {
@@ -11020,14 +11089,28 @@ function handleAgentApi(req, res) {
11020
11089
  return true;
11021
11090
  }
11022
11091
  if (url.pathname === "/api/agent/approve" && method === "POST") {
11023
- readBody2(req).then((text) => {
11092
+ readBody2(req).then(async (text) => {
11024
11093
  const body = JSON.parse(text);
11025
11094
  const session = sessions.get(body.sessionId ?? "");
11026
11095
  if (!session) {
11027
11096
  json2(res, 404, { error: "Session not found" });
11028
11097
  return;
11029
11098
  }
11030
- session.approve(String(body.requestId ?? ""), body.decision ?? "reject");
11099
+ const requestId = String(body.requestId ?? "");
11100
+ const decision = body.decision ?? "reject";
11101
+ const toolCall = session.pendingToolCalls().get(requestId);
11102
+ if (toolCall) {
11103
+ if (decision === "reject") {
11104
+ session.resolveToolCall(requestId, "Tool call was rejected by the user.");
11105
+ } else {
11106
+ const result = await tools.execute(toolCall.name, toolCall.args, app);
11107
+ const resultText = result.ok ? `Result: ${JSON.stringify(result.value)}` : `Error: ${result.error}`;
11108
+ session.resolveToolCall(requestId, resultText);
11109
+ }
11110
+ json2(res, 200, { ok: true });
11111
+ return;
11112
+ }
11113
+ session.approve(requestId, decision);
11031
11114
  json2(res, 200, { ok: true });
11032
11115
  }).catch((err) => json2(res, 500, { error: String(err) }));
11033
11116
  return true;
@@ -11055,7 +11138,7 @@ function handleAgentApi(req, res) {
11055
11138
  (async () => {
11056
11139
  for await (const event of session.events()) {
11057
11140
  writeEvent(event);
11058
- if (event.type === "disconnected" || event.type === "stop_reason") {
11141
+ if (event.type === "disconnected") {
11059
11142
  break;
11060
11143
  }
11061
11144
  }
@@ -11177,7 +11260,7 @@ function handleFakeJira(req, res, store) {
11177
11260
 
11178
11261
  // src/http.ts
11179
11262
  function handleRequest(req, res, ctx) {
11180
- return handleAppApi(req, res, ctx.app) || handleAgentApi(req, res) || handleFakeJira(req, res, ctx.store);
11263
+ return handleAppApi(req, res, ctx.app) || handleAgentApi(req, res, ctx.app) || handleFakeJira(req, res, ctx.store);
11181
11264
  }
11182
11265
 
11183
11266
  // src/jira-config.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pipe-kan",
3
- "version": "0.17.0",
3
+ "version": "0.18.0",
4
4
  "description": "Local Kanban for jira-cli",
5
5
  "license": "MIT",
6
6
  "type": "module",