@rubytech/taskmaster 1.0.94 → 1.0.95

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 (40) hide show
  1. package/dist/agents/taskmaster-tools.js +4 -4
  2. package/dist/agents/tool-policy.js +2 -2
  3. package/dist/agents/tools/contact-lookup-tool.js +45 -0
  4. package/dist/agents/tools/contact-update-tool.js +68 -0
  5. package/dist/agents/tools/memory-tool.js +10 -3
  6. package/dist/build-info.json +3 -3
  7. package/dist/cli/provision-seed.js +2 -2
  8. package/dist/control-ui/assets/{index-B7exVNNa.css → index-BWth4bv5.css} +1 -1
  9. package/dist/control-ui/assets/{index-DfQL37PU.js → index-Bem0-Ojd.js} +220 -220
  10. package/dist/control-ui/assets/index-Bem0-Ojd.js.map +1 -0
  11. package/dist/control-ui/index.html +2 -2
  12. package/dist/gateway/chat-sanitize.js +121 -5
  13. package/dist/gateway/media-http.js +120 -0
  14. package/dist/gateway/public-chat-api.js +5 -3
  15. package/dist/gateway/server-http.js +3 -0
  16. package/dist/gateway/server-methods/chat.js +5 -3
  17. package/dist/infra/heartbeat-infra-alert.js +143 -0
  18. package/dist/infra/heartbeat-runner.js +13 -0
  19. package/dist/memory/manager.js +15 -8
  20. package/extensions/diagnostics-otel/node_modules/.bin/acorn +0 -0
  21. package/extensions/googlechat/node_modules/.bin/taskmaster +0 -0
  22. package/extensions/line/node_modules/.bin/taskmaster +0 -0
  23. package/extensions/matrix/node_modules/.bin/markdown-it +0 -0
  24. package/extensions/matrix/node_modules/.bin/taskmaster +0 -0
  25. package/extensions/memory-lancedb/node_modules/.bin/arrow2csv +0 -0
  26. package/extensions/memory-lancedb/node_modules/.bin/openai +0 -0
  27. package/extensions/msteams/node_modules/.bin/taskmaster +0 -0
  28. package/extensions/nostr/node_modules/.bin/taskmaster +0 -0
  29. package/extensions/nostr/node_modules/.bin/tsc +0 -0
  30. package/extensions/nostr/node_modules/.bin/tsserver +0 -0
  31. package/extensions/zalo/node_modules/.bin/taskmaster +0 -0
  32. package/extensions/zalouser/node_modules/.bin/taskmaster +0 -0
  33. package/package.json +64 -54
  34. package/scripts/install.sh +0 -0
  35. package/taskmaster-docs/USER-GUIDE.md +1 -1
  36. package/dist/control-ui/assets/index-DfQL37PU.js.map +0 -1
  37. package/templates/.DS_Store +0 -0
  38. package/templates/customer/.DS_Store +0 -0
  39. package/templates/customer/agents/.DS_Store +0 -0
  40. package/templates/taskmaster/.gitignore +0 -1
@@ -22,8 +22,8 @@ import { createTtsTool } from "./tools/tts-tool.js";
22
22
  import { createCurrentTimeTool } from "./tools/current-time.js";
23
23
  import { createAuthorizeAdminTool, createListAdminsTool, createRevokeAdminTool, } from "./tools/authorize-admin-tool.js";
24
24
  import { createLicenseGenerateTool } from "./tools/license-tool.js";
25
- import { createCustomerLookupTool } from "./tools/customer-lookup-tool.js";
26
- import { createCustomerUpdateTool } from "./tools/customer-update-tool.js";
25
+ import { createContactLookupTool } from "./tools/contact-lookup-tool.js";
26
+ import { createContactUpdateTool } from "./tools/contact-update-tool.js";
27
27
  import { createRelayMessageTool } from "./tools/relay-message-tool.js";
28
28
  import { createSkillReadTool } from "./tools/skill-read-tool.js";
29
29
  import { createApiKeysTool } from "./tools/apikeys-tool.js";
