@troykelly/openclaw-projects 0.0.37 → 0.0.38

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 (88) hide show
  1. package/dist/api-client.js +1 -1
  2. package/dist/api-client.js.map +1 -1
  3. package/dist/cli.js +1 -1
  4. package/dist/cli.js.map +1 -1
  5. package/dist/gateway/oauth-rpc-methods.js +11 -11
  6. package/dist/gateway/oauth-rpc-methods.js.map +1 -1
  7. package/dist/gateway/rpc-methods.js +1 -1
  8. package/dist/gateway/rpc-methods.js.map +1 -1
  9. package/dist/hooks.js +5 -5
  10. package/dist/hooks.js.map +1 -1
  11. package/dist/register-openclaw.d.ts.map +1 -1
  12. package/dist/register-openclaw.js +85 -50
  13. package/dist/register-openclaw.js.map +1 -1
  14. package/dist/services/api-source-service.js +9 -9
  15. package/dist/services/api-source-service.js.map +1 -1
  16. package/dist/services/notification-service.js +1 -1
  17. package/dist/services/notification-service.js.map +1 -1
  18. package/dist/tool-guidance/catalog.d.ts.map +1 -1
  19. package/dist/tool-guidance/catalog.js +15 -3
  20. package/dist/tool-guidance/catalog.js.map +1 -1
  21. package/dist/tools/contacts.js +3 -3
  22. package/dist/tools/contacts.js.map +1 -1
  23. package/dist/tools/context-search.d.ts +4 -4
  24. package/dist/tools/context-search.d.ts.map +1 -1
  25. package/dist/tools/context-search.js +38 -8
  26. package/dist/tools/context-search.js.map +1 -1
  27. package/dist/tools/dev-prompts.d.ts +214 -0
  28. package/dist/tools/dev-prompts.d.ts.map +1 -0
  29. package/dist/tools/dev-prompts.js +415 -0
  30. package/dist/tools/dev-prompts.js.map +1 -0
  31. package/dist/tools/dev-session-search.d.ts +76 -0
  32. package/dist/tools/dev-session-search.d.ts.map +1 -0
  33. package/dist/tools/dev-session-search.js +118 -0
  34. package/dist/tools/dev-session-search.js.map +1 -0
  35. package/dist/tools/dev-sessions.d.ts +24 -4
  36. package/dist/tools/dev-sessions.d.ts.map +1 -1
  37. package/dist/tools/dev-sessions.js +68 -11
  38. package/dist/tools/dev-sessions.js.map +1 -1
  39. package/dist/tools/email-send.js +1 -1
  40. package/dist/tools/email-send.js.map +1 -1
  41. package/dist/tools/entity-links.js +8 -8
  42. package/dist/tools/entity-links.js.map +1 -1
  43. package/dist/tools/file-share.js +1 -1
  44. package/dist/tools/file-share.js.map +1 -1
  45. package/dist/tools/index.d.ts +3 -1
  46. package/dist/tools/index.d.ts.map +1 -1
  47. package/dist/tools/index.js +4 -0
  48. package/dist/tools/index.js.map +1 -1
  49. package/dist/tools/memory-forget.js +3 -3
  50. package/dist/tools/memory-forget.js.map +1 -1
  51. package/dist/tools/memory-recall.js +1 -1
  52. package/dist/tools/memory-recall.js.map +1 -1
  53. package/dist/tools/memory-store.js +1 -1
  54. package/dist/tools/memory-store.js.map +1 -1
  55. package/dist/tools/message-search.js +1 -1
  56. package/dist/tools/message-search.js.map +1 -1
  57. package/dist/tools/notebooks.js +3 -3
  58. package/dist/tools/notebooks.js.map +1 -1
  59. package/dist/tools/notes.js +5 -5
  60. package/dist/tools/notes.js.map +1 -1
  61. package/dist/tools/project-search.js +1 -1
  62. package/dist/tools/project-search.js.map +1 -1
  63. package/dist/tools/projects.js +3 -3
  64. package/dist/tools/projects.js.map +1 -1
  65. package/dist/tools/relationships.js +2 -2
  66. package/dist/tools/relationships.js.map +1 -1
  67. package/dist/tools/skill-store.js +11 -11
  68. package/dist/tools/skill-store.js.map +1 -1
  69. package/dist/tools/sms-send.js +1 -1
  70. package/dist/tools/sms-send.js.map +1 -1
  71. package/dist/tools/terminal-connections.js +8 -8
  72. package/dist/tools/terminal-connections.js.map +1 -1
  73. package/dist/tools/terminal-search.js +2 -2
  74. package/dist/tools/terminal-search.js.map +1 -1
  75. package/dist/tools/terminal-sessions.js +7 -7
  76. package/dist/tools/terminal-sessions.js.map +1 -1
  77. package/dist/tools/terminal-tunnels.js +3 -3
  78. package/dist/tools/terminal-tunnels.js.map +1 -1
  79. package/dist/tools/threads.js +2 -2
  80. package/dist/tools/threads.js.map +1 -1
  81. package/dist/tools/todo-search.js +1 -1
  82. package/dist/tools/todo-search.js.map +1 -1
  83. package/dist/tools/todos.js +3 -3
  84. package/dist/tools/todos.js.map +1 -1
  85. package/dist/utils/auto-linker.js +5 -5
  86. package/dist/utils/auto-linker.js.map +1 -1
  87. package/openclaw.plugin.json +1 -1
  88. package/package.json +1 -1
