@pat-lewczuk/cezar 0.1.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/README.md +90 -0
- package/dist/core/agent-runner.d.ts +95 -0
- package/dist/core/agent-runner.js +8 -0
- package/dist/core/agent-runner.js.map +1 -0
- package/dist/core/backend-detect.d.ts +14 -0
- package/dist/core/backend-detect.js +78 -0
- package/dist/core/backend-detect.js.map +1 -0
- package/dist/core/claude-cli-runner.d.ts +68 -0
- package/dist/core/claude-cli-runner.js +424 -0
- package/dist/core/claude-cli-runner.js.map +1 -0
- package/dist/core/usage.d.ts +11 -0
- package/dist/core/usage.js +15 -0
- package/dist/core/usage.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +294 -0
- package/dist/index.js.map +1 -0
- package/dist/runs/store.d.ts +218 -0
- package/dist/runs/store.js +286 -0
- package/dist/runs/store.js.map +1 -0
- package/dist/server/git.d.ts +21 -0
- package/dist/server/git.js +54 -0
- package/dist/server/git.js.map +1 -0
- package/dist/server/open-in-terminal.d.ts +11 -0
- package/dist/server/open-in-terminal.js +84 -0
- package/dist/server/open-in-terminal.js.map +1 -0
- package/dist/server/server.d.ts +12 -0
- package/dist/server/server.js +243 -0
- package/dist/server/server.js.map +1 -0
- package/dist/skills.d.ts +31 -0
- package/dist/skills.js +117 -0
- package/dist/skills.js.map +1 -0
- package/dist/workflows/load.d.ts +15 -0
- package/dist/workflows/load.js +58 -0
- package/dist/workflows/load.js.map +1 -0
- package/dist/workflows/run.d.ts +52 -0
- package/dist/workflows/run.js +452 -0
- package/dist/workflows/run.js.map +1 -0
- package/dist/workflows/types.d.ts +202 -0
- package/dist/workflows/types.js +56 -0
- package/dist/workflows/types.js.map +1 -0
- package/package.json +44 -0
- package/scripts/mock-claude.mjs +106 -0
- package/web/app.js +634 -0
- package/web/index.html +48 -0
- package/web/style.css +317 -0
package/README.md
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# cezar ⚡
|
|
2
|
+
|
|
3
|
+
Local cockpit for running and tracking AI agent tasks in your repo. Single
|
|
4
|
+
user, zero config, one command:
|
|
5
|
+
|
|
6
|
+
```bash
|
|
7
|
+
cd your-repo
|
|
8
|
+
npx cezar
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
That's it. If you have the `claude` CLI logged in (Pro/Max subscription) and
|
|
12
|
+
`gh` authenticated, there is nothing to configure — cez opens a browser
|
|
13
|
+
cockpit at `http://localhost:4321` where you type a task, pick a workflow and
|
|
14
|
+
watch the agent work live (steps, tool calls, tokens), with a repo view
|
|
15
|
+
(status / diff / log) right next to it.
|
|
16
|
+
|
|
17
|
+
No accounts, no database, no cloud. State lives in `.ai/cezar/` inside your repo.
|
|
18
|
+
|
|
19
|
+
## What it does
|
|
20
|
+
|
|
21
|
+
- **Runs** — every agent task is a run: queued → running → done/failed, with a
|
|
22
|
+
live event log (agent text, tool calls, tool results), token usage per step
|
|
23
|
+
and cancel/delete controls. Failed run? Take the session over interactively:
|
|
24
|
+
`claude --resume <session-id>` (shown in the run header).
|
|
25
|
+
- **Workflows** — a YAML file: agent steps + shell checks, with bounded
|
|
26
|
+
retry loops (`onFail: retry`). The built-in `quick-task` workflow (one agent
|
|
27
|
+
step) works with zero setup.
|
|
28
|
+
- **Skills** — Markdown files in `.ai/skills/` or `.ai/cezar/skills/`; a workflow
|
|
29
|
+
step references one via `skill: <name>` and its body becomes the agent's
|
|
30
|
+
extra system prompt.
|
|
31
|
+
- **Repo view** — branch, working-tree status, diff vs HEAD, recent commits.
|
|
32
|
+
|
|
33
|
+
## Commands
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npx cezar # start the cockpit for the current repo
|
|
37
|
+
npx cezar run "task" # headless run in the terminal (CI-friendly)
|
|
38
|
+
npx cezar init # scaffold .ai/cezar/ with an example workflow + skill
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Workflow format
|
|
42
|
+
|
|
43
|
+
`.ai/cezar/workflows/fix-and-verify.yaml`:
|
|
44
|
+
|
|
45
|
+
```yaml
|
|
46
|
+
name: fix-and-verify
|
|
47
|
+
description: Implement, then verify; retry with failing output on red.
|
|
48
|
+
steps:
|
|
49
|
+
- id: implement
|
|
50
|
+
name: Implement
|
|
51
|
+
prompt: "{{task}}"
|
|
52
|
+
skill: project-conventions # optional, from .ai/skills or .ai/cezar/skills
|
|
53
|
+
# model: opus # optional per-step override
|
|
54
|
+
# allowedTools: [Read, Edit, Write, Grep, Glob, Bash]
|
|
55
|
+
- id: verify
|
|
56
|
+
name: Verify
|
|
57
|
+
command: "npm test"
|
|
58
|
+
onFail:
|
|
59
|
+
retry: implement # loop back, at most:
|
|
60
|
+
max: 2
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
`{{task}}` is replaced with the task you typed. When a check fails and loops
|
|
64
|
+
back, the failing output is appended to the retried agent's prompt.
|
|
65
|
+
|
|
66
|
+
## How it runs agents
|
|
67
|
+
|
|
68
|
+
cez shells out to your locally installed, logged-in `claude` CLI in headless
|
|
69
|
+
stream-json mode — your subscription, no API key. Tool access is
|
|
70
|
+
default-deny via `--allowedTools`; edits are auto-accepted
|
|
71
|
+
(`--permission-mode acceptEdits`) inside the repo directory.
|
|
72
|
+
|
|
73
|
+
Useful env vars:
|
|
74
|
+
|
|
75
|
+
- `CEZ_DRY_RUN=1` — use the bundled mock instead of the real CLI (demo/dev).
|
|
76
|
+
- `CEZ_CLAUDE_BIN=/path/to/claude` — override the binary.
|
|
77
|
+
|
|
78
|
+
## Development
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
npm install
|
|
82
|
+
npm run dev # tsx src/index.ts
|
|
83
|
+
npm run build # tsc → dist/
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
cez is the radically-simple, single-user sibling of
|
|
89
|
+
[cezar](https://github.com/...) — same core ideas (agent runner, skills,
|
|
90
|
+
declarative workflows, run cockpit), none of the SaaS.
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The backend-agnostic seam for running one agent task. Adapted from
|
|
3
|
+
* @cezar/core's `agents/agent-runner.ts`, trimmed for single-user local use:
|
|
4
|
+
* no token-budget circuit breaker, no zod response schemas — one run is one
|
|
5
|
+
* `claude` CLI invocation streaming normalized events.
|
|
6
|
+
*/
|
|
7
|
+
export type AgentBackend = 'claude-cli';
|
|
8
|
+
export interface AgentRunSpec {
|
|
9
|
+
/** Appended to the CLI's default system prompt (`--append-system-prompt`). */
|
|
10
|
+
systemPrompt?: string;
|
|
11
|
+
userPrompt: string;
|
|
12
|
+
/** The directory the agent runs in — also the only writable root. */
|
|
13
|
+
cwd: string;
|
|
14
|
+
/** Tool allowlist; the CLI is default-deny for anything not listed. */
|
|
15
|
+
allowedTools?: string[];
|
|
16
|
+
/** When `Bash` is allowed, restrict it to commands starting with one of these. */
|
|
17
|
+
bashAllowlist?: string[];
|
|
18
|
+
/** Extra directories the agent may read/write besides `cwd`. */
|
|
19
|
+
additionalDirectories?: string[];
|
|
20
|
+
model?: string;
|
|
21
|
+
/** Wall-clock kill switch for the run (ms). */
|
|
22
|
+
timeoutMs?: number;
|
|
23
|
+
/**
|
|
24
|
+
* Stable session id (UUID) so the user can take over interactively later:
|
|
25
|
+
* `cd <repo> && claude --resume <sessionId>`.
|
|
26
|
+
*/
|
|
27
|
+
sessionId?: string;
|
|
28
|
+
/**
|
|
29
|
+
* Spawn `claude --resume <sessionId>` instead of starting a fresh session —
|
|
30
|
+
* picks up the on-disk conversation (used by "Continue" after a run ends).
|
|
31
|
+
*/
|
|
32
|
+
resume?: boolean;
|
|
33
|
+
}
|
|
34
|
+
/** One content block of a user message — mirrors the Anthropic wire format
|
|
35
|
+
* so it can be written to the claude CLI's stdin verbatim. */
|
|
36
|
+
export type ContentBlock = {
|
|
37
|
+
type: 'text';
|
|
38
|
+
text: string;
|
|
39
|
+
} | {
|
|
40
|
+
type: 'image';
|
|
41
|
+
source: {
|
|
42
|
+
type: 'base64';
|
|
43
|
+
media_type: string;
|
|
44
|
+
data: string;
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
/** Normalized event stream — the GUI renders these, the store persists them. */
|
|
48
|
+
export type AgentEvent = {
|
|
49
|
+
type: 'text';
|
|
50
|
+
text: string;
|
|
51
|
+
} | {
|
|
52
|
+
type: 'tool-call';
|
|
53
|
+
id: string;
|
|
54
|
+
tool: string;
|
|
55
|
+
input: unknown;
|
|
56
|
+
} | {
|
|
57
|
+
type: 'tool-result';
|
|
58
|
+
toolCallId: string;
|
|
59
|
+
result: string;
|
|
60
|
+
isError: boolean;
|
|
61
|
+
} | {
|
|
62
|
+
type: 'token-usage';
|
|
63
|
+
tokensUsed: number;
|
|
64
|
+
} | {
|
|
65
|
+
type: 'cost';
|
|
66
|
+
usd: number;
|
|
67
|
+
} | {
|
|
68
|
+
type: 'turn-end';
|
|
69
|
+
} | {
|
|
70
|
+
type: 'note';
|
|
71
|
+
message: string;
|
|
72
|
+
} | {
|
|
73
|
+
type: 'done';
|
|
74
|
+
} | {
|
|
75
|
+
type: 'error';
|
|
76
|
+
message: string;
|
|
77
|
+
};
|
|
78
|
+
export interface AgentToolCallRecord {
|
|
79
|
+
id: string;
|
|
80
|
+
name: string;
|
|
81
|
+
input: unknown;
|
|
82
|
+
}
|
|
83
|
+
export interface AgentRunResult {
|
|
84
|
+
/** Concatenated assistant text across the run, trimmed. */
|
|
85
|
+
text: string;
|
|
86
|
+
toolCalls: AgentToolCallRecord[];
|
|
87
|
+
/** Cost-weighted token usage; 0 when the backend surfaced no telemetry. */
|
|
88
|
+
tokensUsed: number;
|
|
89
|
+
sessionId?: string;
|
|
90
|
+
}
|
|
91
|
+
export interface AgentRunner {
|
|
92
|
+
readonly backend: AgentBackend;
|
|
93
|
+
run(spec: AgentRunSpec, onEvent?: (event: AgentEvent) => void): Promise<AgentRunResult>;
|
|
94
|
+
interrupt(): Promise<void>;
|
|
95
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The backend-agnostic seam for running one agent task. Adapted from
|
|
3
|
+
* @cezar/core's `agents/agent-runner.ts`, trimmed for single-user local use:
|
|
4
|
+
* no token-budget circuit breaker, no zod response schemas — one run is one
|
|
5
|
+
* `claude` CLI invocation streaming normalized events.
|
|
6
|
+
*/
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=agent-runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-runner.js","sourceRoot":"","sources":["../../src/core/agent-runner.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface BackendCheck {
|
|
2
|
+
name: 'claude' | 'gh' | 'git';
|
|
3
|
+
available: boolean;
|
|
4
|
+
version?: string;
|
|
5
|
+
hint?: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Probe the host for everything cez leans on: the `claude` CLI (the agent
|
|
9
|
+
* backend), `gh` (GitHub auth for PR creation) and `git`. Nothing is required
|
|
10
|
+
* except `claude` — the GUI degrades gracefully and shows the hints instead.
|
|
11
|
+
*/
|
|
12
|
+
export declare function detectEnvironment(): Promise<BackendCheck[]>;
|
|
13
|
+
/** The host's GitHub token: logged-in `gh` first, `GITHUB_TOKEN` fallback. */
|
|
14
|
+
export declare function readHostGithubToken(): Promise<string | null>;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
|
+
import { promisify } from 'node:util';
|
|
3
|
+
const exec = promisify(execFile);
|
|
4
|
+
/**
|
|
5
|
+
* Probe the host for everything cez leans on: the `claude` CLI (the agent
|
|
6
|
+
* backend), `gh` (GitHub auth for PR creation) and `git`. Nothing is required
|
|
7
|
+
* except `claude` — the GUI degrades gracefully and shows the hints instead.
|
|
8
|
+
*/
|
|
9
|
+
export async function detectEnvironment() {
|
|
10
|
+
return Promise.all([probeClaude(), probeGh(), probeGit()]);
|
|
11
|
+
}
|
|
12
|
+
async function probeClaude() {
|
|
13
|
+
if (process.env.CEZ_DRY_RUN === '1') {
|
|
14
|
+
return { name: 'claude', available: true, version: 'mock (CEZ_DRY_RUN=1)' };
|
|
15
|
+
}
|
|
16
|
+
try {
|
|
17
|
+
const { stdout } = await exec('claude', ['--version'], { timeout: 10_000 });
|
|
18
|
+
const version = stdout.trim();
|
|
19
|
+
// A generic `claude` binary (a shell wrapper, an unrelated tool) can shadow
|
|
20
|
+
// the real CLI on $PATH — reject anything that doesn't match the banner.
|
|
21
|
+
if (!/^\d+\.\d+|^claude(\s+code)?\s+version\s+\d+\.\d+/i.test(version)) {
|
|
22
|
+
return {
|
|
23
|
+
name: 'claude',
|
|
24
|
+
available: false,
|
|
25
|
+
hint: `\`claude\` is on PATH but doesn't look like Claude Code (got: ${version.slice(0, 80)})`,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
name: 'claude',
|
|
30
|
+
available: true,
|
|
31
|
+
version,
|
|
32
|
+
hint: 'if not authenticated, run `claude` once and log in',
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return {
|
|
37
|
+
name: 'claude',
|
|
38
|
+
available: false,
|
|
39
|
+
hint: 'install Claude Code (npm i -g @anthropic-ai/claude-code) and log in',
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
async function probeGh() {
|
|
44
|
+
try {
|
|
45
|
+
const { stdout } = await exec('gh', ['auth', 'token'], { timeout: 10_000 });
|
|
46
|
+
return { name: 'gh', available: stdout.trim().length > 0, version: 'authenticated' };
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return {
|
|
50
|
+
name: 'gh',
|
|
51
|
+
available: false,
|
|
52
|
+
hint: 'install the GitHub CLI and run `gh auth login` (only needed for PR creation)',
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
async function probeGit() {
|
|
57
|
+
try {
|
|
58
|
+
const { stdout } = await exec('git', ['--version'], { timeout: 10_000 });
|
|
59
|
+
return { name: 'git', available: true, version: stdout.trim() };
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
return { name: 'git', available: false, hint: 'install git' };
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/** The host's GitHub token: logged-in `gh` first, `GITHUB_TOKEN` fallback. */
|
|
66
|
+
export async function readHostGithubToken() {
|
|
67
|
+
try {
|
|
68
|
+
const { stdout } = await exec('gh', ['auth', 'token'], { timeout: 10_000 });
|
|
69
|
+
const token = stdout.trim();
|
|
70
|
+
if (token)
|
|
71
|
+
return token;
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
// fall through to the env var
|
|
75
|
+
}
|
|
76
|
+
return process.env.GITHUB_TOKEN?.trim() || null;
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=backend-detect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backend-detect.js","sourceRoot":"","sources":["../../src/core/backend-detect.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { AgentEvent, AgentRunResult, AgentRunSpec, AgentRunner, ContentBlock } from './agent-runner.js';
|
|
2
|
+
/** Default wall-clock cap for a single run before SIGTERM → SIGKILL.
|
|
3
|
+
* Interactive sessions pass `timeoutMs: 0` to disable it entirely. */
|
|
4
|
+
export declare const DEFAULT_RUN_TIMEOUT_MS: number;
|
|
5
|
+
/** Grace period between SIGTERM and SIGKILL when a timeout fires. */
|
|
6
|
+
export declare const KILL_GRACE_MS = 10000;
|
|
7
|
+
/** After `end()` closes stdin: claude in stream-json mode can ignore EOF and
|
|
8
|
+
* hang (janitor-confirmed CLI bug) — escalate SIGTERM, then SIGKILL. */
|
|
9
|
+
export declare const EOF_TERM_GRACE_MS = 8000;
|
|
10
|
+
export declare const EOF_KILL_GRACE_MS = 4000;
|
|
11
|
+
/** Reopen window after a turn ends before an auto-ended session closes stdin. */
|
|
12
|
+
export declare const AUTO_END_DELAY_MS = 250;
|
|
13
|
+
export interface ClaudeCliRunnerOptions {
|
|
14
|
+
/** Override the binary name/path; defaults to `claude` on PATH. */
|
|
15
|
+
bin?: string;
|
|
16
|
+
/** Wall-clock timeout for a run (ms); per-spec `timeoutMs` still wins. */
|
|
17
|
+
timeoutMs?: number;
|
|
18
|
+
}
|
|
19
|
+
export interface SessionOptions {
|
|
20
|
+
/** Close the session shortly after the first turn ends (single-turn
|
|
21
|
+
* behavior, used for non-interactive workflow steps). Interactive
|
|
22
|
+
* sessions omit this and control `end()` themselves. */
|
|
23
|
+
autoEndAfterFirstTurn?: boolean;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* A live agent session over one spawned claude process. The process stays
|
|
27
|
+
* alive between turns (no `-p`) and reads further user messages from stdin —
|
|
28
|
+
* that's what makes mid-task follow-ups and pasted screenshots possible.
|
|
29
|
+
*/
|
|
30
|
+
export interface AgentSession {
|
|
31
|
+
/** Resolves when the claude process exits — the session is fully over. */
|
|
32
|
+
result: Promise<AgentRunResult>;
|
|
33
|
+
/** Write a user message into the live session. False when stdin is closed. */
|
|
34
|
+
sendMessage(content: ContentBlock[]): boolean;
|
|
35
|
+
/** Graceful close: EOF on stdin, then the SIGTERM→SIGKILL watchdog. */
|
|
36
|
+
end(): void;
|
|
37
|
+
/** Hard stop (used by cancel). */
|
|
38
|
+
interrupt(): void;
|
|
39
|
+
/** True while the session still accepts messages. */
|
|
40
|
+
readonly open: boolean;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* `AgentRunner` over the Claude Code CLI in headless stream-json mode. Auth =
|
|
44
|
+
* the host's logged-in Pro/Max subscription (no API key needed). Sandboxing is
|
|
45
|
+
* `--allowedTools` (default-deny) + running inside the repo `cwd`; `Bash` is
|
|
46
|
+
* narrowed to `Bash(<prefix>:*)` patterns when `bashAllowlist` is set.
|
|
47
|
+
*
|
|
48
|
+
* Session mechanics (multi-turn stdin, EOF watchdog, reopen window) follow
|
|
49
|
+
* github-janitor's `claudeRunner.ts`; the original single-turn adaptation
|
|
50
|
+
* came from @cezar/core's `ClaudeCodeCliRunner`.
|
|
51
|
+
*/
|
|
52
|
+
export declare class ClaudeCliRunner implements AgentRunner {
|
|
53
|
+
readonly backend: "claude-cli";
|
|
54
|
+
private readonly bin;
|
|
55
|
+
private readonly timeoutMs;
|
|
56
|
+
private lastSession;
|
|
57
|
+
constructor(opts?: ClaudeCliRunnerOptions);
|
|
58
|
+
/** One-shot run: start a session and auto-end it after the first turn. */
|
|
59
|
+
run(spec: AgentRunSpec, onEvent?: (event: AgentEvent) => void): Promise<AgentRunResult>;
|
|
60
|
+
interrupt(): Promise<void>;
|
|
61
|
+
startSession(spec: AgentRunSpec, onEvent?: (event: AgentEvent) => void, opts?: SessionOptions): AgentSession;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Map `allowedTools` onto claude's `--allowedTools` syntax. `Bash` with a
|
|
65
|
+
* `bashAllowlist` becomes one `Bash(<prefix>:*)` entry per allowed prefix;
|
|
66
|
+
* `Bash` with no allowlist stays plain `Bash`.
|
|
67
|
+
*/
|
|
68
|
+
export declare function buildAllowedTools(allowedTools: string[], bashAllowlist?: string[]): string[];
|