Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion packages/security/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ export const riskFromText = (text: string): RiskLevel => {

export const redactSecrets = (input: string) => {
return input
.replace(/sk-[A-Za-z0-9_-]+/g, "[REDACTED_OPENAI_KEY]")
.replace(/sk-ant-[A-Za-z0-9_-]+/g, "[REDACTED_ANTHROPIC_KEY]")
.replace(/sk-(?!ant-)[A-Za-z0-9_-]+/g, "[REDACTED_OPENAI_KEY]")
.replace(/ghp_[A-Za-z0-9_]+/g, "[REDACTED_GITHUB_TOKEN]")
.replace(/AIza[A-Za-z0-9_-]+/g, "[REDACTED_GOOGLE_KEY]")
.replace(/Bearer\s+[A-Za-z0-9._-]+/g, "Bearer [REDACTED_TOKEN]");
};
Expand Down
40 changes: 40 additions & 0 deletions packages/security/src/security_redact.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { describe, expect, it } from "vitest";
import { redactSecrets } from "./index.js";

describe("redactSecrets", () => {
it("redacts OpenAI keys", () => {
const input = "Here is my key: sk-abcdefghijklmnopqrstuvwxyz0123456789ABCD";
const redacted = redactSecrets(input);
expect(redacted).toBe("Here is my key: [REDACTED_OPENAI_KEY]");
});

it("redacts Anthropic keys specifically", () => {
const input = "Anthropic key: sk-ant-api01-abcdefghijklmnopqrstuvwxyz0123456789ABCD-xyz123";
const redacted = redactSecrets(input);
expect(redacted).toBe("Anthropic key: [REDACTED_ANTHROPIC_KEY]");
});

it("distinguishes between OpenAI and Anthropic keys", () => {
const input = "OpenAI: sk-openai123, Anthropic: sk-ant-anthropic456";
const redacted = redactSecrets(input);
expect(redacted).toBe("OpenAI: [REDACTED_OPENAI_KEY], Anthropic: [REDACTED_ANTHROPIC_KEY]");
});

it("redacts GitHub tokens", () => {
const input = "My GitHub token is ghp_1234567890abcdefghijklmnopqrstuvwxyzABCD";
const redacted = redactSecrets(input);
expect(redacted).toBe("My GitHub token is [REDACTED_GITHUB_TOKEN]");
});

it("redacts Google keys", () => {
const input = "Google API key: AIzaSyD-1234567890abcdefghijklmnopqrstuvwxyz";
const redacted = redactSecrets(input);
expect(redacted).toBe("Google API key: [REDACTED_GOOGLE_KEY]");
});

it("redacts Bearer tokens", () => {
const input = "Authorization: Bearer my-secret-token.12345";
const redacted = redactSecrets(input);
expect(redacted).toBe("Authorization: Bearer [REDACTED_TOKEN]");
});
});
1 change: 1 addition & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

54 changes: 47 additions & 7 deletions src/cognitive/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@

from .service import MissionExecutorService

# ANSI color codes for terminal output
COLOR_GREEN = "\033[92m"
COLOR_RED = "\033[91m"
COLOR_YELLOW = "\033[93m"
COLOR_CYAN = "\033[96m"
COLOR_RESET = "\033[0m"


def build_parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(description="JeanBot Python mission runner")
Expand Down Expand Up @@ -53,7 +60,7 @@ async def run_shell(args: argparse.Namespace):

while True:
try:
line = input("\njeanbot> ").strip()
line = input(f"\n{COLOR_CYAN}jeanbot>{COLOR_RESET} ").strip()
if not line:
continue
if line.lower() in ("exit", "quit"):
Expand All @@ -62,19 +69,46 @@ async def run_shell(args: argparse.Namespace):
history.append(line)

if line.lower() == "help":
print("Commands:")
print(f"{COLOR_CYAN}Commands:{COLOR_RESET}")
print(" help Show this help")
print(" history Show command history")
print(" status Show status of the last mission")
print(" plan Show the plan of the last mission")
print(" exit | quit Exit shell")
print(" <objective> Plan and execute a mission")
print(" refine <feedback> Refine the last mission result with feedback")
continue

if line.lower() == "history":
print(f"{COLOR_CYAN}Command History:{COLOR_RESET}")
for i, cmd in enumerate(history, 1):
print(f" {i:3} {cmd}")
continue

if line.lower() == "status":
if not last_result:
print(f"{COLOR_YELLOW}No mission has been run yet.{COLOR_RESET}")
continue
metrics = last_result.metrics
status_color = COLOR_GREEN if last_result.status == "completed" else COLOR_RED
print(f"{COLOR_CYAN}Mission Status:{COLOR_RESET}")
print(f" ID: {last_result.mission_id}")
print(f" Status: {status_color}{last_result.status}{COLOR_RESET}")
print(f" Progress: {metrics.get('completed_steps', 0)}/{metrics.get('total_steps', 0)} steps")
print(f" Average Score: {metrics.get('average_score', 0)}")
continue

if line.lower() == "plan":
if not last_result:
print(f"{COLOR_YELLOW}No mission has been run yet.{COLOR_RESET}")
continue
print(f"{COLOR_CYAN}Mission Plan:{COLOR_RESET}")
for report in last_result.step_reports:
diag = report.diagnostics
status_icon = f"{COLOR_GREEN}✓{COLOR_RESET}" if diag and diag.failure_class == "none" else f"{COLOR_RED}✗{COLOR_RESET}"
print(f" {status_icon} {report.step_id}: {report.summary}")
continue

if line.lower().startswith("refine "):
if not last_result:
print("Nothing to refine. Run a mission first.")
Expand All @@ -97,15 +131,21 @@ async def run_shell(args: argparse.Namespace):
"mode": args.mode,
}