@@ -127,8 +127,8 @@ export function createTaskmasterTools(options) {
127
127
  createRevokeAdminTool(),
128
128
  createListAdminsTool(),
129
129
  createLicenseGenerateTool(),
130
- createCustomerLookupTool(),
131
- createCustomerUpdateTool(),
130
+ createContactLookupTool(),
131
+ createContactUpdateTool(),
132
132
  createRelayMessageTool(),
133
133
  createApiKeysTool(),
134
134
  ];
@@ -112,8 +112,8 @@ const TOOL_PROFILES = {
112
112
  "image",
113
113
  "tts",
114
114
  "license_generate",
115
- "customer_lookup",
116
- "customer_update",
115
+ "contact_lookup",
116
+ "contact_update",
117
117
  "relay_message",
118
118
  "memory_save_media",
119
119
  ],
@@ -0,0 +1,45 @@
1
+ import { Type } from "@sinclair/typebox";
2
+ import { getRecord, listRecords, searchRecords } from "../../records/records-manager.js";
3
+ import { jsonResult } from "./common.js";
4
+ const ContactLookupSchema = Type.Object({
5
+ phone: Type.Optional(Type.String({
6
+ description: "Phone number to look up (e.g. '+447490553305'). Exact match.",
7
+ })),
8
+ name: Type.Optional(Type.String({
9
+ description: "Name to search for (partial match).",
10
+ })),
11
+ });
12
+ export function createContactLookupTool() {
13
+ return {
14
+ label: "Contact Lookup",
15
+ name: "contact_lookup",
16
+ description: "Look up a contact's verified record (payment status, account details). " +
17
+ "These records are managed by the business owner and cannot be modified by agents. " +
18
+ "Provide a phone number for exact lookup, a name for search, or no parameters to list all records.",
19
+ parameters: ContactLookupSchema,
20
+ execute: async (_toolCallId, args) => {
21
+ const params = args;
22
+ const phone = typeof params.phone === "string" ? params.phone.trim() : undefined;
23
+ const name = typeof params.name === "string" ? params.name.trim() : undefined;
24
+ if (!phone && !name) {
25
+ const all = listRecords();
26
+ if (all.length === 0) {
27
+ return jsonResult({ found: false, message: "No contact records exist yet." });
28
+ }
29
+ return jsonResult({ found: true, count: all.length, records: all });
30
+ }
31
+ if (phone) {
32
+ const record = getRecord(phone);
33
+ if (!record) {
34
+ return jsonResult({ found: false, message: `No record found for ${phone}.` });
35
+ }
36
+ return jsonResult({ found: true, record });
37
+ }
38
+ const results = searchRecords(name);
39
+ if (results.length === 0) {
40
+ return jsonResult({ found: false, message: `No records matching "${name}".` });
41
+ }
42
+ return jsonResult({ found: true, count: results.length, records: results });
43
+ },
44
+ };
45
+ }
@@ -0,0 +1,68 @@
1
+ import { Type } from "@sinclair/typebox";
2
+ import { getRecord, setRecordField, deleteRecordField } from "../../records/records-manager.js";
3
+ import { jsonResult } from "./common.js";
4
+ const ContactUpdateSchema = Type.Object({
5
+ phone: Type.String({
6
+ description: "Phone number (record ID) of the contact to update (e.g. '+447490553305').",
7
+ }),
8
+ field: Type.String({
9
+ description: "Field name to set or delete (e.g. 'license_key', 'notes').",
10
+ }),
11
+ value: Type.Optional(Type.String({
12
+ description: "Value to set. Omit to delete the field.",
13
+ })),
14
+ });
15
+ /**
16
+ * Contact record update tool — admin agent only.
17
+ *
18
+ * Allows the admin agent to write individual fields on contact records.
19
+ * The public agent does NOT have access to this tool (same gating as
20
+ * license_generate — not in any profile allow list).
21
+ */
22
+ export function createContactUpdateTool() {
23
+ return {
24
+ label: "Contact Update",
25
+ name: "contact_update",
26
+ description: "Update a field on a contact's verified record. " +
27
+ "Use this to store license keys, notes, or other admin data against a contact. " +
28
+ "The contact must already exist (created via the Contacts admin page).",
29
+ parameters: ContactUpdateSchema,
30
+ execute: async (_toolCallId, args) => {
31
+ const params = args;
32
+ const phone = typeof params.phone === "string" ? params.phone.trim() : "";
33
+ const field = typeof params.field === "string" ? params.field.trim() : "";
34
+ const value = typeof params.value === "string" ? params.value : undefined;
35
+ if (!phone) {
36
+ return jsonResult({ error: "Phone number is required." });
37
+ }
38
+ if (!field) {
39
+ return jsonResult({ error: "Field name is required." });
40
+ }
41
+ const existing = getRecord(phone);
42
+ if (!existing) {
43
+ return jsonResult({
44
+ error: `No contact record found for ${phone}. Create one via the Contacts admin page first.`,
45
+ });
46
+ }
47
+ if (value === undefined) {
48
+ const updated = deleteRecordField(phone, field);
49
+ return jsonResult({
50
+ ok: true,
51
+ action: "deleted",
52
+ phone,
53
+ field,
54
+ record: updated,
55
+ });
56
+ }
57
+ const updated = setRecordField(phone, field, value);
58
+ return jsonResult({
59
+ ok: true,
60
+ action: "set",
61
+ phone,
62
+ field,
63
+ value,
64
+ record: updated,
65
+ });
66
+ },
67
+ };
68
+ }
@@ -25,6 +25,10 @@ const MemorySaveMediaSchema = Type.Object({
25
25
  filename: Type.String({
26
26
  description: "Destination filename with extension (e.g., 'leak-photo-2026-01-29.jpg')",
27
27
  }),
28
+ destFolder: Type.Optional(Type.String({
29
+ description: "Destination folder relative to workspace (e.g., 'memory/admin/media'). " +
30
+ "Defaults to 'memory/users/{phone}/media' when omitted.",
31
+ })),
28
32
  });
