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,115 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import { readConfig, writeConfig, getApiBaseUrl } from "../../shared/config.js";
|
|
4
|
+
import { createServer } from "node:http";
|
|
5
|
+
import { randomBytes } from "node:crypto";
|
|
6
|
+
import { exec } from "node:child_process";
|
|
7
|
+
import { platform } from "node:os";
|
|
8
|
+
const LOGIN_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes
|
|
9
|
+
export const loginCommand = new Command("login")
|
|
10
|
+
.description("Authenticate with Adscriptly via browser")
|
|
11
|
+
.action(async () => {
|
|
12
|
+
const config = readConfig();
|
|
13
|
+
if (config.token) {
|
|
14
|
+
const apiBaseUrl = getApiBaseUrl(config);
|
|
15
|
+
console.log(chalk.green("Already authenticated."));
|
|
16
|
+
console.log(chalk.dim(" API: ") + apiBaseUrl);
|
|
17
|
+
if (config.email) {
|
|
18
|
+
console.log(chalk.dim(" Email: ") + config.email);
|
|
19
|
+
}
|
|
20
|
+
console.log(chalk.dim("\nRun ") + chalk.cyan('"adscriptly logout"') + chalk.dim(" to sign out."));
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
const apiBaseUrl = getApiBaseUrl(config);
|
|
24
|
+
const state = randomBytes(16).toString("hex");
|
|
25
|
+
try {
|
|
26
|
+
const token = await startAuthFlow(apiBaseUrl, state);
|
|
27
|
+
// Store token in config, persisting the API URL used during auth
|
|
28
|
+
// so subsequent commands in fresh terminals hit the same server
|
|
29
|
+
const DEFAULT_API_URL = "https://app.adscriptly.com";
|
|
30
|
+
const configToWrite = { ...config, token };
|
|
31
|
+
if (apiBaseUrl !== DEFAULT_API_URL) {
|
|
32
|
+
configToWrite.apiUrl = apiBaseUrl;
|
|
33
|
+
}
|
|
34
|
+
writeConfig(configToWrite);
|
|
35
|
+
console.log(chalk.green("\nAuthenticated successfully!"));
|
|
36
|
+
console.log(chalk.dim("Token stored in ~/.adscriptly/config.json"));
|
|
37
|
+
console.log(chalk.dim("\nRun ") + chalk.cyan('"adscriptly chat"') + chalk.dim(" to start."));
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
41
|
+
console.error(chalk.red(`\nLogin failed: ${message}`));
|
|
42
|
+
process.exit(1);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
/**
|
|
46
|
+
* Start a temporary localhost HTTP server, open browser to auth page,
|
|
47
|
+
* wait for callback with token, validate state, return token.
|
|
48
|
+
*/
|
|
49
|
+
function startAuthFlow(apiBaseUrl, state) {
|
|
50
|
+
return new Promise((resolve, reject) => {
|
|
51
|
+
const server = createServer((req, res) => {
|
|
52
|
+
const url = new URL(req.url || "/", "http://localhost");
|
|
53
|
+
if (url.pathname !== "/callback") {
|
|
54
|
+
res.writeHead(404, { "Content-Type": "text/plain" });
|
|
55
|
+
res.end("Not found");
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
const token = url.searchParams.get("token");
|
|
59
|
+
const receivedState = url.searchParams.get("state");
|
|
60
|
+
// Send success page to browser
|
|
61
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
62
|
+
res.end([
|
|
63
|
+
"<html><body style=\"background:#000;color:#fff;font-family:system-ui;",
|
|
64
|
+
"display:flex;align-items:center;justify-content:center;height:100vh;margin:0\">",
|
|
65
|
+
"<div style=\"text-align:center\">",
|
|
66
|
+
"<h1 style=\"color:#60a5fa\">✓ Authenticated</h1>",
|
|
67
|
+
"<p style=\"color:#9ca3af\">You can close this tab and return to the terminal.</p>",
|
|
68
|
+
"</div></body></html>",
|
|
69
|
+
].join(""));
|
|
70
|
+
// Close server, then resolve/reject
|
|
71
|
+
server.close();
|
|
72
|
+
clearTimeout(timeout);
|
|
73
|
+
if (!token || !receivedState) {
|
|
74
|
+
reject(new Error("Missing token or state in callback"));
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
if (receivedState !== state) {
|
|
78
|
+
reject(new Error("State parameter mismatch. Login may have been tampered with."));
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
resolve(token);
|
|
82
|
+
});
|
|
83
|
+
// Timeout after 5 minutes
|
|
84
|
+
const timeout = setTimeout(() => {
|
|
85
|
+
server.close();
|
|
86
|
+
reject(new Error("Login timed out after 5 minutes. Please try again."));
|
|
87
|
+
}, LOGIN_TIMEOUT_MS);
|
|
88
|
+
server.listen(0, "127.0.0.1", () => {
|
|
89
|
+
const addr = server.address();
|
|
90
|
+
const port = typeof addr === "object" && addr ? addr.port : 0;
|
|
91
|
+
const redirectUri = `http://127.0.0.1:${port}/callback`;
|
|
92
|
+
const authUrl = `${apiBaseUrl}/cli/auth?state=${encodeURIComponent(state)}&redirect_uri=${encodeURIComponent(redirectUri)}`;
|
|
93
|
+
console.log(chalk.cyan("Opening browser for authentication..."));
|
|
94
|
+
console.log(chalk.dim("\nIf the browser doesn't open, visit:\n ") + authUrl + "\n");
|
|
95
|
+
console.log(chalk.dim("Waiting for authorization..."));
|
|
96
|
+
openBrowser(authUrl);
|
|
97
|
+
});
|
|
98
|
+
server.on("error", (err) => {
|
|
99
|
+
clearTimeout(timeout);
|
|
100
|
+
reject(new Error(`Failed to start auth server: ${err.message}`));
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
function openBrowser(url) {
|
|
105
|
+
const os = platform();
|
|
106
|
+
const cmd = os === "darwin"
|
|
107
|
+
? `open "${url}"`
|
|
108
|
+
: os === "win32"
|
|
109
|
+
? `start "" "${url}"`
|
|
110
|
+
: `xdg-open "${url}"`;
|
|
111
|
+
exec(cmd, () => {
|
|
112
|
+
// Silently ignore errors — URL is printed for manual copy
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=login.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../../src/cli-client/commands/login.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logout.d.ts","sourceRoot":"","sources":["../../../src/cli-client/commands/logout.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AASpC,eAAO,MAAM,aAAa,SAgBtB,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import { readConfig } from "../../shared/config.js";
|
|
4
|
+
import { existsSync, unlinkSync } from "node:fs";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
import { homedir } from "node:os";
|
|
7
|
+
const CONFIG_FILE = join(homedir(), ".adscriptly", "config.json");
|
|
8
|
+
export const logoutCommand = new Command("logout")
|
|
9
|
+
.description("Remove stored authentication token")
|
|
10
|
+
.action(async () => {
|
|
11
|
+
const config = readConfig();
|
|
12
|
+
if (!config.token) {
|
|
13
|
+
console.log(chalk.dim("Not currently authenticated."));
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
if (existsSync(CONFIG_FILE)) {
|
|
17
|
+
unlinkSync(CONFIG_FILE);
|
|
18
|
+
console.log(chalk.green("Logged out.") + chalk.dim(" Token removed from ~/.adscriptly/config.json"));
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
console.log(chalk.dim("No config file found."));
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
//# sourceMappingURL=logout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logout.js","sourceRoot":"","sources":["../../../src/cli-client/commands/logout.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACjD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAElC,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,aAAa,EAAE,aAAa,CAAC,CAAC;AAElE,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC;KAC/C,WAAW,CAAC,oCAAoC,CAAC;KACjD,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAE5B,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QAClB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC,CAAC;QACvD,OAAO;IACT,CAAC;IAED,IAAI,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAC5B,UAAU,CAAC,WAAW,CAAC,CAAC;QACxB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,aAAa,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,+CAA+C,CAAC,CAAC,CAAC;IACvG,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC,CAAC;IAClD,CAAC;AACH,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export interface Spinner {
|
|
2
|
+
update(text: string): void;
|
|
3
|
+
stop(finalText?: string): void;
|
|
4
|
+
}
|
|
5
|
+
export declare function startSpinner(text: string): Spinner;
|
|
6
|
+
export declare function toolCallLabel(toolName: string): string;
|
|
7
|
+
export type StepStatus = "active" | "complete" | "error";
|
|
8
|
+
export interface ToolStep {
|
|
9
|
+
toolName: string;
|
|
10
|
+
status: StepStatus;
|
|
11
|
+
startTime: number;
|
|
12
|
+
endTime?: number;
|
|
13
|
+
error?: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function renderStep(step: ToolStep): string;
|
|
16
|
+
export declare class StepList {
|
|
17
|
+
private steps;
|
|
18
|
+
private spinner;
|
|
19
|
+
startStep(toolName: string): void;
|
|
20
|
+
completeStep(toolName: string): void;
|
|
21
|
+
errorStep(toolName: string, error?: string): void;
|
|
22
|
+
clear(): void;
|
|
23
|
+
private findActive;
|
|
24
|
+
private stopSpinner;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=display.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"display.d.ts","sourceRoot":"","sources":["../../src/cli-client/display.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,OAAO;IACtB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAsBlD;AAoED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEtD;AAID,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,UAAU,GAAG,OAAO,CAAC;AAEzD,MAAM,WAAW,QAAQ;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,UAAU,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,CAkBjD;AAID,qBAAa,QAAQ;IACnB,OAAO,CAAC,KAAK,CAAkB;IAC/B,OAAO,CAAC,OAAO,CAAwB;IAEvC,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAcjC,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAWpC,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI;IAYjD,KAAK,IAAI,IAAI;IAKb,OAAO,CAAC,UAAU;IAMlB,OAAO,CAAC,WAAW;CAMpB"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
// --- Braille spinner ---
|
|
3
|
+
const BRAILLE_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
4
|
+
export function startSpinner(text) {
|
|
5
|
+
let frameIndex = 0;
|
|
6
|
+
const stream = process.stderr;
|
|
7
|
+
const interval = setInterval(() => {
|
|
8
|
+
const frame = chalk.cyan(BRAILLE_FRAMES[frameIndex % BRAILLE_FRAMES.length]);
|
|
9
|
+
stream.write(`\r${frame} ${text}`);
|
|
10
|
+
frameIndex++;
|
|
11
|
+
}, 80);
|
|
12
|
+
return {
|
|
13
|
+
update(newText) {
|
|
14
|
+
text = newText;
|
|
15
|
+
},
|
|
16
|
+
stop(finalText) {
|
|
17
|
+
clearInterval(interval);
|
|
18
|
+
stream.write("\r" + " ".repeat(text.length + 4) + "\r");
|
|
19
|
+
if (finalText) {
|
|
20
|
+
stream.write(finalText + "\n");
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
// --- Tool call labels ---
|
|
26
|
+
const TOOL_LABELS = {
|
|
27
|
+
// Core Google Ads
|
|
28
|
+
list_accounts: "Listing Google Ads accounts",
|
|
29
|
+
execute_gaql_query: "Running GAQL query",
|
|
30
|
+
run_gaql: "Running GAQL query",
|
|
31
|
+
list_gaql_resources: "Loading GAQL resource reference",
|
|
32
|
+
get_account_currency: "Checking account currency",
|
|
33
|
+
// Performance & assets
|
|
34
|
+
get_campaign_performance: "Fetching campaign performance",
|
|
35
|
+
get_ad_performance: "Fetching ad performance",
|
|
36
|
+
get_ad_creatives: "Fetching ad creatives",
|
|
37
|
+
get_image_assets: "Fetching image assets",
|
|
38
|
+
get_image_asset_urls: "Fetching image asset URLs",
|
|
39
|
+
get_asset_usage: "Checking asset usage",
|
|
40
|
+
analyze_image_assets: "Analyzing image assets",
|
|
41
|
+
// Mutations
|
|
42
|
+
execute_mutate: "Executing Google Ads mutation",
|
|
43
|
+
// Tier 1 reports
|
|
44
|
+
get_search_terms_report: "Pulling search terms report",
|
|
45
|
+
get_keyword_report: "Pulling keyword report",
|
|
46
|
+
get_device_report: "Pulling device report",
|
|
47
|
+
get_location_report: "Pulling location report",
|
|
48
|
+
get_schedule_report: "Pulling schedule report",
|
|
49
|
+
get_age_report: "Pulling age demographics report",
|
|
50
|
+
get_gender_report: "Pulling gender demographics report",
|
|
51
|
+
get_income_report: "Pulling income demographics report",
|
|
52
|
+
get_asset_performance_report: "Pulling asset performance report",
|
|
53
|
+
get_auction_insights: "Pulling auction insights",
|
|
54
|
+
// Tier 2 reports
|
|
55
|
+
get_ad_group_report: "Pulling ad group report",
|
|
56
|
+
get_user_location_report: "Checking user location targeting",
|
|
57
|
+
get_conversion_action_report: "Pulling conversion action report",
|
|
58
|
+
get_landing_page_report: "Pulling landing page report",
|
|
59
|
+
get_call_details_report: "Pulling call details report",
|
|
60
|
+
get_change_history: "Pulling change history",
|
|
61
|
+
// Adscriptly read
|
|
62
|
+
get_dashboard_analytics: "Loading dashboard analytics",
|
|
63
|
+
get_keyword_performance: "Loading keyword performance",
|
|
64
|
+
get_keyword_kpis: "Loading keyword KPIs",
|
|
65
|
+
get_conversion_stats: "Loading conversion stats",
|
|
66
|
+
get_conversion_analytics: "Loading conversion analytics",
|
|
67
|
+
get_pending_negative_keywords: "Loading pending negative keywords",
|
|
68
|
+
get_adscriptly_search_terms: "Loading search terms",
|
|
69
|
+
get_negative_keyword_agent_status: "Checking keyword agent status",
|
|
70
|
+
get_pending_positive_keywords: "Loading pending positive keywords",
|
|
71
|
+
get_sync_status: "Checking sync status",
|
|
72
|
+
// Keyword research
|
|
73
|
+
get_keyword_ideas: "Generating keyword ideas",
|
|
74
|
+
get_keyword_metrics: "Fetching keyword metrics",
|
|
75
|
+
// Adscriptly write
|
|
76
|
+
approve_negative_keywords: "Approving negative keywords",
|
|
77
|
+
dismiss_negative_keywords: "Dismissing negative keywords",
|
|
78
|
+
apply_negative_keywords: "Applying negative keywords",
|
|
79
|
+
approve_positive_keywords: "Approving positive keywords",
|
|
80
|
+
trigger_sync: "Triggering data sync",
|
|
81
|
+
};
|
|
82
|
+
export function toolCallLabel(toolName) {
|
|
83
|
+
return TOOL_LABELS[toolName] || `Running ${toolName}`;
|
|
84
|
+
}
|
|
85
|
+
export function renderStep(step) {
|
|
86
|
+
const label = toolCallLabel(step.toolName);
|
|
87
|
+
switch (step.status) {
|
|
88
|
+
case "active": {
|
|
89
|
+
return `${chalk.cyan("⠋")} ${label}`;
|
|
90
|
+
}
|
|
91
|
+
case "complete": {
|
|
92
|
+
const duration = step.endTime
|
|
93
|
+
? ((step.endTime - step.startTime) / 1000).toFixed(1)
|
|
94
|
+
: "0.0";
|
|
95
|
+
return `${chalk.green("✓")} ${label} ${chalk.dim(`(${duration}s)`)}`;
|
|
96
|
+
}
|
|
97
|
+
case "error": {
|
|
98
|
+
const msg = step.error ? ` — ${step.error}` : "";
|
|
99
|
+
return `${chalk.red("✗")} ${label}${chalk.red(msg)}`;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
// --- Step list manager ---
|
|
104
|
+
export class StepList {
|
|
105
|
+
steps = [];
|
|
106
|
+
spinner = null;
|
|
107
|
+
startStep(toolName) {
|
|
108
|
+
// Complete any active spinner
|
|
109
|
+
this.stopSpinner();
|
|
110
|
+
const step = {
|
|
111
|
+
toolName,
|
|
112
|
+
status: "active",
|
|
113
|
+
startTime: Date.now(),
|
|
114
|
+
};
|
|
115
|
+
this.steps.push(step);
|
|
116
|
+
this.spinner = startSpinner(toolCallLabel(toolName));
|
|
117
|
+
}
|
|
118
|
+
completeStep(toolName) {
|
|
119
|
+
this.stopSpinner();
|
|
120
|
+
const step = this.findActive(toolName);
|
|
121
|
+
if (step) {
|
|
122
|
+
step.status = "complete";
|
|
123
|
+
step.endTime = Date.now();
|
|
124
|
+
process.stderr.write(renderStep(step) + "\n");
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
errorStep(toolName, error) {
|
|
128
|
+
this.stopSpinner();
|
|
129
|
+
const step = this.findActive(toolName);
|
|
130
|
+
if (step) {
|
|
131
|
+
step.status = "error";
|
|
132
|
+
step.endTime = Date.now();
|
|
133
|
+
step.error = error;
|
|
134
|
+
process.stderr.write(renderStep(step) + "\n");
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
clear() {
|
|
138
|
+
this.stopSpinner();
|
|
139
|
+
this.steps = [];
|
|
140
|
+
}
|
|
141
|
+
findActive(toolName) {
|
|
142
|
+
return this.steps.find((s) => s.toolName === toolName && s.status === "active");
|
|
143
|
+
}
|
|
144
|
+
stopSpinner() {
|
|
145
|
+
if (this.spinner) {
|
|
146
|
+
this.spinner.stop();
|
|
147
|
+
this.spinner = null;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=display.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"display.js","sourceRoot":"","sources":["../../src/cli-client/display.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,0BAA0B;AAE1B,MAAM,cAAc,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;AAO1E,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,IAAI,UAAU,GAAG,CAAC,CAAC;IACnB,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAE9B,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,EAAE;QAChC,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,UAAU,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC;QAC7E,MAAM,CAAC,KAAK,CAAC,KAAK,KAAK,IAAI,IAAI,EAAE,CAAC,CAAC;QACnC,UAAU,EAAE,CAAC;IACf,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO;QACL,MAAM,CAAC,OAAe;YACpB,IAAI,GAAG,OAAO,CAAC;QACjB,CAAC;QACD,IAAI,CAAC,SAAkB;YACrB,aAAa,CAAC,QAAQ,CAAC,CAAC;YACxB,MAAM,CAAC,KAAK,CAAC,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;YACxD,IAAI,SAAS,EAAE,CAAC;gBACd,MAAM,CAAC,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC;YACjC,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC;AAED,2BAA2B;AAE3B,MAAM,WAAW,GAA2B;IAC1C,kBAAkB;IAClB,aAAa,EAAE,6BAA6B;IAC5C,kBAAkB,EAAE,oBAAoB;IACxC,QAAQ,EAAE,oBAAoB;IAC9B,mBAAmB,EAAE,iCAAiC;IACtD,oBAAoB,EAAE,2BAA2B;IAEjD,uBAAuB;IACvB,wBAAwB,EAAE,+BAA+B;IACzD,kBAAkB,EAAE,yBAAyB;IAC7C,gBAAgB,EAAE,uBAAuB;IACzC,gBAAgB,EAAE,uBAAuB;IACzC,oBAAoB,EAAE,2BAA2B;IACjD,eAAe,EAAE,sBAAsB;IACvC,oBAAoB,EAAE,wBAAwB;IAE9C,YAAY;IACZ,cAAc,EAAE,+BAA+B;IAE/C,iBAAiB;IACjB,uBAAuB,EAAE,6BAA6B;IACtD,kBAAkB,EAAE,wBAAwB;IAC5C,iBAAiB,EAAE,uBAAuB;IAC1C,mBAAmB,EAAE,yBAAyB;IAC9C,mBAAmB,EAAE,yBAAyB;IAC9C,cAAc,EAAE,iCAAiC;IACjD,iBAAiB,EAAE,oCAAoC;IACvD,iBAAiB,EAAE,oCAAoC;IACvD,4BAA4B,EAAE,kCAAkC;IAChE,oBAAoB,EAAE,0BAA0B;IAEhD,iBAAiB;IACjB,mBAAmB,EAAE,yBAAyB;IAC9C,wBAAwB,EAAE,kCAAkC;IAC5D,4BAA4B,EAAE,kCAAkC;IAChE,uBAAuB,EAAE,6BAA6B;IACtD,uBAAuB,EAAE,6BAA6B;IACtD,kBAAkB,EAAE,wBAAwB;IAE5C,kBAAkB;IAClB,uBAAuB,EAAE,6BAA6B;IACtD,uBAAuB,EAAE,6BAA6B;IACtD,gBAAgB,EAAE,sBAAsB;IACxC,oBAAoB,EAAE,0BAA0B;IAChD,wBAAwB,EAAE,8BAA8B;IACxD,6BAA6B,EAAE,mCAAmC;IAClE,2BAA2B,EAAE,sBAAsB;IACnD,iCAAiC,EAAE,+BAA+B;IAClE,6BAA6B,EAAE,mCAAmC;IAClE,eAAe,EAAE,sBAAsB;IAEvC,mBAAmB;IACnB,iBAAiB,EAAE,0BAA0B;IAC7C,mBAAmB,EAAE,0BAA0B;IAE/C,mBAAmB;IACnB,yBAAyB,EAAE,6BAA6B;IACxD,yBAAyB,EAAE,8BAA8B;IACzD,uBAAuB,EAAE,4BAA4B;IACrD,yBAAyB,EAAE,6BAA6B;IACxD,YAAY,EAAE,sBAAsB;CACrC,CAAC;AAEF,MAAM,UAAU,aAAa,CAAC,QAAgB;IAC5C,OAAO,WAAW,CAAC,QAAQ,CAAC,IAAI,WAAW,QAAQ,EAAE,CAAC;AACxD,CAAC;AAcD,MAAM,UAAU,UAAU,CAAC,IAAc;IACvC,MAAM,KAAK,GAAG,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAE3C,QAAQ,IAAI,CAAC,MAAM,EAAE,CAAC;QACpB,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,KAAK,EAAE,CAAC;QACvC,CAAC;QACD,KAAK,UAAU,CAAC,CAAC,CAAC;YAChB,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO;gBAC3B,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;gBACrD,CAAC,CAAC,KAAK,CAAC;YACV,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,KAAK,IAAI,KAAK,CAAC,GAAG,CAAC,IAAI,QAAQ,IAAI,CAAC,EAAE,CAAC;QACvE,CAAC;QACD,KAAK,OAAO,CAAC,CAAC,CAAC;YACb,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACjD,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;QACvD,CAAC;IACH,CAAC;AACH,CAAC;AAED,4BAA4B;AAE5B,MAAM,OAAO,QAAQ;IACX,KAAK,GAAe,EAAE,CAAC;IACvB,OAAO,GAAmB,IAAI,CAAC;IAEvC,SAAS,CAAC,QAAgB;QACxB,8BAA8B;QAC9B,IAAI,CAAC,WAAW,EAAE,CAAC;QAEnB,MAAM,IAAI,GAAa;YACrB,QAAQ;YACR,MAAM,EAAE,QAAQ;YAChB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;SACtB,CAAC;QACF,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAEtB,IAAI,CAAC,OAAO,GAAG,YAAY,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC;IACvD,CAAC;IAED,YAAY,CAAC,QAAgB;QAC3B,IAAI,CAAC,WAAW,EAAE,CAAC;QAEnB,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;QACvC,IAAI,IAAI,EAAE,CAAC;YACT,IAAI,CAAC,MAAM,GAAG,UAAU,CAAC;YACzB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAC1B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;QAChD,CAAC;IACH,CAAC;IAED,SAAS,CAAC,QAAgB,EAAE,KAAc;QACxC,IAAI,CAAC,WAAW,EAAE,CAAC;QAEnB,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;QACvC,IAAI,IAAI,EAAE,CAAC;YACT,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC;YACtB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAC1B,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;YACnB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;QAChD,CAAC;IACH,CAAC;IAED,KAAK;QACH,IAAI,CAAC,WAAW,EAAE,CAAC;QACnB,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;IAClB,CAAC;IAEO,UAAU,CAAC,QAAgB;QACjC,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CACpB,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,KAAK,QAAQ,CACxD,CAAC;IACJ,CAAC;IAEO,WAAW;QACjB,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;YACpB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACtB,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli-client/index.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import { loginCommand } from "./commands/login.js";
|
|
4
|
+
import { logoutCommand } from "./commands/logout.js";
|
|
5
|
+
import { chatCommand } from "./commands/chat.js";
|
|
6
|
+
import { configCommand } from "./commands/config.js";
|
|
7
|
+
const program = new Command();
|
|
8
|
+
program
|
|
9
|
+
.name("adscriptly")
|
|
10
|
+
.description("AI-powered CLI for managing Google Ads from the terminal")
|
|
11
|
+
.version("0.1.0");
|
|
12
|
+
program.addCommand(loginCommand);
|
|
13
|
+
program.addCommand(logoutCommand);
|
|
14
|
+
program.addCommand(chatCommand, { isDefault: true });
|
|
15
|
+
program.addCommand(configCommand);
|
|
16
|
+
program.parse();
|
|
17
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli-client/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAErD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,YAAY,CAAC;KAClB,WAAW,CAAC,0DAA0D,CAAC;KACvE,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;AACjC,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;AAClC,OAAO,CAAC,UAAU,CAAC,WAAW,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;AACrD,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;AAElC,OAAO,CAAC,KAAK,EAAE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report-prompt.d.ts","sourceRoot":"","sources":["../../src/cli-client/report-prompt.ts"],"names":[],"mappings":"AAAA,KAAK,MAAM,GAAG,QAAQ,GAAG,SAAS,GAAG,WAAW,CAAC;AACjD,KAAK,MAAM,GAAG,IAAI,GAAG,KAAK,GAAG,MAAM,CAAC;AAwKpC,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,GAC1B,MAAM,CAyCR"}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
const DATE_RANGES = {
|
|
2
|
+
weekly: { current: "LAST_7_DAYS", previous: "the 7 days before that", label: "Week" },
|
|
3
|
+
monthly: { current: "LAST_30_DAYS", previous: "the 30 days before that", label: "Month" },
|
|
4
|
+
quarterly: { current: "last 90 days", previous: "the 90 days before that", label: "Quarter" },
|
|
5
|
+
};
|
|
6
|
+
function getMarkdownTemplate(period) {
|
|
7
|
+
if (period === "weekly") {
|
|
8
|
+
return `
|
|
9
|
+
Output the report as markdown directly. Use this structure:
|
|
10
|
+
|
|
11
|
+
## Weekly Report — [Campaign Name]
|
|
12
|
+
**[Date Range]**
|
|
13
|
+
|
|
14
|
+
### Performance
|
|
15
|
+
| Metric | This Week | Last Week | Change |
|
|
16
|
+
|--------|-----------|-----------|--------|
|
|
17
|
+
| Conversions | [value] | [value] | [+/-X% ▲/▼] |
|
|
18
|
+
| CPA | [value] | [value] | [+/-X% ▲/▼] |
|
|
19
|
+
| Spend | [value] | [value] | [+/-X% ▲/▼] |
|
|
20
|
+
| CTR | [value] | [value] | [+/-X% ▲/▼] |
|
|
21
|
+
|
|
22
|
+
### Conversions
|
|
23
|
+
| Type | Count |
|
|
24
|
+
|------|-------|
|
|
25
|
+
| [type] | [count] |
|
|
26
|
+
|
|
27
|
+
### Changes Made
|
|
28
|
+
- [list optimizations from change history]
|
|
29
|
+
|
|
30
|
+
### Next Week
|
|
31
|
+
- [2-3 actionable recommendations]`;
|
|
32
|
+
}
|
|
33
|
+
if (period === "monthly") {
|
|
34
|
+
return `
|
|
35
|
+
Output the report as markdown directly. Use this structure:
|
|
36
|
+
|
|
37
|
+
## Monthly Report — [Campaign Name]
|
|
38
|
+
**[Month Year]**
|
|
39
|
+
|
|
40
|
+
### Executive Summary
|
|
41
|
+
[2-3 sentence overview: conversions, CPA trend, key wins, impression share opportunity]
|
|
42
|
+
|
|
43
|
+
### Performance
|
|
44
|
+
| Metric | This Month | Last Month | Change |
|
|
45
|
+
|--------|------------|------------|--------|
|
|
46
|
+
| Conversions | [value] | [value] | [+/-X% ▲/▼] |
|
|
47
|
+
| CPA | [value] | [value] | [+/-X% ▲/▼] |
|
|
48
|
+
| Spend | [value] | [value] | [+/-X% ▲/▼] |
|
|
49
|
+
| Conv Rate | [value] | [value] | [+/-X% ▲/▼] |
|
|
50
|
+
| CTR | [value] | [value] | [+/-X% ▲/▼] |
|
|
51
|
+
|
|
52
|
+
### Signed Cases (if Adscriptly offline data available)
|
|
53
|
+
| Name | Date | Status |
|
|
54
|
+
|------|------|--------|
|
|
55
|
+
| [name] | [date] | [status] |
|
|
56
|
+
|
|
57
|
+
**Signed:** [n] | **Pending:** [n] | **Close Rate:** [n%]
|
|
58
|
+
|
|
59
|
+
(If no Adscriptly data, show conversion breakdown by type instead)
|
|
60
|
+
|
|
61
|
+
### Competitive Position
|
|
62
|
+
| Metric | Current |
|
|
63
|
+
|--------|---------|
|
|
64
|
+
| Impression Share | [value] |
|
|
65
|
+
| Lost to Rank | [value] |
|
|
66
|
+
| Lost to Budget | [value] |
|
|
67
|
+
| Est. Ceiling | [calculated: current spend / current IS * 0.85] |
|
|
68
|
+
|
|
69
|
+
### Optimizations Completed
|
|
70
|
+
| Category | Changes | Impact |
|
|
71
|
+
|----------|---------|--------|
|
|
72
|
+
| [category] | [description] | [impact] |
|
|
73
|
+
|
|
74
|
+
### Recommendations
|
|
75
|
+
| Priority | Action | Expected Impact |
|
|
76
|
+
|----------|--------|-----------------|
|
|
77
|
+
| 1 | [action] | [impact] |
|
|
78
|
+
| 2 | [action] | [impact] |
|
|
79
|
+
| 3 | [action] | [impact] |`;
|
|
80
|
+
}
|
|
81
|
+
// quarterly
|
|
82
|
+
return `
|
|
83
|
+
Output the report as markdown directly. Use this structure:
|
|
84
|
+
|
|
85
|
+
## Q[N] [Year] Report — [Campaign Name]
|
|
86
|
+
|
|
87
|
+
### Executive Summary
|
|
88
|
+
[3-4 sentence overview: business impact, ROI, trajectory, scaling opportunity]
|
|
89
|
+
|
|
90
|
+
### Business Impact
|
|
91
|
+
| Metric | Q[N] [Year] |
|
|
92
|
+
|--------|-------------|
|
|
93
|
+
| Signed Cases | [value] |
|
|
94
|
+
| Total Spend | [value] |
|
|
95
|
+
| Cost per Signed Case | [value] |
|
|
96
|
+
| Est. Revenue Generated | [value] |
|
|
97
|
+
| ROI | [value] |
|
|
98
|
+
|
|
99
|
+
(If no Adscriptly signed case data, show total conversions and CPA instead)
|
|
100
|
+
|
|
101
|
+
### Performance Trend
|
|
102
|
+
| Month | Conversions | CPA | Spend |
|
|
103
|
+
|-------|-------------|-----|-------|
|
|
104
|
+
| [month 1] | [value] | [value] | [value] |
|
|
105
|
+
| [month 2] | [value] | [value] | [value] |
|
|
106
|
+
| [month 3] | [value] | [value] | [value] |
|
|
107
|
+
|
|
108
|
+
### Competitive Position
|
|
109
|
+
| Metric | Current |
|
|
110
|
+
|--------|---------|
|
|
111
|
+
| Impression Share | [value] |
|
|
112
|
+
| Lost to Rank | [value] |
|
|
113
|
+
| Lost to Budget | [value] |
|
|
114
|
+
|
|
115
|
+
### Optimizations Completed
|
|
116
|
+
| Category | Changes | Impact |
|
|
117
|
+
|----------|---------|--------|
|
|
118
|
+
| [category] | [description] | [impact] |
|
|
119
|
+
|
|
120
|
+
### Scaling Roadmap
|
|
121
|
+
| Phase | Action | Investment | Projected Return |
|
|
122
|
+
|-------|--------|------------|------------------|
|
|
123
|
+
| Now | [action] | [amount] | [projection] |
|
|
124
|
+
| Next Quarter | [action] | [amount] | [projection] |
|
|
125
|
+
| Future | [action] | [amount] | [projection] |
|
|
126
|
+
|
|
127
|
+
### Recommendations for Next Quarter
|
|
128
|
+
1. [recommendation]
|
|
129
|
+
2. [recommendation]
|
|
130
|
+
3. [recommendation]`;
|
|
131
|
+
}
|
|
132
|
+
function getFormatInstructions(period, format) {
|
|
133
|
+
if (format === "md") {
|
|
134
|
+
return getMarkdownTemplate(period);
|
|
135
|
+
}
|
|
136
|
+
const toolCallInstructions = `After gathering and analyzing the data, call the generate_report_file tool with:
|
|
137
|
+
- format: "${format}"
|
|
138
|
+
- title: The report title (e.g. "${DATE_RANGES[period].label} Report — [Campaign Name]")
|
|
139
|
+
- sections: An array of section objects. Each section has:
|
|
140
|
+
- heading (string): The section title
|
|
141
|
+
- body (string, optional): Paragraph text
|
|
142
|
+
- table (optional): { headers: string[], rows: string[][] }
|
|
143
|
+
|
|
144
|
+
Structure your sections to match the report template — one section per major area (Executive Summary, Performance, Conversions, Competitive Position, Optimizations, Recommendations, etc.).
|
|
145
|
+
|
|
146
|
+
IMPORTANT: All table cell values must be strings. Convert numbers to strings (e.g. "47" not 47, "$1,312" not 1312).
|
|
147
|
+
|
|
148
|
+
The tool returns a download URL. Show the URL to the user so they can download the file.`;
|
|
149
|
+
if (format === "pdf") {
|
|
150
|
+
return `${toolCallInstructions}
|
|
151
|
+
|
|
152
|
+
Format as a clean professional document with an executive summary section followed by detailed data sections with tables.`;
|
|
153
|
+
}
|
|
154
|
+
// docx
|
|
155
|
+
return `${toolCallInstructions}
|
|
156
|
+
|
|
157
|
+
This is a full narrative document — use detailed body text in each section. More verbose than a presentation, suitable for clients who want to read, edit, or annotate.`;
|
|
158
|
+
}
|
|
159
|
+
export function buildReportPrompt(period, format, accountName) {
|
|
160
|
+
const range = DATE_RANGES[period];
|
|
161
|
+
return `Generate a ${period} performance report${accountName ? ` for ${accountName}` : ""}.
|
|
162
|
+
|
|
163
|
+
## Instructions
|
|
164
|
+
|
|
165
|
+
### Step 1: Gather Data
|
|
166
|
+
Call these tools to collect data:
|
|
167
|
+
- get_campaign_performance for ${range.current} — get spend, conversions, CPA, CTR, impression share
|
|
168
|
+
- get_campaign_performance for ${range.previous} — same metrics for comparison period
|
|
169
|
+
- get_conversion_action_report — conversion types breakdown
|
|
170
|
+
- get_conversion_analytics — Adscriptly offline conversion data (signed cases if available)
|
|
171
|
+
- get_change_history — what optimizations were made this period
|
|
172
|
+
${period !== "weekly" ? `- get_auction_insights — competitive position data` : ""}
|
|
173
|
+
|
|
174
|
+
### Step 2: Calculate Comparisons
|
|
175
|
+
For each metric, calculate:
|
|
176
|
+
- Absolute values for both periods
|
|
177
|
+
- % change = ((current - previous) / previous) * 100
|
|
178
|
+
- Use ▲ for improvements (more conversions, lower CPA, higher CTR)
|
|
179
|
+
- Use ▼ for declines
|
|
180
|
+
|
|
181
|
+
### Step 3: Detect Conversion Source
|
|
182
|
+
- If Adscriptly offline conversions exist → show "Signed Cases" table with names, dates, status
|
|
183
|
+
- If only Google Ads conversions → show conversion counts by type
|
|
184
|
+
- If no conversions → flag "Conversion Tracking Gap" and generate traffic-only report
|
|
185
|
+
|
|
186
|
+
### Step 4: Generate Report
|
|
187
|
+
${getFormatInstructions(period, format)}
|
|
188
|
+
|
|
189
|
+
### Error Handling
|
|
190
|
+
- If no account is selected, ask which account to report on
|
|
191
|
+
- If insufficient data for the period, say how much data is available and offer a partial report
|
|
192
|
+
- If a tool call fails, continue with available data and note what's missing
|
|
193
|
+
|
|
194
|
+
### Important
|
|
195
|
+
- Use actual numbers from tool results, never make up data
|
|
196
|
+
- Format currency based on account currency (use get_account_currency if unsure)
|
|
197
|
+
- Keep the tone professional and client-ready
|
|
198
|
+
- Every metric comparison must show the actual values AND the % change`;
|
|
199
|
+
}
|
|
200
|
+
//# sourceMappingURL=report-prompt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report-prompt.js","sourceRoot":"","sources":["../../src/cli-client/report-prompt.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,GAAyE;IACxF,MAAM,EAAE,EAAE,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,wBAAwB,EAAE,KAAK,EAAE,MAAM,EAAE;IACrF,OAAO,EAAE,EAAE,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,yBAAyB,EAAE,KAAK,EAAE,OAAO,EAAE;IACzF,SAAS,EAAE,EAAE,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,yBAAyB,EAAE,KAAK,EAAE,SAAS,EAAE;CAC9F,CAAC;AAEF,SAAS,mBAAmB,CAAC,MAAc;IACzC,IAAI,MAAM,KAAK,QAAQ,EAAE,CAAC;QACxB,OAAO;;;;;;;;;;;;;;;;;;;;;;;mCAuBwB,CAAC;IAClC,CAAC;IAED,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4BA6CiB,CAAC;IAC3B,CAAC;IAED,YAAY;IACZ,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oBAgDW,CAAC;AACrB,CAAC;AAED,SAAS,qBAAqB,CAAC,MAAc,EAAE,MAAc;IAC3D,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;QACpB,OAAO,mBAAmB,CAAC,MAAM,CAAC,CAAC;IACrC,CAAC;IAED,MAAM,oBAAoB,GAAG;aAClB,MAAM;mCACgB,WAAW,CAAC,MAAM,CAAC,CAAC,KAAK;;;;;;;;;;yFAU6B,CAAC;IAExF,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;QACrB,OAAO,GAAG,oBAAoB;;0HAEwF,CAAC;IACzH,CAAC;IAED,OAAO;IACP,OAAO,GAAG,oBAAoB;;wKAEwI,CAAC;AACzK,CAAC;AAED,MAAM,UAAU,iBAAiB,CAC/B,MAAc,EACd,MAAc,EACd,WAA2B;IAE3B,MAAM,KAAK,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;IAElC,OAAO,cAAc,MAAM,sBAAsB,WAAW,CAAC,CAAC,CAAC,QAAQ,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE;;;;;;iCAM1D,KAAK,CAAC,OAAO;iCACb,KAAK,CAAC,QAAQ;;;;EAI7C,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,oDAAoD,CAAC,CAAC,CAAC,EAAE;;;;;;;;;;;;;;;EAe/E,qBAAqB,CAAC,MAAM,EAAE,MAAM,CAAC;;;;;;;;;;;uEAWgC,CAAC;AACxE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sse.d.ts","sourceRoot":"","sources":["../../src/cli-client/sse.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAuB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,GAAG,cAAc,CAAC,QAAQ,CAAC,CAwC5E"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export async function* parseSSE(response) {
|
|
2
|
+
const body = response.body;
|
|
3
|
+
if (!body)
|
|
4
|
+
return;
|
|
5
|
+
const reader = body.getReader();
|
|
6
|
+
const decoder = new TextDecoder();
|
|
7
|
+
let buffer = "";
|
|
8
|
+
try {
|
|
9
|
+
for (;;) {
|
|
10
|
+
const { done, value } = await reader.read();
|
|
11
|
+
if (done)
|
|
12
|
+
break;
|
|
13
|
+
buffer += decoder.decode(value, { stream: true });
|
|
14
|
+
const parts = buffer.split("\n\n");
|
|
15
|
+
buffer = parts.pop();
|
|
16
|
+
for (const part of parts) {
|
|
17
|
+
if (!part.trim())
|
|
18
|
+
continue;
|
|
19
|
+
let event = "";
|
|
20
|
+
let data = "";
|
|
21
|
+
for (const line of part.split("\n")) {
|
|
22
|
+
if (line.startsWith("event: ")) {
|
|
23
|
+
event = line.slice(7);
|
|
24
|
+
}
|
|
25
|
+
else if (line.startsWith("data: ")) {
|
|
26
|
+
data = line.slice(6);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
if (event && data) {
|
|
30
|
+
yield { event, data };
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
finally {
|
|
36
|
+
reader.releaseLock();
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=sse.js.map
|