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.
Files changed (46) hide show
  1. package/README.md +100 -0
  2. package/dist/cli-client/charts.d.ts +7 -0
  3. package/dist/cli-client/charts.d.ts.map +1 -0
  4. package/dist/cli-client/charts.js +417 -0
  5. package/dist/cli-client/charts.js.map +1 -0
  6. package/dist/cli-client/commands/chat.d.ts +3 -0
  7. package/dist/cli-client/commands/chat.d.ts.map +1 -0
  8. package/dist/cli-client/commands/chat.js +523 -0
  9. package/dist/cli-client/commands/chat.js.map +1 -0
  10. package/dist/cli-client/commands/config.d.ts +3 -0
  11. package/dist/cli-client/commands/config.d.ts.map +1 -0
  12. package/dist/cli-client/commands/config.js +23 -0
  13. package/dist/cli-client/commands/config.js.map +1 -0
  14. package/dist/cli-client/commands/login.d.ts +3 -0
  15. package/dist/cli-client/commands/login.d.ts.map +1 -0
  16. package/dist/cli-client/commands/login.js +115 -0
  17. package/dist/cli-client/commands/login.js.map +1 -0
  18. package/dist/cli-client/commands/logout.d.ts +3 -0
  19. package/dist/cli-client/commands/logout.d.ts.map +1 -0
  20. package/dist/cli-client/commands/logout.js +24 -0
  21. package/dist/cli-client/commands/logout.js.map +1 -0
  22. package/dist/cli-client/display.d.ts +26 -0
  23. package/dist/cli-client/display.d.ts.map +1 -0
  24. package/dist/cli-client/display.js +151 -0
  25. package/dist/cli-client/display.js.map +1 -0
  26. package/dist/cli-client/index.d.ts +3 -0
  27. package/dist/cli-client/index.d.ts.map +1 -0
  28. package/dist/cli-client/index.js +17 -0
  29. package/dist/cli-client/index.js.map +1 -0
  30. package/dist/cli-client/report-prompt.d.ts +5 -0
  31. package/dist/cli-client/report-prompt.d.ts.map +1 -0
  32. package/dist/cli-client/report-prompt.js +200 -0
  33. package/dist/cli-client/report-prompt.js.map +1 -0
  34. package/dist/cli-client/sse.d.ts +6 -0
  35. package/dist/cli-client/sse.d.ts.map +1 -0
  36. package/dist/cli-client/sse.js +39 -0
  37. package/dist/cli-client/sse.js.map +1 -0
  38. package/dist/mcp-server/index.d.ts +3 -0
  39. package/dist/mcp-server/index.d.ts.map +1 -0
  40. package/dist/mcp-server/index.js +266 -0
  41. package/dist/mcp-server/index.js.map +1 -0
  42. package/dist/shared/config.d.ts +21 -0
  43. package/dist/shared/config.d.ts.map +1 -0
  44. package/dist/shared/config.js +41 -0
  45. package/dist/shared/config.js.map +1 -0
  46. 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,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -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
+ }