@revenium/claude-code-metering 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/CHANGELOG.md +50 -0
- package/LICENSE +21 -0
- package/README.md +274 -0
- package/dist/cli/commands/backfill.d.ts +11 -0
- package/dist/cli/commands/backfill.d.ts.map +1 -0
- package/dist/cli/commands/backfill.js +390 -0
- package/dist/cli/commands/backfill.js.map +1 -0
- package/dist/cli/commands/setup.d.ts +13 -0
- package/dist/cli/commands/setup.d.ts.map +1 -0
- package/dist/cli/commands/setup.js +177 -0
- package/dist/cli/commands/setup.js.map +1 -0
- package/dist/cli/commands/status.d.ts +5 -0
- package/dist/cli/commands/status.d.ts.map +1 -0
- package/dist/cli/commands/status.js +95 -0
- package/dist/cli/commands/status.js.map +1 -0
- package/dist/cli/commands/test.d.ts +9 -0
- package/dist/cli/commands/test.d.ts.map +1 -0
- package/dist/cli/commands/test.js +67 -0
- package/dist/cli/commands/test.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +65 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/core/api/client.d.ts +28 -0
- package/dist/core/api/client.d.ts.map +1 -0
- package/dist/core/api/client.js +127 -0
- package/dist/core/api/client.js.map +1 -0
- package/dist/core/config/loader.d.ts +35 -0
- package/dist/core/config/loader.d.ts.map +1 -0
- package/dist/core/config/loader.js +162 -0
- package/dist/core/config/loader.js.map +1 -0
- package/dist/core/config/validator.d.ts +19 -0
- package/dist/core/config/validator.d.ts.map +1 -0
- package/dist/core/config/validator.js +101 -0
- package/dist/core/config/validator.js.map +1 -0
- package/dist/core/config/writer.d.ts +11 -0
- package/dist/core/config/writer.d.ts.map +1 -0
- package/dist/core/config/writer.js +145 -0
- package/dist/core/config/writer.js.map +1 -0
- package/dist/core/shell/detector.d.ts +14 -0
- package/dist/core/shell/detector.d.ts.map +1 -0
- package/dist/core/shell/detector.js +69 -0
- package/dist/core/shell/detector.js.map +1 -0
- package/dist/core/shell/profile-updater.d.ts +11 -0
- package/dist/core/shell/profile-updater.d.ts.map +1 -0
- package/dist/core/shell/profile-updater.js +101 -0
- package/dist/core/shell/profile-updater.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/dist/types/index.d.ts +96 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +3 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/constants.d.ts +68 -0
- package/dist/utils/constants.d.ts.map +1 -0
- package/dist/utils/constants.js +73 -0
- package/dist/utils/constants.js.map +1 -0
- package/dist/utils/masking.d.ts +14 -0
- package/dist/utils/masking.d.ts.map +1 -0
- package/dist/utils/masking.js +33 -0
- package/dist/utils/masking.js.map +1 -0
- package/package.json +61 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ReveniumConfig, ValidationResult } from '../../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Validates that an API key has the correct format.
|
|
4
|
+
* Valid format: hak_{tenant}_{random}
|
|
5
|
+
*/
|
|
6
|
+
export declare function validateApiKey(apiKey: string): ValidationResult;
|
|
7
|
+
/**
|
|
8
|
+
* Validates an email address format.
|
|
9
|
+
*/
|
|
10
|
+
export declare function validateEmail(email: string): ValidationResult;
|
|
11
|
+
/**
|
|
12
|
+
* Validates a subscription tier.
|
|
13
|
+
*/
|
|
14
|
+
export declare function validateSubscriptionTier(tier: string): ValidationResult;
|
|
15
|
+
/**
|
|
16
|
+
* Validates a complete Revenium configuration.
|
|
17
|
+
*/
|
|
18
|
+
export declare function validateConfig(config: Partial<ReveniumConfig>): ValidationResult;
|
|
19
|
+
//# sourceMappingURL=validator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../../../src/core/config/validator.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAE7E;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,gBAAgB,CA2B/D;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,gBAAgB,CAiB7D;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,CAmBvE;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,OAAO,CAAC,cAAc,CAAC,GAAG,gBAAgB,CA4BhF"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.validateApiKey = validateApiKey;
|
|
4
|
+
exports.validateEmail = validateEmail;
|
|
5
|
+
exports.validateSubscriptionTier = validateSubscriptionTier;
|
|
6
|
+
exports.validateConfig = validateConfig;
|
|
7
|
+
const constants_js_1 = require("../../utils/constants.js");
|
|
8
|
+
const VALID_TIERS = Object.keys(constants_js_1.SUBSCRIPTION_TIER_CONFIG);
|
|
9
|
+
/**
|
|
10
|
+
* Validates that an API key has the correct format.
|
|
11
|
+
* Valid format: hak_{tenant}_{random}
|
|
12
|
+
*/
|
|
13
|
+
function validateApiKey(apiKey) {
|
|
14
|
+
const errors = [];
|
|
15
|
+
if (!apiKey || apiKey.trim() === '') {
|
|
16
|
+
errors.push('API key is required');
|
|
17
|
+
return { valid: false, errors };
|
|
18
|
+
}
|
|
19
|
+
if (!apiKey.startsWith(constants_js_1.API_KEY_PREFIX)) {
|
|
20
|
+
errors.push(`API key must start with "${constants_js_1.API_KEY_PREFIX}"`);
|
|
21
|
+
}
|
|
22
|
+
// Check for at least two underscores (hak_tenant_random)
|
|
23
|
+
const parts = apiKey.split('_');
|
|
24
|
+
if (parts.length < 3) {
|
|
25
|
+
errors.push('API key format should be: hak_{tenant}_{key}');
|
|
26
|
+
}
|
|
27
|
+
// Minimum length check
|
|
28
|
+
if (apiKey.length < 12) {
|
|
29
|
+
errors.push('API key appears too short');
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
valid: errors.length === 0,
|
|
33
|
+
errors,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Validates an email address format.
|
|
38
|
+
*/
|
|
39
|
+
function validateEmail(email) {
|
|
40
|
+
const errors = [];
|
|
41
|
+
if (!email || email.trim() === '') {
|
|
42
|
+
// Email is optional
|
|
43
|
+
return { valid: true, errors: [] };
|
|
44
|
+
}
|
|
45
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
46
|
+
if (!emailRegex.test(email)) {
|
|
47
|
+
errors.push('Invalid email format');
|
|
48
|
+
}
|
|
49
|
+
return {
|
|
50
|
+
valid: errors.length === 0,
|
|
51
|
+
errors,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Validates a subscription tier.
|
|
56
|
+
*/
|
|
57
|
+
function validateSubscriptionTier(tier) {
|
|
58
|
+
const errors = [];
|
|
59
|
+
if (!tier || tier.trim() === '') {
|
|
60
|
+
// Tier is optional
|
|
61
|
+
return { valid: true, errors: [] };
|
|
62
|
+
}
|
|
63
|
+
const lowerTier = tier.toLowerCase();
|
|
64
|
+
if (!VALID_TIERS.includes(lowerTier)) {
|
|
65
|
+
errors.push(`Invalid subscription tier. Valid options: ${VALID_TIERS.join(', ')}`);
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
valid: errors.length === 0,
|
|
69
|
+
errors,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Validates a complete Revenium configuration.
|
|
74
|
+
*/
|
|
75
|
+
function validateConfig(config) {
|
|
76
|
+
const allErrors = [];
|
|
77
|
+
const apiKeyResult = validateApiKey(config.apiKey || '');
|
|
78
|
+
allErrors.push(...apiKeyResult.errors);
|
|
79
|
+
const emailResult = validateEmail(config.email || '');
|
|
80
|
+
allErrors.push(...emailResult.errors);
|
|
81
|
+
if (config.subscriptionTier) {
|
|
82
|
+
const tierResult = validateSubscriptionTier(config.subscriptionTier);
|
|
83
|
+
allErrors.push(...tierResult.errors);
|
|
84
|
+
}
|
|
85
|
+
if (!config.endpoint || config.endpoint.trim() === '') {
|
|
86
|
+
allErrors.push('Endpoint URL is required');
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
try {
|
|
90
|
+
new URL(config.endpoint);
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
allErrors.push('Invalid endpoint URL format');
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
valid: allErrors.length === 0,
|
|
98
|
+
errors: allErrors,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validator.js","sourceRoot":"","sources":["../../../src/core/config/validator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ReveniumConfig } from '../../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Writes the Revenium configuration to ~/.claude/revenium.env.
|
|
4
|
+
* Creates the directory if it doesn't exist and sets file permissions to 600.
|
|
5
|
+
*/
|
|
6
|
+
export declare function writeConfig(config: ReveniumConfig): Promise<string>;
|
|
7
|
+
/**
|
|
8
|
+
* Gets the path where the config file would be written.
|
|
9
|
+
*/
|
|
10
|
+
export declare function getConfigFilePath(): string;
|
|
11
|
+
//# sourceMappingURL=writer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"writer.d.ts","sourceRoot":"","sources":["../../../src/core/config/writer.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AA4H3D;;;GAGG;AACH,wBAAsB,WAAW,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAezE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C"}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.writeConfig = writeConfig;
|
|
4
|
+
exports.getConfigFilePath = getConfigFilePath;
|
|
5
|
+
const node_os_1 = require("node:os");
|
|
6
|
+
const node_path_1 = require("node:path");
|
|
7
|
+
const promises_1 = require("node:fs/promises");
|
|
8
|
+
const constants_js_1 = require("../../utils/constants.js");
|
|
9
|
+
const loader_js_1 = require("./loader.js");
|
|
10
|
+
/**
|
|
11
|
+
* Escapes a value for use in OTEL_RESOURCE_ATTRIBUTES.
|
|
12
|
+
* OTEL_RESOURCE_ATTRIBUTES uses comma as delimiter and equals as key-value separator.
|
|
13
|
+
* Characters that need escaping: comma (,), equals (=), and double-quote (").
|
|
14
|
+
* We URL-encode these characters to ensure safe parsing.
|
|
15
|
+
*/
|
|
16
|
+
function escapeResourceAttributeValue(value) {
|
|
17
|
+
return value
|
|
18
|
+
.replace(/%/g, '%25') // Escape % first to avoid double-encoding
|
|
19
|
+
.replace(/,/g, '%2C')
|
|
20
|
+
.replace(/=/g, '%3D')
|
|
21
|
+
.replace(/"/g, '%22');
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Gets the path to the Claude config directory.
|
|
25
|
+
*/
|
|
26
|
+
function getClaudeConfigDir() {
|
|
27
|
+
return (0, node_path_1.join)((0, node_os_1.homedir)(), constants_js_1.CLAUDE_CONFIG_DIR);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Generates the content for the revenium.env file.
|
|
31
|
+
*/
|
|
32
|
+
function generateEnvContent(config) {
|
|
33
|
+
const fullEndpoint = (0, loader_js_1.getFullOtlpEndpoint)(config.endpoint);
|
|
34
|
+
const lines = [
|
|
35
|
+
'# Revenium Claude Code Metering Configuration',
|
|
36
|
+
'# Generated by @revenium/claude-code-metering',
|
|
37
|
+
'#',
|
|
38
|
+
'# To load these variables, add to your shell profile:',
|
|
39
|
+
'# source ~/.claude/revenium.env',
|
|
40
|
+
'',
|
|
41
|
+
'# Enable Claude Code telemetry export',
|
|
42
|
+
`export ${constants_js_1.ENV_VARS.TELEMETRY_ENABLED}=1`,
|
|
43
|
+
'',
|
|
44
|
+
'# OTLP endpoint for Revenium metering',
|
|
45
|
+
`export ${constants_js_1.ENV_VARS.OTLP_ENDPOINT}=${fullEndpoint}`,
|
|
46
|
+
'',
|
|
47
|
+
'# Authentication header with API key',
|
|
48
|
+
`export ${constants_js_1.ENV_VARS.OTLP_HEADERS}="x-api-key=${config.apiKey}"`,
|
|
49
|
+
'',
|
|
50
|
+
'# OTLP protocol (required for Claude Code)',
|
|
51
|
+
`export ${constants_js_1.ENV_VARS.OTLP_PROTOCOL}=http/json`,
|
|
52
|
+
'',
|
|
53
|
+
'# Enable OTLP metrics exporter (required to send telemetry)',
|
|
54
|
+
'export OTEL_METRICS_EXPORTER=otlp',
|
|
55
|
+
];
|
|
56
|
+
// Add optional fields
|
|
57
|
+
if (config.email) {
|
|
58
|
+
lines.push('');
|
|
59
|
+
lines.push('# Subscriber email for attribution');
|
|
60
|
+
lines.push(`export ${constants_js_1.ENV_VARS.SUBSCRIBER_EMAIL}=${config.email}`);
|
|
61
|
+
}
|
|
62
|
+
if (config.subscriptionTier) {
|
|
63
|
+
const tier = config.subscriptionTier;
|
|
64
|
+
const costMultiplier = config.costMultiplierOverride ?? (0, constants_js_1.getCostMultiplier)(tier);
|
|
65
|
+
const discountPercent = Math.round((1 - costMultiplier) * 100);
|
|
66
|
+
lines.push('');
|
|
67
|
+
lines.push('# Claude Code subscription tier');
|
|
68
|
+
lines.push(`export ${constants_js_1.ENV_VARS.SUBSCRIPTION}=${config.subscriptionTier}`);
|
|
69
|
+
lines.push('');
|
|
70
|
+
lines.push('# Cost multiplier for subscription tier');
|
|
71
|
+
lines.push('# This adjusts Claude Code costs based on your subscription discount');
|
|
72
|
+
lines.push(`# ${tier}: ${discountPercent}% discount vs API rates`);
|
|
73
|
+
if (config.costMultiplierOverride !== undefined) {
|
|
74
|
+
lines.push('# (custom override applied)');
|
|
75
|
+
lines.push(`export ${constants_js_1.ENV_VARS.COST_MULTIPLIER}=${costMultiplier}`);
|
|
76
|
+
}
|
|
77
|
+
// Build OTEL_RESOURCE_ATTRIBUTES with cost_multiplier and optional fields
|
|
78
|
+
// Special characters (,=") in values are URL-encoded to ensure safe parsing
|
|
79
|
+
const resourceAttrs = [`cost_multiplier=${costMultiplier}`];
|
|
80
|
+
if (config.organizationId) {
|
|
81
|
+
resourceAttrs.push(`organization.id=${escapeResourceAttributeValue(config.organizationId)}`);
|
|
82
|
+
}
|
|
83
|
+
if (config.productId) {
|
|
84
|
+
resourceAttrs.push(`product.id=${escapeResourceAttributeValue(config.productId)}`);
|
|
85
|
+
}
|
|
86
|
+
lines.push(`export OTEL_RESOURCE_ATTRIBUTES="${resourceAttrs.join(',')}"`);
|
|
87
|
+
}
|
|
88
|
+
// Add advanced configuration section (commented out by default)
|
|
89
|
+
lines.push('');
|
|
90
|
+
lines.push('# ─────────────────────────────────────────────────────────────────────────────');
|
|
91
|
+
lines.push('# Advanced Configuration (Optional)');
|
|
92
|
+
lines.push('# ─────────────────────────────────────────────────────────────────────────────');
|
|
93
|
+
lines.push('#');
|
|
94
|
+
lines.push('# IMPORTANT: If you enable organization/product attribution below, you must also');
|
|
95
|
+
lines.push('# update OTEL_RESOURCE_ATTRIBUTES above to include them. For example:');
|
|
96
|
+
lines.push('# export OTEL_RESOURCE_ATTRIBUTES="cost_multiplier=0.08,organization.id=my-org,product.id=my-product"');
|
|
97
|
+
lines.push('# Otherwise, the telemetry sent to Revenium will not include the attribution data.');
|
|
98
|
+
lines.push('# Run `npx @revenium/claude-code-metering setup` again to regenerate this file with');
|
|
99
|
+
lines.push('# the correct OTEL_RESOURCE_ATTRIBUTES if you want automatic configuration.');
|
|
100
|
+
lines.push('#');
|
|
101
|
+
lines.push('# Organization ID: Attribute Claude Code costs to a specific customer or company.');
|
|
102
|
+
lines.push('# Use this when you want to track AI development costs by client/organization.');
|
|
103
|
+
lines.push('# Example: Your consulting firm tracks costs per client project.');
|
|
104
|
+
if (config.organizationId) {
|
|
105
|
+
lines.push(`export ${constants_js_1.ENV_VARS.ORGANIZATION_ID}=${config.organizationId}`);
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
lines.push(`# export ${constants_js_1.ENV_VARS.ORGANIZATION_ID}=your-organization-id`);
|
|
109
|
+
}
|
|
110
|
+
lines.push('#');
|
|
111
|
+
lines.push('# Product ID: Attribute Claude Code costs to a specific product or project.');
|
|
112
|
+
lines.push('# Use this when you want to track AI development costs by internal product.');
|
|
113
|
+
lines.push('# Example: Separate AI costs for "mobile-app" vs "backend-api" development.');
|
|
114
|
+
if (config.productId) {
|
|
115
|
+
lines.push(`export ${constants_js_1.ENV_VARS.PRODUCT_ID}=${config.productId}`);
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
lines.push(`# export ${constants_js_1.ENV_VARS.PRODUCT_ID}=your-product-id`);
|
|
119
|
+
}
|
|
120
|
+
lines.push('');
|
|
121
|
+
return lines.join('\n');
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Writes the Revenium configuration to ~/.claude/revenium.env.
|
|
125
|
+
* Creates the directory if it doesn't exist and sets file permissions to 600.
|
|
126
|
+
*/
|
|
127
|
+
async function writeConfig(config) {
|
|
128
|
+
const configDir = getClaudeConfigDir();
|
|
129
|
+
const configPath = (0, node_path_1.join)(configDir, constants_js_1.REVENIUM_ENV_FILE);
|
|
130
|
+
// Ensure the directory exists
|
|
131
|
+
await (0, promises_1.mkdir)(configDir, { recursive: true });
|
|
132
|
+
// Generate and write the content
|
|
133
|
+
const content = generateEnvContent(config);
|
|
134
|
+
await (0, promises_1.writeFile)(configPath, content, { encoding: 'utf-8' });
|
|
135
|
+
// Set restrictive permissions (owner read/write only)
|
|
136
|
+
await (0, promises_1.chmod)(configPath, constants_js_1.CONFIG_FILE_MODE);
|
|
137
|
+
return configPath;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Gets the path where the config file would be written.
|
|
141
|
+
*/
|
|
142
|
+
function getConfigFilePath() {
|
|
143
|
+
return (0, node_path_1.join)(getClaudeConfigDir(), constants_js_1.REVENIUM_ENV_FILE);
|
|
144
|
+
}
|
|
145
|
+
//# sourceMappingURL=writer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"writer.js","sourceRoot":"","sources":["../../../src/core/config/writer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ShellType } from '../../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Detects the current shell type based on environment variables.
|
|
4
|
+
*/
|
|
5
|
+
export declare function detectShell(): ShellType;
|
|
6
|
+
/**
|
|
7
|
+
* Gets the profile file path for a given shell type.
|
|
8
|
+
*/
|
|
9
|
+
export declare function getProfilePath(shellType: ShellType): string | null;
|
|
10
|
+
/**
|
|
11
|
+
* Generates the source command for a given shell type.
|
|
12
|
+
*/
|
|
13
|
+
export declare function getSourceCommand(shellType: ShellType, configPath: string): string;
|
|
14
|
+
//# sourceMappingURL=detector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detector.d.ts","sourceRoot":"","sources":["../../../src/core/shell/detector.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEtD;;GAEG;AACH,wBAAgB,WAAW,IAAI,SAAS,CA0BvC;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,SAAS,GAAG,MAAM,GAAG,IAAI,CAiBlE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CASjF"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.detectShell = detectShell;
|
|
4
|
+
exports.getProfilePath = getProfilePath;
|
|
5
|
+
exports.getSourceCommand = getSourceCommand;
|
|
6
|
+
const node_os_1 = require("node:os");
|
|
7
|
+
const node_path_1 = require("node:path");
|
|
8
|
+
const node_fs_1 = require("node:fs");
|
|
9
|
+
/**
|
|
10
|
+
* Detects the current shell type based on environment variables.
|
|
11
|
+
*/
|
|
12
|
+
function detectShell() {
|
|
13
|
+
const shell = process.env.SHELL || '';
|
|
14
|
+
if (shell.includes('zsh')) {
|
|
15
|
+
return 'zsh';
|
|
16
|
+
}
|
|
17
|
+
if (shell.includes('fish')) {
|
|
18
|
+
return 'fish';
|
|
19
|
+
}
|
|
20
|
+
if (shell.includes('bash')) {
|
|
21
|
+
return 'bash';
|
|
22
|
+
}
|
|
23
|
+
// Fallback: check for rc files
|
|
24
|
+
const home = (0, node_os_1.homedir)();
|
|
25
|
+
if ((0, node_fs_1.existsSync)((0, node_path_1.join)(home, '.zshrc'))) {
|
|
26
|
+
return 'zsh';
|
|
27
|
+
}
|
|
28
|
+
if ((0, node_fs_1.existsSync)((0, node_path_1.join)(home, '.config', 'fish', 'config.fish'))) {
|
|
29
|
+
return 'fish';
|
|
30
|
+
}
|
|
31
|
+
if ((0, node_fs_1.existsSync)((0, node_path_1.join)(home, '.bashrc'))) {
|
|
32
|
+
return 'bash';
|
|
33
|
+
}
|
|
34
|
+
return 'unknown';
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Gets the profile file path for a given shell type.
|
|
38
|
+
*/
|
|
39
|
+
function getProfilePath(shellType) {
|
|
40
|
+
const home = (0, node_os_1.homedir)();
|
|
41
|
+
switch (shellType) {
|
|
42
|
+
case 'zsh':
|
|
43
|
+
return (0, node_path_1.join)(home, '.zshrc');
|
|
44
|
+
case 'bash':
|
|
45
|
+
// Prefer .bashrc, fallback to .bash_profile
|
|
46
|
+
if ((0, node_fs_1.existsSync)((0, node_path_1.join)(home, '.bashrc'))) {
|
|
47
|
+
return (0, node_path_1.join)(home, '.bashrc');
|
|
48
|
+
}
|
|
49
|
+
return (0, node_path_1.join)(home, '.bash_profile');
|
|
50
|
+
case 'fish':
|
|
51
|
+
return (0, node_path_1.join)(home, '.config', 'fish', 'config.fish');
|
|
52
|
+
default:
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Generates the source command for a given shell type.
|
|
58
|
+
*/
|
|
59
|
+
function getSourceCommand(shellType, configPath) {
|
|
60
|
+
switch (shellType) {
|
|
61
|
+
case 'fish':
|
|
62
|
+
// Fish uses a different syntax for sourcing env files
|
|
63
|
+
return `# Source Revenium Claude Code metering config\nif test -f ${configPath}\n export (cat ${configPath} | grep -v '^#' | xargs -L 1)\nend`;
|
|
64
|
+
default:
|
|
65
|
+
// Bash and Zsh use the same syntax
|
|
66
|
+
return `# Source Revenium Claude Code metering config\nif [ -f "${configPath}" ]; then\n source "${configPath}"\nfi`;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=detector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detector.js","sourceRoot":"","sources":["../../../src/core/shell/detector.ts"],"names":[],"mappings":";;AAQA,kCA0BC;AAKD,wCAiBC;AAKD,4CASC;AAtED,qCAAkC;AAClC,yCAAiC;AACjC,qCAAqC;AAGrC;;GAEG;AACH,SAAgB,WAAW;IACzB,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC;IAEtC,IAAI,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QAC3B,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QAC3B,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,+BAA+B;IAC/B,MAAM,IAAI,GAAG,IAAA,iBAAO,GAAE,CAAC;IACvB,IAAI,IAAA,oBAAU,EAAC,IAAA,gBAAI,EAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,EAAE,CAAC;QACrC,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,IAAA,oBAAU,EAAC,IAAA,gBAAI,EAAC,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC;QAC7D,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,IAAI,IAAA,oBAAU,EAAC,IAAA,gBAAI,EAAC,IAAI,EAAE,SAAS,CAAC,CAAC,EAAE,CAAC;QACtC,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;GAEG;AACH,SAAgB,cAAc,CAAC,SAAoB;IACjD,MAAM,IAAI,GAAG,IAAA,iBAAO,GAAE,CAAC;IAEvB,QAAQ,SAAS,EAAE,CAAC;QAClB,KAAK,KAAK;YACR,OAAO,IAAA,gBAAI,EAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QAC9B,KAAK,MAAM;YACT,4CAA4C;YAC5C,IAAI,IAAA,oBAAU,EAAC,IAAA,gBAAI,EAAC,IAAI,EAAE,SAAS,CAAC,CAAC,EAAE,CAAC;gBACtC,OAAO,IAAA,gBAAI,EAAC,IAAI,EAAE,SAAS,CAAC,CAAC;YAC/B,CAAC;YACD,OAAO,IAAA,gBAAI,EAAC,IAAI,EAAE,eAAe,CAAC,CAAC;QACrC,KAAK,MAAM;YACT,OAAO,IAAA,gBAAI,EAAC,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,CAAC,CAAC;QACtD;YACE,OAAO,IAAI,CAAC;IAChB,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAgB,gBAAgB,CAAC,SAAoB,EAAE,UAAkB;IACvE,QAAQ,SAAS,EAAE,CAAC;QAClB,KAAK,MAAM;YACT,sDAAsD;YACtD,OAAO,6DAA6D,UAAU,qBAAqB,UAAU,oCAAoC,CAAC;QACpJ;YACE,mCAAmC;YACnC,OAAO,2DAA2D,UAAU,0BAA0B,UAAU,OAAO,CAAC;IAC5H,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ShellType, ShellUpdateResult } from '../../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Updates the shell profile to source the Revenium configuration file.
|
|
4
|
+
* Returns details about the update operation.
|
|
5
|
+
*/
|
|
6
|
+
export declare function updateShellProfile(): Promise<ShellUpdateResult>;
|
|
7
|
+
/**
|
|
8
|
+
* Gets instructions for manual shell profile configuration.
|
|
9
|
+
*/
|
|
10
|
+
export declare function getManualInstructions(shellType: ShellType): string;
|
|
11
|
+
//# sourceMappingURL=profile-updater.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"profile-updater.d.ts","sourceRoot":"","sources":["../../../src/core/shell/profile-updater.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AA6CzE;;;GAGG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,iBAAiB,CAAC,CAuDrE;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,SAAS,GAAG,MAAM,CAMlE"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.updateShellProfile = updateShellProfile;
|
|
4
|
+
exports.getManualInstructions = getManualInstructions;
|
|
5
|
+
const promises_1 = require("node:fs/promises");
|
|
6
|
+
const node_fs_1 = require("node:fs");
|
|
7
|
+
const detector_js_1 = require("./detector.js");
|
|
8
|
+
const writer_js_1 = require("../config/writer.js");
|
|
9
|
+
/** Marker comment to identify our configuration block */
|
|
10
|
+
const CONFIG_MARKER_START = '# >>> revenium-claude-code-metering >>>';
|
|
11
|
+
const CONFIG_MARKER_END = '# <<< revenium-claude-code-metering <<<';
|
|
12
|
+
/**
|
|
13
|
+
* Checks if the shell profile already has the Revenium source command.
|
|
14
|
+
*/
|
|
15
|
+
async function hasReveniumConfig(profilePath) {
|
|
16
|
+
if (!(0, node_fs_1.existsSync)(profilePath)) {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
const content = await (0, promises_1.readFile)(profilePath, 'utf-8');
|
|
20
|
+
return content.includes(CONFIG_MARKER_START);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Generates the complete configuration block for the shell profile.
|
|
24
|
+
*/
|
|
25
|
+
function generateConfigBlock(shellType, configPath) {
|
|
26
|
+
const sourceCmd = (0, detector_js_1.getSourceCommand)(shellType, configPath);
|
|
27
|
+
return `\n${CONFIG_MARKER_START}\n${sourceCmd}\n${CONFIG_MARKER_END}\n`;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Removes existing Revenium configuration from profile content.
|
|
31
|
+
*/
|
|
32
|
+
function removeExistingConfig(content) {
|
|
33
|
+
const startIndex = content.indexOf(CONFIG_MARKER_START);
|
|
34
|
+
const endIndex = content.indexOf(CONFIG_MARKER_END);
|
|
35
|
+
if (startIndex === -1 || endIndex === -1) {
|
|
36
|
+
return content;
|
|
37
|
+
}
|
|
38
|
+
const before = content.substring(0, startIndex).trimEnd();
|
|
39
|
+
const after = content.substring(endIndex + CONFIG_MARKER_END.length).trimStart();
|
|
40
|
+
return before + (after ? '\n' + after : '');
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Updates the shell profile to source the Revenium configuration file.
|
|
44
|
+
* Returns details about the update operation.
|
|
45
|
+
*/
|
|
46
|
+
async function updateShellProfile() {
|
|
47
|
+
const shellType = (0, detector_js_1.detectShell)();
|
|
48
|
+
if (shellType === 'unknown') {
|
|
49
|
+
return {
|
|
50
|
+
success: false,
|
|
51
|
+
shellType,
|
|
52
|
+
message: 'Could not detect shell type. Please manually add the source command to your shell profile.',
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
const profilePath = (0, detector_js_1.getProfilePath)(shellType);
|
|
56
|
+
if (!profilePath) {
|
|
57
|
+
return {
|
|
58
|
+
success: false,
|
|
59
|
+
shellType,
|
|
60
|
+
message: `Could not determine profile path for ${shellType}.`,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
const configPath = (0, writer_js_1.getConfigFilePath)();
|
|
64
|
+
// Check if already configured
|
|
65
|
+
if (await hasReveniumConfig(profilePath)) {
|
|
66
|
+
// Remove existing and re-add (in case config path changed)
|
|
67
|
+
let content = await (0, promises_1.readFile)(profilePath, 'utf-8');
|
|
68
|
+
content = removeExistingConfig(content);
|
|
69
|
+
const configBlock = generateConfigBlock(shellType, configPath);
|
|
70
|
+
await (0, promises_1.writeFile)(profilePath, content + configBlock, 'utf-8');
|
|
71
|
+
return {
|
|
72
|
+
success: true,
|
|
73
|
+
shellType,
|
|
74
|
+
profilePath,
|
|
75
|
+
message: `Updated existing configuration in ${profilePath}`,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
// Add new configuration
|
|
79
|
+
let content = '';
|
|
80
|
+
if ((0, node_fs_1.existsSync)(profilePath)) {
|
|
81
|
+
content = await (0, promises_1.readFile)(profilePath, 'utf-8');
|
|
82
|
+
}
|
|
83
|
+
const configBlock = generateConfigBlock(shellType, configPath);
|
|
84
|
+
await (0, promises_1.writeFile)(profilePath, content + configBlock, 'utf-8');
|
|
85
|
+
return {
|
|
86
|
+
success: true,
|
|
87
|
+
shellType,
|
|
88
|
+
profilePath,
|
|
89
|
+
message: `Added configuration to ${profilePath}`,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Gets instructions for manual shell profile configuration.
|
|
94
|
+
*/
|
|
95
|
+
function getManualInstructions(shellType) {
|
|
96
|
+
const configPath = (0, writer_js_1.getConfigFilePath)();
|
|
97
|
+
const sourceCmd = (0, detector_js_1.getSourceCommand)(shellType, configPath);
|
|
98
|
+
const profilePath = (0, detector_js_1.getProfilePath)(shellType);
|
|
99
|
+
return `Add the following to ${profilePath || 'your shell profile'}:\n\n${sourceCmd}`;
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=profile-updater.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"profile-updater.js","sourceRoot":"","sources":["../../../src/core/shell/profile-updater.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export * from './types/index.js';
|
|
2
|
+
export * from './utils/constants.js';
|
|
3
|
+
export * from './utils/masking.js';
|
|
4
|
+
export * from './core/config/loader.js';
|
|
5
|
+
export * from './core/config/writer.js';
|
|
6
|
+
export * from './core/config/validator.js';
|
|
7
|
+
export * from './core/api/client.js';
|
|
8
|
+
export * from './core/shell/detector.js';
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,yBAAyB,CAAC;AACxC,cAAc,yBAAyB,CAAC;AACxC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,sBAAsB,CAAC;AACrC,cAAc,0BAA0B,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
// Re-export types and utilities for programmatic use
|
|
18
|
+
__exportStar(require("./types/index.js"), exports);
|
|
19
|
+
__exportStar(require("./utils/constants.js"), exports);
|
|
20
|
+
__exportStar(require("./utils/masking.js"), exports);
|
|
21
|
+
__exportStar(require("./core/config/loader.js"), exports);
|
|
22
|
+
__exportStar(require("./core/config/writer.js"), exports);
|
|
23
|
+
__exportStar(require("./core/config/validator.js"), exports);
|
|
24
|
+
__exportStar(require("./core/api/client.js"), exports);
|
|
25
|
+
__exportStar(require("./core/shell/detector.js"), exports);
|
|
26
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,qDAAqD;AACrD,mDAAiC;AACjC,uDAAqC;AACrC,qDAAmC;AACnC,0DAAwC;AACxC,0DAAwC;AACxC,6DAA2C;AAC3C,uDAAqC;AACrC,2DAAyC"}
|