29
33
  export function createMemorySearchTool(options) {
30
34
  const cfg = options.config;
@@ -194,14 +198,16 @@ export function createMemorySaveMediaTool(options) {
194
198
  return {
195
199
  label: "Memory Save Media",
196
200
  name: "memory_save_media",
197
- description: "Save a media file (photo, document) from inbound storage to the user's persistent media folder. " +
198
- "Use this to preserve important customer photos (job sites, faults, completed work) for future reference. " +
199
- "The file will be stored in memory/users/{phone}/media/{filename}. " +
201
+ description: "Save a media file (photo, document) to persistent storage. " +
202
+ "Use this to preserve important photos (job sites, faults, completed work) for future reference. " +
203
+ "By default the file is stored in memory/users/{phone}/media/{filename}. " +
204
+ "Set destFolder to save elsewhere (e.g., 'memory/admin/media' for admin-scoped files). " +
200
205
  "Provide a descriptive filename (e.g., 'boiler-fault-2026-01-29.jpg').",
201
206
  parameters: MemorySaveMediaSchema,
202
207
  execute: async (_toolCallId, params) => {
203
208
  const sourcePath = readStringParam(params, "sourcePath", { required: true });
204
209
  const filename = readStringParam(params, "filename", { required: true });
210
+ const destFolder = readStringParam(params, "destFolder");
205
211
  const { manager, error } = await getMemorySearchManager({
206
212
  cfg,
207
213
  agentId,
@@ -213,6 +219,7 @@ export function createMemorySaveMediaTool(options) {
213
219
  const result = await manager.writeMedia({
214
220
  sourcePath,
215
221
  destFilename: filename,
222
+ destFolder: destFolder || undefined,
216
223
  sessionKey: options.agentSessionKey,
217
224
  });
218
225
  return jsonResult({ ...result, success: true });
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.0.94",
3
- "commit": "c6a83535c28ce1a760452843f09b8a749d8765d8",
4
- "builtAt": "2026-02-21T10:04:43.874Z"
2
+ "version": "1.0.95",
3
+ "commit": "f38c78e4169ff530c491b0f5699e33aae3d13ea6",
4
+ "builtAt": "2026-02-21T16:32:15.565Z"
5
5
  }
@@ -137,8 +137,8 @@ export function buildDefaultAgentList(workspaceRoot) {
137
137
  "session_status",
138
138
  "cron",
139
139
  "license_generate",
140
- "customer_lookup",
141
- "customer_update",
140
+ "contact_lookup",
141
+ "contact_update",
142
142
  "authorize_admin",
143
143
  "revoke_admin",
144
144
  "list_admins",