adscriptly 0.1.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.
- package/README.md +100 -0
- package/dist/cli-client/charts.d.ts +7 -0
- package/dist/cli-client/charts.d.ts.map +1 -0
- package/dist/cli-client/charts.js +417 -0
- package/dist/cli-client/charts.js.map +1 -0
- package/dist/cli-client/commands/chat.d.ts +3 -0
- package/dist/cli-client/commands/chat.d.ts.map +1 -0
- package/dist/cli-client/commands/chat.js +523 -0
- package/dist/cli-client/commands/chat.js.map +1 -0
- package/dist/cli-client/commands/config.d.ts +3 -0
- package/dist/cli-client/commands/config.d.ts.map +1 -0
- package/dist/cli-client/commands/config.js +23 -0
- package/dist/cli-client/commands/config.js.map +1 -0
- package/dist/cli-client/commands/login.d.ts +3 -0
- package/dist/cli-client/commands/login.d.ts.map +1 -0
- package/dist/cli-client/commands/login.js +115 -0
- package/dist/cli-client/commands/login.js.map +1 -0
- package/dist/cli-client/commands/logout.d.ts +3 -0
- package/dist/cli-client/commands/logout.d.ts.map +1 -0
- package/dist/cli-client/commands/logout.js +24 -0
- package/dist/cli-client/commands/logout.js.map +1 -0
- package/dist/cli-client/display.d.ts +26 -0
- package/dist/cli-client/display.d.ts.map +1 -0
- package/dist/cli-client/display.js +151 -0
- package/dist/cli-client/display.js.map +1 -0
- package/dist/cli-client/index.d.ts +3 -0
- package/dist/cli-client/index.d.ts.map +1 -0
- package/dist/cli-client/index.js +17 -0
- package/dist/cli-client/index.js.map +1 -0
- package/dist/cli-client/report-prompt.d.ts +5 -0
- package/dist/cli-client/report-prompt.d.ts.map +1 -0
- package/dist/cli-client/report-prompt.js +200 -0
- package/dist/cli-client/report-prompt.js.map +1 -0
- package/dist/cli-client/sse.d.ts +6 -0
- package/dist/cli-client/sse.d.ts.map +1 -0
- package/dist/cli-client/sse.js +39 -0
- package/dist/cli-client/sse.js.map +1 -0
- package/dist/mcp-server/index.d.ts +3 -0
- package/dist/mcp-server/index.d.ts.map +1 -0
- package/dist/mcp-server/index.js +266 -0
- package/dist/mcp-server/index.js.map +1 -0
- package/dist/shared/config.d.ts +21 -0
- package/dist/shared/config.d.ts.map +1 -0
- package/dist/shared/config.js +41 -0
- package/dist/shared/config.js.map +1 -0
- package/package.json +59 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sse.js","sourceRoot":"","sources":["../../src/cli-client/sse.ts"],"names":[],"mappings":"AAKA,MAAM,CAAC,KAAK,SAAS,CAAC,CAAC,QAAQ,CAAC,QAAkB;IAChD,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC;IAC3B,IAAI,CAAC,IAAI;QAAE,OAAO;IAElB,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;IAChC,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;IAClC,IAAI,MAAM,GAAG,EAAE,CAAC;IAEhB,IAAI,CAAC;QACH,SAAS,CAAC;YACR,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;YAC5C,IAAI,IAAI;gBAAE,MAAM;YAEhB,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;YAElD,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YACnC,MAAM,GAAG,KAAK,CAAC,GAAG,EAAG,CAAC;YAEtB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACzB,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;oBAAE,SAAS;gBAE3B,IAAI,KAAK,GAAG,EAAE,CAAC;gBACf,IAAI,IAAI,GAAG,EAAE,CAAC;gBAEd,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;oBACpC,IAAI,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;wBAC/B,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;oBACxB,CAAC;yBAAM,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;wBACrC,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;oBACvB,CAAC;gBACH,CAAC;gBAED,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;oBAClB,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;gBACxB,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;YAAS,CAAC;QACT,MAAM,CAAC,WAAW,EAAE,CAAC;IACvB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mcp-server/index.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
import { readConfig, getApiBaseUrl } from "../shared/config.js";
|
|
5
|
+
// -- API Client --
|
|
6
|
+
class AdscriptlyApiClient {
|
|
7
|
+
baseUrl;
|
|
8
|
+
token;
|
|
9
|
+
constructor(baseUrl, token) {
|
|
10
|
+
this.baseUrl = baseUrl;
|
|
11
|
+
this.token = token;
|
|
12
|
+
}
|
|
13
|
+
get headers() {
|
|
14
|
+
return {
|
|
15
|
+
Authorization: `Bearer ${this.token}`,
|
|
16
|
+
"Content-Type": "application/json",
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
/** Fetch all tool definitions from the server. */
|
|
20
|
+
async fetchToolDefinitions() {
|
|
21
|
+
const res = await fetch(`${this.baseUrl}/api/cli/tools`, {
|
|
22
|
+
headers: this.headers,
|
|
23
|
+
});
|
|
24
|
+
if (!res.ok) {
|
|
25
|
+
throw new Error(`Failed to fetch tool definitions: ${res.status} ${res.statusText}`);
|
|
26
|
+
}
|
|
27
|
+
const data = (await res.json());
|
|
28
|
+
return data.tools;
|
|
29
|
+
}
|
|
30
|
+
/** Execute a tool by name via the server. */
|
|
31
|
+
async executeTool(toolName, input) {
|
|
32
|
+
const res = await fetch(`${this.baseUrl}/api/cli/tools/execute`, {
|
|
33
|
+
method: "POST",
|
|
34
|
+
headers: this.headers,
|
|
35
|
+
body: JSON.stringify({ tool: toolName, input }),
|
|
36
|
+
});
|
|
37
|
+
if (!res.ok) {
|
|
38
|
+
const text = await res.text();
|
|
39
|
+
throw new Error(`Tool execution failed (${res.status}): ${text}`);
|
|
40
|
+
}
|
|
41
|
+
return res.json();
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
// -- GAQL Reference --
|
|
45
|
+
const GAQL_REFERENCE = `# Google Ads Query Language (GAQL) Reference
|
|
46
|
+
|
|
47
|
+
## Available Resources
|
|
48
|
+
|
|
49
|
+
| Resource | Description |
|
|
50
|
+
|----------|-------------|
|
|
51
|
+
| campaign | Campaign settings, status, bidding strategy, budget |
|
|
52
|
+
| ad_group | Ad group settings, status, CPC bid |
|
|
53
|
+
| ad_group_ad | Ads within ad groups, RSA headlines/descriptions |
|
|
54
|
+
| ad_group_criterion | Keywords and other targeting criteria |
|
|
55
|
+
| campaign_criterion | Campaign-level targeting (locations, languages, etc.) |
|
|
56
|
+
| campaign_budget | Shared and campaign budgets |
|
|
57
|
+
| bidding_strategy | Portfolio bidding strategies |
|
|
58
|
+
| search_term_view | Actual search terms that triggered ads |
|
|
59
|
+
| keyword_view | Keyword performance with quality score |
|
|
60
|
+
| geographic_view | Performance by geographic location |
|
|
61
|
+
| user_location_view | Performance by user physical location |
|
|
62
|
+
| gender_view | Performance by gender demographic |
|
|
63
|
+
| age_range_view | Performance by age range |
|
|
64
|
+
| income_range_view | Performance by household income tier |
|
|
65
|
+
| ad_group_ad_asset_view | RSA asset (headline/description) performance |
|
|
66
|
+
| landing_page_view | Landing page performance metrics |
|
|
67
|
+
| change_event | Account change history (who changed what) |
|
|
68
|
+
| call_view | Call extension details (duration, area code) |
|
|
69
|
+
| conversion_action | Conversion tracking actions and their settings |
|
|
70
|
+
| asset | Account-level assets (images, text, etc.) |
|
|
71
|
+
| customer | Account-level settings (currency, timezone, name) |
|
|
72
|
+
| label | Labels applied to campaigns, ad groups, keywords |
|
|
73
|
+
| auction_insight | Competitive auction metrics (impression share, overlap rate) |
|
|
74
|
+
| ad_schedule_view | Performance by day of week and hour |
|
|
75
|
+
|
|
76
|
+
## Common Query Patterns
|
|
77
|
+
|
|
78
|
+
### Campaign performance (last 30 days)
|
|
79
|
+
\`\`\`sql
|
|
80
|
+
SELECT campaign.name, campaign.status,
|
|
81
|
+
metrics.impressions, metrics.clicks, metrics.cost_micros,
|
|
82
|
+
metrics.conversions, metrics.cost_per_conversion
|
|
83
|
+
FROM campaign
|
|
84
|
+
WHERE segments.date DURING LAST_30_DAYS
|
|
85
|
+
AND campaign.status != 'REMOVED'
|
|
86
|
+
ORDER BY metrics.cost_micros DESC
|
|
87
|
+
\`\`\`
|
|
88
|
+
|
|
89
|
+
### Search terms with match type
|
|
90
|
+
\`\`\`sql
|
|
91
|
+
SELECT search_term_view.search_term,
|
|
92
|
+
segments.keyword.info.match_type,
|
|
93
|
+
metrics.impressions, metrics.clicks, metrics.cost_micros,
|
|
94
|
+
metrics.conversions
|
|
95
|
+
FROM search_term_view
|
|
96
|
+
WHERE segments.date DURING LAST_30_DAYS
|
|
97
|
+
ORDER BY metrics.impressions DESC
|
|
98
|
+
LIMIT 100
|
|
99
|
+
\`\`\`
|
|
100
|
+
|
|
101
|
+
### Keyword quality score
|
|
102
|
+
\`\`\`sql
|
|
103
|
+
SELECT ad_group_criterion.keyword.text,
|
|
104
|
+
ad_group_criterion.quality_info.quality_score,
|
|
105
|
+
ad_group_criterion.quality_info.creative_quality_score,
|
|
106
|
+
ad_group_criterion.quality_info.post_click_quality_score,
|
|
107
|
+
ad_group_criterion.quality_info.search_predicted_ctr,
|
|
108
|
+
metrics.impressions, metrics.clicks, metrics.conversions
|
|
109
|
+
FROM keyword_view
|
|
110
|
+
WHERE segments.date DURING LAST_30_DAYS
|
|
111
|
+
ORDER BY metrics.impressions DESC
|
|
112
|
+
\`\`\`
|
|
113
|
+
|
|
114
|
+
## Notes
|
|
115
|
+
- Cost values are in micros (divide by 1,000,000 for actual currency amount)
|
|
116
|
+
- Use \`segments.date DURING LAST_7_DAYS|LAST_14_DAYS|LAST_30_DAYS|LAST_90_DAYS\` for date ranges
|
|
117
|
+
- Filter removed entities with \`campaign.status != 'REMOVED'\`
|
|
118
|
+
- Use \`LIMIT\` to cap result count for large accounts
|
|
119
|
+
`;
|
|
120
|
+
// -- Workflow Prompts --
|
|
121
|
+
const WORKFLOW_PROMPTS = {
|
|
122
|
+
google_ads_audit: {
|
|
123
|
+
description: "Run a comprehensive Google Ads account audit — systematic review of search terms, keywords, QS, ad copy, bid adjustments, and competitive position.",
|
|
124
|
+
content: `/audit
|
|
125
|
+
|
|
126
|
+
Run a full 8-step Google Ads account optimization audit:
|
|
127
|
+
1. Account Context — list accounts, get campaign performance
|
|
128
|
+
2. Search Term Analysis — review search terms, pending negatives/positives
|
|
129
|
+
3. Keyword Performance — identify bleeders, winners, QS issues
|
|
130
|
+
4. Quality Score Deep Dive — analyze QS components (CTR, relevance, landing page)
|
|
131
|
+
5. Ad Copy Audit — review asset performance, identify underperformers
|
|
132
|
+
6. Bid Adjustments — analyze device, location, schedule, demographic data
|
|
133
|
+
7. Competitive Position — check auction insights and impression share
|
|
134
|
+
8. Generate Summary — client-ready optimization report`,
|
|
135
|
+
},
|
|
136
|
+
google_ads_diagnose: {
|
|
137
|
+
description: "Diagnose a Google Ads performance issue — find root cause for CPA increases, conversion drops, or spend changes.",
|
|
138
|
+
content: `/diagnose
|
|
139
|
+
|
|
140
|
+
Run a 9-step performance troubleshooting workflow:
|
|
141
|
+
1. Establish the Problem — what metric changed, when did it start
|
|
142
|
+
2. Check Change History — what was modified in the account
|
|
143
|
+
3. Check Conversion Tracking — are conversions firing correctly
|
|
144
|
+
4. Competitive Landscape — auction insights for competitive shifts
|
|
145
|
+
5. Quality Score Check — QS degradation
|
|
146
|
+
6. Search Term Analysis — new irrelevant queries
|
|
147
|
+
7. Geo Leakage Detection — user location vs targeted location
|
|
148
|
+
8. Budget & Delivery — budget-limited, delivery issues
|
|
149
|
+
9. Root Cause Summary — diagnosis with recommended fixes`,
|
|
150
|
+
},
|
|
151
|
+
google_ads_scale: {
|
|
152
|
+
description: "Plan a Google Ads scaling strategy — ceiling analysis, keyword expansion, geo expansion, and budget scenarios.",
|
|
153
|
+
content: `/scale
|
|
154
|
+
|
|
155
|
+
Run an 8-step growth planning workflow:
|
|
156
|
+
1. Current State — baseline metrics and campaign structure
|
|
157
|
+
2. Ceiling Calculation — impression share gaps, budget constraints
|
|
158
|
+
3. Keyword Expansion — new keyword opportunities from search terms
|
|
159
|
+
4. Geo Expansion — location performance and expansion candidates
|
|
160
|
+
5. Campaign Type Expansion — new campaign types (Performance Max, Display, Video)
|
|
161
|
+
6. Budget Scenarios — model different spend levels and projected returns
|
|
162
|
+
7. Scaling Roadmap — prioritized growth actions
|
|
163
|
+
8. Proposal — client-ready scaling proposal`,
|
|
164
|
+
},
|
|
165
|
+
gaql_help: {
|
|
166
|
+
description: "Get help writing GAQL (Google Ads Query Language) queries — resource reference, field names, common patterns.",
|
|
167
|
+
content: `Help me write a GAQL query. I have access to the execute_gaql_query tool and list_gaql_resources tool.
|
|
168
|
+
|
|
169
|
+
Available GAQL resources include: campaign, ad_group, ad_group_ad, ad_group_criterion, campaign_criterion, campaign_budget, bidding_strategy, search_term_view, keyword_view, geographic_view, user_location_view, gender_view, age_range_view, income_range_view, ad_group_ad_asset_view, landing_page_view, change_event, call_view, conversion_action, asset, customer, label, auction_insight, ad_schedule_view.
|
|
170
|
+
|
|
171
|
+
Cost values are in micros (divide by 1,000,000). Use segments.date DURING LAST_30_DAYS for date ranges.
|
|
172
|
+
|
|
173
|
+
What would you like to query?`,
|
|
174
|
+
},
|
|
175
|
+
};
|
|
176
|
+
// -- Main --
|
|
177
|
+
async function main() {
|
|
178
|
+
// 1. Read config and validate token
|
|
179
|
+
const config = readConfig();
|
|
180
|
+
if (!config.token) {
|
|
181
|
+
process.stderr.write("Error: Not authenticated. Run `adscriptly login` first.\n");
|
|
182
|
+
process.exit(1);
|
|
183
|
+
}
|
|
184
|
+
const apiBaseUrl = getApiBaseUrl(config);
|
|
185
|
+
const client = new AdscriptlyApiClient(apiBaseUrl, config.token);
|
|
186
|
+
// 2. Fetch tool definitions from server
|
|
187
|
+
let tools;
|
|
188
|
+
try {
|
|
189
|
+
tools = await client.fetchToolDefinitions();
|
|
190
|
+
}
|
|
191
|
+
catch (err) {
|
|
192
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
193
|
+
process.stderr.write(`Error: Failed to load tools: ${msg}\n`);
|
|
194
|
+
process.stderr.write("Check your authentication token and API connectivity.\n");
|
|
195
|
+
process.exit(1);
|
|
196
|
+
}
|
|
197
|
+
// 3. Create MCP server
|
|
198
|
+
const server = new McpServer({ name: "adscriptly", version: "0.1.0" }, {
|
|
199
|
+
capabilities: {
|
|
200
|
+
tools: {},
|
|
201
|
+
resources: {},
|
|
202
|
+
prompts: {},
|
|
203
|
+
},
|
|
204
|
+
});
|
|
205
|
+
// 4. Register all tools
|
|
206
|
+
for (const tool of tools) {
|
|
207
|
+
// Build JSON Schema object for the tool's input
|
|
208
|
+
const inputSchema = tool.inputSchema;
|
|
209
|
+
// Use the low-level server.tool() API with raw JSON schema
|
|
210
|
+
// McpServer.tool(name, description, schema, callback)
|
|
211
|
+
server.tool(tool.name, tool.description, inputSchema, async (args) => {
|
|
212
|
+
try {
|
|
213
|
+
const result = await client.executeTool(tool.name, args);
|
|
214
|
+
return {
|
|
215
|
+
content: [
|
|
216
|
+
{
|
|
217
|
+
type: "text",
|
|
218
|
+
text: JSON.stringify(result, null, 2),
|
|
219
|
+
},
|
|
220
|
+
],
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
catch (err) {
|
|
224
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
225
|
+
return {
|
|
226
|
+
content: [{ type: "text", text: `Error: ${msg}` }],
|
|
227
|
+
isError: true,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
// 5. Register GAQL reference as a resource
|
|
233
|
+
server.resource("GAQL Reference", "gaql://reference", {
|
|
234
|
+
description: "Google Ads Query Language (GAQL) reference — available resources, field names, and common query patterns.",
|
|
235
|
+
mimeType: "text/markdown",
|
|
236
|
+
}, async () => ({
|
|
237
|
+
contents: [
|
|
238
|
+
{
|
|
239
|
+
uri: "gaql://reference",
|
|
240
|
+
mimeType: "text/markdown",
|
|
241
|
+
text: GAQL_REFERENCE,
|
|
242
|
+
},
|
|
243
|
+
],
|
|
244
|
+
}));
|
|
245
|
+
// 6. Register workflow prompts
|
|
246
|
+
for (const [name, prompt] of Object.entries(WORKFLOW_PROMPTS)) {
|
|
247
|
+
server.prompt(name, prompt.description, async () => ({
|
|
248
|
+
messages: [
|
|
249
|
+
{
|
|
250
|
+
role: "user",
|
|
251
|
+
content: { type: "text", text: prompt.content },
|
|
252
|
+
},
|
|
253
|
+
],
|
|
254
|
+
}));
|
|
255
|
+
}
|
|
256
|
+
// 7. Connect to stdio transport
|
|
257
|
+
const transport = new StdioServerTransport();
|
|
258
|
+
await server.connect(transport);
|
|
259
|
+
// Log startup to stderr (stdout is reserved for MCP protocol)
|
|
260
|
+
process.stderr.write(`Adscriptly MCP server started (${tools.length} tools registered)\n`);
|
|
261
|
+
}
|
|
262
|
+
main().catch((err) => {
|
|
263
|
+
process.stderr.write(`Fatal error: ${err}\n`);
|
|
264
|
+
process.exit(1);
|
|
265
|
+
});
|
|
266
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/mcp-server/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export interface AdscriptlyConfig {
|
|
2
|
+
token?: string;
|
|
3
|
+
email?: string;
|
|
4
|
+
apiUrl?: string;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Read the Adscriptly CLI config from ~/.adscriptly/config.json.
|
|
8
|
+
* Returns empty object if file doesn't exist.
|
|
9
|
+
*/
|
|
10
|
+
export declare function readConfig(): AdscriptlyConfig;
|
|
11
|
+
/**
|
|
12
|
+
* Write the Adscriptly CLI config to ~/.adscriptly/config.json.
|
|
13
|
+
* Creates the directory if it doesn't exist.
|
|
14
|
+
*/
|
|
15
|
+
export declare function writeConfig(config: AdscriptlyConfig): void;
|
|
16
|
+
/**
|
|
17
|
+
* Get the API base URL from config or environment variable.
|
|
18
|
+
* Priority: ADSCRIPTLY_API_URL env var > config.apiUrl > default.
|
|
19
|
+
*/
|
|
20
|
+
export declare function getApiBaseUrl(config: AdscriptlyConfig): string;
|
|
21
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/shared/config.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAKD;;;GAGG;AACH,wBAAgB,UAAU,IAAI,gBAAgB,CAU7C;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAK1D;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,CAM9D"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
const CONFIG_DIR = join(homedir(), ".adscriptly");
|
|
5
|
+
const CONFIG_FILE = join(CONFIG_DIR, "config.json");
|
|
6
|
+
/**
|
|
7
|
+
* Read the Adscriptly CLI config from ~/.adscriptly/config.json.
|
|
8
|
+
* Returns empty object if file doesn't exist.
|
|
9
|
+
*/
|
|
10
|
+
export function readConfig() {
|
|
11
|
+
if (!existsSync(CONFIG_FILE)) {
|
|
12
|
+
return {};
|
|
13
|
+
}
|
|
14
|
+
try {
|
|
15
|
+
const raw = readFileSync(CONFIG_FILE, "utf-8");
|
|
16
|
+
return JSON.parse(raw);
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
return {};
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Write the Adscriptly CLI config to ~/.adscriptly/config.json.
|
|
24
|
+
* Creates the directory if it doesn't exist.
|
|
25
|
+
*/
|
|
26
|
+
export function writeConfig(config) {
|
|
27
|
+
if (!existsSync(CONFIG_DIR)) {
|
|
28
|
+
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
29
|
+
}
|
|
30
|
+
writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2) + "\n");
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Get the API base URL from config or environment variable.
|
|
34
|
+
* Priority: ADSCRIPTLY_API_URL env var > config.apiUrl > default.
|
|
35
|
+
*/
|
|
36
|
+
export function getApiBaseUrl(config) {
|
|
37
|
+
return (process.env.ADSCRIPTLY_API_URL ||
|
|
38
|
+
config.apiUrl ||
|
|
39
|
+
"https://app.adscriptly.com");
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/shared/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAQlC,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,aAAa,CAAC,CAAC;AAClD,MAAM,WAAW,GAAG,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;AAEpD;;;GAGG;AACH,MAAM,UAAU,UAAU;IACxB,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAC7B,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QAC/C,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAqB,CAAC;IAC7C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,MAAwB;IAClD,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5B,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7C,CAAC;IACD,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;AACrE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,MAAwB;IACpD,OAAO,CACL,OAAO,CAAC,GAAG,CAAC,kBAAkB;QAC9B,MAAM,CAAC,MAAM;QACb,4BAA4B,CAC7B,CAAC;AACJ,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "adscriptly",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "AI-powered CLI and MCP server for managing Google Ads from the terminal",
|
|
6
|
+
"author": "Adscriptly",
|
|
7
|
+
"homepage": "https://app.adscriptly.com",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "https://github.com/adscriptly/adscriptly-cli"
|
|
11
|
+
},
|
|
12
|
+
"bin": {
|
|
13
|
+
"adscriptly": "./dist/cli-client/index.js",
|
|
14
|
+
"adscriptly-mcp-server": "./dist/mcp-server/index.js"
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"engines": {
|
|
20
|
+
"node": ">=18.0.0"
|
|
21
|
+
},
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "tsc",
|
|
24
|
+
"dev": "tsc --watch",
|
|
25
|
+
"typecheck": "tsc --noEmit",
|
|
26
|
+
"test": "vitest",
|
|
27
|
+
"test:run": "vitest run",
|
|
28
|
+
"prepublishOnly": "npm run build && npm run test:run"
|
|
29
|
+
},
|
|
30
|
+
"keywords": [
|
|
31
|
+
"google-ads",
|
|
32
|
+
"cli",
|
|
33
|
+
"mcp",
|
|
34
|
+
"ai",
|
|
35
|
+
"advertising",
|
|
36
|
+
"ppc",
|
|
37
|
+
"sem",
|
|
38
|
+
"claude",
|
|
39
|
+
"model-context-protocol"
|
|
40
|
+
],
|
|
41
|
+
"license": "UNLICENSED",
|
|
42
|
+
"publishConfig": {
|
|
43
|
+
"access": "public"
|
|
44
|
+
},
|
|
45
|
+
"dependencies": {
|
|
46
|
+
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
47
|
+
"chalk": "^5.4.1",
|
|
48
|
+
"commander": "^13.1.0",
|
|
49
|
+
"eventsource": "^3.0.6",
|
|
50
|
+
"gradient-string": "^3.0.0"
|
|
51
|
+
},
|
|
52
|
+
"devDependencies": {
|
|
53
|
+
"@types/eventsource": "^1.1.15",
|
|
54
|
+
"@types/gradient-string": "^1.1.6",
|
|
55
|
+
"@types/node": "^22.15.0",
|
|
56
|
+
"typescript": "^5.9.3",
|
|
57
|
+
"vitest": "^3.2.4"
|
|
58
|
+
}
|
|
59
|
+
}
|