@@ -21,12 +21,16 @@ import { createContextSearchTool, createLinksQueryTool, createLinksRemoveTool, c
21
21
  createTerminalConnectionListTool, createTerminalConnectionCreateTool, createTerminalConnectionUpdateTool, createTerminalConnectionDeleteTool, createTerminalConnectionTestTool, createTerminalCredentialCreateTool, createTerminalCredentialListTool, createTerminalCredentialDeleteTool, createTerminalSessionStartTool, createTerminalSessionListTool, createTerminalSessionTerminateTool, createTerminalSessionInfoTool, createTerminalSendCommandTool, createTerminalSendKeysTool, createTerminalCapturePaneTool, createTerminalSearchTool, createTerminalAnnotateTool, createTerminalTunnelCreateTool, createTerminalTunnelListTool, createTerminalTunnelCloseTool,
22
22
  // Dev session tools (Issue #1896)
23
23
  createDevSessionCreateTool, createDevSessionListTool, createDevSessionGetTool, createDevSessionUpdateTool, createDevSessionCompleteTool,
24
+ // Dev session search (Issue #1987)
25
+ createDevSessionSearchTool,
24
26
  // Note tools (Issue #1921)
25
27
  createNoteCreateTool, createNoteGetTool, createNoteUpdateTool, createNoteDeleteTool, createNoteSearchTool,
26
28
  // Notebook tools (Issue #1921)
27
29
  createNotebookListTool, createNotebookCreateTool, createNotebookGetTool,
28
30
  // Tool guide meta-tool (Issue #1923)
29
- createToolGuideTool, } from './tools/index.js';
31
+ createToolGuideTool,
32
+ // Dev prompt tools (Epic #2011, Issue #2015)
33
+ createDevPromptListTool, createDevPromptGetTool, createDevPromptCreateTool, createDevPromptUpdateTool, createDevPromptResetTool, } from './tools/index.js';
30
34
  import { zodToJsonSchema } from './utils/zod-to-json-schema.js';
31
35
  import { autoLinkInboundMessage } from './utils/auto-linker.js';
32
36
  import { blendScores, computeGeoScore, haversineDistanceKm } from './utils/geo.js';
