cashclaw 1.0.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 (39) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +281 -0
  3. package/bin/cashclaw.js +2 -0
  4. package/missions/blog-post-1500.json +21 -0
  5. package/missions/blog-post-500.json +19 -0
  6. package/missions/lead-list-50.json +20 -0
  7. package/missions/seo-audit-basic.json +19 -0
  8. package/missions/seo-audit-pro.json +23 -0
  9. package/missions/social-media-weekly.json +19 -0
  10. package/missions/whatsapp-setup.json +22 -0
  11. package/package.json +45 -0
  12. package/skills/cashclaw-content-writer/SKILL.md +245 -0
  13. package/skills/cashclaw-core/SKILL.md +251 -0
  14. package/skills/cashclaw-invoicer/SKILL.md +395 -0
  15. package/skills/cashclaw-invoicer/scripts/stripe-ops.js +441 -0
  16. package/skills/cashclaw-lead-generator/SKILL.md +246 -0
  17. package/skills/cashclaw-lead-generator/scripts/scraper.js +356 -0
  18. package/skills/cashclaw-seo-auditor/SKILL.md +240 -0
  19. package/skills/cashclaw-seo-auditor/scripts/audit.js +401 -0
  20. package/skills/cashclaw-social-media/SKILL.md +374 -0
  21. package/skills/cashclaw-whatsapp-manager/SKILL.md +357 -0
  22. package/src/cli/commands/dashboard.js +72 -0
  23. package/src/cli/commands/init.js +290 -0
  24. package/src/cli/commands/status.js +174 -0
  25. package/src/cli/index.js +496 -0
  26. package/src/cli/utils/banner.js +44 -0
  27. package/src/cli/utils/config.js +170 -0
  28. package/src/dashboard/public/app.js +329 -0
  29. package/src/dashboard/public/index.html +139 -0
  30. package/src/dashboard/public/style.css +464 -0
  31. package/src/dashboard/server.js +224 -0
  32. package/src/engine/earnings-tracker.js +184 -0
  33. package/src/engine/mission-runner.js +224 -0
  34. package/src/engine/scheduler.js +139 -0
  35. package/src/integrations/hyrve-bridge.js +213 -0
  36. package/src/integrations/openclaw-bridge.js +207 -0
  37. package/src/integrations/stripe-connect.js +204 -0
  38. package/templates/config.default.json +83 -0
  39. package/templates/invoice.html +260 -0
