@skillrecordings/cli 0.3.0 → 0.4.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/dist/{chunk-MF3GI37W.js → chunk-TFLLCHUX.js} +23 -5
- package/dist/chunk-TFLLCHUX.js.map +1 -0
- package/dist/index.js +3 -3
- package/dist/{pipeline-F5FZCKB7.js → pipeline-DRKFIH73.js} +2 -2
- package/dist/preload.js +54 -1
- package/dist/preload.js.map +1 -1
- package/package.json +2 -1
- package/dist/chunk-MF3GI37W.js.map +0 -1
- /package/dist/{pipeline-F5FZCKB7.js.map → pipeline-DRKFIH73.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -35,7 +35,7 @@ import {
|
|
|
35
35
|
runPipeline,
|
|
36
36
|
validate,
|
|
37
37
|
validateSync
|
|
38
|
-
} from "./chunk-
|
|
38
|
+
} from "./chunk-TFLLCHUX.js";
|
|
39
39
|
import "./chunk-KEV3QKXP.js";
|
|
40
40
|
import "./chunk-HK3PEWFD.js";
|
|
41
41
|
import "./chunk-WYKL32C3.js";
|
|
@@ -79353,7 +79353,7 @@ async function runValidateEval(scenarios, options) {
|
|
|
79353
79353
|
return results;
|
|
79354
79354
|
}
|
|
79355
79355
|
async function runE2EEval(scenarios, options) {
|
|
79356
|
-
const { runPipeline: runPipeline2 } = await import("./pipeline-
|
|
79356
|
+
const { runPipeline: runPipeline2 } = await import("./pipeline-DRKFIH73.js");
|
|
79357
79357
|
const concurrency = options.parallel || 1;
|
|
79358
79358
|
let completed = 0;
|
|
79359
79359
|
if (options.realTools && options.verbose) {
|
|
@@ -111537,7 +111537,7 @@ function registerPipelineCommands(program3) {
|
|
|
111537
111537
|
await runE2EEval2(opts);
|
|
111538
111538
|
});
|
|
111539
111539
|
pipeline.command("run").description("Run pipeline on a single message").requiredOption("--subject <text>", "Message subject").requiredOption("--body <text>", "Message body").option("--app <id>", "App ID", "total-typescript").option("--dry-run", "Don't actually send", true).option("--json", "JSON output").action(async (opts) => {
|
|
111540
|
-
const { runPipeline: runPipeline2 } = await import("./pipeline-
|
|
111540
|
+
const { runPipeline: runPipeline2 } = await import("./pipeline-DRKFIH73.js");
|
|
111541
111541
|
const result = await runPipeline2({
|
|
111542
111542
|
message: {
|
|
111543
111543
|
subject: opts.subject,
|
|
@@ -53,7 +53,7 @@ import {
|
|
|
53
53
|
storeDraftSuccess,
|
|
54
54
|
validate,
|
|
55
55
|
validateSync
|
|
56
|
-
} from "./chunk-
|
|
56
|
+
} from "./chunk-TFLLCHUX.js";
|
|
57
57
|
import "./chunk-KEV3QKXP.js";
|
|
58
58
|
import "./chunk-HK3PEWFD.js";
|
|
59
59
|
import "./chunk-WYKL32C3.js";
|
|
@@ -117,4 +117,4 @@ export {
|
|
|
117
117
|
validate,
|
|
118
118
|
validateSync
|
|
119
119
|
};
|
|
120
|
-
//# sourceMappingURL=pipeline-
|
|
120
|
+
//# sourceMappingURL=pipeline-DRKFIH73.js.map
|
package/dist/preload.js
CHANGED
|
@@ -11,6 +11,18 @@ init_esm_shims();
|
|
|
11
11
|
import fs from "fs/promises";
|
|
12
12
|
import path from "path";
|
|
13
13
|
import { config } from "dotenv-flow";
|
|
14
|
+
|
|
15
|
+
// src/lib/crypto.ts
|
|
16
|
+
init_esm_shims();
|
|
17
|
+
import { Decrypter } from "age-encryption";
|
|
18
|
+
async function decrypt(encrypted, privateKey) {
|
|
19
|
+
const decrypter = new Decrypter();
|
|
20
|
+
decrypter.addIdentity(privateKey);
|
|
21
|
+
const input = encrypted instanceof Buffer ? new Uint8Array(encrypted) : encrypted;
|
|
22
|
+
return decrypter.decrypt(input, "text");
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// src/lib/env-loader.ts
|
|
14
26
|
async function loadSecrets(cliDirOverride) {
|
|
15
27
|
const cliDir2 = cliDirOverride ?? path.resolve(import.meta.dirname, "../..");
|
|
16
28
|
const localEnvExists = await checkLocalEnv(cliDir2);
|
|
@@ -18,8 +30,28 @@ async function loadSecrets(cliDirOverride) {
|
|
|
18
30
|
config({ path: cliDir2, silent: true });
|
|
19
31
|
return;
|
|
20
32
|
}
|
|
33
|
+
const encryptedPath = path.join(cliDir2, ".env.encrypted");
|
|
34
|
+
if (await fileExists(encryptedPath)) {
|
|
35
|
+
const privateKey = process.env.AGE_SECRET_KEY;
|
|
36
|
+
if (!privateKey) {
|
|
37
|
+
throw new Error(
|
|
38
|
+
'Found .env.encrypted but AGE_SECRET_KEY is not set.\n\nAdd to your shell profile (~/.zshrc):\n export AGE_SECRET_KEY="AGE-SECRET-KEY-1..."\n\nOr create .env.local in the CLI package directory to bypass encryption.'
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
try {
|
|
42
|
+
const encryptedData = await fs.readFile(encryptedPath);
|
|
43
|
+
const decrypted = await decrypt(encryptedData, privateKey);
|
|
44
|
+
parseAndInjectEnv(decrypted);
|
|
45
|
+
return;
|
|
46
|
+
} catch (error) {
|
|
47
|
+
throw new Error(
|
|
48
|
+
`Failed to decrypt .env.encrypted: ${error instanceof Error ? error.message : String(error)}
|
|
49
|
+
Check that AGE_SECRET_KEY matches the encryption key.`
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
21
53
|
throw new Error(
|
|
22
|
-
"No environment configuration found.\n\nOptions:\n1. Create .env.local in
|
|
54
|
+
"No environment configuration found.\n\nOptions:\n1. Set AGE_SECRET_KEY in your shell profile (for .env.encrypted)\n2. Create .env.local in the CLI package directory\n\nSee docs/CLI-AUTH.md for setup instructions."
|
|
23
55
|
);
|
|
24
56
|
}
|
|
25
57
|
async function checkLocalEnv(dir) {
|
|
@@ -39,6 +71,27 @@ async function fileExists(filePath) {
|
|
|
39
71
|
return false;
|
|
40
72
|
}
|
|
41
73
|
}
|
|
74
|
+
function parseAndInjectEnv(content) {
|
|
75
|
+
const lines = content.split("\n");
|
|
76
|
+
for (const line of lines) {
|
|
77
|
+
const trimmed = line.trim();
|
|
78
|
+
if (!trimmed || trimmed.startsWith("#")) {
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
const eqIndex = trimmed.indexOf("=");
|
|
82
|
+
if (eqIndex === -1) {
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
const key = trimmed.slice(0, eqIndex).trim();
|
|
86
|
+
let value = trimmed.slice(eqIndex + 1).trim();
|
|
87
|
+
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
88
|
+
value = value.slice(1, -1);
|
|
89
|
+
}
|
|
90
|
+
if (key && process.env[key] === void 0) {
|
|
91
|
+
process.env[key] = value;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
42
95
|
|
|
43
96
|
// preload.ts
|
|
44
97
|
var dirname = import.meta.dirname;
|
package/dist/preload.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../preload.ts","../src/lib/env-loader.ts"],"sourcesContent":["import path from 'node:path'\nimport { loadSecrets } from './src/lib/env-loader.js'\n\n// Calculate CLI package root - works for both dev (preload.ts) and bundled (dist/preload.js)\n// In dev: dirname is packages/cli, so '..' goes to packages, '../..' to root - wrong, we want '.'\n// In bundle: dirname is packages/cli/dist, so '..' goes to packages/cli - correct\n// Solution: check if we're in dist/ and adjust accordingly\nconst dirname = import.meta.dirname\nconst cliDir =\n dirname.endsWith('/dist') || dirname.endsWith('\\\\dist')\n ? path.resolve(dirname, '..')\n : dirname\n\n// Don't crash for commands that don't need secrets (--help, auth, etc.)\nconst noSecretsNeeded =\n process.argv.length <= 2 ||\n process.argv.some((a) =>\n ['--help', '-h', '--version', '-V', 'auth'].includes(a)\n )\n\ntry {\n await loadSecrets(cliDir)\n} catch (err) {\n if (noSecretsNeeded) {\n // Skip env validation so index.js can load without DATABASE_URL\n process.env.SKIP_ENV_VALIDATION = '1'\n } else {\n console.error(err instanceof Error ? err.message : String(err))\n process.exit(1)\n }\n}\n","import fs from 'node:fs/promises'\nimport path from 'node:path'\nimport { config } from 'dotenv-flow'\n\n/**\n * Load secrets from layered fallback:\n * 1. Local .env/.env.local files\n * 2. Fail with clear instructions\n *\n * Injects secrets into process.env\n *\n * @param cliDirOverride - Optional path to CLI package root (use when calling from bundled code)\n */\nexport async function loadSecrets(cliDirOverride?: string): Promise<void> {\n const cliDir = cliDirOverride ?? path.resolve(import.meta.dirname, '../..')\n\n // Layer 1: Check for local .env files\n const localEnvExists = await checkLocalEnv(cliDir)\n if (localEnvExists) {\n config({ path: cliDir, silent: true })\n return\n }\n\n // Layer 2:
|
|
1
|
+
{"version":3,"sources":["../preload.ts","../src/lib/env-loader.ts","../src/lib/crypto.ts"],"sourcesContent":["import path from 'node:path'\nimport { loadSecrets } from './src/lib/env-loader.js'\n\n// Calculate CLI package root - works for both dev (preload.ts) and bundled (dist/preload.js)\n// In dev: dirname is packages/cli, so '..' goes to packages, '../..' to root - wrong, we want '.'\n// In bundle: dirname is packages/cli/dist, so '..' goes to packages/cli - correct\n// Solution: check if we're in dist/ and adjust accordingly\nconst dirname = import.meta.dirname\nconst cliDir =\n dirname.endsWith('/dist') || dirname.endsWith('\\\\dist')\n ? path.resolve(dirname, '..')\n : dirname\n\n// Don't crash for commands that don't need secrets (--help, auth, etc.)\nconst noSecretsNeeded =\n process.argv.length <= 2 ||\n process.argv.some((a) =>\n ['--help', '-h', '--version', '-V', 'auth'].includes(a)\n )\n\ntry {\n await loadSecrets(cliDir)\n} catch (err) {\n if (noSecretsNeeded) {\n // Skip env validation so index.js can load without DATABASE_URL\n process.env.SKIP_ENV_VALIDATION = '1'\n } else {\n console.error(err instanceof Error ? err.message : String(err))\n process.exit(1)\n }\n}\n","import fs from 'node:fs/promises'\nimport path from 'node:path'\nimport { config } from 'dotenv-flow'\nimport { decrypt } from './crypto.js'\n\n/**\n * Load secrets from layered fallback:\n * 1. Local .env/.env.local files (dev override)\n * 2. Encrypted .env.encrypted + AGE_SECRET_KEY (npm installs)\n * 3. Fail with clear instructions\n *\n * Injects secrets into process.env\n *\n * @param cliDirOverride - Optional path to CLI package root (use when calling from bundled code)\n */\nexport async function loadSecrets(cliDirOverride?: string): Promise<void> {\n const cliDir = cliDirOverride ?? path.resolve(import.meta.dirname, '../..')\n\n // Layer 1: Check for local .env files (takes priority — dev workflow)\n const localEnvExists = await checkLocalEnv(cliDir)\n if (localEnvExists) {\n config({ path: cliDir, silent: true })\n return\n }\n\n // Layer 2: Decrypt .env.encrypted with AGE_SECRET_KEY\n const encryptedPath = path.join(cliDir, '.env.encrypted')\n if (await fileExists(encryptedPath)) {\n const privateKey = process.env.AGE_SECRET_KEY\n if (!privateKey) {\n throw new Error(\n 'Found .env.encrypted but AGE_SECRET_KEY is not set.\\n\\n' +\n 'Add to your shell profile (~/.zshrc):\\n' +\n ' export AGE_SECRET_KEY=\"AGE-SECRET-KEY-1...\"\\n\\n' +\n 'Or create .env.local in the CLI package directory to bypass encryption.'\n )\n }\n\n try {\n const encryptedData = await fs.readFile(encryptedPath)\n const decrypted = await decrypt(encryptedData, privateKey)\n parseAndInjectEnv(decrypted)\n return\n } catch (error) {\n throw new Error(\n `Failed to decrypt .env.encrypted: ${error instanceof Error ? error.message : String(error)}\\n` +\n 'Check that AGE_SECRET_KEY matches the encryption key.'\n )\n }\n }\n\n // Layer 3: Nothing found\n throw new Error(\n 'No environment configuration found.\\n\\n' +\n 'Options:\\n' +\n '1. Set AGE_SECRET_KEY in your shell profile (for .env.encrypted)\\n' +\n '2. Create .env.local in the CLI package directory\\n\\n' +\n 'See docs/CLI-AUTH.md for setup instructions.'\n )\n}\n\n/**\n * Check if any local .env files exist\n */\nasync function checkLocalEnv(dir: string): Promise<boolean> {\n const candidates = ['.env.local', '.env']\n for (const file of candidates) {\n if (await fileExists(path.join(dir, file))) {\n return true\n }\n }\n return false\n}\n\n/**\n * Check if a file exists\n */\nasync function fileExists(filePath: string): Promise<boolean> {\n try {\n await fs.access(filePath)\n return true\n } catch {\n return false\n }\n}\n\n/**\n * Parse env file format (KEY=VALUE) and inject into process.env\n * Handles quoted values, comments, and empty lines\n */\nfunction parseAndInjectEnv(content: string): void {\n const lines = content.split('\\n')\n\n for (const line of lines) {\n const trimmed = line.trim()\n\n // Skip comments and empty lines\n if (!trimmed || trimmed.startsWith('#')) {\n continue\n }\n\n const eqIndex = trimmed.indexOf('=')\n if (eqIndex === -1) {\n continue\n }\n\n const key = trimmed.slice(0, eqIndex).trim()\n let value = trimmed.slice(eqIndex + 1).trim()\n\n // Remove quotes if present\n if (\n (value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))\n ) {\n value = value.slice(1, -1)\n }\n\n // Only set if not already defined (respect existing env vars)\n if (key && process.env[key] === undefined) {\n process.env[key] = value\n }\n }\n}\n","import { Decrypter } from 'age-encryption'\n\n/**\n * Decrypt data with an age private key\n * @param encrypted - Encrypted data as Uint8Array or Buffer\n * @param privateKey - age private key (AGE-SECRET-KEY-1...)\n * @returns Decrypted data as string\n */\nexport async function decrypt(\n encrypted: Uint8Array | Buffer,\n privateKey: string\n): Promise<string> {\n const decrypter = new Decrypter()\n decrypter.addIdentity(privateKey)\n\n const input =\n encrypted instanceof Buffer ? new Uint8Array(encrypted) : encrypted\n return decrypter.decrypt(input, 'text')\n}\n"],"mappings":"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","names":["path","cliDir","path"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@skillrecordings/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"skill": "./bin/skill.mjs"
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"@axiomhq/js": "^1.3.1",
|
|
28
28
|
"@inquirer/prompts": "^8.2.0",
|
|
29
|
+
"age-encryption": "^0.3.0",
|
|
29
30
|
"ai": "^6.0.49",
|
|
30
31
|
"commander": "^12.1.0",
|
|
31
32
|
"dotenv-flow": "^4.1.0",
|