continum 0.0.2

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 ADDED
@@ -0,0 +1,258 @@
1
+ # create-continum
2
+
3
+ Interactive CLI to set up Continum SDK in your project with zero configuration.
4
+
5
+ ## Usage
6
+
7
+ Run this command in your project directory:
8
+
9
+ ```bash
10
+ npx create-continum
11
+ ```
12
+
13
+ No installation required! The CLI will guide you through:
14
+
15
+ 1. **Product Type** - What kind of AI product you're building
16
+ 2. **LLM Providers** - Which providers you're using (OpenAI, Anthropic, etc.)
17
+ 3. **Compliance Frameworks** - Which regulations you need to comply with
18
+ 4. **Alert Channels** - Real-time notifications for violations (Slack, PagerDuty, Discord, Webhooks)
19
+ 5. **API Key** - Your Continum API key
20
+
21
+ ## What It Creates
22
+
23
+ After running `npx create-continum`, you'll have:
24
+
25
+ - ✅ `continum.config.ts` (or `.js`) - Your Continum configuration
26
+ - ✅ `.env` - Updated with API key and alert webhooks
27
+ - ✅ `continum-example.ts` (or `.js`) - Sample code to get started
28
+
29
+ ## Example Session
30
+
31
+ ```bash
32
+ $ npx create-continum
33
+
34
+ ┌ Continum Setup
35
+
36
+ ◇ Set up Continum AI compliance in your project?
37
+ │ Yes
38
+
39
+ ◇ What kind of AI product are you building?
40
+ │ 💬 Customer support bot
41
+
42
+ ◇ Which LLM providers are you using?
43
+ │ ◼ OpenAI
44
+ │ ◼ Anthropic
45
+
46
+ ◇ Do you need to comply with any specific frameworks?
47
+ │ ◼ GDPR
48
+ │ ◼ SOC2
49
+
50
+ ◇ Set up real-time alerts for compliance violations?
51
+ │ Yes
52
+
53
+ ◇ Which alert channels do you want to configure?
54
+ │ ◼ Slack
55
+ │ ◼ PagerDuty
56
+
57
+ ◇ Slack webhook URL (or press Enter to use env var):
58
+ │ https://hooks.slack.com/services/...
59
+
60
+ ◇ PagerDuty integration key (or press Enter to use env var):
61
+ │ R0123456789ABCDEF
62
+
63
+ ◇ Paste your Continum API key:
64
+ │ co_live_...
65
+
66
+ ◆ Setting up Continum...
67
+
68
+ ├ Files Created
69
+
70
+ │ ✓ Created continum.config.ts
71
+ │ ✓ Updated .env with API key and alert webhooks
72
+ │ ✓ Created continum-example.ts with sample code
73
+
74
+ └ Next steps:
75
+
76
+ 1. Install the SDK: npm install @continum/sdk
77
+ 2. Wrap your first LLM call with protect()
78
+ 3. Check continum-example.ts for examples
79
+
80
+ Docs: https://docs.continum.co/quickstart
81
+ Dashboard: https://app.continum.co
82
+ ```
83
+
84
+ ## Features
85
+
86
+ ### 🎯 Smart Defaults
87
+
88
+ The CLI automatically:
89
+ - Detects TypeScript vs JavaScript
90
+ - Suggests appropriate presets based on your product type
91
+ - Configures compliance frameworks
92
+ - Sets up alert channels
93
+
94
+ ### 🔒 Secure by Default
95
+
96
+ - API keys and webhooks stored in `.env` (not committed)
97
+ - HTTPS validation for all webhook URLs
98
+ - Environment variable references in config files
99
+
100
+ ### 📝 Complete Examples
101
+
102
+ Generates three example patterns:
103
+ 1. Basic usage with inline config
104
+ 2. Global configuration (recommended)
105
+ 3. Blocking mode for high-risk scenarios
106
+
107
+ ### 🚀 Zero Installation
108
+
109
+ Run with `npx` - no global installation needed.
110
+
111
+ ## Configuration File
112
+
113
+ The generated `continum.config.ts` looks like:
114
+
115
+ ```typescript
116
+ import type { ContinumConfig } from '@continum/sdk';
117
+
118
+ const config: ContinumConfig = {
119
+ apiKey: process.env.CONTINUM_API_KEY,
120
+ preset: 'customer-support',
121
+ comply: ['GDPR', 'SOC2'],
122
+ alerts: {
123
+ slack: process.env.SLACK_WEBHOOK_URL,
124
+ pagerduty: process.env.PAGERDUTY_KEY,
125
+ },
126
+ };
127
+
128
+ export default config;
129
+ ```
130
+
131
+ ## Example Code
132
+
133
+ The generated `continum-example.ts` includes:
134
+
135
+ ```typescript
136
+ import { protect } from '@continum/sdk';
137
+ import OpenAI from 'openai';
138
+
139
+ const openai = new OpenAI();
140
+
141
+ // Example 1: Basic usage
142
+ const response = await protect(
143
+ () => openai.chat.completions.create({
144
+ model: 'gpt-4',
145
+ messages: [{ role: 'user', content: 'Hello!' }]
146
+ }),
147
+ {
148
+ apiKey: process.env.CONTINUM_API_KEY!,
149
+ preset: 'customer-support',
150
+ comply: ['GDPR', 'SOC2'],
151
+ alerts: {
152
+ slack: process.env.SLACK_WEBHOOK_URL,
153
+ pagerduty: process.env.PAGERDUTY_KEY,
154
+ }
155
+ }
156
+ );
157
+
158
+ console.log(response.choices[0].message.content);
159
+ ```
160
+
161
+ ## Product Types
162
+
163
+ Choose from:
164
+ - 💬 Customer support bot
165
+ - 💻 Coding assistant
166
+ - ⚖️ Legal or research tool
167
+ - 🏥 Healthcare application
168
+ - 💰 Financial services
169
+ - 🤖 AI agent with tool use
170
+ - ✍️ Content generation
171
+ - 🔧 Internal team tool
172
+ - 📊 Data pipeline
173
+ - 🎓 Education tool
174
+
175
+ ## Compliance Frameworks
176
+
177
+ Supported frameworks:
178
+ - GDPR (EU data protection)
179
+ - CCPA (California privacy)
180
+ - SOC2 (Security & availability)
181
+ - HIPAA (US healthcare data)
182
+ - EU AI Act (EU AI regulation)
183
+ - ISO 27001 (Information security)
184
+ - FINRA (US financial services)
185
+ - PCI DSS (Payment card security)
186
+ - NIST AI RMF (AI risk management)
187
+
188
+ ## Alert Channels
189
+
190
+ Configure real-time alerts for:
191
+ - **Slack** - Team notifications
192
+ - **PagerDuty** - Critical incidents
193
+ - **Discord** - Community alerts
194
+ - **Custom Webhook** - Your own endpoint
195
+
196
+ All webhook URLs must use HTTPS for security.
197
+
198
+ ## Requirements
199
+
200
+ - Node.js >= 18.0.0
201
+ - A Continum API key (get one at https://app.continum.co)
202
+
203
+ ## Get Your API Key
204
+
205
+ ```bash
206
+ # Individual Account (DEV plan - Free: 1,000 audits)
207
+ curl -X POST https://api.continum.io/customers \
208
+ -H "Content-Type: application/json" \
209
+ -d '{"email":"you@example.com"}'
210
+
211
+ # Company Account (PRO/PRO_MAX/ENTERPRISE)
212
+ curl -X POST https://api.continum.io/customers \
213
+ -H "Content-Type: application/json" \
214
+ -d '{
215
+ "email":"you@company.com",
216
+ "name":"Your Company",
217
+ "accountType":"COMPANY",
218
+ "plan":"PRO"
219
+ }'
220
+ ```
221
+
222
+ ## Next Steps
223
+
224
+ After running `npx create-continum`:
225
+
226
+ 1. Install the SDK:
227
+ ```bash
228
+ npm install @continum/sdk
229
+ ```
230
+
231
+ 2. Import and use in your code:
232
+ ```typescript
233
+ import { protect } from '@continum/sdk';
234
+
235
+ const response = await protect(() => yourLLMCall());
236
+ ```
237
+
238
+ 3. Check the dashboard:
239
+ ```
240
+ https://app.continum.co
241
+ ```
242
+
243
+ ## Documentation
244
+
245
+ - [Quick Start Guide](https://docs.continum.co/quickstart)
246
+ - [SDK Documentation](https://docs.continum.co/sdk)
247
+ - [Alert Setup Guide](https://docs.continum.co/alerts)
248
+ - [API Reference](https://docs.continum.co/api)
249
+
250
+ ## Support
251
+
252
+ - **Docs**: https://docs.continum.co
253
+ - **Dashboard**: https://app.continum.co
254
+ - **Email**: support@continum.co
255
+
256
+ ## License
257
+
258
+ MIT
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
package/dist/index.js ADDED
@@ -0,0 +1,603 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/index.ts
4
+ import * as p from "@clack/prompts";
5
+ import { existsSync, writeFileSync, readFileSync } from "fs";
6
+ import pc from "picocolors";
7
+ var args = process.argv.slice(2);
8
+ var command = args[0];
9
+ if (command !== "init") {
10
+ console.error(pc.red(`
11
+ Error: Command required`));
12
+ console.log(`
13
+ Usage: ${pc.cyan("npx continum init")}
14
+ `);
15
+ process.exit(1);
16
+ }
17
+ main().catch(console.error);
18
+ async function main() {
19
+ console.clear();
20
+ p.intro(pc.bgCyan(pc.black(" Continum Setup ")));
21
+ const shouldContinue = await p.confirm({
22
+ message: "Set up Continum AI compliance in your project?",
23
+ initialValue: true
24
+ });
25
+ if (p.isCancel(shouldContinue) || !shouldContinue) {
26
+ p.cancel("Setup cancelled");
27
+ process.exit(0);
28
+ }
29
+ const config = {};
30
+ const productType = await p.select({
31
+ message: "What kind of AI product are you building?",
32
+ options: [
33
+ { value: "customer-support", label: "\u{1F4AC} Customer support bot", hint: "Chat, help desk, Q&A" },
34
+ { value: "coding-assistant", label: "\u{1F4BB} Coding assistant", hint: "Code generation, review" },
35
+ { value: "legal-ai", label: "\u2696\uFE0F Legal or research tool", hint: "Document analysis, research" },
36
+ { value: "healthcare-ai", label: "\u{1F3E5} Healthcare application", hint: "Medical advice, diagnosis" },
37
+ { value: "fintech-ai", label: "\u{1F4B0} Financial services", hint: "Trading, advice, analysis" },
38
+ { value: "agent", label: "\u{1F916} AI agent with tool use", hint: "Autonomous actions, APIs" },
39
+ { value: "content-generation", label: "\u270D\uFE0F Content generation", hint: "Writing, marketing, creative" },
40
+ { value: "internal-tool", label: "\u{1F527} Internal team tool", hint: "Productivity, automation" },
41
+ { value: "data-pipeline", label: "\u{1F4CA} Data pipeline", hint: "ETL, processing, analysis" },
42
+ { value: "education-ai", label: "\u{1F393} Education tool", hint: "Tutoring, learning, training" }
43
+ ]
44
+ });
45
+ if (p.isCancel(productType)) {
46
+ p.cancel("Setup cancelled");
47
+ process.exit(0);
48
+ }
49
+ config.productType = productType;
50
+ const providers = await p.multiselect({
51
+ message: "Which LLM providers are you using?",
52
+ options: [
53
+ { value: "openai", label: "OpenAI", hint: "GPT-4o, GPT-4, o1, o3" },
54
+ { value: "anthropic", label: "Anthropic", hint: "Claude Opus, Sonnet, Haiku" },
55
+ { value: "google", label: "Google Gemini", hint: "Gemini Pro, Flash" },
56
+ { value: "azure", label: "Azure OpenAI", hint: "OpenAI via Azure" },
57
+ { value: "bedrock", label: "AWS Bedrock", hint: "Any model via Bedrock" },
58
+ { value: "other", label: "Other", hint: "Custom or multiple providers" }
59
+ ],
60
+ required: true
61
+ });
62
+ if (p.isCancel(providers)) {
63
+ p.cancel("Setup cancelled");
64
+ process.exit(0);
65
+ }
66
+ config.providers = providers;
67
+ const frameworks = await p.multiselect({
68
+ message: "Do you need to comply with any specific frameworks?",
69
+ options: [
70
+ { value: "GDPR", label: "GDPR", hint: "EU data protection" },
71
+ { value: "CCPA", label: "CCPA", hint: "California privacy" },
72
+ { value: "SOC2", label: "SOC2", hint: "Security & availability" },
73
+ { value: "HIPAA", label: "HIPAA", hint: "US healthcare data" },
74
+ { value: "EU_AI_ACT", label: "EU AI Act", hint: "EU AI regulation" },
75
+ { value: "ISO_27001", label: "ISO 27001", hint: "Information security" },
76
+ { value: "FINRA", label: "FINRA", hint: "US financial services" },
77
+ { value: "PCI_DSS", label: "PCI DSS", hint: "Payment card security" },
78
+ { value: "NIST_AI_RMF", label: "NIST AI RMF", hint: "AI risk management" }
79
+ ],
80
+ required: false
81
+ });
82
+ if (p.isCancel(frameworks)) {
83
+ p.cancel("Setup cancelled");
84
+ process.exit(0);
85
+ }
86
+ config.frameworks = frameworks || [];
87
+ const wantsAlerts = await p.confirm({
88
+ message: "Set up real-time alerts for compliance violations?",
89
+ initialValue: true
90
+ });
91
+ if (p.isCancel(wantsAlerts)) {
92
+ p.cancel("Setup cancelled");
93
+ process.exit(0);
94
+ }
95
+ config.alerts = { enabled: wantsAlerts };
96
+ if (wantsAlerts) {
97
+ p.note(
98
+ "Configure alert channels to receive notifications when violations are detected.\nYou can add webhook URLs now or set them as environment variables later.",
99
+ "Alert Channels"
100
+ );
101
+ const alertChannels = await p.multiselect({
102
+ message: "Which alert channels do you want to configure?",
103
+ options: [
104
+ { value: "slack", label: "Slack", hint: "Team notifications" },
105
+ { value: "pagerduty", label: "PagerDuty", hint: "Critical incidents" },
106
+ { value: "discord", label: "Discord", hint: "Community alerts" },
107
+ { value: "webhook", label: "Custom Webhook", hint: "Your own endpoint" }
108
+ ],
109
+ required: false
110
+ });
111
+ if (!p.isCancel(alertChannels)) {
112
+ const channels = alertChannels;
113
+ if (channels.includes("slack")) {
114
+ const slackWebhook = await p.text({
115
+ message: "Slack webhook URL (or press Enter to use env var):",
116
+ placeholder: "https://hooks.slack.com/services/...",
117
+ validate: (v) => {
118
+ if (!v) return void 0;
119
+ if (!v.startsWith("https://")) return "Must be HTTPS URL";
120
+ return void 0;
121
+ }
122
+ });
123
+ if (!p.isCancel(slackWebhook) && slackWebhook) {
124
+ config.alerts.slack = slackWebhook;
125
+ }
126
+ }
127
+ if (channels.includes("pagerduty")) {
128
+ const pagerdutyKey = await p.text({
129
+ message: "PagerDuty integration key (or press Enter to use env var):",
130
+ placeholder: "R0123456789ABCDEF",
131
+ validate: (v) => {
132
+ if (!v) return void 0;
133
+ return void 0;
134
+ }
135
+ });
136
+ if (!p.isCancel(pagerdutyKey) && pagerdutyKey) {
137
+ config.alerts.pagerduty = pagerdutyKey;
138
+ }
139
+ }
140
+ if (channels.includes("discord")) {
141
+ const discordWebhook = await p.text({
142
+ message: "Discord webhook URL (or press Enter to use env var):",
143
+ placeholder: "https://discord.com/api/webhooks/...",
144
+ validate: (v) => {
145
+ if (!v) return void 0;
146
+ if (!v.startsWith("https://")) return "Must be HTTPS URL";
147
+ return void 0;
148
+ }
149
+ });
150
+ if (!p.isCancel(discordWebhook) && discordWebhook) {
151
+ config.alerts.discord = discordWebhook;
152
+ }
153
+ }
154
+ if (channels.includes("webhook")) {
155
+ const customWebhook = await p.text({
156
+ message: "Custom webhook URL (or press Enter to use env var):",
157
+ placeholder: "https://your-app.com/continum-alerts",
158
+ validate: (v) => {
159
+ if (!v) return void 0;
160
+ if (!v.startsWith("https://")) return "Must be HTTPS URL";
161
+ return void 0;
162
+ }
163
+ });
164
+ if (!p.isCancel(customWebhook) && customWebhook) {
165
+ config.alerts.webhook = customWebhook;
166
+ }
167
+ }
168
+ }
169
+ }
170
+ const shouldInstallSDK = await p.confirm({
171
+ message: "Install @continum/sdk now?",
172
+ initialValue: true
173
+ });
174
+ if (p.isCancel(shouldInstallSDK)) {
175
+ p.cancel("Setup cancelled");
176
+ process.exit(0);
177
+ }
178
+ if (shouldInstallSDK) {
179
+ const installSpinner = p.spinner();
180
+ installSpinner.start("Installing @continum/sdk...");
181
+ try {
182
+ await installSDK();
183
+ installSpinner.stop("\u2713 @continum/sdk installed!");
184
+ } catch (error) {
185
+ installSpinner.stop("Installation failed");
186
+ p.log.error(error instanceof Error ? error.message : "Unknown error");
187
+ p.note(
188
+ `You can install it manually later:
189
+
190
+ ${pc.cyan("npm install @continum/sdk")}`,
191
+ "Manual Installation"
192
+ );
193
+ const continueAnyway = await p.confirm({
194
+ message: "Continue with configuration setup?",
195
+ initialValue: true
196
+ });
197
+ if (p.isCancel(continueAnyway) || !continueAnyway) {
198
+ p.cancel("Setup cancelled");
199
+ process.exit(0);
200
+ }
201
+ }
202
+ }
203
+ const hasTypeScript = existsSync("tsconfig.json");
204
+ config.projectType = hasTypeScript ? "typescript" : "javascript";
205
+ const s = p.spinner();
206
+ s.start("Creating configuration files...");
207
+ try {
208
+ await generateConfigFile(config);
209
+ await updateEnvFile(config);
210
+ await generateExampleFile(config);
211
+ s.stop("\u2713 Configuration files created!");
212
+ const filesCreated = [
213
+ `${pc.green("\u2713")} Created ${pc.cyan("continum.config." + (config.projectType === "typescript" ? "ts" : "js"))}`,
214
+ `${pc.green("\u2713")} Created ${pc.cyan(".env")} with placeholder values`,
215
+ `${pc.green("\u2713")} Created ${pc.cyan("continum-example." + (config.projectType === "typescript" ? "ts" : "js"))} with sample code`
216
+ ];
217
+ if (shouldInstallSDK) {
218
+ filesCreated.push(`${pc.green("\u2713")} Installed ${pc.cyan("@continum/sdk")}`);
219
+ }
220
+ p.note(filesCreated.join("\n"), "Setup Complete");
221
+ p.note(
222
+ `${pc.yellow("\u26A0")} Add your Continum API key to ${pc.cyan(".env")}:
223
+
224
+ ${pc.dim("CONTINUM_API_KEY=")}${pc.cyan("your_api_key_here")}
225
+
226
+ Get your API key at: ${pc.underline("https://app.continum.co")}`,
227
+ "Action Required"
228
+ );
229
+ const nextSteps = shouldInstallSDK ? [
230
+ ` 1. Add your API key to ${pc.cyan(".env")}`,
231
+ ` 2. Wrap your first LLM call with ${pc.cyan("protect()")}`,
232
+ ` 3. Check ${pc.cyan("continum-example." + (config.projectType === "typescript" ? "ts" : "js"))} for examples`,
233
+ ` 4. Run your app and view violations in the dashboard`
234
+ ] : [
235
+ ` 1. Install the SDK: ${pc.cyan("npm install @continum/sdk")}`,
236
+ ` 2. Add your API key to ${pc.cyan(".env")}`,
237
+ ` 3. Wrap your first LLM call with ${pc.cyan("protect()")}`,
238
+ ` 4. Check ${pc.cyan("continum-example." + (config.projectType === "typescript" ? "ts" : "js"))} for examples`,
239
+ ` 5. Run your app and view violations in the dashboard`
240
+ ];
241
+ p.outro(
242
+ pc.bold("Next steps:\n\n") + nextSteps.join("\n") + `
243
+
244
+ ${pc.dim("Docs:")} ${pc.underline("https://docs.continum.co/quickstart")}
245
+ ${pc.dim("Dashboard:")} ${pc.underline("https://app.continum.co")}`
246
+ );
247
+ } catch (error) {
248
+ s.stop("Setup failed");
249
+ p.cancel(`Error: ${error instanceof Error ? error.message : "Unknown error"}`);
250
+ process.exit(1);
251
+ }
252
+ }
253
+ async function generateConfigFile(config) {
254
+ const ext = config.projectType === "typescript" ? "ts" : "js";
255
+ const filename = `continum.config.${ext}`;
256
+ let content = "";
257
+ if (config.projectType === "typescript") {
258
+ content += `import type { ContinumConfig } from '@continum/sdk';
259
+
260
+ `;
261
+ content += `const config: ContinumConfig = {
262
+ `;
263
+ } else {
264
+ content += `/** @type {import('@continum/sdk').ContinumConfig} */
265
+ `;
266
+ content += `const config = {
267
+ `;
268
+ }
269
+ content += ` apiKey: process.env.CONTINUM_API_KEY,
270
+ `;
271
+ content += ` preset: '${config.productType}',
272
+ `;
273
+ if (config.frameworks.length > 0) {
274
+ content += ` comply: [${config.frameworks.map((f) => `'${f}'`).join(", ")}],
275
+ `;
276
+ }
277
+ if (config.alerts.enabled) {
278
+ content += ` alerts: {
279
+ `;
280
+ if (config.alerts.slack) {
281
+ content += ` slack: process.env.SLACK_WEBHOOK_URL,
282
+ `;
283
+ }
284
+ if (config.alerts.pagerduty) {
285
+ content += ` pagerduty: process.env.PAGERDUTY_KEY,
286
+ `;
287
+ }
288
+ if (config.alerts.discord) {
289
+ content += ` discord: process.env.DISCORD_WEBHOOK_URL,
290
+ `;
291
+ }
292
+ if (config.alerts.webhook) {
293
+ content += ` webhook: process.env.CUSTOM_WEBHOOK_URL,
294
+ `;
295
+ }
296
+ content += ` },
297
+ `;
298
+ }
299
+ content += `};
300
+
301
+ `;
302
+ if (config.projectType === "typescript") {
303
+ content += `export default config;
304
+ `;
305
+ } else {
306
+ content += `module.exports = config;
307
+ `;
308
+ }
309
+ writeFileSync(filename, content);
310
+ }
311
+ async function updateEnvFile(config) {
312
+ const envFile = ".env";
313
+ let envContent = "";
314
+ if (existsSync(envFile)) {
315
+ envContent = readFileSync(envFile, "utf-8");
316
+ }
317
+ const newVars = [];
318
+ if (!envContent.includes("CONTINUM_API_KEY")) {
319
+ newVars.push(`CONTINUM_API_KEY=your_api_key_here`);
320
+ }
321
+ if (config.alerts.enabled) {
322
+ if (config.alerts.slack && !envContent.includes("SLACK_WEBHOOK_URL")) {
323
+ newVars.push(`SLACK_WEBHOOK_URL=${config.alerts.slack}`);
324
+ } else if (!config.alerts.slack && !envContent.includes("SLACK_WEBHOOK_URL")) {
325
+ newVars.push(`SLACK_WEBHOOK_URL=https://hooks.slack.com/services/YOUR/WEBHOOK/URL`);
326
+ }
327
+ if (config.alerts.pagerduty && !envContent.includes("PAGERDUTY_KEY")) {
328
+ newVars.push(`PAGERDUTY_KEY=${config.alerts.pagerduty}`);
329
+ } else if (!config.alerts.pagerduty && !envContent.includes("PAGERDUTY_KEY")) {
330
+ newVars.push(`PAGERDUTY_KEY=YOUR_PAGERDUTY_INTEGRATION_KEY`);
331
+ }
332
+ if (config.alerts.discord && !envContent.includes("DISCORD_WEBHOOK_URL")) {
333
+ newVars.push(`DISCORD_WEBHOOK_URL=${config.alerts.discord}`);
334
+ } else if (!config.alerts.discord && !envContent.includes("DISCORD_WEBHOOK_URL")) {
335
+ newVars.push(`DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/YOUR/WEBHOOK`);
336
+ }
337
+ if (config.alerts.webhook && !envContent.includes("CUSTOM_WEBHOOK_URL")) {
338
+ newVars.push(`CUSTOM_WEBHOOK_URL=${config.alerts.webhook}`);
339
+ } else if (!config.alerts.webhook && !envContent.includes("CUSTOM_WEBHOOK_URL")) {
340
+ newVars.push(`CUSTOM_WEBHOOK_URL=https://your-app.com/continum-alerts`);
341
+ }
342
+ }
343
+ if (newVars.length > 0) {
344
+ if (envContent && !envContent.endsWith("\n")) {
345
+ envContent += "\n";
346
+ }
347
+ envContent += "\n# Continum Configuration\n";
348
+ envContent += newVars.join("\n") + "\n";
349
+ writeFileSync(envFile, envContent);
350
+ }
351
+ }
352
+ async function generateExampleFile(config) {
353
+ const ext = config.projectType === "typescript" ? "ts" : "js";
354
+ const filename = `continum-example.${ext}`;
355
+ let content = "";
356
+ content += `import { protect } from '@continum/sdk';
357
+ `;
358
+ if (config.providers.includes("openai")) {
359
+ content += `import OpenAI from 'openai';
360
+ `;
361
+ }
362
+ if (config.providers.includes("anthropic")) {
363
+ content += `import Anthropic from '@anthropic-ai/sdk';
364
+ `;
365
+ }
366
+ if (config.providers.includes("google")) {
367
+ content += `import { GoogleGenerativeAI } from '@google/generative-ai';
368
+ `;
369
+ }
370
+ content += `
371
+ `;
372
+ if (config.providers.includes("openai")) {
373
+ content += `const openai = new OpenAI();
374
+ `;
375
+ }
376
+ if (config.providers.includes("anthropic")) {
377
+ content += `const anthropic = new Anthropic();
378
+ `;
379
+ }
380
+ if (config.providers.includes("google")) {
381
+ content += `const genai = new GoogleGenerativeAI(process.env.GOOGLE_API_KEY!);
382
+ `;
383
+ }
384
+ content += `
385
+ `;
386
+ content += `// Example 1: Basic usage with protect()
387
+ `;
388
+ content += `async function example1() {
389
+ `;
390
+ content += ` const response = await protect(
391
+ `;
392
+ if (config.providers.includes("openai")) {
393
+ content += ` () => openai.chat.completions.create({
394
+ `;
395
+ content += ` model: 'gpt-4',
396
+ `;
397
+ content += ` messages: [{ role: 'user', content: 'Hello!' }]
398
+ `;
399
+ content += ` }),
400
+ `;
401
+ } else if (config.providers.includes("anthropic")) {
402
+ content += ` () => anthropic.messages.create({
403
+ `;
404
+ content += ` model: 'claude-3-5-sonnet-20241022',
405
+ `;
406
+ content += ` max_tokens: 1024,
407
+ `;
408
+ content += ` messages: [{ role: 'user', content: 'Hello!' }]
409
+ `;
410
+ content += ` }),
411
+ `;
412
+ } else {
413
+ content += ` () => yourLLMCall(),
414
+ `;
415
+ }
416
+ content += ` {
417
+ `;
418
+ content += ` apiKey: process.env.CONTINUM_API_KEY!,
419
+ `;
420
+ content += ` preset: '${config.productType}',
421
+ `;
422
+ if (config.frameworks.length > 0) {
423
+ content += ` comply: [${config.frameworks.map((f) => `'${f}'`).join(", ")}],
424
+ `;
425
+ }
426
+ if (config.alerts.enabled) {
427
+ content += ` alerts: {
428
+ `;
429
+ if (config.alerts.slack) {
430
+ content += ` slack: process.env.SLACK_WEBHOOK_URL,
431
+ `;
432
+ }
433
+ if (config.alerts.pagerduty) {
434
+ content += ` pagerduty: process.env.PAGERDUTY_KEY,
435
+ `;
436
+ }
437
+ if (config.alerts.discord) {
438
+ content += ` discord: process.env.DISCORD_WEBHOOK_URL,
439
+ `;
440
+ }
441
+ if (config.alerts.webhook) {
442
+ content += ` webhook: process.env.CUSTOM_WEBHOOK_URL,
443
+ `;
444
+ }
445
+ content += ` },
446
+ `;
447
+ }
448
+ content += ` }
449
+ `;
450
+ content += ` );
451
+
452
+ `;
453
+ if (config.providers.includes("openai")) {
454
+ content += ` console.log(response.choices[0].message.content);
455
+ `;
456
+ } else if (config.providers.includes("anthropic")) {
457
+ content += ` console.log(response.content[0].text);
458
+ `;
459
+ } else {
460
+ content += ` console.log(response);
461
+ `;
462
+ }
463
+ content += `}
464
+
465
+ `;
466
+ content += `// Example 2: Global configuration (recommended for production)
467
+ `;
468
+ content += `import { continum } from '@continum/sdk';
469
+
470
+ `;
471
+ content += `continum.configure({
472
+ `;
473
+ content += ` apiKey: process.env.CONTINUM_API_KEY!,
474
+ `;
475
+ content += ` preset: '${config.productType}',
476
+ `;
477
+ if (config.frameworks.length > 0) {
478
+ content += ` comply: [${config.frameworks.map((f) => `'${f}'`).join(", ")}],
479
+ `;
480
+ }
481
+ if (config.alerts.enabled) {
482
+ content += ` alerts: {
483
+ `;
484
+ if (config.alerts.slack) {
485
+ content += ` slack: process.env.SLACK_WEBHOOK_URL,
486
+ `;
487
+ }
488
+ if (config.alerts.pagerduty) {
489
+ content += ` pagerduty: process.env.PAGERDUTY_KEY,
490
+ `;
491
+ }
492
+ if (config.alerts.discord) {
493
+ content += ` discord: process.env.DISCORD_WEBHOOK_URL,
494
+ `;
495
+ }
496
+ if (config.alerts.webhook) {
497
+ content += ` webhook: process.env.CUSTOM_WEBHOOK_URL,
498
+ `;
499
+ }
500
+ content += ` },
501
+ `;
502
+ }
503
+ content += `});
504
+
505
+ `;
506
+ content += `async function example2() {
507
+ `;
508
+ content += ` // Now you can use protect() without passing config every time
509
+ `;
510
+ content += ` const response = await continum.protect(
511
+ `;
512
+ if (config.providers.includes("openai")) {
513
+ content += ` () => openai.chat.completions.create({
514
+ `;
515
+ content += ` model: 'gpt-4',
516
+ `;
517
+ content += ` messages: [{ role: 'user', content: 'Hello!' }]
518
+ `;
519
+ content += ` })
520
+ `;
521
+ } else {
522
+ content += ` () => yourLLMCall()
523
+ `;
524
+ }
525
+ content += ` );
526
+ `;
527
+ content += `}
528
+
529
+ `;
530
+ content += `// Example 3: Blocking mode (wait for audit before returning)
531
+ `;
532
+ content += `async function example3() {
533
+ `;
534
+ content += ` try {
535
+ `;
536
+ content += ` const response = await protect(
537
+ `;
538
+ if (config.providers.includes("openai")) {
539
+ content += ` () => openai.chat.completions.create({
540
+ `;
541
+ content += ` model: 'gpt-4',
542
+ `;
543
+ content += ` messages: [{ role: 'user', content: 'Process this payment' }]
544
+ `;
545
+ content += ` }),
546
+ `;
547
+ } else {
548
+ content += ` () => yourLLMCall(),
549
+ `;
550
+ }
551
+ content += ` {
552
+ `;
553
+ content += ` apiKey: process.env.CONTINUM_API_KEY!,
554
+ `;
555
+ content += ` blockOn: 'HIGH' // Block if risk level is HIGH or CRITICAL
556
+ `;
557
+ content += ` }
558
+ `;
559
+ content += ` );
560
+ `;
561
+ content += ` } catch (error) {
562
+ `;
563
+ content += ` if (error.name === 'ContinumBlockedError') {
564
+ `;
565
+ content += ` console.error('Blocked:', error.signal.violations);
566
+ `;
567
+ content += ` // Handle blocked request
568
+ `;
569
+ content += ` }
570
+ `;
571
+ content += ` }
572
+ `;
573
+ content += `}
574
+ `;
575
+ writeFileSync(filename, content);
576
+ }
577
+ async function installSDK() {
578
+ const { execSync } = await import("child_process");
579
+ if (!existsSync("package.json")) {
580
+ throw new Error('No package.json found. Please run "npm init" first.');
581
+ }
582
+ let packageManager = "npm";
583
+ if (existsSync("pnpm-lock.yaml")) {
584
+ packageManager = "pnpm";
585
+ } else if (existsSync("yarn.lock")) {
586
+ packageManager = "yarn";
587
+ } else if (existsSync("bun.lockb")) {
588
+ packageManager = "bun";
589
+ }
590
+ try {
591
+ if (packageManager === "npm") {
592
+ execSync("npm install @continum/sdk", { stdio: "ignore" });
593
+ } else if (packageManager === "pnpm") {
594
+ execSync("pnpm add @continum/sdk", { stdio: "ignore" });
595
+ } else if (packageManager === "yarn") {
596
+ execSync("yarn add @continum/sdk", { stdio: "ignore" });
597
+ } else if (packageManager === "bun") {
598
+ execSync("bun add @continum/sdk", { stdio: "ignore" });
599
+ }
600
+ } catch (error) {
601
+ throw new Error(`Failed to install @continum/sdk using ${packageManager}`);
602
+ }
603
+ }
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "continum",
3
+ "version": "0.0.2",
4
+ "description": "Interactive CLI to set up Continum SDK in your project",
5
+ "type": "module",
6
+ "bin": {
7
+ "continum": "dist/index.js"
8
+ },
9
+ "files": [
10
+ "dist"
11
+ ],
12
+ "scripts": {
13
+ "build": "tsup src/index.ts --format esm --dts --clean",
14
+ "dev": "tsup src/index.ts --format esm --watch",
15
+ "test": "vitest"
16
+ },
17
+ "keywords": [
18
+ "continum",
19
+ "ai",
20
+ "compliance",
21
+ "llm",
22
+ "setup",
23
+ "init"
24
+ ],
25
+ "author": "Continum",
26
+ "license": "MIT",
27
+ "dependencies": {
28
+ "@clack/prompts": "^0.7.0",
29
+ "picocolors": "^1.0.0"
30
+ },
31
+ "devDependencies": {
32
+ "@types/node": "^20.0.0",
33
+ "tsup": "^8.0.0",
34
+ "typescript": "^5.3.0",
35
+ "vitest": "^1.0.0"
36
+ },
37
+ "engines": {
38
+ "node": ">=18.0.0"
39
+ }
40
+ }