@@ -0,0 +1,213 @@
1
+ import { loadConfig } from '../cli/utils/config.js';
2
+
3
+ const DEFAULT_API_URL = 'https://api.hyrveai.com/v1';
4
+
5
+ /**
6
+ * Get the HYRVE API base URL from config or default.
7
+ */
8
+ async function getApiUrl() {
9
+ const config = await loadConfig();
10
+ return config.hyrve?.api_url || DEFAULT_API_URL;
11
+ }
12
+
13
+ /**
14
+ * Build request headers for HYRVE API calls.
15
+ */
16
+ async function getHeaders(config = null) {
17
+ if (!config) config = await loadConfig();
18
+ return {
19
+ 'Content-Type': 'application/json',
20
+ 'User-Agent': 'CashClaw/1.0.0',
21
+ 'X-Agent-Id': config.hyrve?.agent_id || '',
22
+ 'X-Agent-Name': config.agent?.name || '',
23
+ };
24
+ }
25
+
26
+ /**
27
+ * Register the CashClaw agent on the HYRVEai marketplace.
28
+ * This makes the agent discoverable to potential clients.
29
+ * @param {object} config - CashClaw configuration
30
+ * @returns {object} Registration result with agent_id
31
+ */
32
+ export async function registerAgent(config) {
33
+ const apiUrl = config.hyrve?.api_url || DEFAULT_API_URL;
34
+
35
+ const enabledServices = Object.entries(config.services || {})
36
+ .filter(([_, svc]) => svc.enabled)
37
+ .map(([key, svc]) => ({
38
+ type: key,
39
+ pricing: svc.pricing,
40
+ description: svc.description,
41
+ }));
42
+
43
+ const payload = {
44
+ agent_name: config.agent?.name || 'CashClaw Agent',
45
+ owner_name: config.agent?.owner || '',
46
+ email: config.agent?.email || '',
47
+ currency: config.agent?.currency || 'USD',
48
+ services: enabledServices,
49
+ stripe_connected: !!config.stripe?.secret_key,
50
+ version: '1.0.0',
51
+ };
52
+
53
+ try {
54
+ const response = await fetch(`${apiUrl}/agents/register`, {
55
+ method: 'POST',
56
+ headers: await getHeaders(config),
57
+ body: JSON.stringify(payload),
58
+ });
59
+
60
+ if (!response.ok) {
61
+ const errBody = await response.text();
62
+ throw new Error(`HYRVE API error (${response.status}): ${errBody}`);
63
+ }
64
+
65
+ const data = await response.json();
66
+ return {
67
+ success: true,
68
+ agent_id: data.agent_id || data.id,
69
+ message: data.message || 'Agent registered successfully',
70
+ };
71
+ } catch (err) {
72
+ // If the API is not reachable, return a graceful failure
73
+ if (err.cause?.code === 'ECONNREFUSED' || err.cause?.code === 'ENOTFOUND' || err.message.includes('fetch')) {
74
+ return {
75
+ success: false,
76
+ agent_id: null,
77
+ message: 'HYRVEai marketplace is not yet available. Your agent is configured locally and will auto-register when the marketplace launches.',
78
+ };
79
+ }
80
+ return {
81
+ success: false,
82
+ agent_id: null,
83
+ message: `Registration failed: ${err.message}`,
84
+ };
85
+ }
86
+ }
87
+
88
+ /**
89
+ * Sync agent status with HYRVE marketplace.
90
+ * Sends current earnings, mission count, and availability.
91
+ */
92
+ export async function syncStatus() {
93
+ const config = await loadConfig();
94
+ const apiUrl = await getApiUrl();
95
+
96
+ if (!config.hyrve?.agent_id) {
97
+ return {
98
+ success: false,
99
+ message: 'Agent not registered with HYRVE. Run "cashclaw init" first.',
100
+ };
101
+ }
102
+
103
+ try {
104
+ const response = await fetch(`${apiUrl}/agents/${config.hyrve.agent_id}/sync`, {
105
+ method: 'POST',
106
+ headers: await getHeaders(config),
107
+ body: JSON.stringify({
108
+ status: 'active',
109
+ stats: config.stats || {},
110
+ updated_at: new Date().toISOString(),
111
+ }),
112
+ });
113
+
114
+ if (!response.ok) {
115
+ throw new Error(`Sync failed (${response.status})`);
116
+ }
117
+
118
+ return { success: true, message: 'Status synced with HYRVE marketplace' };
119
+ } catch (err) {
120
+ return {
121
+ success: false,
122
+ message: `Sync unavailable: ${err.message}. Local data is up to date.`,
123
+ };
124
+ }
125
+ }
126
+
127
+ /**
128
+ * List available jobs from the HYRVE marketplace that match
129
+ * this agent's enabled services.
130
+ */
131
+ export async function listAvailableJobs() {
132
+ const config = await loadConfig();
133
+ const apiUrl = await getApiUrl();
134
+
135
+ const enabledTypes = Object.entries(config.services || {})
136
+ .filter(([_, svc]) => svc.enabled)
137
+ .map(([key]) => key);
138
+
139
+ try {
140
+ const params = new URLSearchParams({
141
+ service_types: enabledTypes.join(','),
142
+ currency: config.agent?.currency || 'USD',
143
+ limit: '20',
144
+ });
145
+
146
+ const response = await fetch(`${apiUrl}/jobs?${params}`, {
147
+ headers: await getHeaders(config),
148
+ });
149
+
150
+ if (!response.ok) {
151
+ throw new Error(`Failed to fetch jobs (${response.status})`);
152
+ }
153
+
154
+ const data = await response.json();
155
+ return {
156
+ success: true,
157
+ jobs: data.jobs || [],
158
+ total: data.total || 0,
159
+ };
160
+ } catch (err) {
161
+ return {
162
+ success: false,
163
+ jobs: [],
164
+ total: 0,
165
+ message: `Marketplace unavailable: ${err.message}. Jobs will appear here when HYRVEai launches.`,
166
+ };
167
+ }
168
+ }
169
+
170
+ /**
171
+ * Accept a job from the HYRVE marketplace.
172
+ * This creates a mission locally and notifies the marketplace.
173
+ * @param {string} jobId - The HYRVE job ID to accept
174
+ */
175
+ export async function acceptJob(jobId) {
176
+ const config = await loadConfig();
177
+ const apiUrl = await getApiUrl();
178
+
179
+ if (!config.hyrve?.agent_id) {
180
+ return {
181
+ success: false,
182
+ message: 'Agent not registered. Run "cashclaw init" first.',
183
+ };
184
+ }
185
+
186
+ try {
187
+ const response = await fetch(`${apiUrl}/jobs/${jobId}/accept`, {
188
+ method: 'POST',
189
+ headers: await getHeaders(config),
190
+ body: JSON.stringify({
191
+ agent_id: config.hyrve.agent_id,
192
+ accepted_at: new Date().toISOString(),
193
+ }),
194
+ });
195
+
196
+ if (!response.ok) {
197
+ throw new Error(`Failed to accept job (${response.status})`);
198
+ }
199
+
200
+ const data = await response.json();
201
+ return {
202
+ success: true,
203
+ job: data.job || {},
204
+ mission_template: data.mission_template || null,
205
+ message: data.message || 'Job accepted successfully',
206
+ };
207
+ } catch (err) {
208
+ return {
209
+ success: false,
210
+ message: `Could not accept job: ${err.message}`,
211
+ };
212
+ }
213
+ }
@@ -0,0 +1,207 @@
1
+ import fs from 'fs-extra';
2
+ import path from 'path';
3
+ import os from 'os';
4
+ import { fileURLToPath } from 'url';
5
+
6
+ const __filename = fileURLToPath(import.meta.url);
7
+ const __dirname = path.dirname(__filename);
8
+
9
+ // CashClaw skills directory (shipped with the package)
10
+ const CASHCLAW_SKILLS_DIR = path.resolve(__dirname, '../../skills');
11
+
12
+ // Possible OpenClaw workspace locations
13
+ const OPENCLAW_PATHS = [
14
+ path.join(os.homedir(), '.openclaw', 'workspace', 'skills'),
15
+ path.join(os.homedir(), 'clawd', 'skills'),
16
+ path.join(os.homedir(), '.clawd', 'skills'),
17
+ path.join(os.homedir(), 'openclaw', 'skills'),
18
+ ];
19
+
20
+ /**
21
+ * Detect if OpenClaw is installed by checking known paths.
22
+ * @returns {object} { found: boolean, path: string|null, paths_checked: string[] }
23
+ */
24
+ export async function detectOpenClaw() {
25
+ for (const skillsPath of OPENCLAW_PATHS) {
26
+ try {
27
+ const exists = await fs.pathExists(skillsPath);
28
+ if (exists) {
29
+ return {
30
+ found: true,
31
+ path: path.dirname(skillsPath), // workspace root
32
+ skills_dir: skillsPath,
33
+ paths_checked: OPENCLAW_PATHS,
34
+ };
35
+ }
36
+ } catch {
37
+ continue;
38
+ }
39
+ }
40
+
41
+ return {
42
+ found: false,
43
+ path: null,
44
+ skills_dir: null,
45
+ paths_checked: OPENCLAW_PATHS,
46
+ };
47
+ }
48
+
49
+ /**
50
+ * Get the OpenClaw skills directory.
51
+ * Uses auto-detection or config override.
52
+ * @param {string} configOverride - Optional explicit path from config
53
+ * @returns {string|null} Path to skills directory
54
+ */
55
+ export async function getSkillsDir(configOverride = null) {
56
+ if (configOverride && await fs.pathExists(configOverride)) {
57
+ return configOverride;
58
+ }
59
+
60
+ const detection = await detectOpenClaw();
61
+ return detection.skills_dir;
62
+ }
63
+
64
+ /**
65
+ * List available CashClaw skills that can be installed.
66
+ * Reads from the cashclaw/skills/ directory shipped with the package.
67
+ * @returns {Array} List of skill objects
68
+ */
69
+ export async function listAvailableSkills() {
70
+ try {
71
+ const exists = await fs.pathExists(CASHCLAW_SKILLS_DIR);
72
+ if (!exists) {
73
+ return [];
74
+ }
75
+
76
+ const entries = await fs.readdir(CASHCLAW_SKILLS_DIR, { withFileTypes: true });
77
+ const skills = [];
78
+
79
+ for (const entry of entries) {
80
+ if (entry.isDirectory()) {
81
+ const skillPath = path.join(CASHCLAW_SKILLS_DIR, entry.name);
82
+ const skillMd = path.join(skillPath, 'SKILL.md');
83
+ const hasSkillMd = await fs.pathExists(skillMd);
84
+
85
+ skills.push({
86
+ name: entry.name,
87
+ path: skillPath,
88
+ has_skill_md: hasSkillMd,
89
+ });
90
+ }
91
+ }
92
+
93
+ return skills;
94
+ } catch (err) {
95
+ console.error(`Error listing skills: ${err.message}`);
96
+ return [];
97
+ }
98
+ }
99
+
100
+ /**
101
+ * List skills currently installed in the OpenClaw workspace.
102
+ * @param {string} configOverride - Optional explicit skills dir path
103
+ * @returns {Array} List of installed skill names
104
+ */
105
+ export async function listInstalledSkills(configOverride = null) {
106
+ const skillsDir = await getSkillsDir(configOverride);
107
+ if (!skillsDir) {
108
+ return [];
109
+ }
110
+
111
+ try {
112
+ const entries = await fs.readdir(skillsDir, { withFileTypes: true });
113
+ return entries
114
+ .filter((e) => e.isDirectory() && e.name.startsWith('cashclaw-'))
115
+ .map((e) => e.name);
116
+ } catch (err) {
117
+ return [];
118
+ }
119
+ }
120
+
121
+ /**
122
+ * Install CashClaw skills into the OpenClaw workspace.
123
+ * Copies skill directories from cashclaw/skills/ to the OpenClaw skills folder.
124
+ * @param {string[]} skillNames - Array of skill folder names (e.g. ['cashclaw-seo-auditor'])
125
+ * @param {string} configOverride - Optional explicit skills dir path
126
+ * @returns {object} Installation results
127
+ */
128
+ export async function installSkills(skillNames, configOverride = null) {
129
+ const targetDir = await getSkillsDir(configOverride);
130
+
131
+ if (!targetDir) {
132
+ return {
133
+ success: false,
134
+ installed: [],
135
+ failed: skillNames.map((n) => ({ name: n, error: 'OpenClaw workspace not found' })),
136
+ message:
137
+ 'OpenClaw workspace not found. Please install OpenClaw first or set the skills path in config.',
138
+ };
139
+ }
140
+
141
+ await fs.ensureDir(targetDir);
142
+
143
+ const installed = [];
144
+ const failed = [];
145
+
146
+ for (const skillName of skillNames) {
147
+ const sourcePath = path.join(CASHCLAW_SKILLS_DIR, skillName);
148
+ const destPath = path.join(targetDir, skillName);
149
+
150
+ try {
151
+ const sourceExists = await fs.pathExists(sourcePath);
152
+ if (!sourceExists) {
153
+ failed.push({ name: skillName, error: 'Skill not found in CashClaw package' });
154
+ continue;
155
+ }
156
+
157
+ // Copy the entire skill directory
158
+ await fs.copy(sourcePath, destPath, { overwrite: true });
159
+ installed.push(skillName);
160
+ } catch (err) {
161
+ failed.push({ name: skillName, error: err.message });
162
+ }
163
+ }
164
+
165
+ return {
166
+ success: failed.length === 0,
167
+ installed,
168
+ failed,
169
+ target_dir: targetDir,
170
+ message:
171
+ installed.length > 0
172
+ ? `Installed ${installed.length} skill(s) to ${targetDir}`
173
+ : 'No skills were installed',
174
+ };
175
+ }
176
+
177
+ /**
178
+ * Uninstall CashClaw skills from OpenClaw workspace.
179
+ * @param {string[]} skillNames - Array of skill names to remove
180
+ * @param {string} configOverride - Optional explicit skills dir path
181
+ */
182
+ export async function uninstallSkills(skillNames, configOverride = null) {
183
+ const targetDir = await getSkillsDir(configOverride);
184
+ if (!targetDir) {
185
+ return { success: false, removed: [], message: 'OpenClaw workspace not found' };
186
+ }
187
+
188
+ const removed = [];
189
+ for (const skillName of skillNames) {
190
+ const destPath = path.join(targetDir, skillName);
191
+ try {
192
+ const exists = await fs.pathExists(destPath);
193
+ if (exists) {
194
+ await fs.remove(destPath);
195
+ removed.push(skillName);
196
+ }
197
+ } catch {
198
+ continue;
199
+ }
200
+ }
201
+
202
+ return {
203
+ success: true,
204
+ removed,
205
+ message: `Removed ${removed.length} skill(s)`,
206
+ };
207
+ }
@@ -0,0 +1,204 @@
1
+ import Stripe from 'stripe';
2
+ import { loadConfig } from '../cli/utils/config.js';
3
+
4
+ let stripeClient = null;
5
+
6
+ /**
7
+ * Initialize or return the Stripe client.
8
+ * Reads the secret key from CashClaw config.
9
+ */
10
+ async function getStripe() {
11
+ if (stripeClient) return stripeClient;
12
+
13
+ const config = await loadConfig();
14
+ const secretKey = config.stripe?.secret_key;
15
+
16
+ if (!secretKey) {
17
+ throw new Error(
18
+ 'Stripe secret key not configured. Run "cashclaw init" or "cashclaw config set stripe.secret_key <key>"'
19
+ );
20
+ }
21
+
22
+ stripeClient = new Stripe(secretKey, {
23
+ apiVersion: '2024-12-18.acacia',
24
+ });
25
+
26
+ return stripeClient;
27
+ }
28
+
29
+ /**
30
+ * Create a Stripe Payment Link for a one-time payment.
31
+ * @param {number} amount - Amount in the smallest currency unit (e.g., cents for USD)
32
+ * @param {string} currency - Three-letter currency code (e.g., 'usd')
33
+ * @param {string} description - Description of what the payment is for
34
+ * @returns {object} { id, url, amount, currency }
35
+ */
36
+ export async function createPaymentLink(amount, currency = 'usd', description = 'CashClaw Service') {
37
+ const stripe = await getStripe();
38
+
39
+ // Create a price for this one-time payment
40
+ const price = await stripe.prices.create({
41
+ unit_amount: Math.round(amount * 100), // Convert dollars to cents
42
+ currency: currency.toLowerCase(),
43
+ product_data: {
44
+ name: description,
45
+ },
46
+ });
47
+
48
+ // Create the payment link
49
+ const paymentLink = await stripe.paymentLinks.create({
50
+ line_items: [
51
+ {
52
+ price: price.id,
53
+ quantity: 1,
54
+ },
55
+ ],
56
+ metadata: {
57
+ source: 'cashclaw',
58
+ description,
59
+ },
60
+ });
61
+
62
+ return {
63
+ id: paymentLink.id,
64
+ url: paymentLink.url,
65
+ amount,
66
+ currency: currency.toLowerCase(),
67
+ description,
68
+ };
69
+ }
70
+
71
+ /**
72
+ * Create a Stripe Invoice and send it to a customer.
73
+ * @param {string} customerEmail - Customer's email address
74
+ * @param {Array} items - Array of { description, amount, currency }
75
+ * @returns {object} Invoice details
76
+ */
77
+ export async function createInvoice(customerEmail, items = []) {
78
+ const stripe = await getStripe();
79
+
80
+ // Find or create customer
81
+ const customers = await stripe.customers.list({ email: customerEmail, limit: 1 });
82
+ let customer;
83
+ if (customers.data.length > 0) {
84
+ customer = customers.data[0];
85
+ } else {
86
+ customer = await stripe.customers.create({
87
+ email: customerEmail,
88
+ metadata: { source: 'cashclaw' },
89
+ });
90
+ }
91
+
92
+ // Create invoice
93
+ const invoice = await stripe.invoices.create({
94
+ customer: customer.id,
95
+ collection_method: 'send_invoice',
96
+ days_until_due: 7,
97
+ metadata: { source: 'cashclaw' },
98
+ });
99
+
100
+ // Add line items
101
+ for (const item of items) {
102
+ await stripe.invoiceItems.create({
103
+ customer: customer.id,
104
+ invoice: invoice.id,
105
+ amount: Math.round((item.amount || 0) * 100),
106
+ currency: (item.currency || 'usd').toLowerCase(),
107
+ description: item.description || 'CashClaw Service',
108
+ });
109
+ }
110
+
111
+ // Finalize and send
112
+ const finalizedInvoice = await stripe.invoices.finalizeInvoice(invoice.id);
113
+ await stripe.invoices.sendInvoice(invoice.id);
114
+
115
+ return {
116
+ id: finalizedInvoice.id,
117
+ number: finalizedInvoice.number,
118
+ status: finalizedInvoice.status,
119
+ amount_due: finalizedInvoice.amount_due / 100,
120
+ currency: finalizedInvoice.currency,
121
+ hosted_invoice_url: finalizedInvoice.hosted_invoice_url,
122
+ customer_email: customerEmail,
123
+ };
124
+ }
125
+
126
+ /**
127
+ * Check the status of a Stripe payment or payment intent.
128
+ * @param {string} paymentId - Payment Intent ID (pi_...) or Payment Link ID (plink_...)
129
+ * @returns {object} Payment status details
130
+ */
131
+ export async function getPaymentStatus(paymentId) {
132
+ const stripe = await getStripe();
133
+
134
+ try {
135
+ if (paymentId.startsWith('pi_')) {
136
+ const intent = await stripe.paymentIntents.retrieve(paymentId);
137
+ return {
138
+ id: intent.id,
139
+ status: intent.status,
140
+ amount: intent.amount / 100,
141
+ currency: intent.currency,
142
+ created: new Date(intent.created * 1000).toISOString(),
143
+ };
144
+ } else if (paymentId.startsWith('in_')) {
145
+ const invoice = await stripe.invoices.retrieve(paymentId);
146
+ return {
147
+ id: invoice.id,
148
+ status: invoice.status,
149
+ amount: invoice.amount_due / 100,
150
+ currency: invoice.currency,
151
+ created: new Date(invoice.created * 1000).toISOString(),
152
+ paid: invoice.paid,
153
+ };
154
+ } else {
155
+ throw new Error(`Unknown payment ID format: ${paymentId}`);
156
+ }
157
+ } catch (err) {
158
+ throw new Error(`Could not retrieve payment ${paymentId}: ${err.message}`);
159
+ }
160
+ }
161
+
162
+ /**
163
+ * List recent payments.
164
+ * @param {number} limit - Max number of payments to return (default 10)
165
+ * @returns {Array} List of payment details
166
+ */
167
+ export async function listPayments(limit = 10) {
168
+ const stripe = await getStripe();
169
+
170
+ const paymentIntents = await stripe.paymentIntents.list({
171
+ limit,
172
+ metadata: { source: 'cashclaw' },
173
+ });
174
+
175
+ return paymentIntents.data.map((pi) => ({
176
+ id: pi.id,
177
+ status: pi.status,
178
+ amount: pi.amount / 100,
179
+ currency: pi.currency,
180
+ description: pi.description || '',
181
+ created: new Date(pi.created * 1000).toISOString(),
182
+ }));
183
+ }
184
+
185
+ /**
186
+ * Test the Stripe connection with the configured key.
187
+ * @returns {boolean} true if the connection is valid
188
+ */
189
+ export async function testConnection() {
190
+ try {
191
+ const stripe = await getStripe();
192
+ const account = await stripe.accounts.retrieve();
193
+ return {
194
+ connected: true,
195
+ account_id: account.id,
196
+ email: account.email,
197
+ };
198
+ } catch (err) {
199
+ return {
200
+ connected: false,
201
+ error: err.message,
202
+ };
203
+ }
204
+ }
@@ -0,0 +1,83 @@
1
+ {
2
+ "agent": {
3
+ "name": "MyCashClaw",
4
+ "owner": "",
5
+ "email": "",
6
+ "currency": "USD",
7
+ "created_at": ""
8
+ },
9
+ "stripe": {
10
+ "secret_key": "",
11
+ "connected": false,
12
+ "mode": "test"
13
+ },
14
+ "server": {
15
+ "port": 3847,
16
+ "host": "localhost"
17
+ },
18
+ "services": {
19
+ "seo_audit": {
20
+ "enabled": false,
21
+ "pricing": {
22
+ "basic": 9,
23
+ "standard": 29,
24
+ "pro": 59
25
+ },
26
+ "description": "Automated SEO audits with actionable recommendations"
27
+ },
28
+ "content_writing": {
29
+ "enabled": false,
30
+ "pricing": {
31
+ "post_500": 5,
32
+ "post_1500": 12,
33
+ "newsletter": 9
34
+ },
35
+ "description": "AI-powered blog posts, articles, and newsletters"
36
+ },
37
+ "lead_generation": {
38
+ "enabled": false,
39
+ "pricing": {
40
+ "starter_25": 9,
41
+ "standard_50": 15,
42
+ "pro_100": 25
43
+ },
44
+ "description": "Targeted lead lists with contact info and scoring"
45
+ },
46
+ "whatsapp_management": {
47
+ "enabled": false,
48
+ "pricing": {
49
+ "setup": 19,
50
+ "monthly": 49
51
+ },
52
+ "description": "WhatsApp Business setup and automated responses"
53
+ },
54
+ "social_media": {
55
+ "enabled": false,
56
+ "pricing": {
57
+ "weekly_1": 9,
58
+ "weekly_3": 19,
59
+ "monthly_full": 49
60
+ },
61
+ "description": "Social media content creation and scheduling"
62
+ }
63
+ },
64
+ "hyrve": {
65
+ "api_url": "https://api.hyrveai.com/v1",
66
+ "registered": false,
67
+ "agent_id": ""
68
+ },
69
+ "openclaw": {
70
+ "workspace": "",
71
+ "skills_dir": "",
72
+ "auto_detected": false
73
+ },
74
+ "heartbeat": {
75
+ "enabled": false,
76
+ "interval_ms": 60000
77
+ },
78
+ "stats": {
79
+ "total_missions": 0,
80
+ "completed_missions": 0,
81
+ "total_earned": 0
82
+ }
83
+ }