@rubytech/taskmaster 1.16.0 → 1.16.2

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.
@@ -19,9 +19,7 @@ const applyPatchSchema = Type.Object({
19
19
  description: "Patch content using the *** Begin Patch/End Patch format.",
20
20
  }),
21
21
  });
22
- export function createApplyPatchTool(options = {}
23
- // biome-ignore lint/suspicious/noExplicitAny: TypeBox schema type from pi-agent-core uses a different module instance.
24
- ) {
22
+ export function createApplyPatchTool(options = {}) {
25
23
  const cwd = options.cwd ?? process.cwd();
26
24
  const sandboxRoot = options.sandboxRoot;
27
25
  return {
@@ -513,9 +513,7 @@ async function runExecProcess(opts) {
513
513
  kill: () => killSession(session),
514
514
  };
515
515
  }
516
- export function createExecTool(defaults
517
- // biome-ignore lint/suspicious/noExplicitAny: TypeBox schema type from pi-agent-core uses a different module instance.
518
- ) {
516
+ export function createExecTool(defaults) {
519
517
  const defaultBackgroundMs = clampNumber(defaults?.backgroundMs ?? readEnvInt("PI_BASH_YIELD_MS"), 10_000, 10, 120_000);
520
518
  const allowBackground = defaults?.allowBackground ?? true;
521
519
  const defaultTimeoutSec = typeof defaults?.timeoutSec === "number" && defaults.timeoutSec > 0
@@ -15,9 +15,7 @@ const processSchema = Type.Object({
15
15
  offset: Type.Optional(Type.Number({ description: "Log offset" })),
16
16
  limit: Type.Optional(Type.Number({ description: "Log length" })),
17
17
  });
18
- export function createProcessTool(defaults
19
- // biome-ignore lint/suspicious/noExplicitAny: TypeBox schema type from pi-agent-core uses a different module instance.
20
- ) {
18
+ export function createProcessTool(defaults) {
21
19
  if (defaults?.cleanupMs !== undefined) {
22
20
  setJobTtlMs(defaults.cleanupMs);
23
21
  }
@@ -15,7 +15,7 @@ export function createQrGenerateTool() {
15
15
  label: "QR Code Generator",
16
16
  name: "qr_generate",
17
17
  description: "Generate a QR code PNG from any string (URL, text, vCard, WhatsApp link). " +
18
- "Returns a MEDIA: path — copy it into the message tool's media parameter to send the image.",
18
+ "Returns a MEDIA: path — copy the MEDIA: line exactly into your response to deliver the image.",
19
19
  parameters: QrGenerateSchema,
20
20
  execute: async (_toolCallId, params) => {
21
21
  const data = readStringParam(params, "data");
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.16.0",
3
- "commit": "9830d785665203ad352817c2a66187770e603d2b",
4
- "builtAt": "2026-03-04T17:18:30.230Z"
2
+ "version": "1.16.2",
3
+ "commit": "5b738cb70310248225f83f6a39d49c7f9abcbe71",
4
+ "builtAt": "2026-03-04T17:48:55.756Z"
5
5
  }
@@ -124,6 +124,38 @@ export function reconcileStaleToolEntries(params) {
124
124
  }
125
125
  return { config, changes };
126
126
  }
127
+ /**
128
+ * Add `qr_generate` to any agent whose explicit allow list contains `document_to_pdf`.
129
+ *
130
+ * Both tools are in `group:documents`. Agents that reference the group by name already
131
+ * receive `qr_generate` automatically. Agents with explicit allow lists do not — this
132
+ * reconciliation patches them on gateway startup.
133
+ *
134
+ * Idempotent — skips agents that already have `qr_generate`.
135
+ */
136
+ export function reconcileQrGenerateTool(params) {
137
+ const config = structuredClone(params.config);
138
+ const changes = [];
139
+ const agents = config.agents?.list;
140
+ if (!Array.isArray(agents))
141
+ return { config, changes };
142
+ for (const agent of agents) {
143
+ if (!agent)
144
+ continue;
145
+ const allow = agent.tools?.allow;
146
+ if (!Array.isArray(allow))
147
+ continue;
148
+ // Only patch agents that explicitly have document_to_pdf and lack qr_generate
149
+ if (!allow.includes("document_to_pdf"))
150
+ continue;
151
+ if (allow.includes("qr_generate"))
152
+ continue;
153
+ const idx = allow.indexOf("document_to_pdf");
154
+ allow.splice(idx + 1, 0, "qr_generate");
155
+ changes.push(`Added qr_generate to agent "${agent.id ?? "<unnamed>"}" tools.allow.`);
156
+ }
157
+ return { config, changes };
158
+ }
127
159
  /**
128
160
  * Remove privileged tools (`message`, `contact_lookup`, `group:contacts`) from
129
161
  * Beagle public agent allow lists.
@@ -10,7 +10,7 @@ import { CONFIG_PATH_TASKMASTER, isNixMode, loadConfig, migrateLegacyConfig, rea
10
10
  import { VERSION } from "../version.js";
11
11
  import { isDiagnosticsEnabled } from "../infra/diagnostic-events.js";
12
12
  import { logAcceptedEnvOption } from "../infra/env.js";
13
- import { reconcileAgentContactTools, reconcileBeaglePublicTools, reconcileStaleToolEntries, } from "../config/agent-tools-reconcile.js";
13
+ import { reconcileAgentContactTools, reconcileBeaglePublicTools, reconcileQrGenerateTool, reconcileStaleToolEntries, } from "../config/agent-tools-reconcile.js";
14
14
  import { applyPluginAutoEnable } from "../config/plugin-auto-enable.js";
15
15
  import { clearAgentRunContext, onAgentEvent } from "../infra/agent-events.js";
16
16
  import { onHeartbeatEvent } from "../infra/heartbeat-events.js";
@@ -184,6 +184,20 @@ export async function startGatewayServer(port = 18789, opts = {}) {
184
184
  log.warn(`gateway: failed to persist Beagle public tools reconciliation: ${String(err)}`);
185
185
  }
186
186
  }
187
+ // Add qr_generate to agents that have document_to_pdf in their explicit allow list.
188
+ const qrReconcile = reconcileQrGenerateTool({ config: configSnapshot.config });
189
+ if (qrReconcile.changes.length > 0) {
190
+ try {
191
+ await writeConfigFile(qrReconcile.config);
192
+ configSnapshot = await readConfigFileSnapshot();
193
+ log.info(`gateway: reconciled qr_generate tool:\n${qrReconcile.changes
194
+ .map((entry) => `- ${entry}`)
195
+ .join("\n")}`);
196
+ }
197
+ catch (err) {
198
+ log.warn(`gateway: failed to persist qr_generate tool reconciliation: ${String(err)}`);
199
+ }
200
+ }
187
201
  // Stamp config with running version on startup so upgrades keep the stamp current.
188
202
  const storedVersion = configSnapshot.config.meta?.lastTouchedVersion;
189
203
  if (configSnapshot.exists && storedVersion !== VERSION) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rubytech/taskmaster",
3
- "version": "1.16.0",
3
+ "version": "1.16.2",
4
4
  "description": "AI-powered business assistant for small businesses",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -18,10 +18,14 @@ Generate a QR code image and send it via the `message` tool.
18
18
 
19
19
  1. **Assemble the data string** (see Content Types below)
20
20
  2. **Call `qr_generate`** with the assembled string as `data`
21
- 3. **Copy the `MEDIA:` path** from the tool result exactly
22
- 4. **Call `message`** with that path as the `media` parameter and a short caption
21
+ 3. **Copy the `MEDIA:` line from the tool result verbatim into your response** — do not convert it to markdown or a URL. Write it exactly as returned (e.g. `MEDIA:/tmp/qr-1234567890.png`). The channel delivers it as an image attachment automatically.
22
+ 4. **Add a brief caption** as a separate line of text before or after the `MEDIA:` line.
23
23
 
24
- Example caption: "Here's your QR code — scan to open the listing."
24
+ Example response:
25
+ ```
26
+ Here's your QR code — scan to open the listing.
27
+ MEDIA:/tmp/qr-1234567890.png
28
+ ```
25
29
 
26
30
  ## Content Types
27
31