@ezlkg/shn 1.0.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/commands/logs.d.ts +5 -0
- package/dist/commands/logs.d.ts.map +1 -0
- package/dist/commands/logs.js +53 -0
- package/dist/commands/logs.js.map +1 -0
- package/dist/commands/start.d.ts +14 -0
- package/dist/commands/start.d.ts.map +1 -0
- package/dist/commands/start.js +146 -0
- package/dist/commands/start.js.map +1 -0
- package/dist/commands/status.d.ts +5 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +23 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/stop.d.ts +5 -0
- package/dist/commands/stop.d.ts.map +1 -0
- package/dist/commands/stop.js +9 -0
- package/dist/commands/stop.js.map +1 -0
- package/dist/commands/update.d.ts +5 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +9 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/commands/workspaces.d.ts +5 -0
- package/dist/commands/workspaces.d.ts.map +1 -0
- package/dist/commands/workspaces.js +19 -0
- package/dist/commands/workspaces.js.map +1 -0
- package/dist/docker.d.ts +58 -0
- package/dist/docker.d.ts.map +1 -0
- package/dist/docker.js +159 -0
- package/dist/docker.js.map +1 -0
- package/dist/env.d.ts +26 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +119 -0
- package/dist/env.js.map +1 -0
- package/dist/home.d.ts +16 -0
- package/dist/home.d.ts.map +1 -0
- package/dist/home.js +52 -0
- package/dist/home.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +167 -0
- package/dist/index.js.map +1 -0
- package/dist/paths.d.ts +25 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +57 -0
- package/dist/paths.js.map +1 -0
- package/dist/splash.d.ts +5 -0
- package/dist/splash.d.ts.map +1 -0
- package/dist/splash.js +38 -0
- package/dist/splash.js.map +1 -0
- package/infra/compose.yml +50 -0
- package/infra/router-config.json +33 -0
- package/package.json +42 -0
package/dist/env.js
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Environment variable loading and credential validation.
|
|
3
|
+
*
|
|
4
|
+
* Loads ~/.shannon/.env and validates that at least one authentication
|
|
5
|
+
* method is configured (API key, OAuth, Bedrock, Vertex, or router).
|
|
6
|
+
*/
|
|
7
|
+
import dotenv from 'dotenv';
|
|
8
|
+
import { getEnvFile } from './home.js';
|
|
9
|
+
/** Environment variables forwarded to worker containers. */
|
|
10
|
+
const FORWARD_VARS = [
|
|
11
|
+
'ANTHROPIC_API_KEY',
|
|
12
|
+
'ANTHROPIC_BASE_URL',
|
|
13
|
+
'ANTHROPIC_AUTH_TOKEN',
|
|
14
|
+
'ROUTER_DEFAULT',
|
|
15
|
+
'CLAUDE_CODE_OAUTH_TOKEN',
|
|
16
|
+
'CLAUDE_CODE_USE_BEDROCK',
|
|
17
|
+
'AWS_REGION',
|
|
18
|
+
'AWS_BEARER_TOKEN_BEDROCK',
|
|
19
|
+
'CLAUDE_CODE_USE_VERTEX',
|
|
20
|
+
'CLOUD_ML_REGION',
|
|
21
|
+
'ANTHROPIC_VERTEX_PROJECT_ID',
|
|
22
|
+
'GOOGLE_APPLICATION_CREDENTIALS',
|
|
23
|
+
'ANTHROPIC_SMALL_MODEL',
|
|
24
|
+
'ANTHROPIC_MEDIUM_MODEL',
|
|
25
|
+
'ANTHROPIC_LARGE_MODEL',
|
|
26
|
+
'CLAUDE_CODE_MAX_OUTPUT_TOKENS',
|
|
27
|
+
];
|
|
28
|
+
/**
|
|
29
|
+
* Load ~/.shannon/.env into process.env.
|
|
30
|
+
* Existing env vars take precedence (standard dotenv behavior).
|
|
31
|
+
*/
|
|
32
|
+
export function loadEnv() {
|
|
33
|
+
dotenv.config({ path: getEnvFile() });
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Build `-e KEY=VALUE` flags for docker run, only for set variables.
|
|
37
|
+
*/
|
|
38
|
+
export function buildEnvFlags() {
|
|
39
|
+
const flags = ['-e', 'TEMPORAL_ADDRESS=shannon-temporal:7233'];
|
|
40
|
+
for (const key of FORWARD_VARS) {
|
|
41
|
+
const value = process.env[key];
|
|
42
|
+
if (value) {
|
|
43
|
+
flags.push('-e', `${key}=${value}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return flags;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Validate that at least one authentication method is configured.
|
|
50
|
+
*/
|
|
51
|
+
export function validateCredentials(useRouter) {
|
|
52
|
+
if (process.env.ANTHROPIC_API_KEY) {
|
|
53
|
+
return { valid: true, mode: 'api-key' };
|
|
54
|
+
}
|
|
55
|
+
if (process.env.CLAUDE_CODE_OAUTH_TOKEN) {
|
|
56
|
+
return { valid: true, mode: 'oauth' };
|
|
57
|
+
}
|
|
58
|
+
if (process.env.CLAUDE_CODE_USE_BEDROCK === '1') {
|
|
59
|
+
const missing = [];
|
|
60
|
+
if (!process.env.AWS_REGION)
|
|
61
|
+
missing.push('AWS_REGION');
|
|
62
|
+
if (!process.env.AWS_BEARER_TOKEN_BEDROCK)
|
|
63
|
+
missing.push('AWS_BEARER_TOKEN_BEDROCK');
|
|
64
|
+
if (!process.env.ANTHROPIC_SMALL_MODEL)
|
|
65
|
+
missing.push('ANTHROPIC_SMALL_MODEL');
|
|
66
|
+
if (!process.env.ANTHROPIC_MEDIUM_MODEL)
|
|
67
|
+
missing.push('ANTHROPIC_MEDIUM_MODEL');
|
|
68
|
+
if (!process.env.ANTHROPIC_LARGE_MODEL)
|
|
69
|
+
missing.push('ANTHROPIC_LARGE_MODEL');
|
|
70
|
+
if (missing.length > 0) {
|
|
71
|
+
return {
|
|
72
|
+
valid: false,
|
|
73
|
+
mode: 'bedrock',
|
|
74
|
+
error: `Bedrock mode requires: ${missing.join(', ')}`,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
return { valid: true, mode: 'bedrock' };
|
|
78
|
+
}
|
|
79
|
+
if (process.env.CLAUDE_CODE_USE_VERTEX === '1') {
|
|
80
|
+
const missing = [];
|
|
81
|
+
if (!process.env.CLOUD_ML_REGION)
|
|
82
|
+
missing.push('CLOUD_ML_REGION');
|
|
83
|
+
if (!process.env.ANTHROPIC_VERTEX_PROJECT_ID)
|
|
84
|
+
missing.push('ANTHROPIC_VERTEX_PROJECT_ID');
|
|
85
|
+
if (!process.env.ANTHROPIC_SMALL_MODEL)
|
|
86
|
+
missing.push('ANTHROPIC_SMALL_MODEL');
|
|
87
|
+
if (!process.env.ANTHROPIC_MEDIUM_MODEL)
|
|
88
|
+
missing.push('ANTHROPIC_MEDIUM_MODEL');
|
|
89
|
+
if (!process.env.ANTHROPIC_LARGE_MODEL)
|
|
90
|
+
missing.push('ANTHROPIC_LARGE_MODEL');
|
|
91
|
+
if (missing.length > 0) {
|
|
92
|
+
return {
|
|
93
|
+
valid: false,
|
|
94
|
+
mode: 'vertex',
|
|
95
|
+
error: `Vertex AI mode requires: ${missing.join(', ')}`,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
if (!process.env.GOOGLE_APPLICATION_CREDENTIALS) {
|
|
99
|
+
return {
|
|
100
|
+
valid: false,
|
|
101
|
+
mode: 'vertex',
|
|
102
|
+
error: 'Vertex AI mode requires GOOGLE_APPLICATION_CREDENTIALS',
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
return { valid: true, mode: 'vertex' };
|
|
106
|
+
}
|
|
107
|
+
if (useRouter && (process.env.OPENAI_API_KEY || process.env.OPENROUTER_API_KEY)) {
|
|
108
|
+
// Set a placeholder so the worker doesn't reject the missing key
|
|
109
|
+
process.env.ANTHROPIC_API_KEY = 'router-mode';
|
|
110
|
+
return { valid: true, mode: 'router' };
|
|
111
|
+
}
|
|
112
|
+
return {
|
|
113
|
+
valid: false,
|
|
114
|
+
mode: 'api-key',
|
|
115
|
+
error: 'No credentials found. Set ANTHROPIC_API_KEY in ~/.shannon/.env\n' +
|
|
116
|
+
' (or use CLAUDE_CODE_OAUTH_TOKEN, CLAUDE_CODE_USE_BEDROCK=1, CLAUDE_CODE_USE_VERTEX=1)',
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=env.js.map
|
package/dist/env.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.js","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"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"}
|
package/dist/home.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shannon home directory management (~/.shannon/).
|
|
3
|
+
*
|
|
4
|
+
* Handles initialization, directory creation, and permission checks
|
|
5
|
+
* for the global state directory used by the npx CLI.
|
|
6
|
+
*/
|
|
7
|
+
export declare function getHome(): string;
|
|
8
|
+
export declare function getWorkspacesDir(): string;
|
|
9
|
+
export declare function getEnvFile(): string;
|
|
10
|
+
export declare function getCredentialsPath(): string;
|
|
11
|
+
/**
|
|
12
|
+
* Initialize ~/.shannon/ directory structure.
|
|
13
|
+
* Creates directories if missing, warns on overly permissive permissions.
|
|
14
|
+
*/
|
|
15
|
+
export declare function initHome(): void;
|
|
16
|
+
//# sourceMappingURL=home.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"home.d.ts","sourceRoot":"","sources":["../src/home.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAWH,wBAAgB,OAAO,IAAI,MAAM,CAEhC;AAED,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAED,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAED;;;GAGG;AACH,wBAAgB,QAAQ,IAAI,IAAI,CAO/B"}
|
package/dist/home.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shannon home directory management (~/.shannon/).
|
|
3
|
+
*
|
|
4
|
+
* Handles initialization, directory creation, and permission checks
|
|
5
|
+
* for the global state directory used by the npx CLI.
|
|
6
|
+
*/
|
|
7
|
+
import fs from 'node:fs';
|
|
8
|
+
import path from 'node:path';
|
|
9
|
+
import os from 'node:os';
|
|
10
|
+
const SHANNON_HOME = path.join(os.homedir(), '.shannon');
|
|
11
|
+
const WORKSPACES_DIR = path.join(SHANNON_HOME, 'workspaces');
|
|
12
|
+
const ENV_FILE = path.join(SHANNON_HOME, '.env');
|
|
13
|
+
const CREDENTIALS_DIR = SHANNON_HOME;
|
|
14
|
+
export function getHome() {
|
|
15
|
+
return SHANNON_HOME;
|
|
16
|
+
}
|
|
17
|
+
export function getWorkspacesDir() {
|
|
18
|
+
return WORKSPACES_DIR;
|
|
19
|
+
}
|
|
20
|
+
export function getEnvFile() {
|
|
21
|
+
return ENV_FILE;
|
|
22
|
+
}
|
|
23
|
+
export function getCredentialsPath() {
|
|
24
|
+
return path.join(CREDENTIALS_DIR, 'google-sa-vertex-key.json');
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Initialize ~/.shannon/ directory structure.
|
|
28
|
+
* Creates directories if missing, warns on overly permissive permissions.
|
|
29
|
+
*/
|
|
30
|
+
export function initHome() {
|
|
31
|
+
// 1. Create directories
|
|
32
|
+
fs.mkdirSync(WORKSPACES_DIR, { recursive: true, mode: 0o700 });
|
|
33
|
+
// 2. Check permissions on sensitive files
|
|
34
|
+
checkPermissions(ENV_FILE, 0o600, '.env (contains API keys)');
|
|
35
|
+
checkPermissions(getCredentialsPath(), 0o600, 'GCP service account key');
|
|
36
|
+
}
|
|
37
|
+
function checkPermissions(filePath, expectedMode, label) {
|
|
38
|
+
try {
|
|
39
|
+
const stats = fs.statSync(filePath);
|
|
40
|
+
const actualMode = stats.mode & 0o777;
|
|
41
|
+
if (actualMode > expectedMode) {
|
|
42
|
+
const actual = '0' + actualMode.toString(8);
|
|
43
|
+
const expected = '0' + expectedMode.toString(8);
|
|
44
|
+
console.warn(`WARNING: ${label} has permissions ${actual}, expected ${expected} or stricter.`);
|
|
45
|
+
console.warn(` Fix with: chmod ${expected} ${filePath}`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
// File doesn't exist yet — that's fine
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=home.js.map
|
package/dist/home.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"home.js","sourceRoot":"","sources":["../src/home.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,SAAS,CAAC;AAEzB,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,UAAU,CAAC,CAAC;AACzD,MAAM,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC;AAC7D,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;AACjD,MAAM,eAAe,GAAG,YAAY,CAAC;AAErC,MAAM,UAAU,OAAO;IACrB,OAAO,YAAY,CAAC;AACtB,CAAC;AAED,MAAM,UAAU,gBAAgB;IAC9B,OAAO,cAAc,CAAC;AACxB,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,kBAAkB;IAChC,OAAO,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,2BAA2B,CAAC,CAAC;AACjE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,QAAQ;IACtB,wBAAwB;IACxB,EAAE,CAAC,SAAS,CAAC,cAAc,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAE/D,0CAA0C;IAC1C,gBAAgB,CAAC,QAAQ,EAAE,KAAK,EAAE,0BAA0B,CAAC,CAAC;IAC9D,gBAAgB,CAAC,kBAAkB,EAAE,EAAE,KAAK,EAAE,yBAAyB,CAAC,CAAC;AAC3E,CAAC;AAED,SAAS,gBAAgB,CAAC,QAAgB,EAAE,YAAoB,EAAE,KAAa;IAC7E,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACpC,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,GAAG,KAAK,CAAC;QACtC,IAAI,UAAU,GAAG,YAAY,EAAE,CAAC;YAC9B,MAAM,MAAM,GAAG,GAAG,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;YAC5C,MAAM,QAAQ,GAAG,GAAG,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;YAChD,OAAO,CAAC,IAAI,CACV,YAAY,KAAK,oBAAoB,MAAM,cAAc,QAAQ,eAAe,CACjF,CAAC;YACF,OAAO,CAAC,IAAI,CAAC,qBAAqB,QAAQ,IAAI,QAAQ,EAAE,CAAC,CAAC;QAC5D,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,uCAAuC;IACzC,CAAC;AACH,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Shannon CLI — AI Penetration Testing Framework
|
|
4
|
+
*
|
|
5
|
+
* Zero-install CLI that orchestrates Docker containers for security scans.
|
|
6
|
+
* Uses pre-built images from Docker Hub and stores state in ~/.shannon/.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* npx @ezlkg/shn start --url <url> --repo <path> [options]
|
|
10
|
+
* npx @ezlkg/shn stop [--clean]
|
|
11
|
+
* npx @ezlkg/shn workspaces
|
|
12
|
+
* npx @ezlkg/shn logs <workspace>
|
|
13
|
+
* npx @ezlkg/shn status
|
|
14
|
+
* npx @ezlkg/shn update
|
|
15
|
+
*/
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;;;GAaG"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Shannon CLI — AI Penetration Testing Framework
|
|
4
|
+
*
|
|
5
|
+
* Zero-install CLI that orchestrates Docker containers for security scans.
|
|
6
|
+
* Uses pre-built images from Docker Hub and stores state in ~/.shannon/.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* npx @ezlkg/shn start --url <url> --repo <path> [options]
|
|
10
|
+
* npx @ezlkg/shn stop [--clean]
|
|
11
|
+
* npx @ezlkg/shn workspaces
|
|
12
|
+
* npx @ezlkg/shn logs <workspace>
|
|
13
|
+
* npx @ezlkg/shn status
|
|
14
|
+
* npx @ezlkg/shn update
|
|
15
|
+
*/
|
|
16
|
+
import fs from 'node:fs';
|
|
17
|
+
import path from 'node:path';
|
|
18
|
+
import { fileURLToPath } from 'node:url';
|
|
19
|
+
import { start } from './commands/start.js';
|
|
20
|
+
import { stop } from './commands/stop.js';
|
|
21
|
+
import { logs } from './commands/logs.js';
|
|
22
|
+
import { workspaces } from './commands/workspaces.js';
|
|
23
|
+
import { status } from './commands/status.js';
|
|
24
|
+
import { update } from './commands/update.js';
|
|
25
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
26
|
+
function getVersion() {
|
|
27
|
+
try {
|
|
28
|
+
const pkgPath = path.join(__dirname, '..', 'package.json');
|
|
29
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
|
|
30
|
+
return pkg.version || '1.0.0';
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return '1.0.0';
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function showHelp() {
|
|
37
|
+
console.log(`
|
|
38
|
+
Shannon - AI Penetration Testing Framework
|
|
39
|
+
|
|
40
|
+
Usage:
|
|
41
|
+
shannon start --url <url> --repo <path> [options] Start a pentest scan
|
|
42
|
+
shannon stop [--clean] Stop all containers
|
|
43
|
+
shannon workspaces List all workspaces
|
|
44
|
+
shannon logs <workspace> Tail workflow log
|
|
45
|
+
shannon status Show running workers
|
|
46
|
+
shannon update Pull latest image
|
|
47
|
+
shannon help Show this help
|
|
48
|
+
|
|
49
|
+
Options for 'start':
|
|
50
|
+
-u, --url <url> Target URL (required)
|
|
51
|
+
-r, --repo <path> Repository path (required)
|
|
52
|
+
-c, --config <path> Configuration file (YAML)
|
|
53
|
+
-w, --workspace <name> Named workspace (auto-resumes if exists)
|
|
54
|
+
--pipeline-testing Use minimal prompts for fast testing
|
|
55
|
+
--router Route requests through claude-code-router
|
|
56
|
+
|
|
57
|
+
Examples:
|
|
58
|
+
npx @ezlkg/shn start -u https://example.com -r ./my-repo
|
|
59
|
+
npx @ezlkg/shn start -u https://example.com -r /path/to/repo -c config.yaml -w q1-audit
|
|
60
|
+
npx @ezlkg/shn logs q1-audit
|
|
61
|
+
npx @ezlkg/shn stop --clean
|
|
62
|
+
|
|
63
|
+
State directory: ~/.shannon/
|
|
64
|
+
Monitor workflows at http://localhost:8233
|
|
65
|
+
`);
|
|
66
|
+
}
|
|
67
|
+
function parseStartArgs(argv) {
|
|
68
|
+
let url = '';
|
|
69
|
+
let repo = '';
|
|
70
|
+
let config;
|
|
71
|
+
let workspace;
|
|
72
|
+
let pipelineTesting = false;
|
|
73
|
+
let router = false;
|
|
74
|
+
for (let i = 0; i < argv.length; i++) {
|
|
75
|
+
const arg = argv[i];
|
|
76
|
+
const next = argv[i + 1];
|
|
77
|
+
switch (arg) {
|
|
78
|
+
case '-u':
|
|
79
|
+
case '--url':
|
|
80
|
+
if (next && !next.startsWith('-')) {
|
|
81
|
+
url = next;
|
|
82
|
+
i++;
|
|
83
|
+
}
|
|
84
|
+
break;
|
|
85
|
+
case '-r':
|
|
86
|
+
case '--repo':
|
|
87
|
+
if (next && !next.startsWith('-')) {
|
|
88
|
+
repo = next;
|
|
89
|
+
i++;
|
|
90
|
+
}
|
|
91
|
+
break;
|
|
92
|
+
case '-c':
|
|
93
|
+
case '--config':
|
|
94
|
+
if (next && !next.startsWith('-')) {
|
|
95
|
+
config = next;
|
|
96
|
+
i++;
|
|
97
|
+
}
|
|
98
|
+
break;
|
|
99
|
+
case '-w':
|
|
100
|
+
case '--workspace':
|
|
101
|
+
if (next && !next.startsWith('-')) {
|
|
102
|
+
workspace = next;
|
|
103
|
+
i++;
|
|
104
|
+
}
|
|
105
|
+
break;
|
|
106
|
+
case '--pipeline-testing':
|
|
107
|
+
pipelineTesting = true;
|
|
108
|
+
break;
|
|
109
|
+
case '--router':
|
|
110
|
+
router = true;
|
|
111
|
+
break;
|
|
112
|
+
default:
|
|
113
|
+
console.error(`Unknown option: ${arg}`);
|
|
114
|
+
console.error('Run "shannon help" for usage');
|
|
115
|
+
process.exit(1);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
if (!url || !repo) {
|
|
119
|
+
console.error('ERROR: --url and --repo are required');
|
|
120
|
+
console.error('Usage: shannon start -u <url> -r <path>');
|
|
121
|
+
process.exit(1);
|
|
122
|
+
}
|
|
123
|
+
return { url, repo, pipelineTesting, router, ...(config && { config }), ...(workspace && { workspace }) };
|
|
124
|
+
}
|
|
125
|
+
// === Main Dispatch ===
|
|
126
|
+
const args = process.argv.slice(2);
|
|
127
|
+
const command = args[0];
|
|
128
|
+
switch (command) {
|
|
129
|
+
case 'start': {
|
|
130
|
+
const parsed = parseStartArgs(args.slice(1));
|
|
131
|
+
start({ ...parsed, version: getVersion() });
|
|
132
|
+
break;
|
|
133
|
+
}
|
|
134
|
+
case 'stop':
|
|
135
|
+
stop(args.includes('--clean'));
|
|
136
|
+
break;
|
|
137
|
+
case 'logs': {
|
|
138
|
+
const workspaceId = args[1];
|
|
139
|
+
if (!workspaceId) {
|
|
140
|
+
console.error('ERROR: Workspace ID is required');
|
|
141
|
+
console.error('Usage: shannon logs <workspace>');
|
|
142
|
+
process.exit(1);
|
|
143
|
+
}
|
|
144
|
+
logs(workspaceId);
|
|
145
|
+
break;
|
|
146
|
+
}
|
|
147
|
+
case 'workspaces':
|
|
148
|
+
workspaces();
|
|
149
|
+
break;
|
|
150
|
+
case 'status':
|
|
151
|
+
status();
|
|
152
|
+
break;
|
|
153
|
+
case 'update':
|
|
154
|
+
update();
|
|
155
|
+
break;
|
|
156
|
+
case 'help':
|
|
157
|
+
case '--help':
|
|
158
|
+
case '-h':
|
|
159
|
+
case undefined:
|
|
160
|
+
showHelp();
|
|
161
|
+
break;
|
|
162
|
+
default:
|
|
163
|
+
console.error(`Unknown command: ${command}`);
|
|
164
|
+
showHelp();
|
|
165
|
+
process.exit(1);
|
|
166
|
+
}
|
|
167
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/paths.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Path resolution for --repo and --config arguments.
|
|
3
|
+
*
|
|
4
|
+
* Resolves user-provided paths to absolute host paths and generates
|
|
5
|
+
* corresponding container mount paths.
|
|
6
|
+
*/
|
|
7
|
+
export interface MountPair {
|
|
8
|
+
hostPath: string;
|
|
9
|
+
containerPath: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Resolve --repo to absolute path and container mount.
|
|
13
|
+
* Unlike the bash CLI, there is no ./repos/ convention — all paths
|
|
14
|
+
* are resolved against CWD.
|
|
15
|
+
*/
|
|
16
|
+
export declare function resolveRepo(repoArg: string): MountPair;
|
|
17
|
+
/**
|
|
18
|
+
* Resolve --config to absolute path and container mount.
|
|
19
|
+
*/
|
|
20
|
+
export declare function resolveConfig(configArg: string): MountPair;
|
|
21
|
+
/**
|
|
22
|
+
* Ensure the deliverables directory exists and is writable by the container user.
|
|
23
|
+
*/
|
|
24
|
+
export declare function ensureDeliverables(repoHostPath: string): void;
|
|
25
|
+
//# sourceMappingURL=paths.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAkBtD;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,CAkB1D;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAI7D"}
|
package/dist/paths.js
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Path resolution for --repo and --config arguments.
|
|
3
|
+
*
|
|
4
|
+
* Resolves user-provided paths to absolute host paths and generates
|
|
5
|
+
* corresponding container mount paths.
|
|
6
|
+
*/
|
|
7
|
+
import fs from 'node:fs';
|
|
8
|
+
import path from 'node:path';
|
|
9
|
+
/**
|
|
10
|
+
* Resolve --repo to absolute path and container mount.
|
|
11
|
+
* Unlike the bash CLI, there is no ./repos/ convention — all paths
|
|
12
|
+
* are resolved against CWD.
|
|
13
|
+
*/
|
|
14
|
+
export function resolveRepo(repoArg) {
|
|
15
|
+
const hostPath = path.resolve(repoArg);
|
|
16
|
+
if (!fs.existsSync(hostPath)) {
|
|
17
|
+
console.error(`ERROR: Repository not found: ${hostPath}`);
|
|
18
|
+
process.exit(1);
|
|
19
|
+
}
|
|
20
|
+
if (!fs.statSync(hostPath).isDirectory()) {
|
|
21
|
+
console.error(`ERROR: Not a directory: ${hostPath}`);
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
const basename = path.basename(hostPath);
|
|
25
|
+
return {
|
|
26
|
+
hostPath,
|
|
27
|
+
containerPath: `/repos/${basename}`,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Resolve --config to absolute path and container mount.
|
|
32
|
+
*/
|
|
33
|
+
export function resolveConfig(configArg) {
|
|
34
|
+
const hostPath = path.resolve(configArg);
|
|
35
|
+
if (!fs.existsSync(hostPath)) {
|
|
36
|
+
console.error(`ERROR: Config file not found: ${hostPath}`);
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
if (!fs.statSync(hostPath).isFile()) {
|
|
40
|
+
console.error(`ERROR: Not a file: ${hostPath}`);
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
const basename = path.basename(hostPath);
|
|
44
|
+
return {
|
|
45
|
+
hostPath,
|
|
46
|
+
containerPath: `/app/configs/${basename}`,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Ensure the deliverables directory exists and is writable by the container user.
|
|
51
|
+
*/
|
|
52
|
+
export function ensureDeliverables(repoHostPath) {
|
|
53
|
+
const deliverables = path.join(repoHostPath, 'deliverables');
|
|
54
|
+
fs.mkdirSync(deliverables, { recursive: true });
|
|
55
|
+
fs.chmodSync(deliverables, 0o777);
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAO7B;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAAC,OAAe;IACzC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAEvC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC7B,OAAO,CAAC,KAAK,CAAC,gCAAgC,QAAQ,EAAE,CAAC,CAAC;QAC1D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;QACzC,OAAO,CAAC,KAAK,CAAC,2BAA2B,QAAQ,EAAE,CAAC,CAAC;QACrD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACzC,OAAO;QACL,QAAQ;QACR,aAAa,EAAE,UAAU,QAAQ,EAAE;KACpC,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,SAAiB;IAC7C,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAEzC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC7B,OAAO,CAAC,KAAK,CAAC,iCAAiC,QAAQ,EAAE,CAAC,CAAC;QAC3D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC;QACpC,OAAO,CAAC,KAAK,CAAC,sBAAsB,QAAQ,EAAE,CAAC,CAAC;QAChD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACzC,OAAO;QACL,QAAQ;QACR,aAAa,EAAE,gBAAgB,QAAQ,EAAE;KAC1C,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,YAAoB;IACrD,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,cAAc,CAAC,CAAC;IAC7D,EAAE,CAAC,SAAS,CAAC,YAAY,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAChD,EAAE,CAAC,SAAS,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC;AACpC,CAAC"}
|
package/dist/splash.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"splash.d.ts","sourceRoot":"","sources":["../src/splash.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CA4CnD"}
|
package/dist/splash.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Splash screen display — pure terminal output, no npm dependencies.
|
|
3
|
+
*/
|
|
4
|
+
export function displaySplash(version) {
|
|
5
|
+
const GOLD = '\x1b[38;2;244;197;66m';
|
|
6
|
+
const CYAN = '\x1b[36;1m';
|
|
7
|
+
const WHITE = '\x1b[1;37m';
|
|
8
|
+
const GRAY = '\x1b[0;37m';
|
|
9
|
+
const YELLOW = '\x1b[1;33m';
|
|
10
|
+
const RESET = '\x1b[0m';
|
|
11
|
+
const B = `${CYAN}\u2551${RESET}`;
|
|
12
|
+
const S67 = ' '.repeat(67);
|
|
13
|
+
const HR = '\u2550'.repeat(67);
|
|
14
|
+
const lines = [
|
|
15
|
+
'',
|
|
16
|
+
` ${CYAN}\u2554${HR}\u2557${RESET}`,
|
|
17
|
+
` ${B}${S67}${B}`,
|
|
18
|
+
` ${B} ${GOLD}\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557 \u2588\u2588\u2557${RESET} ${B}`,
|
|
19
|
+
` ${B} ${GOLD}\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551${RESET} ${B}`,
|
|
20
|
+
` ${B} ${GOLD}\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551${RESET} ${B}`,
|
|
21
|
+
` ${B} ${GOLD}\u255A\u2550\u2550\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2551\u255A\u2588\u2588\u2557\u2588\u2588\u2551\u2588\u2588\u2551\u255A\u2588\u2588\u2557\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551\u255A\u2588\u2588\u2557\u2588\u2588\u2551${RESET} ${B}`,
|
|
22
|
+
` ${B} ${GOLD}\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551${RESET} ${B}`,
|
|
23
|
+
` ${B} ${GOLD}\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D${RESET} ${B}`,
|
|
24
|
+
` ${B}${S67}${B}`,
|
|
25
|
+
` ${B} ${CYAN}\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557${RESET} ${B}`,
|
|
26
|
+
` ${B} ${CYAN}\u2551${RESET} ${WHITE}AI Penetration Testing Framework${RESET} ${CYAN}\u2551${RESET} ${B}`,
|
|
27
|
+
` ${B} ${CYAN}\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D${RESET} ${B}`,
|
|
28
|
+
` ${B}${S67}${B}`,
|
|
29
|
+
];
|
|
30
|
+
// Center the version string
|
|
31
|
+
const verStr = `v${version}`;
|
|
32
|
+
const verPadLeft = Math.floor((67 - verStr.length) / 2);
|
|
33
|
+
const verPadRight = 67 - verStr.length - verPadLeft;
|
|
34
|
+
lines.push(` ${B}${' '.repeat(verPadLeft)}${GRAY}${verStr}${RESET}${' '.repeat(verPadRight)}${B}`);
|
|
35
|
+
lines.push(` ${B}${S67}${B}`, ` ${B} ${YELLOW}\uD83D\uDD10 DEFENSIVE SECURITY ONLY \uD83D\uDD10${RESET} ${B}`, ` ${B}${S67}${B}`, ` ${CYAN}\u255A${HR}\u255D${RESET}`, '');
|
|
36
|
+
console.log(lines.join('\n'));
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=splash.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"splash.js","sourceRoot":"","sources":["../src/splash.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,UAAU,aAAa,CAAC,OAAe;IAC3C,MAAM,IAAI,GAAG,uBAAuB,CAAC;IACrC,MAAM,IAAI,GAAG,YAAY,CAAC;IAC1B,MAAM,KAAK,GAAG,YAAY,CAAC;IAC3B,MAAM,IAAI,GAAG,YAAY,CAAC;IAC1B,MAAM,MAAM,GAAG,YAAY,CAAC;IAC5B,MAAM,KAAK,GAAG,SAAS,CAAC;IAExB,MAAM,CAAC,GAAG,GAAG,IAAI,SAAS,KAAK,EAAE,CAAC;IAClC,MAAM,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAC3B,MAAM,EAAE,GAAG,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAE/B,MAAM,KAAK,GAAG;QACZ,EAAE;QACF,KAAK,IAAI,SAAS,EAAE,SAAS,KAAK,EAAE;QACpC,KAAK,CAAC,GAAG,GAAG,GAAG,CAAC,EAAE;QAClB,KAAK,CAAC,KAAK,IAAI,kTAAkT,KAAK,KAAK,CAAC,EAAE;QAC9U,KAAK,CAAC,KAAK,IAAI,qVAAqV,KAAK,KAAK,CAAC,EAAE;QACjX,KAAK,CAAC,KAAK,IAAI,+VAA+V,KAAK,KAAK,CAAC,EAAE;QAC3X,KAAK,CAAC,KAAK,IAAI,8WAA8W,KAAK,KAAK,CAAC,EAAE;QAC1Y,KAAK,CAAC,KAAK,IAAI,0VAA0V,KAAK,KAAK,CAAC,EAAE;QACtX,KAAK,CAAC,KAAK,IAAI,iUAAiU,KAAK,KAAK,CAAC,EAAE;QAC7V,KAAK,CAAC,GAAG,GAAG,GAAG,CAAC,EAAE;QAClB,KAAK,CAAC,iBAAiB,IAAI,uOAAuO,KAAK,kBAAkB,CAAC,EAAE;QAC5R,KAAK,CAAC,iBAAiB,IAAI,SAAS,KAAK,KAAK,KAAK,mCAAmC,KAAK,KAAK,IAAI,SAAS,KAAK,kBAAkB,CAAC,EAAE;QACvI,KAAK,CAAC,iBAAiB,IAAI,uOAAuO,KAAK,kBAAkB,CAAC,EAAE;QAC5R,KAAK,CAAC,GAAG,GAAG,GAAG,CAAC,EAAE;KACnB,CAAC;IAEF,4BAA4B;IAC5B,MAAM,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;IAC7B,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;IACxD,MAAM,WAAW,GAAG,EAAE,GAAG,MAAM,CAAC,MAAM,GAAG,UAAU,CAAC;IACpD,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,GAAG,IAAI,GAAG,MAAM,GAAG,KAAK,GAAG,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAEpG,KAAK,CAAC,IAAI,CACR,KAAK,CAAC,GAAG,GAAG,GAAG,CAAC,EAAE,EAClB,KAAK,CAAC,uBAAuB,MAAM,oDAAoD,KAAK,qBAAqB,CAAC,EAAE,EACpH,KAAK,CAAC,GAAG,GAAG,GAAG,CAAC,EAAE,EAClB,KAAK,IAAI,SAAS,EAAE,SAAS,KAAK,EAAE,EACpC,EAAE,CACH,CAAC;IAEF,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;AAChC,CAAC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
networks:
|
|
2
|
+
default:
|
|
3
|
+
name: shannon-net
|
|
4
|
+
|
|
5
|
+
services:
|
|
6
|
+
temporal:
|
|
7
|
+
image: temporalio/temporal:latest
|
|
8
|
+
container_name: shannon-temporal
|
|
9
|
+
command: ["server", "start-dev", "--db-filename", "/home/temporal/temporal.db", "--ip", "0.0.0.0"]
|
|
10
|
+
ports:
|
|
11
|
+
- "7233:7233"
|
|
12
|
+
- "8233:8233"
|
|
13
|
+
volumes:
|
|
14
|
+
- temporal-data:/home/temporal
|
|
15
|
+
healthcheck:
|
|
16
|
+
test: ["CMD", "temporal", "operator", "cluster", "health", "--address", "localhost:7233"]
|
|
17
|
+
interval: 10s
|
|
18
|
+
timeout: 5s
|
|
19
|
+
retries: 10
|
|
20
|
+
start_period: 30s
|
|
21
|
+
|
|
22
|
+
router:
|
|
23
|
+
image: node:20-slim
|
|
24
|
+
container_name: shannon-router
|
|
25
|
+
profiles: ["router"]
|
|
26
|
+
command: >
|
|
27
|
+
sh -c "apt-get update && apt-get install -y gettext-base &&
|
|
28
|
+
npm install -g @musistudio/claude-code-router &&
|
|
29
|
+
mkdir -p /root/.claude-code-router &&
|
|
30
|
+
envsubst < /config/router-config.json > /root/.claude-code-router/config.json &&
|
|
31
|
+
ccr start"
|
|
32
|
+
ports:
|
|
33
|
+
- "3456:3456"
|
|
34
|
+
volumes:
|
|
35
|
+
- ./router-config.json:/config/router-config.json:ro
|
|
36
|
+
environment:
|
|
37
|
+
- HOST=0.0.0.0
|
|
38
|
+
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY:-}
|
|
39
|
+
- OPENAI_API_KEY=${OPENAI_API_KEY:-}
|
|
40
|
+
- OPENROUTER_API_KEY=${OPENROUTER_API_KEY:-}
|
|
41
|
+
- ROUTER_DEFAULT=${ROUTER_DEFAULT:-openai,gpt-4o}
|
|
42
|
+
healthcheck:
|
|
43
|
+
test: ["CMD", "node", "-e", "require('http').get('http://localhost:3456/health', r => process.exit(r.statusCode === 200 ? 0 : 1)).on('error', () => process.exit(1))"]
|
|
44
|
+
interval: 10s
|
|
45
|
+
timeout: 5s
|
|
46
|
+
retries: 5
|
|
47
|
+
start_period: 30s
|
|
48
|
+
|
|
49
|
+
volumes:
|
|
50
|
+
temporal-data:
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"HOST": "0.0.0.0",
|
|
3
|
+
"APIKEY": "shannon-router-key",
|
|
4
|
+
"LOG": true,
|
|
5
|
+
"LOG_LEVEL": "info",
|
|
6
|
+
"NON_INTERACTIVE_MODE": true,
|
|
7
|
+
"API_TIMEOUT_MS": 600000,
|
|
8
|
+
"Providers": [
|
|
9
|
+
{
|
|
10
|
+
"name": "openai",
|
|
11
|
+
"api_base_url": "https://api.openai.com/v1/chat/completions",
|
|
12
|
+
"api_key": "$OPENAI_API_KEY",
|
|
13
|
+
"models": ["gpt-5.2", "gpt-5-mini"],
|
|
14
|
+
"transformer": {
|
|
15
|
+
"use": [["maxcompletiontokens", { "max_completion_tokens": 16384 }]]
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"name": "openrouter",
|
|
20
|
+
"api_base_url": "https://openrouter.ai/api/v1/chat/completions",
|
|
21
|
+
"api_key": "$OPENROUTER_API_KEY",
|
|
22
|
+
"models": [
|
|
23
|
+
"google/gemini-3-flash-preview"
|
|
24
|
+
],
|
|
25
|
+
"transformer": {
|
|
26
|
+
"use": ["openrouter"]
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
],
|
|
30
|
+
"Router": {
|
|
31
|
+
"default": "$ROUTER_DEFAULT"
|
|
32
|
+
}
|
|
33
|
+
}
|