ghost-dragon 4.2.1
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/.github/workflows/ci.yml +23 -0
- package/CHANGELOG.md +96 -0
- package/README.md +193 -0
- package/bootstrap.ps1 +83 -0
- package/bootstrap.sh +71 -0
- package/dist/agent/loop.d.ts +68 -0
- package/dist/agent/loop.d.ts.map +1 -0
- package/dist/agent/loop.js +135 -0
- package/dist/agent/mcp.d.ts +33 -0
- package/dist/agent/mcp.d.ts.map +1 -0
- package/dist/agent/mcp.js +107 -0
- package/dist/agent/session.d.ts +16 -0
- package/dist/agent/session.d.ts.map +1 -0
- package/dist/agent/session.js +55 -0
- package/dist/agent/skills.d.ts +36 -0
- package/dist/agent/skills.d.ts.map +1 -0
- package/dist/agent/skills.js +153 -0
- package/dist/agent/stack.d.ts +21 -0
- package/dist/agent/stack.d.ts.map +1 -0
- package/dist/agent/stack.js +158 -0
- package/dist/agent/task.d.ts +21 -0
- package/dist/agent/task.d.ts.map +1 -0
- package/dist/agent/task.js +45 -0
- package/dist/agent/tools.d.ts +44 -0
- package/dist/agent/tools.d.ts.map +1 -0
- package/dist/agent/tools.js +262 -0
- package/dist/agent/trace.d.ts +34 -0
- package/dist/agent/trace.d.ts.map +1 -0
- package/dist/agent/trace.js +72 -0
- package/dist/agent.d.ts +46 -0
- package/dist/agent.d.ts.map +1 -0
- package/dist/agent.js +103 -0
- package/dist/auth.d.ts +74 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +116 -0
- package/dist/brain/anthropic.d.ts +19 -0
- package/dist/brain/anthropic.d.ts.map +1 -0
- package/dist/brain/anthropic.js +74 -0
- package/dist/brain/claude-cli.d.ts +20 -0
- package/dist/brain/claude-cli.d.ts.map +1 -0
- package/dist/brain/claude-cli.js +79 -0
- package/dist/brain/ghost-ember.d.ts +28 -0
- package/dist/brain/ghost-ember.d.ts.map +1 -0
- package/dist/brain/ghost-ember.js +97 -0
- package/dist/brain/index.d.ts +22 -0
- package/dist/brain/index.d.ts.map +1 -0
- package/dist/brain/index.js +95 -0
- package/dist/brain/openai-compat.d.ts +21 -0
- package/dist/brain/openai-compat.d.ts.map +1 -0
- package/dist/brain/openai-compat.js +119 -0
- package/dist/brain/router/classify.d.ts +23 -0
- package/dist/brain/router/classify.d.ts.map +1 -0
- package/dist/brain/router/classify.js +160 -0
- package/dist/brain/router/execute.d.ts +23 -0
- package/dist/brain/router/execute.d.ts.map +1 -0
- package/dist/brain/router/execute.js +84 -0
- package/dist/brain/router/index.d.ts +26 -0
- package/dist/brain/router/index.d.ts.map +1 -0
- package/dist/brain/router/index.js +118 -0
- package/dist/brain/router/routing-memory.d.ts +27 -0
- package/dist/brain/router/routing-memory.d.ts.map +1 -0
- package/dist/brain/router/routing-memory.js +77 -0
- package/dist/brain/router/select.d.ts +32 -0
- package/dist/brain/router/select.d.ts.map +1 -0
- package/dist/brain/router/select.js +146 -0
- package/dist/brain/router/two-hop.d.ts +23 -0
- package/dist/brain/router/two-hop.d.ts.map +1 -0
- package/dist/brain/router/two-hop.js +39 -0
- package/dist/brain/router/verify.d.ts +37 -0
- package/dist/brain/router/verify.d.ts.map +1 -0
- package/dist/brain/router/verify.js +111 -0
- package/dist/brain/types.d.ts +55 -0
- package/dist/brain/types.d.ts.map +1 -0
- package/dist/brain/types.js +16 -0
- package/dist/brain/worker.d.ts +27 -0
- package/dist/brain/worker.d.ts.map +1 -0
- package/dist/brain/worker.js +71 -0
- package/dist/commands/ai.d.ts +24 -0
- package/dist/commands/ai.d.ts.map +1 -0
- package/dist/commands/ai.js +137 -0
- package/dist/commands/alerts.d.ts +19 -0
- package/dist/commands/alerts.d.ts.map +1 -0
- package/dist/commands/alerts.js +114 -0
- package/dist/commands/billing.d.ts +13 -0
- package/dist/commands/billing.d.ts.map +1 -0
- package/dist/commands/billing.js +55 -0
- package/dist/commands/chat.d.ts +22 -0
- package/dist/commands/chat.d.ts.map +1 -0
- package/dist/commands/chat.js +422 -0
- package/dist/commands/config.d.ts +18 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +136 -0
- package/dist/commands/doctor.d.ts +11 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +73 -0
- package/dist/commands/global.d.ts +11 -0
- package/dist/commands/global.d.ts.map +1 -0
- package/dist/commands/global.js +253 -0
- package/dist/commands/keep.d.ts +12 -0
- package/dist/commands/keep.d.ts.map +1 -0
- package/dist/commands/keep.js +58 -0
- package/dist/commands/lifecycle.d.ts +17 -0
- package/dist/commands/lifecycle.d.ts.map +1 -0
- package/dist/commands/lifecycle.js +267 -0
- package/dist/commands/login.d.ts +16 -0
- package/dist/commands/login.d.ts.map +1 -0
- package/dist/commands/login.js +234 -0
- package/dist/commands/maintenance.d.ts +12 -0
- package/dist/commands/maintenance.d.ts.map +1 -0
- package/dist/commands/maintenance.js +76 -0
- package/dist/commands/mcp.d.ts +16 -0
- package/dist/commands/mcp.d.ts.map +1 -0
- package/dist/commands/mcp.js +56 -0
- package/dist/commands/memory.d.ts +13 -0
- package/dist/commands/memory.d.ts.map +1 -0
- package/dist/commands/memory.js +218 -0
- package/dist/commands/osint.d.ts +14 -0
- package/dist/commands/osint.d.ts.map +1 -0
- package/dist/commands/osint.js +161 -0
- package/dist/commands/pentest.d.ts +13 -0
- package/dist/commands/pentest.d.ts.map +1 -0
- package/dist/commands/pentest.js +131 -0
- package/dist/commands/scale.d.ts +14 -0
- package/dist/commands/scale.d.ts.map +1 -0
- package/dist/commands/scale.js +191 -0
- package/dist/commands/serve.d.ts +16 -0
- package/dist/commands/serve.d.ts.map +1 -0
- package/dist/commands/serve.js +167 -0
- package/dist/commands/tui.d.ts +17 -0
- package/dist/commands/tui.d.ts.map +1 -0
- package/dist/commands/tui.js +138 -0
- package/dist/commands/wyrm.d.ts +20 -0
- package/dist/commands/wyrm.d.ts.map +1 -0
- package/dist/commands/wyrm.js +274 -0
- package/dist/config.d.ts +67 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +54 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +85 -0
- package/dist/manifest.d.ts +31 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +83 -0
- package/dist/ui.d.ts +57 -0
- package/dist/ui.d.ts.map +1 -0
- package/dist/ui.js +174 -0
- package/dist/utils.d.ts +33 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +155 -0
- package/dist/wyrm/mcp.d.ts +37 -0
- package/dist/wyrm/mcp.d.ts.map +1 -0
- package/dist/wyrm/mcp.js +137 -0
- package/docs/SYSTEM-PREMORTEM.md +397 -0
- package/dragon-manifest.toml +241 -0
- package/dragon.py +177 -0
- package/install/launchd/lk.ghosts.dragonkeep.plist +57 -0
- package/install/systemd/dragonkeep.service +40 -0
- package/media/dragon-silver-lockup.svg +931 -0
- package/media/dragon-silver-mark.svg +931 -0
- package/media/dragon-silver.png +0 -0
- package/package.json +45 -0
- package/specs/001-godmode/constitution.md +54 -0
- package/specs/001-godmode/plan.md +30 -0
- package/specs/001-godmode/spec.md +64 -0
- package/specs/001-godmode/tasks.md +35 -0
- package/specs/002-premortem-positioning/premortem.md +211 -0
- package/src/agent/loop.ts +165 -0
- package/src/agent/mcp.ts +92 -0
- package/src/agent/session.ts +48 -0
- package/src/agent/skills.ts +138 -0
- package/src/agent/stack.ts +154 -0
- package/src/agent/task.ts +55 -0
- package/src/agent/tools.ts +255 -0
- package/src/agent/trace.ts +76 -0
- package/src/agent.ts +114 -0
- package/src/auth.ts +133 -0
- package/src/brain/anthropic.ts +83 -0
- package/src/brain/claude-cli.ts +78 -0
- package/src/brain/ghost-ember.ts +94 -0
- package/src/brain/index.ts +99 -0
- package/src/brain/openai-compat.ts +115 -0
- package/src/brain/router/classify.ts +167 -0
- package/src/brain/router/execute.ts +80 -0
- package/src/brain/router/index.ts +125 -0
- package/src/brain/router/routing-memory.ts +71 -0
- package/src/brain/router/select.ts +156 -0
- package/src/brain/router/two-hop.ts +62 -0
- package/src/brain/router/verify.ts +123 -0
- package/src/brain/types.ts +61 -0
- package/src/brain/worker.ts +72 -0
- package/src/commands/ai.ts +144 -0
- package/src/commands/alerts.ts +131 -0
- package/src/commands/billing.ts +59 -0
- package/src/commands/chat.ts +318 -0
- package/src/commands/config.ts +137 -0
- package/src/commands/doctor.ts +71 -0
- package/src/commands/global.ts +256 -0
- package/src/commands/keep.ts +67 -0
- package/src/commands/lifecycle.ts +273 -0
- package/src/commands/login.ts +184 -0
- package/src/commands/maintenance.ts +54 -0
- package/src/commands/mcp.ts +57 -0
- package/src/commands/memory.ts +229 -0
- package/src/commands/osint.ts +171 -0
- package/src/commands/pentest.ts +140 -0
- package/src/commands/scale.ts +185 -0
- package/src/commands/serve.ts +171 -0
- package/src/commands/tui.ts +126 -0
- package/src/commands/wyrm.ts +269 -0
- package/src/config.ts +93 -0
- package/src/index.ts +92 -0
- package/src/manifest.ts +104 -0
- package/src/ui.ts +188 -0
- package/src/utils.ts +153 -0
- package/src/wyrm/mcp.ts +130 -0
- package/test/auth.test.ts +70 -0
- package/test/brain.test.ts +39 -0
- package/test/security.test.ts +104 -0
- package/test/skills.test.ts +38 -0
- package/test/ui.test.ts +46 -0
- package/tsconfig.json +19 -0
- package/worker/package-lock.json +1527 -0
- package/worker/package.json +17 -0
- package/worker/src/index.ts +76 -0
- package/worker/tsconfig.json +15 -0
- package/worker/wrangler.toml +26 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dragon doctor — one-glance health check of everything the agent depends on:
|
|
3
|
+
* node, the active brain + readiness, auth, Wyrm memory, Ollama, the skill library,
|
|
4
|
+
* disk, and config-file permissions. Read-only; green/amber/red per check.
|
|
5
|
+
*
|
|
6
|
+
* Copyright 2026 Ghost Protocol (Pvt) Ltd. All Rights Reserved.
|
|
7
|
+
*/
|
|
8
|
+
import { loadConfig } from '../config.js';
|
|
9
|
+
import { C } from '../utils.js';
|
|
10
|
+
import { panel, chrome } from '../ui.js';
|
|
11
|
+
import { resolveAuth, whoami } from '../auth.js';
|
|
12
|
+
import { resolveProvider } from '../brain/index.js';
|
|
13
|
+
import { Wyrm } from '../wyrm/mcp.js';
|
|
14
|
+
import { loadSkillLibrary } from '../agent/skills.js';
|
|
15
|
+
import { existsSync, statSync, statfsSync } from 'node:fs';
|
|
16
|
+
import { homedir } from 'node:os';
|
|
17
|
+
import { join } from 'node:path';
|
|
18
|
+
const mark = (s) => (s === 'ok' ? C.accent('●') : s === 'warn' ? C.high('◐') : C.critical('○'));
|
|
19
|
+
const paint = (s, v) => (s === 'fail' ? C.critical(v) : s === 'warn' ? C.high(v) : C.info(v));
|
|
20
|
+
export function registerDoctorCommands(program, _config) {
|
|
21
|
+
program
|
|
22
|
+
.command('doctor')
|
|
23
|
+
.description('Health check — brain, auth, memory, models, disk, perms')
|
|
24
|
+
.action(async () => {
|
|
25
|
+
const rows = [];
|
|
26
|
+
const cfg = loadConfig();
|
|
27
|
+
const a = resolveAuth();
|
|
28
|
+
const ollama = ['/usr/local/bin/ollama', '/usr/bin/ollama', join(homedir(), '.local/bin/ollama')].some(existsSync);
|
|
29
|
+
const major = Number(process.version.slice(1).split('.')[0]);
|
|
30
|
+
rows.push([major >= 20 ? 'ok' : 'warn', 'node', `${process.version}${major >= 20 ? '' : ' (20+ recommended)'}`]);
|
|
31
|
+
const active = resolveProvider();
|
|
32
|
+
const ready = {
|
|
33
|
+
claude: !!(process.env.ANTHROPIC_API_KEY || cfg.brain?.keys?.anthropic),
|
|
34
|
+
worker: a.mode !== 'none',
|
|
35
|
+
local: ollama,
|
|
36
|
+
openai: !!(process.env.OPENAI_API_KEY || cfg.brain?.keys?.openai),
|
|
37
|
+
custom: !!(process.env.DRAGON_OPENAI_BASE || cfg.brain?.customBaseURL),
|
|
38
|
+
ghost: false,
|
|
39
|
+
};
|
|
40
|
+
const brainOk = ready[active] ?? false;
|
|
41
|
+
rows.push([brainOk ? 'ok' : 'warn', 'brain', `${active}${brainOk ? ' · ready' : ' · not set up (will fall back)'}`]);
|
|
42
|
+
if (a.mode === 'none')
|
|
43
|
+
rows.push(['warn', 'auth', 'not signed in — run `dragon login`']);
|
|
44
|
+
else {
|
|
45
|
+
const me = await whoami();
|
|
46
|
+
rows.push([me.ok ? 'ok' : 'fail', 'auth', me.ok ? `${a.mode} · ${me.email ?? 'verified'}` : `${a.mode} · invalid (re-login)`]);
|
|
47
|
+
}
|
|
48
|
+
const w = new Wyrm();
|
|
49
|
+
const wok = await w.connect();
|
|
50
|
+
rows.push([wok ? 'ok' : 'warn', 'memory', wok ? `Wyrm · ${w.toolSpecs().length} tools` : 'Wyrm unavailable (agent works without it)']);
|
|
51
|
+
await w.close();
|
|
52
|
+
rows.push([ollama ? 'ok' : 'warn', 'ollama', ollama ? 'installed' : 'not found (local brain needs it)']);
|
|
53
|
+
const sk = loadSkillLibrary();
|
|
54
|
+
rows.push([sk.count > 0 ? 'ok' : 'warn', 'skills', `${sk.count} loaded`]);
|
|
55
|
+
try {
|
|
56
|
+
const st = statfsSync(process.cwd());
|
|
57
|
+
const g = (st.bavail * st.bsize) / 1e9;
|
|
58
|
+
rows.push([g > 2 ? 'ok' : g > 0.5 ? 'warn' : 'fail', 'disk', `${g.toFixed(1)} GB free`]);
|
|
59
|
+
}
|
|
60
|
+
catch { /* skip */ }
|
|
61
|
+
try {
|
|
62
|
+
const m = statSync(join(homedir(), '.dragon', 'config.json')).mode & 0o777;
|
|
63
|
+
rows.push([m === 0o600 ? 'ok' : 'warn', 'config', `~/.dragon/config.json ${m.toString(8)}${m === 0o600 ? '' : ' (expected 600)'}`]);
|
|
64
|
+
}
|
|
65
|
+
catch { /* no config yet */ }
|
|
66
|
+
console.log();
|
|
67
|
+
console.log(panel(rows.map(([s, k, v]) => `${mark(s)} ${C.faint(k.padEnd(7))} ${paint(s, v)}`), { title: chrome('DOCTOR') }));
|
|
68
|
+
const fails = rows.filter((r) => r[0] === 'fail').length;
|
|
69
|
+
const warns = rows.filter((r) => r[0] === 'warn').length;
|
|
70
|
+
console.log(` ${fails ? C.critical(`${fails} failing`) : warns ? C.high(`${warns} warning${warns > 1 ? 's' : ''}`) : C.accent('all systems green')}`);
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=doctor.js.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dragon init / dragon status / dragon doctor — Global commands
|
|
3
|
+
*
|
|
4
|
+
* - init: Auto-detect product paths and write ~/.dragon/config.json
|
|
5
|
+
* - status: Health check across all products + APIs
|
|
6
|
+
* - doctor: Contract-test the cross-tool flows (lightweight)
|
|
7
|
+
*/
|
|
8
|
+
import type { Command } from 'commander';
|
|
9
|
+
import type { DragonConfig } from '../config.js';
|
|
10
|
+
export declare function registerGlobalCommands(program: Command, config: DragonConfig): void;
|
|
11
|
+
//# sourceMappingURL=global.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"global.d.ts","sourceRoot":"","sources":["../../src/commands/global.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACxC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAsChD,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,YAAY,QAgN5E"}
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dragon init / dragon status / dragon doctor — Global commands
|
|
3
|
+
*
|
|
4
|
+
* - init: Auto-detect product paths and write ~/.dragon/config.json
|
|
5
|
+
* - status: Health check across all products + APIs
|
|
6
|
+
* - doctor: Contract-test the cross-tool flows (lightweight)
|
|
7
|
+
*/
|
|
8
|
+
import { saveConfig } from '../config.js';
|
|
9
|
+
import { label, success, warn } from '../utils.js';
|
|
10
|
+
import chalk from 'chalk';
|
|
11
|
+
import { existsSync, statSync } from 'fs';
|
|
12
|
+
import { join, resolve } from 'path';
|
|
13
|
+
import { homedir } from 'os';
|
|
14
|
+
const KNOWN_MARKERS = {
|
|
15
|
+
scale: { files: ['includes/payment.php', 'admin/orders.php', 'api/health.php'], name: 'DragonScale' },
|
|
16
|
+
wyrm: { files: ['packages/mcp-server/src/index.ts', 'install.sh'], name: 'Wyrm' },
|
|
17
|
+
pentest: { files: ['phantomdragon.py', 'phantom_dragon_ai/control_api.py'], name: 'PhantomDragon' },
|
|
18
|
+
keep: { files: ['src/engine/sentinel.rs', 'src/engine/shield.rs'], name: 'DragonKeep' },
|
|
19
|
+
net: { files: ['packages/api/src/server.ts', 'pnpm-workspace.yaml'], name: 'DragonNet' },
|
|
20
|
+
};
|
|
21
|
+
function detectProduct(dir, product) {
|
|
22
|
+
const markers = KNOWN_MARKERS[product];
|
|
23
|
+
if (!markers)
|
|
24
|
+
return false;
|
|
25
|
+
return markers.files.some(f => existsSync(join(dir, f)));
|
|
26
|
+
}
|
|
27
|
+
async function ping(url, timeoutMs = 1500) {
|
|
28
|
+
try {
|
|
29
|
+
const controller = new AbortController();
|
|
30
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
31
|
+
try {
|
|
32
|
+
const res = await fetch(url, { signal: controller.signal });
|
|
33
|
+
const text = await res.text();
|
|
34
|
+
let parsed = null;
|
|
35
|
+
try {
|
|
36
|
+
parsed = JSON.parse(text);
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
parsed = text;
|
|
40
|
+
}
|
|
41
|
+
return { ok: res.ok, status: res.status, data: parsed };
|
|
42
|
+
}
|
|
43
|
+
finally {
|
|
44
|
+
clearTimeout(timer);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
catch (e) {
|
|
48
|
+
return { ok: false, error: String(e) };
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
export function registerGlobalCommands(program, config) {
|
|
52
|
+
// --- init ---
|
|
53
|
+
program
|
|
54
|
+
.command('init')
|
|
55
|
+
.description('Auto-detect products and configure dragon CLI')
|
|
56
|
+
.option('-d, --dir <dir>', 'Directory to scan', resolve('.'))
|
|
57
|
+
.action(async (opts) => {
|
|
58
|
+
console.log(label('Dragon'), 'Initializing...\n');
|
|
59
|
+
const scanDirs = [
|
|
60
|
+
opts.dir,
|
|
61
|
+
join(homedir(), 'Git Projects'),
|
|
62
|
+
join(homedir(), 'Projects'),
|
|
63
|
+
join(homedir(), 'src'),
|
|
64
|
+
];
|
|
65
|
+
const found = {};
|
|
66
|
+
for (const baseDir of scanDirs) {
|
|
67
|
+
if (!existsSync(baseDir))
|
|
68
|
+
continue;
|
|
69
|
+
const { readdirSync } = await import('fs');
|
|
70
|
+
const entries = readdirSync(baseDir, { withFileTypes: true });
|
|
71
|
+
for (const entry of entries) {
|
|
72
|
+
if (!entry.isDirectory())
|
|
73
|
+
continue;
|
|
74
|
+
const fullPath = join(baseDir, entry.name);
|
|
75
|
+
for (const [product, _] of Object.entries(KNOWN_MARKERS)) {
|
|
76
|
+
if (!found[product] && detectProduct(fullPath, product)) {
|
|
77
|
+
found[product] = fullPath;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
// Update config
|
|
83
|
+
for (const [product, path] of Object.entries(found)) {
|
|
84
|
+
config.products[product].path = path;
|
|
85
|
+
success(`${KNOWN_MARKERS[product].name} → ${chalk.dim(path)}`);
|
|
86
|
+
}
|
|
87
|
+
for (const [product, markers] of Object.entries(KNOWN_MARKERS)) {
|
|
88
|
+
if (!found[product]) {
|
|
89
|
+
warn(`${markers.name} not found`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
saveConfig(config);
|
|
93
|
+
console.log();
|
|
94
|
+
success(`Config saved to ${chalk.dim('~/.dragon/config.json')}`);
|
|
95
|
+
});
|
|
96
|
+
// --- status ---
|
|
97
|
+
program
|
|
98
|
+
.command('status')
|
|
99
|
+
.description('Health check across all products + APIs')
|
|
100
|
+
.action(async () => {
|
|
101
|
+
console.log(label('Dragon'), 'System status:\n');
|
|
102
|
+
// DragonScale
|
|
103
|
+
const scaleUrl = config.products.scale.url;
|
|
104
|
+
const scalePath = config.products.scale.path;
|
|
105
|
+
if (scalePath && existsSync(join(scalePath, 'index.php'))) {
|
|
106
|
+
console.log(` ${chalk.green('●')} DragonScale ${chalk.dim(scaleUrl || scalePath)} ${chalk.green('Installed')}`);
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
console.log(` ${chalk.dim('○')} DragonScale ${chalk.dim('Not configured')}`);
|
|
110
|
+
}
|
|
111
|
+
// Wyrm
|
|
112
|
+
const wyrmPath = config.products.wyrm.path;
|
|
113
|
+
const wyrmPort = config.products.wyrm.port || 3333;
|
|
114
|
+
if (wyrmPath) {
|
|
115
|
+
const r = await ping(`http://localhost:${wyrmPort}/health`);
|
|
116
|
+
if (r.ok) {
|
|
117
|
+
console.log(` ${chalk.green('●')} Wyrm ${chalk.dim(`localhost:${wyrmPort}`)} ${chalk.green('Online')}`);
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
console.log(` ${chalk.yellow('●')} Wyrm ${chalk.dim(`localhost:${wyrmPort}`)} ${chalk.yellow('Installed · Offline')}`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
console.log(` ${chalk.dim('○')} Wyrm ${chalk.dim('Not configured')}`);
|
|
125
|
+
}
|
|
126
|
+
// PhantomDragon engine + control_api
|
|
127
|
+
const pentestPath = config.products.pentest.path;
|
|
128
|
+
if (pentestPath && (existsSync(join(pentestPath, 'phantom_dragon_ai/control_api.py'))
|
|
129
|
+
|| existsSync(join(pentestPath, 'phantomdragon.py')))) {
|
|
130
|
+
console.log(` ${chalk.green('●')} PhantomDragon engine ${chalk.dim(pentestPath)} ${chalk.green('Installed')}`);
|
|
131
|
+
const apiPort = config.products.pentest.controlPort ?? 4091;
|
|
132
|
+
const uiPort = config.products.pentest.controlUiPort ?? 4090;
|
|
133
|
+
const apiR = await ping(`http://localhost:${apiPort}/health`);
|
|
134
|
+
if (apiR.ok && apiR.data) {
|
|
135
|
+
const d = apiR.data;
|
|
136
|
+
console.log(` ${chalk.green('●')} Control API ${chalk.dim(`localhost:${apiPort}`)} ${chalk.green('Online')} ${chalk.dim(`(${d.scan_count} scans, ${d.active_runs} runs)`)}`);
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
console.log(` ${chalk.yellow('●')} Control API ${chalk.dim(`localhost:${apiPort}`)} ${chalk.yellow('Offline')}`);
|
|
140
|
+
}
|
|
141
|
+
const uiR = await ping(`http://localhost:${uiPort}/`);
|
|
142
|
+
if (uiR.ok) {
|
|
143
|
+
console.log(` ${chalk.green('●')} Control Dashboard ${chalk.dim(`localhost:${uiPort}`)} ${chalk.green('Online')}`);
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
console.log(` ${chalk.yellow('●')} Control Dashboard ${chalk.dim(`localhost:${uiPort}`)} ${chalk.yellow('Offline')}`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
console.log(` ${chalk.dim('○')} PhantomDragon engine ${chalk.dim('Not configured')}`);
|
|
151
|
+
}
|
|
152
|
+
// DragonNet
|
|
153
|
+
const netPath = config.products.net.path;
|
|
154
|
+
if (netPath && existsSync(join(netPath, 'pnpm-workspace.yaml'))) {
|
|
155
|
+
console.log(` ${chalk.green('●')} DragonNet ${chalk.dim(netPath)} ${chalk.green('Installed')}`);
|
|
156
|
+
const apiPort = config.products.net.apiPort ?? 4080;
|
|
157
|
+
const uiPort = config.products.net.uiPort ?? 4081;
|
|
158
|
+
const apiR = await ping(`http://localhost:${apiPort}/health`);
|
|
159
|
+
if (apiR.ok) {
|
|
160
|
+
console.log(` ${chalk.green('●')} OSINT API ${chalk.dim(`localhost:${apiPort}`)} ${chalk.green('Online')}`);
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
console.log(` ${chalk.yellow('●')} OSINT API ${chalk.dim(`localhost:${apiPort}`)} ${chalk.yellow('Offline')}`);
|
|
164
|
+
}
|
|
165
|
+
const uiR = await ping(`http://localhost:${uiPort}/`);
|
|
166
|
+
if (uiR.ok) {
|
|
167
|
+
console.log(` ${chalk.green('●')} OSINT Dashboard ${chalk.dim(`localhost:${uiPort}`)} ${chalk.green('Online')}`);
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
console.log(` ${chalk.yellow('●')} OSINT Dashboard ${chalk.dim(`localhost:${uiPort}`)} ${chalk.yellow('Offline')}`);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
console.log(` ${chalk.dim('○')} DragonNet ${chalk.dim('Not configured')}`);
|
|
175
|
+
}
|
|
176
|
+
// Phantom Memory
|
|
177
|
+
const memPath = join(homedir(), '.copilot', 'phantom-memory.db');
|
|
178
|
+
if (existsSync(memPath)) {
|
|
179
|
+
const bytes = statSync(memPath).size;
|
|
180
|
+
const apiPort = config.products.pentest.controlPort ?? 4091;
|
|
181
|
+
const memR = await ping(`http://localhost:${apiPort}/v1/memory`);
|
|
182
|
+
let targetCount = '—';
|
|
183
|
+
if (memR.ok && memR.data?.targets)
|
|
184
|
+
targetCount = String(memR.data.targets.length);
|
|
185
|
+
const sizeStr = bytes < 1024 * 1024 ? `${(bytes / 1024).toFixed(1)} KB` : `${(bytes / 1024 / 1024).toFixed(1)} MB`;
|
|
186
|
+
console.log(` ${chalk.green('●')} Phantom Memory ${chalk.dim(memPath)} ${chalk.green(`${targetCount} targets · ${sizeStr}`)}`);
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
console.log(` ${chalk.dim('○')} Phantom Memory ${chalk.dim('No DB yet — runs auto-create on first scan')}`);
|
|
190
|
+
}
|
|
191
|
+
// DragonKeep (Rust defensive backbone)
|
|
192
|
+
const keepPath = config.products.keep.path;
|
|
193
|
+
if (keepPath && existsSync(join(keepPath, 'Cargo.toml'))) {
|
|
194
|
+
const dbgBin = join(keepPath, 'target/debug/dragonkeep');
|
|
195
|
+
const relBin = join(keepPath, 'target/release/dragonkeep');
|
|
196
|
+
const built = existsSync(relBin) || existsSync(dbgBin);
|
|
197
|
+
const label_ = built ? chalk.green('Installed · built') : chalk.yellow('Installed · not yet built');
|
|
198
|
+
console.log(` ${chalk.green('●')} DragonKeep ${chalk.dim(keepPath)} ${label_}`);
|
|
199
|
+
if (!built) {
|
|
200
|
+
console.log(` ${chalk.dim('→ cargo build --release in ' + keepPath)}`);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
console.log(` ${chalk.dim('○')} DragonKeep ${chalk.dim('Not configured')}`);
|
|
205
|
+
}
|
|
206
|
+
console.log();
|
|
207
|
+
});
|
|
208
|
+
// --- contract (cross-tool flow checks; `dragon doctor` is the health panel) ---
|
|
209
|
+
program
|
|
210
|
+
.command('contract')
|
|
211
|
+
.description('Contract-test cross-tool flows (Phantom Memory / Control API / DragonNet / Wyrm)')
|
|
212
|
+
.action(async () => {
|
|
213
|
+
console.log(label('Dragon'), 'Contract checks:\n');
|
|
214
|
+
const checks = [];
|
|
215
|
+
// Phantom Memory exists?
|
|
216
|
+
const memPath = join(homedir(), '.copilot', 'phantom-memory.db');
|
|
217
|
+
checks.push({ name: 'Phantom Memory DB present', ok: existsSync(memPath), note: memPath });
|
|
218
|
+
// Control API speaks memory?
|
|
219
|
+
const apiPort = config.products.pentest.controlPort ?? 4091;
|
|
220
|
+
const memR = await ping(`http://localhost:${apiPort}/v1/memory`);
|
|
221
|
+
checks.push({
|
|
222
|
+
name: 'Control API /v1/memory reachable',
|
|
223
|
+
ok: memR.ok,
|
|
224
|
+
note: memR.ok ? `${memR.data?.targets?.length ?? 0} targets` : memR.error,
|
|
225
|
+
});
|
|
226
|
+
// DragonNet API reachable?
|
|
227
|
+
const dnPort = config.products.net.apiPort ?? 4080;
|
|
228
|
+
const dnR = await ping(`http://localhost:${dnPort}/health`);
|
|
229
|
+
checks.push({
|
|
230
|
+
name: 'DragonNet /health reachable',
|
|
231
|
+
ok: dnR.ok,
|
|
232
|
+
note: dnR.ok ? 'OK' : 'offline (run: dragon osint serve)',
|
|
233
|
+
});
|
|
234
|
+
// Wyrm reachable?
|
|
235
|
+
const wyrmR = await ping(`http://localhost:${config.products.wyrm.port ?? 3333}/health`);
|
|
236
|
+
checks.push({
|
|
237
|
+
name: 'Wyrm /health reachable',
|
|
238
|
+
ok: wyrmR.ok,
|
|
239
|
+
note: wyrmR.ok ? 'OK' : 'offline (Wyrm integration becomes best-effort)',
|
|
240
|
+
});
|
|
241
|
+
checks.forEach((c) => {
|
|
242
|
+
const sym = c.ok ? chalk.green('✓') : chalk.yellow('⚠');
|
|
243
|
+
console.log(` ${sym} ${c.name.padEnd(40)} ${chalk.dim(c.note ?? '')}`);
|
|
244
|
+
});
|
|
245
|
+
console.log();
|
|
246
|
+
const failing = checks.filter((c) => !c.ok).length;
|
|
247
|
+
if (failing === 0)
|
|
248
|
+
success('All contract checks passing');
|
|
249
|
+
else
|
|
250
|
+
warn(`${failing} check(s) need attention — see ~/Git Projects/dragon-cli/docs/SYSTEM-PREMORTEM.md`);
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
//# sourceMappingURL=global.js.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dragon keep — DragonKeep defensive engine bridge.
|
|
3
|
+
*
|
|
4
|
+
* DragonKeep ships independently as a Rust binary (`dragonkeep`); this
|
|
5
|
+
* subcommand is a thin shim that surfaces its status + control loop
|
|
6
|
+
* from the unified `dragon` CLI so operators don't need to memorise
|
|
7
|
+
* a second toolchain.
|
|
8
|
+
*/
|
|
9
|
+
import type { Command } from 'commander';
|
|
10
|
+
import type { DragonConfig } from '../config.js';
|
|
11
|
+
export declare function registerKeepCommands(program: Command, _config: DragonConfig): void;
|
|
12
|
+
//# sourceMappingURL=keep.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keep.d.ts","sourceRoot":"","sources":["../../src/commands/keep.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACxC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAsBhD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY,QAkC3E"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dragon keep — DragonKeep defensive engine bridge.
|
|
3
|
+
*
|
|
4
|
+
* DragonKeep ships independently as a Rust binary (`dragonkeep`); this
|
|
5
|
+
* subcommand is a thin shim that surfaces its status + control loop
|
|
6
|
+
* from the unified `dragon` CLI so operators don't need to memorise
|
|
7
|
+
* a second toolchain.
|
|
8
|
+
*/
|
|
9
|
+
import { spawnSync } from 'node:child_process';
|
|
10
|
+
import { error, info, label } from '../utils.js';
|
|
11
|
+
import chalk from 'chalk';
|
|
12
|
+
function which(bin) {
|
|
13
|
+
const r = spawnSync('command', ['-v', bin], { shell: true, encoding: 'utf-8' });
|
|
14
|
+
const out = (r.stdout || '').trim();
|
|
15
|
+
return out || null;
|
|
16
|
+
}
|
|
17
|
+
function passthrough(args) {
|
|
18
|
+
const bin = which('dragonkeep');
|
|
19
|
+
if (!bin) {
|
|
20
|
+
error('dragonkeep binary not on PATH');
|
|
21
|
+
info('install it via `dragon install dragonkeep` or build from source in ~/Git Projects/DragonKeep');
|
|
22
|
+
return 127;
|
|
23
|
+
}
|
|
24
|
+
const r = spawnSync(bin, args, { stdio: 'inherit' });
|
|
25
|
+
return r.status ?? 1;
|
|
26
|
+
}
|
|
27
|
+
export function registerKeepCommands(program, _config) {
|
|
28
|
+
const keep = program
|
|
29
|
+
.command('keep')
|
|
30
|
+
.description('DragonKeep — defensive engine (NGAV · MDR · compliance · SOAR)');
|
|
31
|
+
keep
|
|
32
|
+
.command('status')
|
|
33
|
+
.description('Show DragonKeep daemon status + active engines')
|
|
34
|
+
.action(() => { process.exit(passthrough(['status'])); });
|
|
35
|
+
keep
|
|
36
|
+
.command('scan [path]')
|
|
37
|
+
.description('Run an on-demand AV scan')
|
|
38
|
+
.action((path) => { process.exit(passthrough(['scan', ...(path ? [path] : [])])); });
|
|
39
|
+
keep
|
|
40
|
+
.command('engines')
|
|
41
|
+
.description('List the active defensive engines')
|
|
42
|
+
.action(() => { process.exit(passthrough(['engines'])); });
|
|
43
|
+
// Default action: print a short summary instead of dumping help.
|
|
44
|
+
keep.action(() => {
|
|
45
|
+
console.log();
|
|
46
|
+
console.log(` ${label('DragonKeep')} ${chalk.dim('defensive engine · 28 modules · NGAV + MDR')}`);
|
|
47
|
+
console.log();
|
|
48
|
+
console.log(` ${chalk.dim('dragon keep status')} ${chalk.dim('— daemon + engine health')}`);
|
|
49
|
+
console.log(` ${chalk.dim('dragon keep scan')} ${chalk.dim('— on-demand scan')}`);
|
|
50
|
+
console.log(` ${chalk.dim('dragon keep engines')} ${chalk.dim('— list active engines')}`);
|
|
51
|
+
console.log();
|
|
52
|
+
if (!which('dragonkeep')) {
|
|
53
|
+
info(`run ${chalk.green('dragon install dragonkeep')} to install the daemon`);
|
|
54
|
+
console.log();
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=keep.js.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dragon lifecycle commands — bootstrap + update + install + stop
|
|
3
|
+
*
|
|
4
|
+
* dragon up — clone every missing repo, install everything
|
|
5
|
+
* dragon update — git pull every product in the manifest
|
|
6
|
+
* dragon install <key> — install one product
|
|
7
|
+
* dragon uninstall <key> — remove a product directory (asks first)
|
|
8
|
+
* dragon list — print the manifest
|
|
9
|
+
* dragon stop --all — kill every running service (uses ~/.dragon/pids/)
|
|
10
|
+
*
|
|
11
|
+
* Copyright 2026 Ghost Protocol (Pvt) Ltd. All Rights Reserved.
|
|
12
|
+
* Author: Ryan Sebastian <ryan@ghosts.lk>
|
|
13
|
+
*/
|
|
14
|
+
import type { Command } from 'commander';
|
|
15
|
+
import type { DragonConfig } from '../config.js';
|
|
16
|
+
export declare function registerLifecycleCommands(program: Command, _config: DragonConfig): void;
|
|
17
|
+
//# sourceMappingURL=lifecycle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../../src/commands/lifecycle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACxC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAoFhD,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY,QA6KhF"}
|