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
|
Binary file
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ghost-dragon",
|
|
3
|
+
"version": "4.2.1",
|
|
4
|
+
"description": "Ghost Protocol's operator CLI — a Claude-Code-style coding + ops agent on any brain, with deep Wyrm memory, a 200+ skill library, the dragon stack, and any MCP server.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"dragon": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "tsc",
|
|
11
|
+
"dev": "tsx src/index.ts",
|
|
12
|
+
"start": "node dist/index.js",
|
|
13
|
+
"test": "npm run build && vitest run",
|
|
14
|
+
"typecheck": "tsc --noUnusedLocals --noUnusedParameters --noEmit",
|
|
15
|
+
"link": "npm run build && npm link"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"cli",
|
|
19
|
+
"ghost-protocol",
|
|
20
|
+
"dragonscale",
|
|
21
|
+
"wyrm",
|
|
22
|
+
"phantomdragon"
|
|
23
|
+
],
|
|
24
|
+
"author": "Ryan Sebastian <ryan@ghosts.lk>",
|
|
25
|
+
"license": "Proprietary",
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"@anthropic-ai/sdk": "^0.100.1",
|
|
28
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
29
|
+
"boxen": "^8.0.1",
|
|
30
|
+
"chalk": "^5.6.2",
|
|
31
|
+
"commander": "^12.1.0",
|
|
32
|
+
"conf": "^13.1.0",
|
|
33
|
+
"ora": "^8.2.0"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"@types/node": "^22.19.17",
|
|
37
|
+
"tsx": "^4.21.0",
|
|
38
|
+
"typescript": "^5.9.3",
|
|
39
|
+
"vitest": "^4.1.8"
|
|
40
|
+
},
|
|
41
|
+
"repository": {
|
|
42
|
+
"type": "git",
|
|
43
|
+
"url": "https://github.com/ghosts-lk/dragon-cli.git"
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Dragon CLI — Constitution (v1.0 "Godmode")
|
|
2
|
+
|
|
3
|
+
The non-negotiables for turning `dragon` into Ghost Protocol's flagship operator
|
|
4
|
+
toolkit: **Claude-Code + GitHub-CLI in one**, industrial/military-grade under the
|
|
5
|
+
hood, designer-grade on the surface. Every change is checked against these.
|
|
6
|
+
|
|
7
|
+
## North star
|
|
8
|
+
One terminal command — `dragon` — that an operator lives in: an AI coding/ops agent
|
|
9
|
+
that edits code, runs the Ghost stack, remembers across sessions (Wyrm), and works on
|
|
10
|
+
**any** brain (Claude, our free Cloudflare worker, local Ollama, our own DragonSpark, or
|
|
11
|
+
any open OpenAI-compatible endpoint). It should feel like a flagship product on first
|
|
12
|
+
keystroke and never lose your trust.
|
|
13
|
+
|
|
14
|
+
## Principles
|
|
15
|
+
|
|
16
|
+
1. **Safe by default, powerful on request.** The agent can run shell + edit files, so
|
|
17
|
+
destructive actions are gated (approve / `--auto` / per-tool allowlists). The default
|
|
18
|
+
profile cannot rm-rf your machine. Power is opt-in, never the default.
|
|
19
|
+
2. **It always works.** No dead ends. Missing key → fall back to the free worker → local
|
|
20
|
+
Ollama. Unreachable service → clear message + path forward. A crash prints a friendly,
|
|
21
|
+
actionable error (stack only under `--debug`), never a raw trace.
|
|
22
|
+
3. **Sovereign-capable.** A fully local mode (Ollama + Wyrm) where nothing leaves the
|
|
23
|
+
host. Sovereignty is a first-class option, not an afterthought — it's a selling point.
|
|
24
|
+
4. **Quality is enforced, not hoped for.** Pure logic is unit-tested; commands are
|
|
25
|
+
smoke-tested; security-critical paths have adversarial tests. `tsc --noUnusedLocals`
|
|
26
|
+
stays green. CI gates merges.
|
|
27
|
+
5. **Hardened like we'd pentest a client.** We DEF-CON our own tool: no command injection,
|
|
28
|
+
no path traversal, no token leakage (config 0600, secrets redacted from logs/traces),
|
|
29
|
+
bounded loops + output, SSRF/restricted-port guards on every URL.
|
|
30
|
+
6. **Designer-grade surface.** The "ops console" look (stealth silver) is consistent
|
|
31
|
+
across every command — framed panels, status dots, aligned rows, chrome wordmark.
|
|
32
|
+
Output is scannable; errors are beautiful; `--json` everywhere for machines.
|
|
33
|
+
7. **Quality-of-life in abundance.** First-run model picker, `dragon doctor`, shell
|
|
34
|
+
completions, self-update, resume/transcripts, `@file` attach, sane flags, fast help.
|
|
35
|
+
Every friction we hit, we file as a QoL task.
|
|
36
|
+
8. **Memory + skills are the moat.** Wyrm long-term memory and the 200+ skill library are
|
|
37
|
+
wired into the agent (recall, capture, skill-as-tool). This is what no other CLI has.
|
|
38
|
+
9. **Extensible.** Any MCP server, any model endpoint, custom tools. The toolkit grows
|
|
39
|
+
without forking.
|
|
40
|
+
|
|
41
|
+
## Definition of "Godmode" (v1.0 ship gate)
|
|
42
|
+
- Test suite green (unit + smoke + adversarial security tests) in CI.
|
|
43
|
+
- Self-pentest findings: zero CRITICAL/HIGH open; MEDIUM triaged.
|
|
44
|
+
- Global crash handler + `--debug`; every command degrades gracefully.
|
|
45
|
+
- Brain: claude / worker / local / ghost / openai / **custom endpoint**, with picker +
|
|
46
|
+
graceful fallback. Fully-local sovereign mode verified.
|
|
47
|
+
- Safe-by-default permission profiles for the bash/write tools.
|
|
48
|
+
- `dragon doctor` green; shell completions + self-update shipped.
|
|
49
|
+
- The ops-console theme applied to every command surface.
|
|
50
|
+
|
|
51
|
+
## Non-negotiable NOs
|
|
52
|
+
- No telemetry / phone-home. Traces + audit stay local unless the operator ships them.
|
|
53
|
+
- No silent network calls. No secrets in logs, traces, or error output.
|
|
54
|
+
- No unbounded agent loops or tool output. No auto-approve as a default.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Dragon CLI v1.0 "Godmode" — Plan
|
|
2
|
+
|
|
3
|
+
Phased so each lands shippable. **Phase 1 is this session's down payment.**
|
|
4
|
+
|
|
5
|
+
## Phase 1 — Foundation: hardening + tests + first QoL ← THIS SESSION
|
|
6
|
+
- Global crash handler + `--debug` (F1, F2).
|
|
7
|
+
- vitest + unit tests for security-critical pure fns (F3) + a smoke test (F4).
|
|
8
|
+
- Apply self-pentest CRITICAL/HIGH fixes (F6, F7): config 0600 on all writes, secret
|
|
9
|
+
redaction, bash deny-list safe-by-default, bounded output/loops verified.
|
|
10
|
+
- `dragon brains` (list providers + readiness) + custom OpenAI-compatible endpoint (F9 partial, F10).
|
|
11
|
+
- CI workflow (build + tsc-noUnused + test).
|
|
12
|
+
|
|
13
|
+
## Phase 2 — Surface + QoL polish
|
|
14
|
+
- Ops-console theme rolled to every command + `--json` everywhere (F11).
|
|
15
|
+
- `dragon doctor` (F12), shell completions + `dragon upgrade` (F13).
|
|
16
|
+
- Permission profiles (safe/plan/auto), session resume + transcript export (F14).
|
|
17
|
+
|
|
18
|
+
## Phase 3 — The unique moat
|
|
19
|
+
- Stack-fused agent tools (scale/wyrm/pentest/keep/net as agent tools).
|
|
20
|
+
- Skills-as-tools (skill_search/apply over the 200+ library).
|
|
21
|
+
- MCP hub (`dragon mcp add`), sub-agents (`task` tool).
|
|
22
|
+
|
|
23
|
+
## Phase 4 — Sovereign + commercial
|
|
24
|
+
- `--sovereign` (Ollama+Wyrm only), sandboxed bash, live `dragon tui`.
|
|
25
|
+
- Bundle into the DragonBrain appliance; package as the operator console product.
|
|
26
|
+
|
|
27
|
+
## Sequencing notes
|
|
28
|
+
- DragonSpark (the `ghost` brain) trains in parallel (its own repo); the `ghost` provider
|
|
29
|
+
is already wired and lights up when weights land.
|
|
30
|
+
- Each phase ends green on the CI gate. Security findings never carry across a phase.
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Dragon CLI v1.0 "Godmode" — Spec
|
|
2
|
+
|
|
3
|
+
## Goal
|
|
4
|
+
Elevate `dragon` from "a good start" to a flagship, release-grade operator toolkit:
|
|
5
|
+
hardened, tested, beautiful, and uniquely Ghost Protocol.
|
|
6
|
+
|
|
7
|
+
## Functional requirements
|
|
8
|
+
|
|
9
|
+
### Reliability & errors
|
|
10
|
+
- F1. Global crash handler: catch uncaughtException + unhandledRejection → friendly,
|
|
11
|
+
actionable message; full stack only under `--debug`/`DRAGON_DEBUG`.
|
|
12
|
+
- F2. Every command degrades gracefully (no dead ends); network/auth/model failures give
|
|
13
|
+
a clear next step.
|
|
14
|
+
|
|
15
|
+
### Quality / testing
|
|
16
|
+
- F3. Unit tests (vitest) for pure logic: `isBrowsableHttpUrl`, `sanitizeApiBase`, brain
|
|
17
|
+
factory resolution, SSE/tool-call parsing, trace redaction, worker flatten.
|
|
18
|
+
- F4. Smoke tests: `--help`, `config`, brain fallback, login validation — runnable in CI.
|
|
19
|
+
- F5. Adversarial tests for security-critical paths (URL guard, redaction, edit-file
|
|
20
|
+
uniqueness). CI gate: build + tsc-noUnused + tests.
|
|
21
|
+
|
|
22
|
+
### Security (self-pentest → fix)
|
|
23
|
+
- F6. Address every CRITICAL/HIGH from the self-pentest. Bash/write tools safe-by-default
|
|
24
|
+
(approval gate; deny-list of obviously-destructive commands; `--auto` opt-in only).
|
|
25
|
+
- F7. Token hygiene: config 0600 on every write path; secrets never in logs/traces/errors;
|
|
26
|
+
bearer/cookie sent only to the resolved, validated origin.
|
|
27
|
+
- F8. Bounded everything: agent step cap, tool output cap, request timeouts.
|
|
28
|
+
|
|
29
|
+
### Brains / model picker (incl. open source)
|
|
30
|
+
- F9. Providers: claude · worker (free CF) · local (Ollama) · ghost (DragonSpark) · openai
|
|
31
|
+
· **custom** (any OpenAI-compatible base URL → OpenRouter, vLLM, LM Studio, etc.).
|
|
32
|
+
- F10. First-run picker + `dragon brains` (list providers, readiness ● /○, active) +
|
|
33
|
+
`dragon config brain <p>` + per-session `--brain/--model`. Graceful fallback chain.
|
|
34
|
+
|
|
35
|
+
### Surface / QoL
|
|
36
|
+
- F11. Ops-console theme on every command (panels, status dots, `--json` everywhere).
|
|
37
|
+
- F12. `dragon doctor` (brain/auth/wyrm/ollama/disk health, green/amber/red).
|
|
38
|
+
- F13. Shell completions (bash/zsh/fish), `dragon upgrade` (self-update), man/`--help` polish.
|
|
39
|
+
- F14. Agent QoL: session resume + transcript export, `/` slash-command help, `@file`,
|
|
40
|
+
Ctrl-C aborts a turn, permission profiles (safe/auto/plan).
|
|
41
|
+
|
|
42
|
+
## Unique Ghost Protocol toolkit ideas (the "interesting" backlog)
|
|
43
|
+
- **Stack-fused agent** — the same agent that edits code can DRIVE the Ghost stack:
|
|
44
|
+
`dragon` already wraps scale/wyrm/pentest/keep/net, so expose those as agent tools
|
|
45
|
+
("run a pentest on X", "deploy upalis", "what changed in Wyrm?"). Coding agent + ops
|
|
46
|
+
console in one — nobody else has this.
|
|
47
|
+
- **Skills-as-tools** — wire the 200+ skill library in as a `skill_search`/`skill_apply`
|
|
48
|
+
tool so the agent pulls the right playbook mid-task. The library becomes live capability.
|
|
49
|
+
- **Wyrm flywheel** — every session already trains DragonSpark (traces). Surface it:
|
|
50
|
+
`dragon recall`, memory-aware answers, "what did we decide about X?".
|
|
51
|
+
- **Sub-agents** — a `task` tool to fan out parallel sub-agents for big jobs (audits,
|
|
52
|
+
migrations) like Claude Code's Task.
|
|
53
|
+
- **MCP hub** — connect ANY MCP server, not just Wyrm; `dragon mcp add/list`.
|
|
54
|
+
- **Purple-team mode** — an agent persona that orchestrates PhantomDragon + DragonKeep for
|
|
55
|
+
authorized security work, with the audit log as evidence.
|
|
56
|
+
- **Sovereign mode** — `dragon --sovereign`: Ollama + Wyrm only, airtight, for sensitive
|
|
57
|
+
repos / the DragonBrain appliance.
|
|
58
|
+
- **Sandboxed bash** — optional namespace/container isolation for tool execution.
|
|
59
|
+
- **Live TUI** — `dragon tui` operator dashboard (running services, recent agent actions,
|
|
60
|
+
Wyrm activity), and a `dragon` statusline.
|
|
61
|
+
- **Audit everything** — local + Wyrm audit log of every agent action; exportable evidence.
|
|
62
|
+
|
|
63
|
+
## Non-goals (v1.0)
|
|
64
|
+
- A GUI (that's Dragon Console). Telemetry. Windows-first (Linux/macOS lead).
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Dragon CLI v1.0 "Godmode" — Tasks
|
|
2
|
+
|
|
3
|
+
## Phase 1 — Foundation ✅ SHIPPED
|
|
4
|
+
- [x] Global crash handler + `--debug`
|
|
5
|
+
- [x] vitest unit/adversarial tests for security-critical pure logic (21 tests)
|
|
6
|
+
- [x] smoke + CI workflow (build + tsc --noUnusedLocals + test)
|
|
7
|
+
- [x] self-pentest fixes: cwd confinement, protected paths, bash always-dangerous,
|
|
8
|
+
0600 config/traces everywhere, broad redaction, credential header guard
|
|
9
|
+
- [x] `dragon brains` + custom OpenAI-compatible endpoint provider
|
|
10
|
+
- [x] atomic skill `industrial-grade-cli-craft`
|
|
11
|
+
|
|
12
|
+
## Phase 2 — Surface + QoL ✅ SHIPPED
|
|
13
|
+
- [x] ops-console theme (header + agent panel + brains/doctor/mcp panels; silver)
|
|
14
|
+
- [x] `dragon doctor` (brain/auth/wyrm/ollama/skills/disk/perms)
|
|
15
|
+
- [x] shell completions (bash/zsh/fish); `dragon upgrade` self-update
|
|
16
|
+
- [x] permission profiles: `--auto` (safe in-cwd) + `--plan` (read-only) + `/plan`
|
|
17
|
+
- [x] session resume (`--resume`) + transcript export (`/save`)
|
|
18
|
+
|
|
19
|
+
## Phase 3 — Moat ✅ SHIPPED
|
|
20
|
+
- [x] skills-as-tools (skill_search/skill_read over the 200+ library)
|
|
21
|
+
- [x] stack-fused agent tools (stack_status + stack_run)
|
|
22
|
+
- [x] MCP hub (`dragon mcp add/list/remove` → any MCP server's tools)
|
|
23
|
+
- [x] sub-agents (`task` tool — read-only, no recursion)
|
|
24
|
+
|
|
25
|
+
## Phase 4 — Sovereign + commercial ✅ (one item is per-product)
|
|
26
|
+
- [x] `--sovereign` mode (local brain + Wyrm only)
|
|
27
|
+
- [x] sandboxed bash — opt-in `--sandbox` via bwrap (cwd writable, rest read-only,
|
|
28
|
+
credential dirs masked; verified)
|
|
29
|
+
- [x] live `dragon tui` operator dashboard (system + live trace activity, no heavy deps)
|
|
30
|
+
- [x] bundle the agent into the DragonBrain appliance image (Node + dragon CLI)
|
|
31
|
+
- [x] stack actions as STRUCTURED first-class tools — `stack_pentest` (PhantomDragon
|
|
32
|
+
findings.json) + `stack_keep` (DragonKeep --format json); OSINT via the MCP hub
|
|
33
|
+
(`dragon mcp add dragonnet`). Contracts mapped by parallel investigation agents.
|
|
34
|
+
|
|
35
|
+
ALL phases shipped. v4.0 "Godmode" + v4.1 structured stack actions. Nothing open.
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
# dragon-cli — Premortem & Competitive Positioning
|
|
2
|
+
|
|
3
|
+
> Deep analysis, applying the `agentic-cli-premortem` methodology to dragon-cli **v4.2.0**.
|
|
4
|
+
> Author: Ghost Protocol · 2026-06-04. Honest by design — a premortem that flatters is theater.
|
|
5
|
+
|
|
6
|
+
**TL;DR.** dragon-cli is a genuinely well-built agentic CLI. It is *also* competing head-on
|
|
7
|
+
with two of the best-resourced dev tools on earth (Anthropic's Claude Code, GitHub's Copilot
|
|
8
|
+
CLI), with a user base of **one**, while the company's actual Q2 revenue engine is the $2,499
|
|
9
|
+
PTaaS product. As a general-purpose "Claude Code, but ours" it is most likely to die of
|
|
10
|
+
**opportunity cost**, not a technical flaw. As an **operator console for the Ghost Protocol
|
|
11
|
+
stack** — an internal force-multiplier and a sovereign, bundled differentiator for PTaaS /
|
|
12
|
+
DragonBrain — it has a real, defensible wedge that neither incumbent can structurally follow.
|
|
13
|
+
The recommendation is to *reframe what it's for*, not to out-feature the incumbents.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Move 1 — The premortem (it's June 2027; dragon-cli is abandoned. Why?)
|
|
18
|
+
|
|
19
|
+
**The one-sentence obituary, written first and honestly:**
|
|
20
|
+
|
|
21
|
+
> *It died because every hour spent polishing a coding CLI that competes with Anthropic and
|
|
22
|
+
> GitHub was an hour not spent closing PTaaS deals — and the CLI had exactly one user, so the
|
|
23
|
+
> polish never returned a cent.*
|
|
24
|
+
|
|
25
|
+
Everything below is downstream of that sentence. Ranked by `likelihood × impact`:
|
|
26
|
+
|
|
27
|
+
| # | Cause of death | Likelihood | Impact | Verdict |
|
|
28
|
+
|---|---|---|---|---|
|
|
29
|
+
| 1 | **Strategic opportunity-cost** — competes with the $2,499 PTaaS focus for the only scarce resource (Ryan's hours). | High | Fatal | **FATAL** |
|
|
30
|
+
| 2 | **Distribution-zero** — N=1 users; no funnel, no reason for anyone to switch from Claude Code. | High | Fatal (as a *product*) | **FATAL** |
|
|
31
|
+
| 3 | **Model-quality ceiling** — default brain is rented (`claude`); the free fallback (`worker`, Llama 3.3 70B) is a flaky tool-caller; `ghost`/DragonSpark is scaffolded, not trained. Can't out-quality Anthropic. | Certain | High | **STRUCTURAL** |
|
|
32
|
+
| 4 | **Solo-maintenance burden** — model APIs churn, MCP spec moves, terminals differ; the breadth shipped (coding+ops+pentest+memory+TUI+auth backend) is now the surface owed, by one person. | High | High | **SERIOUS** |
|
|
33
|
+
| 5 | **Security surface** — the model can run `bash` and edit files; prompt-injection + over-broad perms are now Ghost Protocol's liability. For a *security* company, one bad auto-run/breach narrative is reputation-fatal. | Medium | Fatal-if-it-lands | **GUARDED** (mitigated, see below) |
|
|
34
|
+
| 6 | **Differentiation fragility** — "we have MCP / subagents / a TUI / skills" — so do both incumbents, with teams. None of those is a moat. | High | Medium | **REFRAME** |
|
|
35
|
+
| 7 | **DragonSpark never ships** — the "own provider" story (`ghost` brain) is the long-term sovereignty bet; if it never trains, the differentiation leans entirely on rented models. | Medium-High | Medium | **DECOUPLE** |
|
|
36
|
+
| 8 | **All-in-one sprawl** — coding + ops + pentest + memory + nano-LLM reads as unfocused; each is a front you can lose on. | Medium | Medium | **NARROW** |
|
|
37
|
+
| 9 | **Untested authed e2e / single-machine** — device-flow + worker-brain only ever exercised on Ryan's box; breaks silently for any second user. | Medium | Low (at N=1) | **WATCH** |
|
|
38
|
+
|
|
39
|
+
### Which are actually fatal, and the only honest mitigations
|
|
40
|
+
|
|
41
|
+
- **#1 opportunity-cost (FATAL).** The only mitigation is to stop treating dragon-cli as a
|
|
42
|
+
product that must win attention, and treat it as (a) infrastructure that makes Ryan faster
|
|
43
|
+
at the work that *does* pay, and (b) a feature of the paid stack — not a standalone bet
|
|
44
|
+
fighting for mindshare. If it can't be justified on those two grounds, it should be frozen,
|
|
45
|
+
not polished. (Honors the maintenance-mode discipline and the 90-day PTaaS focus.)
|
|
46
|
+
- **#2 distribution-zero (FATAL as a product).** Don't fund a funnel for it. Either it rides
|
|
47
|
+
*inside* an existing distribution (bundled with PTaaS/DragonBrain, where the customer is
|
|
48
|
+
already acquired) or it stays internal. A solo founder will not win consumer dev-tool
|
|
49
|
+
distribution against GitHub.
|
|
50
|
+
- **#3 model ceiling (STRUCTURAL).** Unfixable by effort — so *design so it matters less*.
|
|
51
|
+
dragon's value must come from the axes where model quality is not the differentiator
|
|
52
|
+
(memory, stack-fusion, sovereignty, cost), and it should transparently use the best rented
|
|
53
|
+
model when quality matters. Stop comparing dragon's brain to Opus; that's a lost axis.
|
|
54
|
+
- **#5 security (GUARDED → keep it that way).** This is the one fatal risk that is *already*
|
|
55
|
+
well-mitigated, and it's where the security-company DNA actually pays off: cwd-confinement,
|
|
56
|
+
protected-path blocking, bash-is-always-prompt (never auto), bwrap `--sandbox`, 0600
|
|
57
|
+
secrets, broad redaction, SSRF/restricted-port guards, header-injection guard, global crash
|
|
58
|
+
handler. **This must never regress** — it is simultaneously the biggest liability and, told
|
|
59
|
+
correctly, a *selling point* ("the agentic CLI built by pentesters, hardened like we'd
|
|
60
|
+
attack it"). The remaining gap is the untested second-machine path (#9).
|
|
61
|
+
|
|
62
|
+
The survivable-but-not-fatal lines (#4, #6, #7, #8) all resolve into one instruction:
|
|
63
|
+
**narrow the promise.** Breadth is the maintenance bill and the unfocused pitch at once.
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## Move 2 — Competitive teardown (verified, not from the README)
|
|
68
|
+
|
|
69
|
+
### ⚠️ Premise correction: GitHub Copilot CLI is **not** open source
|
|
70
|
+
|
|
71
|
+
The working assumption was "GitHub Copilot CLI, which is open source, you can check the
|
|
72
|
+
source." Verified, that is **false**, and the way it's false is the textbook trap from the
|
|
73
|
+
methodology:
|
|
74
|
+
|
|
75
|
+
- The public repo **`github/copilot-cli`** contains **documentation and issues only** — *no
|
|
76
|
+
product source*. It looks like "the source repo" and isn't.
|
|
77
|
+
- The CLI ships as a **prebuilt, minified npm package `@github/copilot`** (~**301 MB**),
|
|
78
|
+
under a **proprietary "GitHub Copilot CLI" license** (the SDK piece, `@github/copilot-sdk`,
|
|
79
|
+
is the only openly-licensed sliver).
|
|
80
|
+
- So the honest answer to "is it open source?" is: **No — it is closed-source,
|
|
81
|
+
source-unavailable, with a public docs/issues repo named like the product.** It is *not*
|
|
82
|
+
forkable, inspectable, or relicensable. (This is exactly why the methodology says: answer
|
|
83
|
+
with the license + what's actually in the repo, never the homepage adjective.)
|
|
84
|
+
|
|
85
|
+
The genuinely open-source competitors in this category are **aider** (Apache-2.0) and
|
|
86
|
+
**Gemini CLI** (Apache-2.0). Neither GitHub's nor Anthropic's CLI is.
|
|
87
|
+
|
|
88
|
+
### Claude Code (Anthropic) — the quality incumbent
|
|
89
|
+
|
|
90
|
+
- **Closed source**, Anthropic-operated. Models: **Opus 4.8 / Sonnet 4.6 / Haiku 4.5** —
|
|
91
|
+
Anthropic *is* the lab, so it sets the quality floor everyone else rents.
|
|
92
|
+
- Tools: Read / Edit / Write / Bash / Glob / Grep / Agent / Skill / WebFetch / WebSearch /
|
|
93
|
+
Workflow. **Subagents** (Explore / Plan / general — no nesting), **forks**, **agent teams**,
|
|
94
|
+
**Dynamic Workflows** (deterministic multi-agent orchestration).
|
|
95
|
+
- **Plan mode**; **MCP** across http/sse/stdio/ws with 3 scopes, OAuth, and Tool Search;
|
|
96
|
+
**Agent Skills** standard (commands merged into skills); **hooks** (30+ lifecycle events);
|
|
97
|
+
**plugins**; **dual memory** (CLAUDE.md + auto-memory under `~/.claude/projects/<p>/memory/`);
|
|
98
|
+
**6 permission modes** incl. classifier-gated auto + OS sandboxing.
|
|
99
|
+
- **Moat:** owns the frontier model; deep, coherent agent architecture; ecosystem (skills /
|
|
100
|
+
plugins / hooks) with real adoption.
|
|
101
|
+
- **Underbelly:** closed + Anthropic-locked (one vendor, one jurisdiction); **cost** (heavy
|
|
102
|
+
use runs ~$500–2,000/eng/mo); a context-window "quality tax" on very long sessions;
|
|
103
|
+
prompt-injection surface like any agent; **no on-host sovereign mode, no cross-session
|
|
104
|
+
project memory you fully own, no built-in security-stack drivers.**
|
|
105
|
+
|
|
106
|
+
### GitHub Copilot CLI (GitHub / Microsoft) — the distribution incumbent
|
|
107
|
+
|
|
108
|
+
- **Closed source** (see correction above). Agentic, **multi-model**, **default Claude
|
|
109
|
+
Sonnet 4.5** (so it *also* rents Anthropic's quality); MCP support; **custom agents**;
|
|
110
|
+
**`/fleet`** parallel subagents; **`/sandbox`**; `@github/copilot-sdk`.
|
|
111
|
+
- **Moat:** GitHub/Microsoft distribution + brand + the place developers already are; tight
|
|
112
|
+
GitHub/repo/PR integration; effectively unlimited maintenance capacity.
|
|
113
|
+
- **Underbelly:** not OSS/forkable/packageable; **cost burn** (consumes Copilot *premium
|
|
114
|
+
requests*); a **multi-file edit ceiling** reported in practice; **~90s cloud latency** on
|
|
115
|
+
some operations; **cloud-tied memory** (no local-owned project memory); no sovereignty, no
|
|
116
|
+
security-stack fusion.
|
|
117
|
+
|
|
118
|
+
### Three-way capability matrix
|
|
119
|
+
|
|
120
|
+
| Axis | **dragon-cli v4.2.0** | **Claude Code** | **GitHub Copilot CLI** |
|
|
121
|
+
|---|---|---|---|
|
|
122
|
+
| License / source | **Proprietary, but fully self-owned source** | Closed (Anthropic) | Closed (repo = docs/issues only) |
|
|
123
|
+
| Default model | `claude` (Sonnet 4.6) — rented | Opus/Sonnet/Haiku — **owned** | Claude Sonnet 4.5 — rented |
|
|
124
|
+
| Free / zero-key fallback | **✅ `worker` (Cloudflare Workers AI, Llama 3.3 70B)** — *flaky tool-caller* | ❌ | ❌ |
|
|
125
|
+
| Fully local / sovereign | **✅ `--sovereign` (Ollama + Wyrm, no cloud)** | ❌ | ❌ |
|
|
126
|
+
| Own-model roadmap | `ghost` / DragonSpark — **scaffolded, untrained** | N/A (is the lab) | N/A |
|
|
127
|
+
| Cross-session memory you own | **✅ Wyrm by default (16 tools, project context)** | Partial (CLAUDE.md + auto-memory, Anthropic-side) | ❌ (cloud-tied) |
|
|
128
|
+
| Skills | **✅ as live tools over 200+ GP library** | ✅ Agent Skills standard + ecosystem | Custom agents |
|
|
129
|
+
| MCP | ✅ hub (stdio) | ✅ http/sse/stdio/ws, OAuth, 3 scopes, Tool Search | ✅ |
|
|
130
|
+
| Subagents | ✅ read-only `task` | ✅ Explore/Plan/general + teams + workflows | ✅ `/fleet` |
|
|
131
|
+
| Domain stack-fusion | **✅ `stack_pentest` (PhantomDragon) · `stack_keep` (DragonKeep) · `stack_run`** | ❌ | ❌ |
|
|
132
|
+
| Sandbox / hardening | ✅ bwrap, cwd-confine, 0600, redaction, SSRF guard | ✅ OS sandbox + 6 perm modes | ✅ `/sandbox` |
|
|
133
|
+
| TUI craft | **✅ alt-screen, sync-output, sub-cell gauges/sparklines** | Standard | Standard |
|
|
134
|
+
| Cost control | **✅ free/local options → ~$0 floor** | $$$ ($500–2k/eng/mo) | $$ (premium requests) |
|
|
135
|
+
| Maintenance capacity | **1 person** | Large team | Large team (MS-funded) |
|
|
136
|
+
| Distribution / users | **N=1** | Massive | Massive (GitHub) |
|
|
137
|
+
| Ecosystem maturity | New | High | High |
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## Move 3 — Synthesis & decision
|
|
142
|
+
|
|
143
|
+
### Honest scorecard
|
|
144
|
+
|
|
145
|
+
- **dragon genuinely WINS (and can defend):**
|
|
146
|
+
1. **Sovereignty** — `--sovereign` (local Ollama + Wyrm, zero cloud) and a **free zero-key
|
|
147
|
+
fallback**. *Neither incumbent has this. Structural — they sell cloud.*
|
|
148
|
+
2. **Cross-session memory you fully own** — Wyrm, on by default, across 42 projects.
|
|
149
|
+
3. **Security-stack fusion** — it can *drive PhantomDragon and DragonKeep*. No general
|
|
150
|
+
coding CLI does or will; it's specific to this company's products.
|
|
151
|
+
4. **Cost floor ~$0** — for a bootstrapped, Sri-Lanka-cost-basis operator this is real.
|
|
152
|
+
5. **Built-by-pentesters hardening** — credible *because* of the company's DNA.
|
|
153
|
+
- **dragon LOSES (and can't fix by effort):** raw model quality, ecosystem maturity, team
|
|
154
|
+
patch-cadence, distribution, polish-at-scale, breadth-of-tested-environments.
|
|
155
|
+
- **Parity (a checkbox, not a moat):** MCP, subagents, skills, sandbox, plan mode, a nice
|
|
156
|
+
TUI. Having these is table stakes; they do **not** differentiate dragon from the incumbents.
|
|
157
|
+
|
|
158
|
+
If the pitch is "a better Claude Code," every line of the scorecard that matters is a loss.
|
|
159
|
+
The wins only matter if the tool is *about* those wins.
|
|
160
|
+
|
|
161
|
+
### The wedge (one sentence)
|
|
162
|
+
|
|
163
|
+
> **dragon-cli is the sovereign operator console for the Ghost Protocol stack** — the only
|
|
164
|
+
> agentic CLI that runs fully on-host (or free), remembers across every Ghost Protocol
|
|
165
|
+
> project via Wyrm, and *drives the company's own security tooling* — built and hardened by
|
|
166
|
+
> the pentesters who sell PTaaS.
|
|
167
|
+
|
|
168
|
+
That is an axis the incumbents **structurally cannot** follow: Anthropic and GitHub will
|
|
169
|
+
never run fully offline, will never own Wyrm's memory, and will never ship a `stack_pentest`
|
|
170
|
+
for PhantomDragon.
|
|
171
|
+
|
|
172
|
+
### "What would have to be true" for dragon-cli to be worth continuing?
|
|
173
|
+
|
|
174
|
+
1. It measurably makes **Ryan** faster at PTaaS/portfolio work (internal force-multiplier). ✅ plausible.
|
|
175
|
+
2. It can be **bundled** with a thing that already has a buyer (PTaaS report-ops, or the
|
|
176
|
+
DragonBrain sovereign appliance) so distribution is inherited, not funded. ✅ plausible.
|
|
177
|
+
3. It does **not** require winning a consumer dev-tool distribution war vs GitHub. ✅ (only if we don't try).
|
|
178
|
+
4. Its security hardening **never regresses** and the second-machine path gets one real test. ✅ achievable.
|
|
179
|
+
5. DragonSpark/`ghost` is **decoupled** — a nice-to-have sovereignty upgrade, never the thing
|
|
180
|
+
the value depends on. ✅ achievable.
|
|
181
|
+
|
|
182
|
+
It does **NOT** require: a frontier model of our own, thousands of users, or out-featuring
|
|
183
|
+
Anthropic. Good — those were the implausible ones.
|
|
184
|
+
|
|
185
|
+
### Decision
|
|
186
|
+
|
|
187
|
+
**Reframe, don't compete; freeze breadth, protect the wedge.**
|
|
188
|
+
|
|
189
|
+
1. **Stop positioning it as a Claude-Code competitor.** Position = "sovereign operator
|
|
190
|
+
console for the Ghost Protocol stack." Every README/marketing line should lead with
|
|
191
|
+
sovereignty + Wyrm memory + stack-fusion, not "coding agent."
|
|
192
|
+
2. **Bundle, don't distribute.** Ship it *with* DragonBrain (sovereign on-box) and as
|
|
193
|
+
PTaaS report/ops tooling. No standalone growth funnel — that's the PTaaS product's job.
|
|
194
|
+
3. **Freeze feature breadth** for Q2. It's v4.2.0 and complete enough. New work only if it
|
|
195
|
+
(a) speeds Ryan's paid work or (b) hardens the wedge. No parity-chasing.
|
|
196
|
+
4. **Protect the two fatal-but-mitigated risks:** keep security hardening green (it's the
|
|
197
|
+
selling point *and* the liability); add one authed second-machine e2e test (#9).
|
|
198
|
+
5. **Decouple DragonSpark** from dragon-cli's value. It's R&D upside, not a dependency.
|
|
199
|
+
6. **Use it as the everyday driver** — the best proof a force-multiplier works is the founder
|
|
200
|
+
living in it.
|
|
201
|
+
|
|
202
|
+
The premortem's verdict in one line: **dragon-cli doesn't die from being badly built — it
|
|
203
|
+
dies from being aimed at the wrong target. Re-aim it at the stack it was born next to, and
|
|
204
|
+
it's a moat the incumbents can't cross.**
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
*Methodology captured as the `agentic-cli-premortem` skill. Competitor facts verified
|
|
209
|
+
2026-06-04 (licenses, npm artifacts, model backbones, tool surfaces). The "Copilot CLI is
|
|
210
|
+
open source" premise was checked and corrected — it is closed-source with a docs-only public
|
|
211
|
+
repo.*
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The agent loop — Dragon's engine. Runs the model↔tool cycle entirely
|
|
3
|
+
* client-side so tools touch THIS machine:
|
|
4
|
+
*
|
|
5
|
+
* user → brain.turn(tools) → [tool calls?] → execute locally → feed back → repeat
|
|
6
|
+
* └ no calls → final answer, done
|
|
7
|
+
*
|
|
8
|
+
* Tools come from three sources, routed by name: local coding tools (read/edit/
|
|
9
|
+
* bash/grep…), the curated Wyrm memory tools (`wyrm_*` → MCP), and the optional
|
|
10
|
+
* hosted Dragon portal (`portal_ask`). Wyrm is wired by default and the system
|
|
11
|
+
* prompt tells the model to use it as long-term memory.
|
|
12
|
+
*
|
|
13
|
+
* Copyright 2026 Ghost Protocol (Pvt) Ltd. All Rights Reserved.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import type { Brain, BrainMessage, ToolCall, ToolSpec } from '../brain/types.js'
|
|
17
|
+
import { getLocalTool, localToolSpecs, type ToolContext } from './tools.js'
|
|
18
|
+
import type { Wyrm } from '../wyrm/mcp.js'
|
|
19
|
+
import type { SkillLibrary } from './skills.js'
|
|
20
|
+
import type { StackTools } from './stack.js'
|
|
21
|
+
import type { McpHub } from './mcp.js'
|
|
22
|
+
import type { TaskTool } from './task.js'
|
|
23
|
+
|
|
24
|
+
const MAX_STEPS = 60 // hard stop against a runaway tool loop
|
|
25
|
+
|
|
26
|
+
export interface PortalTool {
|
|
27
|
+
spec: ToolSpec
|
|
28
|
+
call(args: Record<string, unknown>): Promise<string>
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface AgentRender {
|
|
32
|
+
/** First text delta of an assistant segment (print the ◆ prefix etc). */
|
|
33
|
+
onAssistantStart(): void
|
|
34
|
+
onDelta(s: string): void
|
|
35
|
+
onToolStart(summary: string): void
|
|
36
|
+
onToolEnd(summary: string, resultPreview: string, ok: boolean): void
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface AgentDeps {
|
|
40
|
+
brain: Brain
|
|
41
|
+
wyrm: Wyrm | null
|
|
42
|
+
portal: PortalTool | null
|
|
43
|
+
skills: SkillLibrary | null
|
|
44
|
+
stack: StackTools | null
|
|
45
|
+
mcp: McpHub | null
|
|
46
|
+
task: TaskTool | null
|
|
47
|
+
cwd: string
|
|
48
|
+
system: string
|
|
49
|
+
toolCtx: ToolContext
|
|
50
|
+
messages: BrainMessage[]
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function buildSystemPrompt(opts: { cwd: string; wyrm: boolean; portal: boolean; brainId: string; skills?: number; primed?: string | null }): string {
|
|
54
|
+
const lines = [
|
|
55
|
+
'You are Dragon — Ghost Protocol\'s terminal coding agent (the `dragon` CLI). You operate like a senior engineer pair: precise, autonomous, and concise.',
|
|
56
|
+
`Working directory: ${opts.cwd}. Platform: ${process.platform}. Reasoning brain: ${opts.brainId}.`,
|
|
57
|
+
'',
|
|
58
|
+
'TOOLS — you have real local tools (read_file, write_file, edit_file, list_dir, glob, grep, bash). Use them to DO the work, not describe it. Explore before you edit (grep/glob/read). Prefer edit_file over rewriting whole files. After code changes, build/test with bash to verify. Keep going until the task is genuinely done.',
|
|
59
|
+
'Be surgical: match the surrounding code style, make the smallest change that works, and never invent file paths — find them.',
|
|
60
|
+
]
|
|
61
|
+
lines.push('', 'STACK — you ARE the `dragon` operator console for the Ghost Protocol stack (scale · wyrm · pentest · keep · net). stack_status shows what is installed/running; stack_pentest runs a PhantomDragon web scan (authorized targets only) and stack_keep runs a DragonKeep system scan — both return STRUCTURED findings; stack_run drives any other dragon subcommand. You are a coding agent AND an operator — reach for the stack when the task is ops, not code.')
|
|
62
|
+
if (opts.skills) {
|
|
63
|
+
lines.push('', `SKILLS — you have ${opts.skills} reusable expert playbooks (design, security, infra, brand, project-specific). Before solving a non-trivial task from scratch, call skill_search for a relevant one and skill_read it, then apply its guidance. This institutional knowledge is your edge — reach for it first.`)
|
|
64
|
+
}
|
|
65
|
+
if (opts.wyrm) {
|
|
66
|
+
lines.push(
|
|
67
|
+
'',
|
|
68
|
+
'MEMORY (Wyrm) — you have persistent cross-session memory via the wyrm_* tools, and you should use it proactively:',
|
|
69
|
+
'• Before non-trivial work, recall context with wyrm_recall / wyrm_search / wyrm_project_context.',
|
|
70
|
+
'• Capture durable decisions, lessons, and gotchas with wyrm_remember / wyrm_capture so future sessions inherit them.',
|
|
71
|
+
'• Track multi-step work as quests (wyrm_quest_add / wyrm_quest_complete). Record decisions with wyrm_decided_because.',
|
|
72
|
+
'• Reach for an existing skill via wyrm_skill_search before solving something from scratch.',
|
|
73
|
+
'Read memory freely without asking. This is what makes you better than a stateless assistant.',
|
|
74
|
+
)
|
|
75
|
+
}
|
|
76
|
+
if (opts.portal) {
|
|
77
|
+
lines.push('', 'PORTAL — use portal_ask for the operator\'s Ghost Protocol account/licenses/catalog/services questions (it reaches the hosted account.ghosts.lk assistant). Not for coding.')
|
|
78
|
+
}
|
|
79
|
+
lines.push('', 'STYLE — terse, operator-grade, GitHub-flavored markdown. No filler, no emoji. Reference code as `path:line`. State what you did, not what you\'re "about to" do.')
|
|
80
|
+
if (opts.primed) {
|
|
81
|
+
lines.push('', '── Project context recalled from Wyrm (treat as background, verify before relying on specifics) ──', opts.primed)
|
|
82
|
+
}
|
|
83
|
+
return lines.join('\n')
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** Build the full tool surface handed to the brain this session. */
|
|
87
|
+
export function buildToolSpecs(deps: { wyrm: Wyrm | null; portal: PortalTool | null; skills: SkillLibrary | null; stack: StackTools | null; mcp: McpHub | null; task: TaskTool | null }): ToolSpec[] {
|
|
88
|
+
return [
|
|
89
|
+
...localToolSpecs(),
|
|
90
|
+
...(deps.skills?.toolSpecs() ?? []),
|
|
91
|
+
...(deps.stack?.specs ?? []),
|
|
92
|
+
...(deps.mcp?.toolSpecs() ?? []),
|
|
93
|
+
...(deps.task ? [deps.task.spec] : []),
|
|
94
|
+
...(deps.wyrm?.toolSpecs() ?? []),
|
|
95
|
+
...(deps.portal ? [deps.portal.spec] : []),
|
|
96
|
+
]
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async function dispatch(call: ToolCall, deps: AgentDeps): Promise<string> {
|
|
100
|
+
const { name, arguments: args } = call
|
|
101
|
+
if (deps.skills?.handles(name)) return deps.skills.call(name, args)
|
|
102
|
+
if (deps.stack?.handles(name)) return deps.stack.call(name, args, deps.toolCtx)
|
|
103
|
+
if (deps.mcp?.handles(name)) return deps.mcp.call(name, args)
|
|
104
|
+
if (deps.task && name === deps.task.spec.name) return deps.task.call(args)
|
|
105
|
+
if (deps.wyrm?.handles(name)) return deps.wyrm.call(name, args)
|
|
106
|
+
if (deps.portal && name === deps.portal.spec.name) return deps.portal.call(args)
|
|
107
|
+
const tool = getLocalTool(name)
|
|
108
|
+
if (!tool) return `error: unknown tool "${name}"`
|
|
109
|
+
try {
|
|
110
|
+
return await tool.run(args, deps.toolCtx)
|
|
111
|
+
} catch (e) {
|
|
112
|
+
return `error running ${name}: ${String(e instanceof Error ? e.message : e)}`
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function toolSummary(call: ToolCall, deps: AgentDeps): string {
|
|
117
|
+
const local = getLocalTool(call.name)
|
|
118
|
+
if (local) return local.summary(call.arguments)
|
|
119
|
+
if (deps.skills?.handles(call.name)) return `${call.name}: ${String((call.arguments as { query?: string; name?: string }).query ?? (call.arguments as { name?: string }).name ?? '')}`
|
|
120
|
+
if (deps.stack?.handles(call.name)) {
|
|
121
|
+
if (call.name === 'stack_pentest') return `pentest: ${String((call.arguments as { url?: string }).url ?? '')}`
|
|
122
|
+
if (call.name === 'stack_keep') return `keep: ${String((call.arguments as { scan_type?: string }).scan_type ?? 'quick')}`
|
|
123
|
+
if (call.name === 'stack_status') return 'stack_status'
|
|
124
|
+
return `stack: ${String((call.arguments as { command?: string }).command ?? '')}`
|
|
125
|
+
}
|
|
126
|
+
if (call.name === deps.task?.spec.name) return `task: ${String((call.arguments as { task?: string }).task ?? '').slice(0, 60)}`
|
|
127
|
+
if (deps.mcp?.handles(call.name)) return call.name
|
|
128
|
+
if (deps.wyrm?.handles(call.name)) return `${call.name}`
|
|
129
|
+
if (call.name === deps.portal?.spec.name) return `portal: ${String((call.arguments as { question?: string }).question ?? '').slice(0, 60)}`
|
|
130
|
+
return call.name
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Run one user message to completion (through any number of tool steps).
|
|
135
|
+
* Mutates deps.messages so the conversation persists across calls.
|
|
136
|
+
*/
|
|
137
|
+
export async function runAgent(deps: AgentDeps, userText: string, render: AgentRender, signal: AbortSignal): Promise<void> {
|
|
138
|
+
const tools = buildToolSpecs(deps)
|
|
139
|
+
deps.messages.push({ role: 'user', content: userText })
|
|
140
|
+
|
|
141
|
+
for (let step = 0; step < MAX_STEPS; step++) {
|
|
142
|
+
let started = false
|
|
143
|
+
const turn = await deps.brain.turn({
|
|
144
|
+
system: deps.system,
|
|
145
|
+
messages: deps.messages,
|
|
146
|
+
tools,
|
|
147
|
+
signal,
|
|
148
|
+
onDelta: (d) => { if (!started) { render.onAssistantStart(); started = true } render.onDelta(d) },
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
deps.messages.push({ role: 'assistant', content: turn.text, toolCalls: turn.toolCalls.length ? turn.toolCalls : undefined })
|
|
152
|
+
|
|
153
|
+
if (!turn.toolCalls.length) return // settled — final answer streamed
|
|
154
|
+
|
|
155
|
+
for (const call of turn.toolCalls) {
|
|
156
|
+
const summary = toolSummary(call, deps)
|
|
157
|
+
render.onToolStart(summary)
|
|
158
|
+
const result = await dispatch(call, deps)
|
|
159
|
+
const ok = !result.startsWith('error')
|
|
160
|
+
render.onToolEnd(summary, result.split('\n')[0]?.slice(0, 120) ?? '', ok)
|
|
161
|
+
deps.messages.push({ role: 'tool', content: result, toolCallId: call.id, toolName: call.name })
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
render.onDelta(`\n[stopped after ${MAX_STEPS} tool steps]`)
|
|
165
|
+
}
|