@alfe.ai/openclaw-mobile 0.0.7 → 0.0.9

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/plugin.cjs CHANGED
@@ -4,10 +4,14 @@ let _alfe_ai_config = require("@alfe.ai/config");
4
4
  /**
5
5
  * @alfe/openclaw-mobile — OpenClaw native plugin
6
6
  *
7
- * Registers mobile tools (SMS, calls) with OpenClaw. Tools call the
8
- * mobile service API using the agent's API key for authentication.
7
+ * Registers mobile tools (SMS, calls, number management) with OpenClaw.
8
+ * Tools call the mobile service API using the agent's API key for authentication.
9
9
  *
10
10
  * This plugin provides:
11
+ * - mobile_get_number — check if a phone number is assigned
12
+ * - mobile_search_numbers — search available numbers for purchase
13
+ * - mobile_assign_number — purchase and assign a phone number
14
+ * - mobile_release_number — release the assigned phone number
11
15
  * - mobile_send_sms — send an SMS message from the agent's phone number
12
16
  * - mobile_call — initiate an outbound phone call
13
17
  */
@@ -46,8 +50,12 @@ function defineTool(def) {
46
50
  }
47
51
  let apiUrl = "";
48
52
  let apiKey = "";
49
- async function mobileApi(method, path, body) {
50
- const url = `${apiUrl}${path}`;
53
+ async function mobileApi(method, path, body, query) {
54
+ let url = `${apiUrl}${path}`;
55
+ if (query) {
56
+ const entries = Object.entries(query).filter((entry) => entry[1] !== void 0);
57
+ if (entries.length > 0) url += `?${new URLSearchParams(entries).toString()}`;
58
+ }
51
59
  const headers = {
52
60
  "Content-Type": "application/json",
53
61
  Authorization: `Bearer ${apiKey}`
@@ -59,39 +67,95 @@ async function mobileApi(method, path, body) {
59
67
  });
60
68
  const json = await res.json();
61
69
  if (!res.ok) {
70
+ const issues = json.issues;
71
+ if (Array.isArray(issues) && issues.length > 0) {
72
+ const details = issues.map((i) => {
73
+ return `${i.path?.join(".") ?? "input"}: ${i.message ?? "invalid"}`;
74
+ }).join("; ");
75
+ throw new Error(`Validation error — ${details}`);
76
+ }
62
77
  const errorMsg = typeof json.error === "string" ? json.error : typeof json.message === "string" ? json.message : `Mobile service returned ${String(res.status)}`;
63
78
  throw new Error(errorMsg);
64
79
  }
65
80
  if (json.data && typeof json.data === "object") return json.data;
66
81
  return json;
67
82
  }
68
- const mobileTools = [defineTool({
69
- name: "mobile_send_sms",
70
- description: "Send an SMS text message from your phone number to the specified number. The recipient number must be in E.164 format (e.g., +12025551234).",
71
- parameters: _sinclair_typebox.Type.Object({
72
- to: _sinclair_typebox.Type.String({ description: "Recipient phone number in E.164 format (e.g., +12025551234)" }),
73
- body: _sinclair_typebox.Type.String({ description: "The text message content to send" })
83
+ const mobileTools = [
84
+ defineTool({
85
+ name: "mobile_get_number",
86
+ description: "Check if you have a phone number assigned. Returns the phone number, country code, monthly price, and status. If no number is assigned, use mobile_search_numbers and mobile_assign_number to get one.",
87
+ parameters: _sinclair_typebox.Type.Object({}),
88
+ handler: async () => {
89
+ return mobileApi("GET", "/mobile/numbers");
90
+ }
74
91
  }),
75
- handler: async (params) => {
76
- const { to, body } = params;
77
- return mobileApi("POST", "/mobile/sms/send", {
78
- to,
79
- body
80
- });
81
- }
82
- }), defineTool({
83
- name: "mobile_call",
84
- description: "Make an outbound phone call to the specified number. When the recipient answers, they will be connected to your voice pipeline. The number must be in E.164 format (e.g., +12025551234).",
85
- parameters: _sinclair_typebox.Type.Object({ to: _sinclair_typebox.Type.String({ description: "Phone number to call in E.164 format (e.g., +12025551234)" }) }),
86
- handler: async (params) => {
87
- const { to } = params;
88
- return mobileApi("POST", "/mobile/calls/outbound", { to });
89
- }
90
- })];
92
+ defineTool({
93
+ name: "mobile_search_numbers",
94
+ description: "Search for available phone numbers that can be purchased. Returns a list of available numbers and the monthly price. Supported countries: AU (Australia), US (United States), CA (Canada), GB (United Kingdom).",
95
+ parameters: _sinclair_typebox.Type.Object({
96
+ country: _sinclair_typebox.Type.Optional(_sinclair_typebox.Type.String({ description: "Country code: AU, US, CA, or GB (default: AU)" })),
97
+ query: _sinclair_typebox.Type.Optional(_sinclair_typebox.Type.String({ description: "Optional search pattern — area code or text to match (e.g., '415' or 'COOL')" }))
98
+ }),
99
+ handler: async (params) => {
100
+ const { country, query } = params;
101
+ return mobileApi("GET", "/mobile/numbers/search", void 0, {
102
+ country,
103
+ query
104
+ });
105
+ }
106
+ }),
107
+ defineTool({
108
+ name: "mobile_assign_number",
109
+ description: "Purchase and assign a phone number to yourself. You must search for available numbers first using mobile_search_numbers, then pass the chosen phoneNumber and countryCode here. Your organisation must have a payment method on file. The number will be billed monthly to the organisation's account.",
110
+ parameters: _sinclair_typebox.Type.Object({
111
+ phoneNumber: _sinclair_typebox.Type.String({ description: "The phone number to purchase (from mobile_search_numbers results)" }),
112
+ countryCode: _sinclair_typebox.Type.String({ description: "Country code: AU, US, CA, or GB" })
113
+ }),
114
+ handler: async (params) => {
115
+ const { phoneNumber, countryCode } = params;
116
+ return mobileApi("POST", "/mobile/numbers/assign", {
117
+ phoneNumber,
118
+ countryCode
119
+ });
120
+ }
121
+ }),
122
+ defineTool({
123
+ name: "mobile_release_number",
124
+ description: "Release your currently assigned phone number. This will cancel the monthly subscription and the number will no longer be available for calls or SMS. This action cannot be undone — the same number may not be available again.",
125
+ parameters: _sinclair_typebox.Type.Object({}),
126
+ handler: async () => {
127
+ return mobileApi("POST", "/mobile/numbers/release", {});
128
+ }
129
+ }),
130
+ defineTool({
131
+ name: "mobile_send_sms",
132
+ description: "Send an SMS text message from your phone number to the specified number. The recipient number must be in E.164 format (e.g., +12025551234).",
133
+ parameters: _sinclair_typebox.Type.Object({
134
+ to: _sinclair_typebox.Type.String({ description: "Recipient phone number in E.164 format (e.g., +12025551234)" }),
135
+ body: _sinclair_typebox.Type.String({ description: "The text message content to send" })
136
+ }),
137
+ handler: async (params) => {
138
+ const { to, body } = params;
139
+ return mobileApi("POST", "/mobile/sms/send", {
140
+ to,
141
+ body
142
+ });
143
+ }
144
+ }),
145
+ defineTool({
146
+ name: "mobile_call",
147
+ description: "Make an outbound phone call to the specified number. When the recipient answers, they will be connected to your voice pipeline. The number must be in E.164 format (e.g., +12025551234).",
148
+ parameters: _sinclair_typebox.Type.Object({ to: _sinclair_typebox.Type.String({ description: "Phone number to call in E.164 format (e.g., +12025551234)" }) }),
149
+ handler: async (params) => {
150
+ const { to } = params;
151
+ return mobileApi("POST", "/mobile/calls/outbound", { to });
152
+ }
153
+ })
154
+ ];
91
155
  const plugin = {
92
156
  id: "@alfe.ai/openclaw-mobile",
93
157
  name: "Alfe Mobile Plugin",
94
- description: "Mobile integration — outbound SMS and phone calls via Twilio",
158
+ description: "Mobile integration — phone number management, SMS, and phone calls via Twilio",
95
159
  version: "0.0.1",
96
160
  activate(api) {
97
161
  const log = api.logger;
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.d.cts","names":[],"sources":["../src/plugin.ts"],"mappings":";;;;AAyBmE,UAXzD,MAAA,CAgBO;EAAA,IAAA,CAAA,GAAA,EAAA,MAAA,EAAA,GAAA,IAAA,EAAA,OAAA,EAAA,CAAA,EAAA,IAAA;MAIH,CAAA,GAAA,EAAA,MAAA,EAAA,GAAA,IAAA,EAAA,OAAA,EAAA,CAAA,EAAA,IAAA;OAC0B,CAAA,GAAA,EAAA,MAAA,EAAA,GAAA,IAAA,EAAA,OAAA,EAAA,CAAA,EAAA,IAAA;OAA4B,CAAA,GAAA,EAAA,MAAA,EAAA,GAAA,IAAA,EAAA,OAAA,EAAA,CAAA,EAAA,IAAA;;AAAO,UAdjE,iBAAA,CAoKT;EAAA,MAAA,EAnKS,MAmKT;cAjCe,CAAA,IAAA,EAjIK,OAiIL,CAAA,EAAA,IAAA;uBA6BE,CAAA,IAAA,EAAA,MAAA,EAAA,OAAA,EAAA,CAAA,GAAA,IAAA,EAAA,OAAA,EAAA,EAAA,GA7JqD,OA6JrD,CAAA,OAAA,CAAA,CAAA,EAAA,IAAA;EAAiB,EAAA,CAAA,KAAA,EAAA,MAAA,EAAA,OAAA,EAAA,CAAA,GAAA,IAAA,EAAA,OAAA,EAAA,EAAA,GAAA,IAAA,GA5JyB,OA4JzB,CAAA,IAAA,CAAA,EAAA,QAAA,EAAA;;;;UAvJzB,OAAA;;;;cAII;wCAC0B,4BAA4B;;;;;;;;cA+G9D;;;;;gBAMU;kBA6BE"}
1
+ {"version":3,"file":"plugin.d.cts","names":[],"sources":["../src/plugin.ts"],"mappings":";;;;UAkBU,MAAA,CAqB0D;EAAO,IAAA,CAAA,GAAA,EAAA,MAAA,EAAA,GAAA,IAAA,EAAA,OAAA,EAAA,CAAA,EAAA,IAAA;EA8LrE,IAAA,CAAA,GAAA,EAuCL,MAAA,EAAA,GAAA,IAAA,EAAA,OAAA,EAAA,CAAA,EAAA,IAAA;EAAA,KAAA,CAAA,GAAA,EAAA,MAAA,EAAA,GAAA,IAAA,EAAA,OAAA,EAAA,CAAA,EAAA,IAAA;OAjCe,CAAA,GAAA,EAAA,MAAA,EAAA,GAAA,IAAA,EAAA,OAAA,EAAA,CAAA,EAAA,IAAA;;UAlNN,iBAAA,CA+OyB;UA9OzB;qBACW;uEACkD;4DACX;;;;UAKlD,OAAA;;;;cAII;wCAC0B,4BAA4B;;;;;;;;cA8L9D;;;;;gBAMU;kBA6BE"}
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.d.ts","names":[],"sources":["../src/plugin.ts"],"mappings":";;;;AAyBmE,UAXzD,MAAA,CAgBO;EAAA,IAAA,CAAA,GAAA,EAAA,MAAA,EAAA,GAAA,IAAA,EAAA,OAAA,EAAA,CAAA,EAAA,IAAA;MAIH,CAAA,GAAA,EAAA,MAAA,EAAA,GAAA,IAAA,EAAA,OAAA,EAAA,CAAA,EAAA,IAAA;OAC0B,CAAA,GAAA,EAAA,MAAA,EAAA,GAAA,IAAA,EAAA,OAAA,EAAA,CAAA,EAAA,IAAA;OAA4B,CAAA,GAAA,EAAA,MAAA,EAAA,GAAA,IAAA,EAAA,OAAA,EAAA,CAAA,EAAA,IAAA;;AAAO,UAdjE,iBAAA,CAoKT;EAAA,MAAA,EAnKS,MAmKT;cAjCe,CAAA,IAAA,EAjIK,OAiIL,CAAA,EAAA,IAAA;uBA6BE,CAAA,IAAA,EAAA,MAAA,EAAA,OAAA,EAAA,CAAA,GAAA,IAAA,EAAA,OAAA,EAAA,EAAA,GA7JqD,OA6JrD,CAAA,OAAA,CAAA,CAAA,EAAA,IAAA;EAAiB,EAAA,CAAA,KAAA,EAAA,MAAA,EAAA,OAAA,EAAA,CAAA,GAAA,IAAA,EAAA,OAAA,EAAA,EAAA,GAAA,IAAA,GA5JyB,OA4JzB,CAAA,IAAA,CAAA,EAAA,QAAA,EAAA;;;;UAvJzB,OAAA;;;;cAII;wCAC0B,4BAA4B;;;;;;;;cA+G9D;;;;;gBAMU;kBA6BE"}
1
+ {"version":3,"file":"plugin.d.ts","names":[],"sources":["../src/plugin.ts"],"mappings":";;;;UAkBU,MAAA,CAqB0D;EAAO,IAAA,CAAA,GAAA,EAAA,MAAA,EAAA,GAAA,IAAA,EAAA,OAAA,EAAA,CAAA,EAAA,IAAA;EA8LrE,IAAA,CAAA,GAAA,EAuCL,MAAA,EAAA,GAAA,IAAA,EAAA,OAAA,EAAA,CAAA,EAAA,IAAA;EAAA,KAAA,CAAA,GAAA,EAAA,MAAA,EAAA,GAAA,IAAA,EAAA,OAAA,EAAA,CAAA,EAAA,IAAA;OAjCe,CAAA,GAAA,EAAA,MAAA,EAAA,GAAA,IAAA,EAAA,OAAA,EAAA,CAAA,EAAA,IAAA;;UAlNN,iBAAA,CA+OyB;UA9OzB;qBACW;uEACkD;4DACX;;;;UAKlD,OAAA;;;;cAII;wCAC0B,4BAA4B;;;;;;;;cA8L9D;;;;;gBAMU;kBA6BE"}
package/dist/plugin.js CHANGED
@@ -4,10 +4,14 @@ import { resolveConfig } from "@alfe.ai/config";
4
4
  /**
5
5
  * @alfe/openclaw-mobile — OpenClaw native plugin
6
6
  *
7
- * Registers mobile tools (SMS, calls) with OpenClaw. Tools call the
8
- * mobile service API using the agent's API key for authentication.
7
+ * Registers mobile tools (SMS, calls, number management) with OpenClaw.
8
+ * Tools call the mobile service API using the agent's API key for authentication.
9
9
  *
10
10
  * This plugin provides:
11
+ * - mobile_get_number — check if a phone number is assigned
12
+ * - mobile_search_numbers — search available numbers for purchase
13
+ * - mobile_assign_number — purchase and assign a phone number
14
+ * - mobile_release_number — release the assigned phone number
11
15
  * - mobile_send_sms — send an SMS message from the agent's phone number
12
16
  * - mobile_call — initiate an outbound phone call
13
17
  */
@@ -46,8 +50,12 @@ function defineTool(def) {
46
50
  }
47
51
  let apiUrl = "";
48
52
  let apiKey = "";
49
- async function mobileApi(method, path, body) {
50
- const url = `${apiUrl}${path}`;
53
+ async function mobileApi(method, path, body, query) {
54
+ let url = `${apiUrl}${path}`;
55
+ if (query) {
56
+ const entries = Object.entries(query).filter((entry) => entry[1] !== void 0);
57
+ if (entries.length > 0) url += `?${new URLSearchParams(entries).toString()}`;
58
+ }
51
59
  const headers = {
52
60
  "Content-Type": "application/json",
53
61
  Authorization: `Bearer ${apiKey}`
@@ -59,39 +67,95 @@ async function mobileApi(method, path, body) {
59
67
  });
60
68
  const json = await res.json();
61
69
  if (!res.ok) {
70
+ const issues = json.issues;
71
+ if (Array.isArray(issues) && issues.length > 0) {
72
+ const details = issues.map((i) => {
73
+ return `${i.path?.join(".") ?? "input"}: ${i.message ?? "invalid"}`;
74
+ }).join("; ");
75
+ throw new Error(`Validation error — ${details}`);
76
+ }
62
77
  const errorMsg = typeof json.error === "string" ? json.error : typeof json.message === "string" ? json.message : `Mobile service returned ${String(res.status)}`;
63
78
  throw new Error(errorMsg);
64
79
  }
65
80
  if (json.data && typeof json.data === "object") return json.data;
66
81
  return json;
67
82
  }
68
- const mobileTools = [defineTool({
69
- name: "mobile_send_sms",
70
- description: "Send an SMS text message from your phone number to the specified number. The recipient number must be in E.164 format (e.g., +12025551234).",
71
- parameters: Type.Object({
72
- to: Type.String({ description: "Recipient phone number in E.164 format (e.g., +12025551234)" }),
73
- body: Type.String({ description: "The text message content to send" })
83
+ const mobileTools = [
84
+ defineTool({
85
+ name: "mobile_get_number",
86
+ description: "Check if you have a phone number assigned. Returns the phone number, country code, monthly price, and status. If no number is assigned, use mobile_search_numbers and mobile_assign_number to get one.",
87
+ parameters: Type.Object({}),
88
+ handler: async () => {
89
+ return mobileApi("GET", "/mobile/numbers");
90
+ }
74
91
  }),
75
- handler: async (params) => {
76
- const { to, body } = params;
77
- return mobileApi("POST", "/mobile/sms/send", {
78
- to,
79
- body
80
- });
81
- }
82
- }), defineTool({
83
- name: "mobile_call",
84
- description: "Make an outbound phone call to the specified number. When the recipient answers, they will be connected to your voice pipeline. The number must be in E.164 format (e.g., +12025551234).",
85
- parameters: Type.Object({ to: Type.String({ description: "Phone number to call in E.164 format (e.g., +12025551234)" }) }),
86
- handler: async (params) => {
87
- const { to } = params;
88
- return mobileApi("POST", "/mobile/calls/outbound", { to });
89
- }
90
- })];
92
+ defineTool({
93
+ name: "mobile_search_numbers",
94
+ description: "Search for available phone numbers that can be purchased. Returns a list of available numbers and the monthly price. Supported countries: AU (Australia), US (United States), CA (Canada), GB (United Kingdom).",
95
+ parameters: Type.Object({
96
+ country: Type.Optional(Type.String({ description: "Country code: AU, US, CA, or GB (default: AU)" })),
97
+ query: Type.Optional(Type.String({ description: "Optional search pattern — area code or text to match (e.g., '415' or 'COOL')" }))
98
+ }),
99
+ handler: async (params) => {
100
+ const { country, query } = params;
101
+ return mobileApi("GET", "/mobile/numbers/search", void 0, {
102
+ country,
103
+ query
104
+ });
105
+ }
106
+ }),
107
+ defineTool({
108
+ name: "mobile_assign_number",
109
+ description: "Purchase and assign a phone number to yourself. You must search for available numbers first using mobile_search_numbers, then pass the chosen phoneNumber and countryCode here. Your organisation must have a payment method on file. The number will be billed monthly to the organisation's account.",
110
+ parameters: Type.Object({
111
+ phoneNumber: Type.String({ description: "The phone number to purchase (from mobile_search_numbers results)" }),
112
+ countryCode: Type.String({ description: "Country code: AU, US, CA, or GB" })
113
+ }),
114
+ handler: async (params) => {
115
+ const { phoneNumber, countryCode } = params;
116
+ return mobileApi("POST", "/mobile/numbers/assign", {
117
+ phoneNumber,
118
+ countryCode
119
+ });
120
+ }
121
+ }),
122
+ defineTool({
123
+ name: "mobile_release_number",
124
+ description: "Release your currently assigned phone number. This will cancel the monthly subscription and the number will no longer be available for calls or SMS. This action cannot be undone — the same number may not be available again.",
125
+ parameters: Type.Object({}),
126
+ handler: async () => {
127
+ return mobileApi("POST", "/mobile/numbers/release", {});
128
+ }
129
+ }),
130
+ defineTool({
131
+ name: "mobile_send_sms",
132
+ description: "Send an SMS text message from your phone number to the specified number. The recipient number must be in E.164 format (e.g., +12025551234).",
133
+ parameters: Type.Object({
134
+ to: Type.String({ description: "Recipient phone number in E.164 format (e.g., +12025551234)" }),
135
+ body: Type.String({ description: "The text message content to send" })
136
+ }),
137
+ handler: async (params) => {
138
+ const { to, body } = params;
139
+ return mobileApi("POST", "/mobile/sms/send", {
140
+ to,
141
+ body
142
+ });
143
+ }
144
+ }),
145
+ defineTool({
146
+ name: "mobile_call",
147
+ description: "Make an outbound phone call to the specified number. When the recipient answers, they will be connected to your voice pipeline. The number must be in E.164 format (e.g., +12025551234).",
148
+ parameters: Type.Object({ to: Type.String({ description: "Phone number to call in E.164 format (e.g., +12025551234)" }) }),
149
+ handler: async (params) => {
150
+ const { to } = params;
151
+ return mobileApi("POST", "/mobile/calls/outbound", { to });
152
+ }
153
+ })
154
+ ];
91
155
  const plugin = {
92
156
  id: "@alfe.ai/openclaw-mobile",
93
157
  name: "Alfe Mobile Plugin",
94
- description: "Mobile integration — outbound SMS and phone calls via Twilio",
158
+ description: "Mobile integration — phone number management, SMS, and phone calls via Twilio",
95
159
  version: "0.0.1",
96
160
  activate(api) {
97
161
  const log = api.logger;
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.js","names":[],"sources":["../src/plugin.ts"],"sourcesContent":["/**\n * @alfe/openclaw-mobile — OpenClaw native plugin\n *\n * Registers mobile tools (SMS, calls) with OpenClaw. Tools call the\n * mobile service API using the agent's API key for authentication.\n *\n * This plugin provides:\n * - mobile_send_sms — send an SMS message from the agent's phone number\n * - mobile_call — initiate an outbound phone call\n */\n\nimport { Type, type TSchema } from \"@sinclair/typebox\";\nimport { resolveConfig } from \"@alfe.ai/config\";\n\ninterface Logger {\n info(msg: string, ...args: unknown[]): void;\n warn(msg: string, ...args: unknown[]): void;\n error(msg: string, ...args: unknown[]): void;\n debug(msg: string, ...args: unknown[]): void;\n}\n\ninterface OpenClawPluginApi {\n logger: Logger;\n registerTool(tool: ToolDef): void;\n registerGatewayMethod(name: string, handler: (...args: unknown[]) => Promise<unknown>): void;\n on(event: string, handler: (...args: unknown[]) => void | Promise<void>, options?: { priority?: number }): void;\n}\n\n// ── Tool types ───────────────────────────────────────────────\n\ninterface ToolDef {\n name: string;\n description: string;\n label: string;\n parameters: TSchema;\n execute: (toolCallId: string, params: Record<string, unknown>) => Promise<{\n content: { type: \"text\"; text: string }[];\n details: unknown;\n }>;\n}\n\nfunction ok(data: unknown) {\n return { content: [{ type: \"text\" as const, text: JSON.stringify(data) }], details: data };\n}\n\nfunction errResult(message: string) {\n return { content: [{ type: \"text\" as const, text: JSON.stringify({ error: message }) }], details: { error: message } };\n}\n\nfunction defineTool(def: {\n name: string;\n description: string;\n parameters: TSchema;\n handler: (params: Record<string, unknown>) => Promise<unknown>;\n}): ToolDef {\n return {\n name: def.name,\n description: def.description,\n label: def.name,\n parameters: def.parameters,\n execute: async (_toolCallId: string, params: Record<string, unknown>) => {\n try {\n const result = await def.handler(params);\n return ok(result);\n } catch (e) {\n return errResult((e as Error).message);\n }\n },\n };\n}\n\n// ── API client ───────────────────────────────────────────────\n\nlet apiUrl = \"\";\nlet apiKey = \"\";\n\nasync function mobileApi(\n method: string,\n path: string,\n body?: Record<string, unknown>,\n): Promise<Record<string, unknown>> {\n const url = `${apiUrl}${path}`;\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${apiKey}`,\n };\n\n const res = await fetch(url, {\n method,\n headers,\n body: body ? JSON.stringify(body) : undefined,\n });\n\n const json = (await res.json()) as Record<string, unknown>;\n if (!res.ok) {\n const errorMsg = typeof json.error === \"string\"\n ? json.error\n : typeof json.message === \"string\"\n ? json.message\n : `Mobile service returned ${String(res.status)}`;\n throw new Error(errorMsg);\n }\n\n // unwrap { data: ... } envelope if present\n if (json.data && typeof json.data === \"object\") {\n return json.data as Record<string, unknown>;\n }\n return json;\n}\n\n// ── Tool definitions ─────────────────────────────────────────\n\nconst mobileTools: ToolDef[] = [\n defineTool({\n name: \"mobile_send_sms\",\n description:\n \"Send an SMS text message from your phone number to the specified number. \" +\n \"The recipient number must be in E.164 format (e.g., +12025551234).\",\n parameters: Type.Object({\n to: Type.String({ description: \"Recipient phone number in E.164 format (e.g., +12025551234)\" }),\n body: Type.String({ description: \"The text message content to send\" }),\n }),\n handler: async (params) => {\n const { to, body } = params as { to: string; body: string };\n return mobileApi(\"POST\", \"/mobile/sms/send\", { to, body });\n },\n }),\n\n defineTool({\n name: \"mobile_call\",\n description:\n \"Make an outbound phone call to the specified number. \" +\n \"When the recipient answers, they will be connected to your voice pipeline. \" +\n \"The number must be in E.164 format (e.g., +12025551234).\",\n parameters: Type.Object({\n to: Type.String({ description: \"Phone number to call in E.164 format (e.g., +12025551234)\" }),\n }),\n handler: async (params) => {\n const { to } = params as { to: string };\n return mobileApi(\"POST\", \"/mobile/calls/outbound\", { to });\n },\n }),\n];\n\n// ── Plugin definition ────────────────────────────────────────\n\nconst plugin = {\n id: \"@alfe.ai/openclaw-mobile\",\n name: \"Alfe Mobile Plugin\",\n description: \"Mobile integration — outbound SMS and phone calls via Twilio\",\n version: \"0.0.1\",\n\n activate(api: OpenClawPluginApi) {\n const log = api.logger;\n\n // Always register tools — OpenClaw may reload the plugin registry per-session\n for (const tool of mobileTools) {\n api.registerTool(tool);\n }\n log.info(`Registered ${String(mobileTools.length)} mobile tools: ${mobileTools.map((t) => t.name).join(\", \")}`);\n\n // Only initialize config once (side effects)\n if (!(globalThis as Record<string, unknown>).__mobilePluginActivated) {\n (globalThis as Record<string, unknown>).__mobilePluginActivated = true;\n log.info(\"Alfe Mobile plugin activating...\");\n\n try {\n const config = resolveConfig();\n apiUrl = config.apiUrl;\n apiKey = config.apiKey;\n } catch (err) {\n log.error(`Failed to resolve config: ${err instanceof Error ? err.message : String(err)}`);\n log.warn(\"Mobile tools will fail — no API config available\");\n }\n\n log.info(`Mobile API: ${apiUrl}`);\n }\n\n log.info(\"Alfe Mobile plugin activated\");\n },\n\n deactivate(api: OpenClawPluginApi) {\n (globalThis as Record<string, unknown>).__mobilePluginActivated = false;\n api.logger.info(\"Alfe Mobile plugin deactivated\");\n },\n};\n\nexport default plugin;\n"],"mappings":";;;;;;;;;;;;;AAyCA,SAAS,GAAG,MAAe;AACzB,QAAO;EAAE,SAAS,CAAC;GAAE,MAAM;GAAiB,MAAM,KAAK,UAAU,KAAK;GAAE,CAAC;EAAE,SAAS;EAAM;;AAG5F,SAAS,UAAU,SAAiB;AAClC,QAAO;EAAE,SAAS,CAAC;GAAE,MAAM;GAAiB,MAAM,KAAK,UAAU,EAAE,OAAO,SAAS,CAAC;GAAE,CAAC;EAAE,SAAS,EAAE,OAAO,SAAS;EAAE;;AAGxH,SAAS,WAAW,KAKR;AACV,QAAO;EACL,MAAM,IAAI;EACV,aAAa,IAAI;EACjB,OAAO,IAAI;EACX,YAAY,IAAI;EAChB,SAAS,OAAO,aAAqB,WAAoC;AACvE,OAAI;AAEF,WAAO,GADQ,MAAM,IAAI,QAAQ,OAAO,CACvB;YACV,GAAG;AACV,WAAO,UAAW,EAAY,QAAQ;;;EAG3C;;AAKH,IAAI,SAAS;AACb,IAAI,SAAS;AAEb,eAAe,UACb,QACA,MACA,MACkC;CAClC,MAAM,MAAM,GAAG,SAAS;CACxB,MAAM,UAAkC;EACtC,gBAAgB;EAChB,eAAe,UAAU;EAC1B;CAED,MAAM,MAAM,MAAM,MAAM,KAAK;EAC3B;EACA;EACA,MAAM,OAAO,KAAK,UAAU,KAAK,GAAG,KAAA;EACrC,CAAC;CAEF,MAAM,OAAQ,MAAM,IAAI,MAAM;AAC9B,KAAI,CAAC,IAAI,IAAI;EACX,MAAM,WAAW,OAAO,KAAK,UAAU,WACnC,KAAK,QACL,OAAO,KAAK,YAAY,WACtB,KAAK,UACL,2BAA2B,OAAO,IAAI,OAAO;AACnD,QAAM,IAAI,MAAM,SAAS;;AAI3B,KAAI,KAAK,QAAQ,OAAO,KAAK,SAAS,SACpC,QAAO,KAAK;AAEd,QAAO;;AAKT,MAAM,cAAyB,CAC7B,WAAW;CACT,MAAM;CACN,aACE;CAEF,YAAY,KAAK,OAAO;EACtB,IAAI,KAAK,OAAO,EAAE,aAAa,+DAA+D,CAAC;EAC/F,MAAM,KAAK,OAAO,EAAE,aAAa,oCAAoC,CAAC;EACvE,CAAC;CACF,SAAS,OAAO,WAAW;EACzB,MAAM,EAAE,IAAI,SAAS;AACrB,SAAO,UAAU,QAAQ,oBAAoB;GAAE;GAAI;GAAM,CAAC;;CAE7D,CAAC,EAEF,WAAW;CACT,MAAM;CACN,aACE;CAGF,YAAY,KAAK,OAAO,EACtB,IAAI,KAAK,OAAO,EAAE,aAAa,6DAA6D,CAAC,EAC9F,CAAC;CACF,SAAS,OAAO,WAAW;EACzB,MAAM,EAAE,OAAO;AACf,SAAO,UAAU,QAAQ,0BAA0B,EAAE,IAAI,CAAC;;CAE7D,CAAC,CACH;AAID,MAAM,SAAS;CACb,IAAI;CACJ,MAAM;CACN,aAAa;CACb,SAAS;CAET,SAAS,KAAwB;EAC/B,MAAM,MAAM,IAAI;AAGhB,OAAK,MAAM,QAAQ,YACjB,KAAI,aAAa,KAAK;AAExB,MAAI,KAAK,cAAc,OAAO,YAAY,OAAO,CAAC,iBAAiB,YAAY,KAAK,MAAM,EAAE,KAAK,CAAC,KAAK,KAAK,GAAG;AAG/G,MAAI,CAAE,WAAuC,yBAAyB;AACnE,cAAuC,0BAA0B;AAClE,OAAI,KAAK,mCAAmC;AAE5C,OAAI;IACF,MAAM,SAAS,eAAe;AAC9B,aAAS,OAAO;AAChB,aAAS,OAAO;YACT,KAAK;AACZ,QAAI,MAAM,6BAA6B,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI,GAAG;AAC1F,QAAI,KAAK,mDAAmD;;AAG9D,OAAI,KAAK,eAAe,SAAS;;AAGnC,MAAI,KAAK,+BAA+B;;CAG1C,WAAW,KAAwB;AAChC,aAAuC,0BAA0B;AAClE,MAAI,OAAO,KAAK,iCAAiC;;CAEpD"}
1
+ {"version":3,"file":"plugin.js","names":[],"sources":["../src/plugin.ts"],"sourcesContent":["/**\n * @alfe/openclaw-mobile — OpenClaw native plugin\n *\n * Registers mobile tools (SMS, calls, number management) with OpenClaw.\n * Tools call the mobile service API using the agent's API key for authentication.\n *\n * This plugin provides:\n * - mobile_get_number — check if a phone number is assigned\n * - mobile_search_numbers — search available numbers for purchase\n * - mobile_assign_number — purchase and assign a phone number\n * - mobile_release_number — release the assigned phone number\n * - mobile_send_sms — send an SMS message from the agent's phone number\n * - mobile_call — initiate an outbound phone call\n */\n\nimport { Type, type TSchema } from \"@sinclair/typebox\";\nimport { resolveConfig } from \"@alfe.ai/config\";\n\ninterface Logger {\n info(msg: string, ...args: unknown[]): void;\n warn(msg: string, ...args: unknown[]): void;\n error(msg: string, ...args: unknown[]): void;\n debug(msg: string, ...args: unknown[]): void;\n}\n\ninterface OpenClawPluginApi {\n logger: Logger;\n registerTool(tool: ToolDef): void;\n registerGatewayMethod(name: string, handler: (...args: unknown[]) => Promise<unknown>): void;\n on(event: string, handler: (...args: unknown[]) => void | Promise<void>, options?: { priority?: number }): void;\n}\n\n// ── Tool types ───────────────────────────────────────────────\n\ninterface ToolDef {\n name: string;\n description: string;\n label: string;\n parameters: TSchema;\n execute: (toolCallId: string, params: Record<string, unknown>) => Promise<{\n content: { type: \"text\"; text: string }[];\n details: unknown;\n }>;\n}\n\nfunction ok(data: unknown) {\n return { content: [{ type: \"text\" as const, text: JSON.stringify(data) }], details: data };\n}\n\nfunction errResult(message: string) {\n return { content: [{ type: \"text\" as const, text: JSON.stringify({ error: message }) }], details: { error: message } };\n}\n\nfunction defineTool(def: {\n name: string;\n description: string;\n parameters: TSchema;\n handler: (params: Record<string, unknown>) => Promise<unknown>;\n}): ToolDef {\n return {\n name: def.name,\n description: def.description,\n label: def.name,\n parameters: def.parameters,\n execute: async (_toolCallId: string, params: Record<string, unknown>) => {\n try {\n const result = await def.handler(params);\n return ok(result);\n } catch (e) {\n return errResult((e as Error).message);\n }\n },\n };\n}\n\n// ── API client ───────────────────────────────────────────────\n\nlet apiUrl = \"\";\nlet apiKey = \"\";\n\nasync function mobileApi(\n method: string,\n path: string,\n body?: Record<string, unknown>,\n query?: Record<string, string | undefined>,\n): Promise<Record<string, unknown>> {\n let url = `${apiUrl}${path}`;\n if (query) {\n const entries = Object.entries(query).filter((entry): entry is [string, string] => entry[1] !== undefined);\n if (entries.length > 0) {\n url += `?${new URLSearchParams(entries).toString()}`;\n }\n }\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${apiKey}`,\n };\n\n const res = await fetch(url, {\n method,\n headers,\n body: body ? JSON.stringify(body) : undefined,\n });\n\n const json = (await res.json()) as Record<string, unknown>;\n if (!res.ok) {\n // Extract Zod validation issues if present (returned as { message: \"CORE_VALIDATION_FAILED\", issues: [...] })\n const issues = json.issues as { path?: string[]; message?: string }[] | undefined;\n if (Array.isArray(issues) && issues.length > 0) {\n const details = issues\n .map((i) => {\n const field = i.path?.join(\".\") ?? \"input\";\n return `${field}: ${i.message ?? \"invalid\"}`;\n })\n .join(\"; \");\n throw new Error(`Validation error — ${details}`);\n }\n\n const errorMsg = typeof json.error === \"string\"\n ? json.error\n : typeof json.message === \"string\"\n ? json.message\n : `Mobile service returned ${String(res.status)}`;\n throw new Error(errorMsg);\n }\n\n // unwrap { data: ... } envelope if present\n if (json.data && typeof json.data === \"object\") {\n return json.data as Record<string, unknown>;\n }\n return json;\n}\n\n// ── Tool definitions ─────────────────────────────────────────\n\nconst mobileTools: ToolDef[] = [\n // ── Number management ───────────────────────────────────────\n defineTool({\n name: \"mobile_get_number\",\n description:\n \"Check if you have a phone number assigned. Returns the phone number, \" +\n \"country code, monthly price, and status. If no number is assigned, \" +\n \"use mobile_search_numbers and mobile_assign_number to get one.\",\n parameters: Type.Object({}),\n handler: async () => {\n return mobileApi(\"GET\", \"/mobile/numbers\");\n },\n }),\n\n defineTool({\n name: \"mobile_search_numbers\",\n description:\n \"Search for available phone numbers that can be purchased. \" +\n \"Returns a list of available numbers and the monthly price. \" +\n \"Supported countries: AU (Australia), US (United States), CA (Canada), GB (United Kingdom).\",\n parameters: Type.Object({\n country: Type.Optional(Type.String({ description: \"Country code: AU, US, CA, or GB (default: AU)\" })),\n query: Type.Optional(Type.String({ description: \"Optional search pattern — area code or text to match (e.g., '415' or 'COOL')\" })),\n }),\n handler: async (params) => {\n const { country, query } = params as { country?: string; query?: string };\n return mobileApi(\"GET\", \"/mobile/numbers/search\", undefined, { country, query });\n },\n }),\n\n defineTool({\n name: \"mobile_assign_number\",\n description:\n \"Purchase and assign a phone number to yourself. You must search for available \" +\n \"numbers first using mobile_search_numbers, then pass the chosen phoneNumber and \" +\n \"countryCode here. Your organisation must have a payment method on file. \" +\n \"The number will be billed monthly to the organisation's account.\",\n parameters: Type.Object({\n phoneNumber: Type.String({ description: \"The phone number to purchase (from mobile_search_numbers results)\" }),\n countryCode: Type.String({ description: \"Country code: AU, US, CA, or GB\" }),\n }),\n handler: async (params) => {\n const { phoneNumber, countryCode } = params as { phoneNumber: string; countryCode: string };\n return mobileApi(\"POST\", \"/mobile/numbers/assign\", { phoneNumber, countryCode });\n },\n }),\n\n defineTool({\n name: \"mobile_release_number\",\n description:\n \"Release your currently assigned phone number. This will cancel the monthly \" +\n \"subscription and the number will no longer be available for calls or SMS. \" +\n \"This action cannot be undone — the same number may not be available again.\",\n parameters: Type.Object({}),\n handler: async () => {\n return mobileApi(\"POST\", \"/mobile/numbers/release\", {});\n },\n }),\n\n // ── Messaging & calls ───────────────────────────────────────\n defineTool({\n name: \"mobile_send_sms\",\n description:\n \"Send an SMS text message from your phone number to the specified number. \" +\n \"The recipient number must be in E.164 format (e.g., +12025551234).\",\n parameters: Type.Object({\n to: Type.String({ description: \"Recipient phone number in E.164 format (e.g., +12025551234)\" }),\n body: Type.String({ description: \"The text message content to send\" }),\n }),\n handler: async (params) => {\n const { to, body } = params as { to: string; body: string };\n return mobileApi(\"POST\", \"/mobile/sms/send\", { to, body });\n },\n }),\n\n defineTool({\n name: \"mobile_call\",\n description:\n \"Make an outbound phone call to the specified number. \" +\n \"When the recipient answers, they will be connected to your voice pipeline. \" +\n \"The number must be in E.164 format (e.g., +12025551234).\",\n parameters: Type.Object({\n to: Type.String({ description: \"Phone number to call in E.164 format (e.g., +12025551234)\" }),\n }),\n handler: async (params) => {\n const { to } = params as { to: string };\n return mobileApi(\"POST\", \"/mobile/calls/outbound\", { to });\n },\n }),\n];\n\n// ── Plugin definition ────────────────────────────────────────\n\nconst plugin = {\n id: \"@alfe.ai/openclaw-mobile\",\n name: \"Alfe Mobile Plugin\",\n description: \"Mobile integration — phone number management, SMS, and phone calls via Twilio\",\n version: \"0.0.1\",\n\n activate(api: OpenClawPluginApi) {\n const log = api.logger;\n\n // Always register tools — OpenClaw may reload the plugin registry per-session\n for (const tool of mobileTools) {\n api.registerTool(tool);\n }\n log.info(`Registered ${String(mobileTools.length)} mobile tools: ${mobileTools.map((t) => t.name).join(\", \")}`);\n\n // Only initialize config once (side effects)\n if (!(globalThis as Record<string, unknown>).__mobilePluginActivated) {\n (globalThis as Record<string, unknown>).__mobilePluginActivated = true;\n log.info(\"Alfe Mobile plugin activating...\");\n\n try {\n const config = resolveConfig();\n apiUrl = config.apiUrl;\n apiKey = config.apiKey;\n } catch (err) {\n log.error(`Failed to resolve config: ${err instanceof Error ? err.message : String(err)}`);\n log.warn(\"Mobile tools will fail — no API config available\");\n }\n\n log.info(`Mobile API: ${apiUrl}`);\n }\n\n log.info(\"Alfe Mobile plugin activated\");\n },\n\n deactivate(api: OpenClawPluginApi) {\n (globalThis as Record<string, unknown>).__mobilePluginActivated = false;\n api.logger.info(\"Alfe Mobile plugin deactivated\");\n },\n};\n\nexport default plugin;\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@alfe.ai/openclaw-mobile",
3
- "version": "0.0.7",
4
- "description": "OpenClaw mobile plugin for Alfe — outbound SMS and phone calls via Twilio",
3
+ "version": "0.0.9",
4
+ "description": "OpenClaw mobile plugin for Alfe — phone number management, SMS, and calls via Twilio",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",
@@ -28,7 +28,7 @@
28
28
  ],
29
29
  "dependencies": {
30
30
  "@sinclair/typebox": "^0.34.48",
31
- "@alfe.ai/config": "0.0.7"
31
+ "@alfe.ai/config": "0.0.8"
32
32
  },
33
33
  "scripts": {
34
34
  "build": "tsdown",