@@ -1560,7 +1564,7 @@ export async function refreshNamespacesAsync(state) {
1560
1564
  return;
1561
1565
  state.refreshInFlight = true;
1562
1566
  try {
1563
- const response = await state.apiClient.get('/api/namespaces', { user_id: state.agentId, user_email: state.agentEmail });
1567
+ const response = await state.apiClient.get('/namespaces', { user_id: state.agentId, user_email: state.agentEmail });
1564
1568
  if (!response.success) {
1565
1569
  state.logger.warn('Namespace discovery failed, keeping cached list', { error: response.error.message });
1566
1570
  // Do NOT update timestamp on failure — let the next check retry sooner
@@ -1657,7 +1661,7 @@ function createToolHandlers(state) {
1657
1661
  const ns = getRecallNamespaces(params);
1658
1662
  if (ns.length > 0)
1659
1663
  queryParams.set('namespaces', ns.join(','));
1660
- const response = await apiClient.get(`/api/memories/search?${queryParams}`, reqOpts());
1664
+ const response = await apiClient.get(`/memories/search?${queryParams}`, reqOpts());
1661
1665
  if (!response.success) {
1662
1666
  return { success: false, error: response.error.message };
1663
1667
  }
@@ -1743,7 +1747,7 @@ function createToolHandlers(state) {
1743
1747
  if (location.place_label)
1744
1748
  payload.place_label = location.place_label;
1745
1749
  }
1746
- const response = await apiClient.post('/api/memories/unified', payload, reqOpts());
1750
+ const response = await apiClient.post('/memories/unified', payload, reqOpts());
1747
1751
  if (!response.success) {
1748
1752
  return { success: false, error: response.error.message };
1749
1753
  }
@@ -1764,7 +1768,7 @@ function createToolHandlers(state) {
1764
1768
  const { memory_id, query } = params;
1765
1769
  try {
1766
1770
  if (memory_id) {
1767
- const response = await apiClient.delete(`/api/memories/${memory_id}`, reqOptsScoped());
1771
+ const response = await apiClient.delete(`/memories/${memory_id}`, reqOptsScoped());
1768
1772
  if (!response.success) {
1769
1773
  return { success: false, error: response.error.message };
1770
1774
  }
@@ -1780,7 +1784,7 @@ function createToolHandlers(state) {
1780
1784
  const forgetNs = getRecallNamespaces(params);
1781
1785
  if (forgetNs.length > 0)
1782
1786
  forgetQp.set('namespaces', forgetNs.join(','));
1783
- const searchResponse = await apiClient.get(`/api/memories/search?${forgetQp}`, reqOpts());
1787
+ const searchResponse = await apiClient.get(`/memories/search?${forgetQp}`, reqOpts());
1784
1788
  if (!searchResponse.success) {
1785
1789
  return { success: false, error: searchResponse.error.message };
1786
1790
  }
@@ -1793,7 +1797,7 @@ function createToolHandlers(state) {
1793
1797
  }
1794
1798
  // Single high-confidence match → auto-delete
1795
1799
  if (matches.length === 1 && (matches[0].similarity ?? 0) > 0.9) {
1796
- const delResponse = await apiClient.delete(`/api/memories/${matches[0].id}`, reqOptsScoped());
1800
+ const delResponse = await apiClient.delete(`/memories/${matches[0].id}`, reqOptsScoped());
1797
1801
  if (!delResponse.success) {
1798
1802
  return { success: false, error: delResponse.error.message };
1799
1803
  }
@@ -1835,7 +1839,7 @@ function createToolHandlers(state) {
1835
1839
  const projListNs = getRecallNamespaces(params);
1836
1840
  if (projListNs.length > 0)
1837
1841
  queryParams.set('namespaces', projListNs.join(','));
1838
- const response = await apiClient.get(`/api/work-items?${queryParams}`, reqOpts());
1842
+ const response = await apiClient.get(`/work-items?${queryParams}`, reqOpts());
1839
1843
  if (!response.success) {
1840
1844
  return { success: false, error: response.error.message };
1841
1845
  }
@@ -1854,7 +1858,7 @@ function createToolHandlers(state) {
1854
1858
  async project_get(params) {
1855
1859
  const { project_id } = params;
1856
1860
  try {
1857
- const response = await apiClient.get(`/api/work-items/${project_id}?user_email=${encodeURIComponent(state.agentId)}`, reqOptsScoped());
1861
+ const response = await apiClient.get(`/work-items/${project_id}?user_email=${encodeURIComponent(state.agentId)}`, reqOptsScoped());
1858
1862
  if (!response.success) {
1859
1863
  return { success: false, error: response.error.message };
1860
1864
  }
@@ -1875,7 +1879,7 @@ function createToolHandlers(state) {
1875
1879
  async project_create(params) {
1876
1880
  const { name, description, status = 'active', } = params;
1877
1881
  try {
1878
- const response = await apiClient.post('/api/work-items', { title: name, description, kind: 'project', status, user_email: state.agentId, namespace: getStoreNamespace(params) }, reqOpts());
1882
+ const response = await apiClient.post('/work-items', { title: name, description, kind: 'project', status, user_email: state.agentId, namespace: getStoreNamespace(params) }, reqOpts());
1879
1883
  if (!response.success) {
1880
1884
  return { success: false, error: response.error.message };
1881
1885
  }
@@ -1910,7 +1914,7 @@ function createToolHandlers(state) {
1910
1914
  const todoListNs = getRecallNamespaces(params);
1911
1915
  if (todoListNs.length > 0)
1912
1916
  queryParams.set('namespaces', todoListNs.join(','));
1913
- const response = await apiClient.get(`/api/work-items?${queryParams}`, reqOpts());
1917
+ const response = await apiClient.get(`/work-items?${queryParams}`, reqOpts());
1914
1918
  if (!response.success) {
1915
1919
  return { success: false, error: response.error.message };
1916
1920
  }
@@ -1924,7 +1928,8 @@ function createToolHandlers(state) {
1924
1928
  }
1925
1929
  const content = todos
1926
1930
  .map((t) => {
1927
- const checkbox = t.completed ? '[x]' : '[ ]';
1931
+ const isComplete = t.status === 'completed' || t.status === 'done' || t.status === 'closed';
1932
+ const checkbox = isComplete ? '[x]' : '[ ]';
1928
1933
  const dueStr = t.dueDate ? ` (due: ${t.dueDate})` : '';
1929
1934
  return `- ${checkbox} ${t.title}${dueStr}`;
1930
1935
  })
@@ -1947,7 +1952,7 @@ function createToolHandlers(state) {
1947
1952
  body.parent_id = project_id;
1948
1953
  if (dueDate)
1949
1954
  body.not_after = dueDate;
1950
- const response = await apiClient.post('/api/work-items', body, reqOpts());
1955
+ const response = await apiClient.post('/work-items', body, reqOpts());
1951
1956
  if (!response.success) {
1952
1957
  return { success: false, error: response.error.message };
1953
1958
  }
@@ -1967,7 +1972,7 @@ function createToolHandlers(state) {
1967
1972
  async todo_complete(params) {
1968
1973
  const { todoId } = params;
1969
1974
  try {
1970
- const response = await apiClient.patch(`/api/work-items/${todoId}/status?user_email=${encodeURIComponent(state.agentId)}`, { status: 'completed' }, reqOptsScoped());
1975
+ const response = await apiClient.patch(`/work-items/${todoId}/status?user_email=${encodeURIComponent(state.agentId)}`, { status: 'completed' }, reqOptsScoped());
1971
1976
  if (!response.success) {
1972
1977
  return { success: false, error: response.error.message };
1973
1978
  }
@@ -2000,7 +2005,7 @@ function createToolHandlers(state) {
2000
2005
  const todoSearchNs = getRecallNamespaces(params);
2001
2006
  if (todoSearchNs.length > 0)
2002
2007
  queryParams.set('namespaces', todoSearchNs.join(','));
2003
- const response = await apiClient.get(`/api/search?${queryParams}`, reqOpts());
2008
+ const response = await apiClient.get(`/search?${queryParams}`, reqOpts());
2004
2009
  if (!response.success) {
2005
2010
  return { success: false, error: response.error.message };
2006
2011
  }
@@ -2070,7 +2075,7 @@ function createToolHandlers(state) {
2070
2075
  const contactSearchNs = getRecallNamespaces(params);
2071
2076
  if (contactSearchNs.length > 0)
2072
2077
  queryParams.set('namespaces', contactSearchNs.join(','));
2073
- const response = await apiClient.get(`/api/contacts?${queryParams}`, {
2078
+ const response = await apiClient.get(`/contacts?${queryParams}`, {
2074
2079
  user_id: state.agentId,
2075
2080
  });
2076
2081
  if (!response.success) {
@@ -2091,7 +2096,7 @@ function createToolHandlers(state) {
2091
2096
  async contact_get(params) {
2092
2097
  const { contact_id } = params;
2093
2098
  try {
2094
- const response = await apiClient.get(`/api/contacts/${contact_id}?user_email=${encodeURIComponent(state.agentId)}`, reqOptsScoped());
2099
+ const response = await apiClient.get(`/contacts/${contact_id}?user_email=${encodeURIComponent(state.agentId)}`, reqOptsScoped());
2095
2100
  if (!response.success) {
2096
2101
  return { success: false, error: response.error.message };
2097
2102
  }
@@ -2156,7 +2161,7 @@ function createToolHandlers(state) {
2156
2161
  endpoints.push({ type: 'phone', value: phone });
2157
2162
  if (endpoints.length > 0)
2158
2163
  body.endpoints = endpoints;
2159
- const response = await apiClient.post('/api/contacts', body, reqOpts());
2164
+ const response = await apiClient.post('/contacts', body, reqOpts());
2160
2165
  if (!response.success) {
2161
2166
  return { success: false, error: response.error.message };
2162
2167
  }
@@ -2183,7 +2188,7 @@ function createToolHandlers(state) {
2183
2188
  if (k !== 'namespace' && v !== undefined)
2184
2189
  body[k] = v;
2185
2190
  }
2186
- const response = await apiClient.patch(`/api/contacts/${contact_id}`, body, reqOptsScoped());
2191
+ const response = await apiClient.patch(`/contacts/${contact_id}`, body, reqOptsScoped());
2187
2192
  if (!response.success) {
2188
2193
  return { success: false, error: response.error.message };
2189
2194
  }
@@ -2205,7 +2210,7 @@ function createToolHandlers(state) {
2205
2210
  if (!survivor_id || !loser_id)
2206
2211
  return { success: false, error: 'survivor_id and loser_id are required' };
2207
2212
  try {
2208
- const response = await apiClient.post('/api/contacts/merge', { survivor_id, loser_id, namespace: getStoreNamespace(params) }, reqOpts());
2213
+ const response = await apiClient.post('/contacts/merge', { survivor_id, loser_id, namespace: getStoreNamespace(params) }, reqOpts());
2209
2214
  if (!response.success) {
2210
2215
  return { success: false, error: response.error.message };
2211
2216
  }
@@ -2227,7 +2232,7 @@ function createToolHandlers(state) {
2227
2232
  if (!contact_id || !tags?.length)
2228
2233
  return { success: false, error: 'contact_id and tags are required' };
2229
2234
  try {
2230
- const response = await apiClient.post(`/api/contacts/${contact_id}/tags`, { tags }, reqOptsScoped());
2235
+ const response = await apiClient.post(`/contacts/${contact_id}/tags`, { tags }, reqOptsScoped());
2231
2236
  if (!response.success) {
2232
2237
  return { success: false, error: response.error.message };
2233
2238
  }
@@ -2249,7 +2254,7 @@ function createToolHandlers(state) {
2249
2254
  if (!contact_id || !tag)
2250
2255
  return { success: false, error: 'contact_id and tag are required' };
2251
2256
  try {
2252
- const response = await apiClient.delete(`/api/contacts/${contact_id}/tags/${encodeURIComponent(tag)}`, reqOptsScoped());
2257
+ const response = await apiClient.delete(`/contacts/${contact_id}/tags/${encodeURIComponent(tag)}`, reqOptsScoped());
2253
2258
  if (!response.success) {
2254
2259
  return { success: false, error: response.error.message };
2255
2260
  }
@@ -2279,7 +2284,7 @@ function createToolHandlers(state) {
2279
2284
  queryParams.set('email', email);
2280
2285
  if (name)
2281
2286
  queryParams.set('name', name);
2282
- const response = await apiClient.get(`/api/contacts/suggest-match?${queryParams}`, reqOpts());
2287
+ const response = await apiClient.get(`/contacts/suggest-match?${queryParams}`, reqOpts());
2283
2288
  if (!response.success) {
2284
2289
  return { success: false, error: response.error.message };
2285
2290
  }
@@ -2350,7 +2355,7 @@ function createToolHandlers(state) {
2350
2355
  hasIdempotencyKey: !!idempotency_key,
2351
2356
  });
2352
2357
  try {
2353
- const response = await apiClient.post('/api/twilio/sms/send', { to, body, idempotency_key }, reqOpts());
2358
+ const response = await apiClient.post('/twilio/sms/send', { to, body, idempotency_key }, reqOpts());
2354
2359
  if (!response.success) {
2355
2360
  logger.error('sms_send API error', {
2356
2361
  user_id: state.agentId,
@@ -2431,7 +2436,7 @@ function createToolHandlers(state) {
2431
2436
  hasIdempotencyKey: !!idempotency_key,
2432
2437
  });
2433
2438
  try {
2434
- const response = await apiClient.post('/api/postmark/email/send', { to, subject, body, html_body, thread_id, idempotency_key }, reqOpts());
2439
+ const response = await apiClient.post('/postmark/email/send', { to, subject, body, html_body, thread_id, idempotency_key }, reqOpts());
2435
2440
  if (!response.success) {
2436
2441
  logger.error('email_send API error', {
2437
2442
  user_id: state.agentId,
@@ -2506,7 +2511,7 @@ function createToolHandlers(state) {
2506
2511
  queryParams.set('include_thread', 'true');
2507
2512
  }
2508
2513
  // Unified search API: returns { results: [{ type, id, title, snippet, score, metadata }], total }
2509
- const response = await apiClient.get(`/api/search?${queryParams}`, reqOpts());
2514
+ const response = await apiClient.get(`/search?${queryParams}`, reqOpts());
2510
2515
  if (!response.success) {
2511
2516
  logger.error('message_search API error', {
2512
2517
  user_id: state.agentId,
@@ -2619,7 +2624,7 @@ function createToolHandlers(state) {
2619
2624
  if (contact_id) {
2620
2625
  queryParams.set('contact_id', contact_id);
2621
2626
  }
2622
- const response = await apiClient.get(`/api/search?${queryParams}`, reqOpts());
2627
+ const response = await apiClient.get(`/search?${queryParams}`, reqOpts());
2623
2628
  if (!response.success) {
2624
2629
  logger.error('thread_list API error', {
2625
2630
  user_id: state.agentId,
@@ -2696,7 +2701,7 @@ function createToolHandlers(state) {
2696
2701
  try {
2697
2702
  const queryParams = new URLSearchParams();
2698
2703
  queryParams.set('limit', String(message_limit));
2699
- const response = await apiClient.get(`/api/threads/${thread_id}/history?${queryParams}`, reqOpts());
2704
+ const response = await apiClient.get(`/threads/${thread_id}/history?${queryParams}`, reqOpts());
2700
2705
  if (!response.success) {
2701
2706
  logger.error('thread_get API error', {
2702
2707
  user_id: state.agentId,
@@ -2810,7 +2815,7 @@ function createToolHandlers(state) {
2810
2815
  }
2811
2816
  // Use user_id + user_email but omit single namespace header so that
2812
2817
  // body.namespaces (multi) is picked up by the middleware instead.
2813
- const response = await apiClient.post('/api/relationships/set', body, { user_id: state.agentId, user_email: state.agentEmail });
2818
+ const response = await apiClient.post('/relationships/set', body, { user_id: state.agentId, user_email: state.agentEmail });
2814
2819
  if (!response.success) {
2815
2820
  return { success: false, error: response.error.message };
2816
2821
  }
@@ -2866,7 +2871,7 @@ function createToolHandlers(state) {
2866
2871
  const searchParams = new URLSearchParams({ search: contact, limit: '1', user_email: state.agentId });
2867
2872
  if (contactSearchNs.length > 0)
2868
2873
  searchParams.set('namespaces', contactSearchNs.join(','));
2869
- const searchResponse = await apiClient.get(`/api/contacts?${searchParams}`, { user_id: state.agentId });
2874
+ const searchResponse = await apiClient.get(`/contacts?${searchParams}`, { user_id: state.agentId });
2870
2875
  if (!searchResponse.success) {
2871
2876
  return { success: false, error: searchResponse.error.message };
2872
2877
  }
@@ -2877,7 +2882,7 @@ function createToolHandlers(state) {
2877
2882
  contact_id = contacts[0].id;
2878
2883
  }
2879
2884
  // Use graph traversal endpoint which returns related_contacts
2880
- const response = await apiClient.get(`/api/contacts/${contact_id}/relationships?user_email=${encodeURIComponent(state.agentId)}`, reqOptsScoped());
2885
+ const response = await apiClient.get(`/contacts/${contact_id}/relationships?user_email=${encodeURIComponent(state.agentId)}`, reqOptsScoped());
2881
2886
  if (!response.success) {
2882
2887
  if (response.error.code === 'NOT_FOUND') {
2883
2888
  return { success: false, error: 'Contact not found.' };
@@ -2945,7 +2950,7 @@ function createToolHandlers(state) {
2945
2950
  if (maxDownloads !== undefined) {
2946
2951
  body.max_downloads = maxDownloads;
2947
2952
  }
2948
- const response = await apiClient.post(`/api/files/${fileId}/share`, body, reqOpts());
2953
+ const response = await apiClient.post(`/files/${fileId}/share`, body, reqOpts());
2949
2954
  if (!response.success) {
2950
2955
  logger.error('file_share API error', {
2951
2956
  user_id: state.agentId,
@@ -3062,7 +3067,7 @@ function createToolHandlers(state) {
3062
3067
  const queryParams = new URLSearchParams({ limit: String(limit), offset: String(offset) });
3063
3068
  if (channel_type)
3064
3069
  queryParams.set('channel_type', channel_type);
3065
- const response = await apiClient.get(`/api/prompt-templates?${queryParams.toString()}`, reqOpts());
3070
+ const response = await apiClient.get(`/prompt-templates?${queryParams.toString()}`, reqOpts());
3066
3071
  if (!response.success) {
3067
3072
  return { success: false, error: response.error.message || 'Failed to list prompt templates' };
3068
3073
  }
@@ -3080,7 +3085,7 @@ function createToolHandlers(state) {
3080
3085
  async prompt_template_get(params) {
3081
3086
  const { id } = params;
3082
3087
  try {
3083
- const response = await apiClient.get(`/api/prompt-templates/${id}`, reqOpts());
3088
+ const response = await apiClient.get(`/prompt-templates/${id}`, reqOpts());
3084
3089
  if (!response.success) {
3085
3090
  return { success: false, error: response.error.message || 'Prompt template not found' };
3086
3091
  }
@@ -3095,7 +3100,7 @@ function createToolHandlers(state) {
3095
3100
  async prompt_template_create(params) {
3096
3101
  const { label, content, channel_type, is_default } = params;
3097
3102
  try {
3098
- const response = await apiClient.post('/api/prompt-templates', { label, content, channel_type, is_default }, reqOpts());
3103
+ const response = await apiClient.post('/prompt-templates', { label, content, channel_type, is_default }, reqOpts());
3099
3104
  if (!response.success) {
3100
3105
  return { success: false, error: response.error.message || 'Failed to create prompt template' };
3101
3106
  }
@@ -3109,7 +3114,7 @@ function createToolHandlers(state) {
3109
3114
  async prompt_template_update(params) {
3110
3115
  const { id, ...updates } = params;
3111
3116
  try {
3112
- const response = await apiClient.put(`/api/prompt-templates/${id}`, updates, reqOpts());
3117
+ const response = await apiClient.put(`/prompt-templates/${id}`, updates, reqOpts());
3113
3118
  if (!response.success) {
3114
3119
  return { success: false, error: response.error.message || 'Failed to update prompt template' };
3115
3120
  }
@@ -3123,7 +3128,7 @@ function createToolHandlers(state) {
3123
3128
  async prompt_template_delete(params) {
3124
3129
  const { id } = params;
3125
3130
  try {
3126
- const response = await apiClient.delete(`/api/prompt-templates/${id}`, reqOpts());
3131
+ const response = await apiClient.delete(`/prompt-templates/${id}`, reqOpts());
3127
3132
  if (!response.success) {
3128
3133
  return { success: false, error: response.error.message || 'Failed to delete prompt template' };
3129
3134
  }
@@ -3152,7 +3157,7 @@ function createToolHandlers(state) {
3152
3157
  queryParams.set('offset', String(offset));
3153
3158
  if (recallNs.length > 0)
3154
3159
  queryParams.set('namespaces', recallNs.join(','));
3155
- const response = await apiClient.get(`/api/inbound-destinations?${queryParams.toString()}`, { user_id: state.agentId, user_email: state.agentEmail });
3160
+ const response = await apiClient.get(`/inbound-destinations?${queryParams.toString()}`, { user_id: state.agentId, user_email: state.agentEmail });
3156
3161
  if (!response.success) {
3157
3162
  return { success: false, error: response.error.message || 'Failed to list inbound destinations' };
3158
3163
  }
@@ -3170,7 +3175,7 @@ function createToolHandlers(state) {
3170
3175
  async inbound_destination_get(params) {
3171
3176
  const { id } = params;
3172
3177
  try {
3173
- const response = await apiClient.get(`/api/inbound-destinations/${id}`, reqOpts());
3178
+ const response = await apiClient.get(`/inbound-destinations/${id}`, reqOpts());
3174
3179
  if (!response.success) {
3175
3180
  return { success: false, error: response.error.message || 'Inbound destination not found' };
3176
3181
  }
@@ -3194,7 +3199,7 @@ function createToolHandlers(state) {
3194
3199
  async inbound_destination_update(params) {
3195
3200
  const { id, ...updates } = params;
3196
3201
  try {
3197
- const response = await apiClient.put(`/api/inbound-destinations/${id}`, updates, reqOpts());
3202
+ const response = await apiClient.put(`/inbound-destinations/${id}`, updates, reqOpts());
3198
3203
  if (!response.success) {
3199
3204
  return { success: false, error: response.error.message || 'Failed to update inbound destination' };
3200
3205
  }
@@ -3208,7 +3213,7 @@ function createToolHandlers(state) {
3208
3213
  // ── Channel Default tools (Issue #1501) ──────────────────
3209
3214
  async channel_default_list() {
3210
3215
  try {
3211
- const response = await apiClient.get('/api/channel-defaults', reqOpts());
3216
+ const response = await apiClient.get('/channel-defaults', reqOpts());
3212
3217
  if (!response.success) {
3213
3218
  return { success: false, error: response.error.message || 'Failed to list channel defaults' };
3214
3219
  }
@@ -3226,7 +3231,7 @@ function createToolHandlers(state) {
3226
3231
  async channel_default_get(params) {
3227
3232
  const { channel_type } = params;
3228
3233
  try {
3229
- const response = await apiClient.get(`/api/channel-defaults/${channel_type}`, reqOpts());
3234
+ const response = await apiClient.get(`/channel-defaults/${channel_type}`, reqOpts());
3230
3235
  if (!response.success) {
3231
3236
  return { success: false, error: response.error.message || 'Channel default not found' };
3232
3237
  }
@@ -3246,7 +3251,7 @@ function createToolHandlers(state) {
3246
3251
  async channel_default_set(params) {
3247
3252
  const { channel_type, agent_id, prompt_template_id, context_id } = params;
3248
3253
  try {
3249
- const response = await apiClient.put(`/api/channel-defaults/${channel_type}`, { agent_id, prompt_template_id, context_id }, reqOpts());
3254
+ const response = await apiClient.put(`/channel-defaults/${channel_type}`, { agent_id, prompt_template_id, context_id }, reqOpts());
3250
3255
  if (!response.success) {
3251
3256
  return { success: false, error: response.error.message || 'Failed to set channel default' };
3252
3257
  }
@@ -3260,7 +3265,7 @@ function createToolHandlers(state) {
3260
3265
  // ── Namespace management handlers (Issue #1536) ──────────────
3261
3266
  async namespace_list() {
3262
3267
  try {
3263
- const response = await apiClient.get('/api/namespaces', reqOpts());
3268
+ const response = await apiClient.get('/namespaces', reqOpts());
3264
3269
  if (!response.success) {
3265
3270
  return { success: false, error: response.error.message || 'Failed to list namespaces' };
3266
3271
  }
@@ -3290,7 +3295,7 @@ function createToolHandlers(state) {
3290
3295
  async namespace_create(params) {
3291
3296
  const { name } = params;
3292
3297
  try {
3293
- const response = await apiClient.post('/api/namespaces', { name }, reqOpts());
3298
+ const response = await apiClient.post('/namespaces', { name }, reqOpts());
3294
3299
  if (!response.success) {
3295
3300
  return { success: false, error: response.error.message || 'Failed to create namespace' };
3296
3301
  }
@@ -3304,7 +3309,7 @@ function createToolHandlers(state) {
3304
3309
  async namespace_grant(params) {
3305
3310
  const { namespace, email, role, is_default } = params;
3306
3311
  try {
3307
- const response = await apiClient.post(`/api/namespaces/${encodeURIComponent(namespace)}/grants`, { email, role: role || 'member', is_default: is_default ?? false }, reqOpts());
3312
+ const response = await apiClient.post(`/namespaces/${encodeURIComponent(namespace)}/grants`, { email, role: role || 'member', is_default: is_default ?? false }, reqOpts());
3308
3313
  if (!response.success) {
3309
3314
  return { success: false, error: response.error.message || 'Failed to grant namespace access' };
3310
3315
  }
@@ -3319,7 +3324,7 @@ function createToolHandlers(state) {
3319
3324
  async namespace_members(params) {
3320
3325
  const { namespace } = params;
3321
3326
  try {
3322
- const response = await apiClient.get(`/api/namespaces/${encodeURIComponent(namespace)}`, reqOpts());
3327
+ const response = await apiClient.get(`/namespaces/${encodeURIComponent(namespace)}`, reqOpts());
3323
3328
  if (!response.success) {
3324
3329
  logger.warn('namespace_members API call failed', {
3325
3330
  namespace,
@@ -3348,7 +3353,7 @@ function createToolHandlers(state) {
3348
3353
  async namespace_revoke(params) {
3349
3354
  const { namespace, grant_id } = params;
3350
3355
  try {
3351
- const response = await apiClient.delete(`/api/namespaces/${encodeURIComponent(namespace)}/grants/${encodeURIComponent(grant_id)}`, reqOpts());
3356
+ const response = await apiClient.delete(`/namespaces/${encodeURIComponent(namespace)}/grants/${encodeURIComponent(grant_id)}`, reqOpts());
3352
3357
  if (!response.success) {
3353
3358
  return { success: false, error: response.error.message || 'Failed to revoke namespace access' };
3354
3359
  }
@@ -4087,6 +4092,7 @@ export const registerOpenClaw = (api) => {
4087
4092
  createDevSessionGetTool,
4088
4093
  createDevSessionUpdateTool,
4089
4094
  createDevSessionCompleteTool,
4095
+ createDevSessionSearchTool,
4090
4096
  ];
4091
4097
  for (const factory of devSessionToolFactories) {
4092
4098
  // eslint-disable-next-line @typescript-eslint/no-explicit-any -- factory functions have heterogeneous option types that share the same shape
@@ -4157,6 +4163,28 @@ export const registerOpenClaw = (api) => {
4157
4163
  },
4158
4164
  });
4159
4165
  }
4166
+ // ── Dev prompt tools (Epic #2011, Issue #2015) ─────────────────
4167
+ // Reuses termToolOpts (same shape: client, logger, config, user_id getter).
4168
+ const devPromptToolFactories = [
4169
+ createDevPromptListTool,
4170
+ createDevPromptGetTool,
4171
+ createDevPromptCreateTool,
4172
+ createDevPromptUpdateTool,
4173
+ createDevPromptResetTool,
4174
+ ];
4175
+ for (const factory of devPromptToolFactories) {
4176
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- factory functions have heterogeneous option types that share the same shape
4177
+ const tool = factory(termToolOpts);
4178
+ tools.push({
4179
+ name: tool.name,
4180
+ description: tool.description,
4181
+ parameters: zodToJsonSchema(tool.parameters),
4182
+ execute: async (_toolCallId, params, _signal, _onUpdate) => {
4183
+ const result = await tool.execute(params);
4184
+ return toAgentToolResult(result);
4185
+ },
4186
+ });
4187
+ }
4160
4188
  // ── Optional tool groups (Issue #1921) ─────────────────────────
4161
4189
  // Mark 61 tools as optional with logical group names.
4162
4190
  // Tools not in this map remain required (core tools like memory, project, todo, etc.)
@@ -4195,12 +4223,13 @@ export const registerOpenClaw = (api) => {
4195
4223
  api_refresh: 'api_management',
4196
4224
  api_remove: 'api_management',
4197
4225
  api_restore: 'api_management',
4198
- // Dev sessions (5)
4226
+ // Dev sessions (6)
4199
4227
  dev_session_create: 'dev_sessions',
4200
4228
  dev_session_list: 'dev_sessions',
4201
4229
  dev_session_get: 'dev_sessions',
4202
4230
  dev_session_update: 'dev_sessions',
4203
4231
  dev_session_complete: 'dev_sessions',
4232
+ dev_session_search: 'dev_sessions',
4204
4233
  // Outbound comms (2)
4205
4234
  sms_send: 'outbound_comms',
4206
4235
  email_send: 'outbound_comms',
@@ -4236,6 +4265,12 @@ export const registerOpenClaw = (api) => {
4236
4265
  notebook_get: 'notebooks',
4237
4266
  // File share (1)
4238
4267
  file_share: 'file_share',
4268
+ // Dev prompts (5)
4269
+ dev_prompt_list: 'dev_prompts',
4270
+ dev_prompt_get: 'dev_prompts',
4271
+ dev_prompt_create: 'dev_prompts',
4272
+ dev_prompt_update: 'dev_prompts',
4273
+ dev_prompt_reset: 'dev_prompts',
4239
4274
  };
4240
4275
  for (const tool of tools) {
4241
4276
  const group = optionalGroups[tool.name];
@@ -4478,7 +4513,7 @@ export const registerOpenClaw = (api) => {
4478
4513
  .description('Show plugin status and statistics')
4479
4514
  .action(async () => {
4480
4515
  try {
4481
- const response = await apiClient.get('/api/health', { user_id: state.agentId, user_email: state.agentEmail });
4516
+ const response = await apiClient.get('/health', { user_id: state.agentId, user_email: state.agentEmail });
4482
4517
  if (response.success) {
4483
4518
  console.log('Plugin Status: Connected');
4484
4519
  }