print(f"Executing: {title}")
print(f"{COLOR_YELLOW}Executing:{COLOR_RESET} {title}")
last_result = await service.execute_payload(payload)

print(f"\nStatus: {last_result.status}")
print(f"Summary: {last_result.verification_summary}")
status_color = COLOR_GREEN if last_result.status == "completed" else COLOR_RED
print(f"\n{COLOR_CYAN}Status:{COLOR_RESET} {status_color}{last_result.status}{COLOR_RESET}")
print(f"{COLOR_CYAN}Summary:{COLOR_RESET} {last_result.verification_summary}")
if last_result.artifacts:
print(f"Artifacts: {len(last_result.artifacts)}")
print(f"{COLOR_CYAN}Artifacts ({len(last_result.artifacts)}):{COLOR_RESET}")
for artifact in last_result.artifacts:
print(f" - {artifact.title}: {artifact.path}")
try:
rel_path = Path(artifact.path).relative_to(Path(args.workspace_root).absolute())
except ValueError:
# Fallback if path is not relative to workspace_root
rel_path = artifact.path
print(f" - {artifact.title}: {rel_path}")

except KeyboardInterrupt:
print("\nInterrupt received, type 'exit' to quit.")
Expand Down
6 changes: 3 additions & 3 deletions workspace/users/{userId}/.jeanbot/context.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# JeanBot User Context

- Current mission: Smoke test
- Updated at: 2026-03-13T21:07:03.733Z
- Completed steps: Inspect workspace files | Load and update memory context | Run policy and risk review | Decompose objective into steps | Create safety checkpoint | Handle finance-sensitive workflows | Synthesize final mission result | Track status and coordination | Synthesize final mission result | Clarify mission constraints | Produce mission documentation
- Current mission: API mission
- Updated at: 2026-05-26T01:30:35.720Z
- Completed steps: Inspect workspace files | Load and update memory context | Run policy and risk review | Decompose objective into steps | Synthesize final mission result | Track status and coordination | Synthesize final mission result | Clarify mission constraints | Produce mission documentation
- In-progress steps: none
- Upcoming steps: none
Loading