@yanzc/claude-pro 0.0.0-stage → 0.4.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/.env.example +41 -0
- package/LICENSE +21 -0
- package/README.md +314 -3
- package/bin/claude-pro.js +32 -0
- package/package.json +40 -6
- package/src/agent.js +752 -0
- package/src/agents.js +186 -0
- package/src/api.js +488 -0
- package/src/cache.js +150 -0
- package/src/checkpoints.js +184 -0
- package/src/claude-code.js +60 -0
- package/src/codex/client.js +300 -0
- package/src/codex/translate-request.js +239 -0
- package/src/codex/translate-stream.js +328 -0
- package/src/commands.js +803 -0
- package/src/config.js +453 -0
- package/src/context.js +109 -0
- package/src/filestate.js +57 -0
- package/src/gateway.js +110 -0
- package/src/hooks.js +81 -0
- package/src/main.js +193 -0
- package/src/mcp.js +290 -0
- package/src/modes.js +154 -0
- package/src/oauth.js +287 -0
- package/src/peers.js +156 -0
- package/src/print.js +106 -0
- package/src/prompts.js +179 -0
- package/src/ratelimit.js +244 -0
- package/src/restart.js +115 -0
- package/src/runtime.js +162 -0
- package/src/selfcheck.js +71 -0
- package/src/session.js +139 -0
- package/src/supervisor.js +110 -0
- package/src/tasks.js +76 -0
- package/src/tools/bash.js +227 -0
- package/src/tools/effort.js +41 -0
- package/src/tools/files.js +352 -0
- package/src/tools/index.js +52 -0
- package/src/tools/interaction.js +157 -0
- package/src/tools/notebook.js +91 -0
- package/src/tools/peers.js +45 -0
- package/src/tools/restart.js +50 -0
- package/src/tools/search.js +458 -0
- package/src/tools/skill.js +32 -0
- package/src/tools/task.js +139 -0
- package/src/tools/web.js +283 -0
- package/src/ui/ansi.js +228 -0
- package/src/ui/dialogs.js +122 -0
- package/src/ui/editor.js +389 -0
- package/src/ui/markdown.js +249 -0
- package/src/ui/render.js +155 -0
- package/src/ui/repl.js +1450 -0
- package/src/ui/screen.js +259 -0
- package/src/updater.js +93 -0
- package/src/utils/clipboard.js +197 -0
- package/src/utils/diff.js +95 -0
- package/src/utils/paths.js +37 -0
- package/src/utils/shell.js +251 -0
package/src/agents.js
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
// Sub-agent definitions: built-ins plus custom agents from markdown files with
|
|
2
|
+
// frontmatter (same format as Claude Code's .claude/agents/*.md).
|
|
3
|
+
|
|
4
|
+
import fs from 'node:fs';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { CONFIG_DIR } from './config.js';
|
|
7
|
+
|
|
8
|
+
const READ_ONLY_TOOLS = ['Glob', 'Grep', 'Read', 'Bash', 'WebFetch', 'WebSearch', 'BashOutput'];
|
|
9
|
+
|
|
10
|
+
export const BUILTIN_AGENTS = [
|
|
11
|
+
{
|
|
12
|
+
name: 'general-purpose',
|
|
13
|
+
description: 'General-purpose agent for researching complex questions, searching for code, and executing multi-step tasks. When you are searching for a keyword or file and are not confident that you will find the right match in the first few tries use this agent to perform the search for you.',
|
|
14
|
+
tools: '*',
|
|
15
|
+
prompt: 'You are an agent for a command line coding assistant. Given the user\'s message, use the tools available to complete the task. Do what has been asked; nothing more, nothing less. When you complete the task, respond with a detailed writeup.\n\nStrengths: searching for code and configuration across large codebases, analyzing multiple files to understand architecture, investigating complex questions, performing multi-step research.\n\nGuidelines: for file searches use Grep or Glob; start broad and narrow down; be thorough, check multiple locations and naming conventions. Create files whenever the task needs them (code, tests, scripts), but prefer editing an existing file when that is the natural place for a change, and do not create documentation files unless asked.',
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
name: 'Explore',
|
|
19
|
+
description: 'Fast agent specialized for exploring codebases. Use this when you need to quickly find files by patterns (eg. "src/components/**/*.tsx"), search code for keywords (eg. "API endpoints"), or answer questions about the codebase (eg. "how do API endpoints work?"). When calling this agent, specify the desired thoroughness level: "quick", "medium", or "very thorough".',
|
|
20
|
+
tools: READ_ONLY_TOOLS,
|
|
21
|
+
prompt: 'You are a file search specialist. You excel at thoroughly navigating and exploring codebases.\n\nThis is a READ-ONLY exploration task. You must not create, modify or delete files, and must only run read-only Bash commands (ls, git status, git log, git diff, find, cat, head, tail).\n\nUse Glob for broad file pattern matching, Grep for searching file contents with regex, and Read when you know the specific file path. Adapt your search approach to the thoroughness level specified by the caller. Make parallel tool calls wherever possible. Return file paths as absolute paths and report your findings clearly.',
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
name: 'Plan',
|
|
25
|
+
description: 'Software architect agent for designing implementation plans. Use this when you need to plan the implementation strategy for a task. Returns step-by-step plans, identifies critical files, and considers architectural trade-offs.',
|
|
26
|
+
tools: READ_ONLY_TOOLS,
|
|
27
|
+
prompt: 'You are a software architect and planning specialist. Explore the codebase with read-only tools and design an implementation plan.\n\nThis is a READ-ONLY task: do not create, modify or delete files, and only run read-only Bash commands.\n\nProcess: understand the requirements; explore thoroughly (existing patterns, similar features, architecture); design the solution with trade-offs; detail the plan step by step with sequencing and dependencies. End your response with a "Critical Files for Implementation" list of 3-5 files, with a brief reason for each.',
|
|
28
|
+
},
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
function unquote(value) {
|
|
32
|
+
const m = /^(["'])([\s\S]*)\1$/.exec(value);
|
|
33
|
+
if (!m) return value;
|
|
34
|
+
// Only a double-quoted YAML string has escapes; agent descriptions often hold "\n" for line breaks.
|
|
35
|
+
return m[1] === '"' ? m[2].replace(/\\(n|"|\\)/g, (all, c) => (c === 'n' ? '\n' : c)) : m[2];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Frontmatter as Claude Code agent, skill and command files write it: `key: value` lines, where the
|
|
39
|
+
// value may be quoted, continue on indented lines, be a block scalar (`|` or `>`) or a list (`[a, b]`
|
|
40
|
+
// or `- a` lines). A byte order mark, which Windows editors like to add, is ignored.
|
|
41
|
+
export function parseFrontmatter(text) {
|
|
42
|
+
const m = /^\uFEFF?---\r?\n([\s\S]*?)\r?\n---[ \t]*(?:\r?\n([\s\S]*))?$/.exec(text);
|
|
43
|
+
if (!m) return null;
|
|
44
|
+
const meta = {};
|
|
45
|
+
const lines = m[1].split(/\r?\n/);
|
|
46
|
+
for (let i = 0; i < lines.length; i++) {
|
|
47
|
+
const kv = /^([\w-]+)\s*:\s*(.*)$/.exec(lines[i]);
|
|
48
|
+
if (!kv) continue;
|
|
49
|
+
let value = kv[2].trim();
|
|
50
|
+
const block = /^([|>])[+-]?$/.exec(value);
|
|
51
|
+
if (block || value === '') {
|
|
52
|
+
// The indented lines after `key: |` (or after a bare `key:`) belong to the value.
|
|
53
|
+
const parts = [];
|
|
54
|
+
while (i + 1 < lines.length && !/^[\w-]+\s*:/.test(lines[i + 1])) parts.push(lines[++i].trim());
|
|
55
|
+
const items = parts.filter(Boolean);
|
|
56
|
+
value = items.length && items.every((p) => /^-\s+/.test(p))
|
|
57
|
+
? items.map((p) => p.replace(/^-\s+/, '')).join(', ')
|
|
58
|
+
: items.join(block && block[1] === '|' ? '\n' : ' ');
|
|
59
|
+
} else {
|
|
60
|
+
while (i + 1 < lines.length && /^\s+\S/.test(lines[i + 1])) value += ` ${lines[++i].trim()}`;
|
|
61
|
+
}
|
|
62
|
+
meta[kv[1]] = unquote(value);
|
|
63
|
+
}
|
|
64
|
+
return { meta, body: (m[2] || '').trim() };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// "Read, Grep", "[Read, Grep]" and "- Read" lists all give ['Read', 'Grep'].
|
|
68
|
+
function toolList(value) {
|
|
69
|
+
return String(value).replace(/^\[|\]$/g, '').split(/\s*,\s*/).map((t) => unquote(t.trim())).filter(Boolean);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function loadAgents(cwd) {
|
|
73
|
+
const agents = new Map(BUILTIN_AGENTS.map((a) => [a.name, { ...a, source: 'built-in' }]));
|
|
74
|
+
const dirs = [
|
|
75
|
+
path.join(CONFIG_DIR, 'agents'),
|
|
76
|
+
path.join(cwd, '.claude', 'agents'),
|
|
77
|
+
path.join(cwd, '.claude-pro', 'agents'),
|
|
78
|
+
];
|
|
79
|
+
for (const dir of dirs) {
|
|
80
|
+
let entries = [];
|
|
81
|
+
try { entries = fs.readdirSync(dir).filter((f) => f.endsWith('.md')); } catch { continue; }
|
|
82
|
+
for (const f of entries) {
|
|
83
|
+
try {
|
|
84
|
+
const parsed = parseFrontmatter(fs.readFileSync(path.join(dir, f), 'utf8'));
|
|
85
|
+
if (!parsed?.meta.name || !parsed.meta.description) continue;
|
|
86
|
+
agents.set(parsed.meta.name, {
|
|
87
|
+
name: parsed.meta.name,
|
|
88
|
+
description: parsed.meta.description,
|
|
89
|
+
tools: parsed.meta.tools ? toolList(parsed.meta.tools) : '*',
|
|
90
|
+
model: parsed.meta.model && parsed.meta.model !== 'inherit' ? parsed.meta.model : null,
|
|
91
|
+
prompt: parsed.body,
|
|
92
|
+
source: path.join(dir, f),
|
|
93
|
+
});
|
|
94
|
+
} catch { /* skip malformed */ }
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return agents;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Skills: <root>/skills/<name>/SKILL.md with frontmatter (name, description), the same layout as
|
|
101
|
+
// Claude Code skills. Later roots win: user skills, then project skills.
|
|
102
|
+
export function loadSkills(cwd) {
|
|
103
|
+
const skills = new Map();
|
|
104
|
+
const roots = [
|
|
105
|
+
[path.join(CONFIG_DIR, 'skills'), 'user'],
|
|
106
|
+
[path.join(cwd, '.claude', 'skills'), 'project'],
|
|
107
|
+
[path.join(cwd, '.claude-pro', 'skills'), 'project'],
|
|
108
|
+
];
|
|
109
|
+
for (const [root, scope] of roots) {
|
|
110
|
+
let dirs = [];
|
|
111
|
+
try { dirs = fs.readdirSync(root, { withFileTypes: true }).filter((e) => e.isDirectory()); } catch { continue; }
|
|
112
|
+
for (const d of dirs) {
|
|
113
|
+
const dir = path.join(root, d.name);
|
|
114
|
+
const file = path.join(dir, 'SKILL.md');
|
|
115
|
+
let text;
|
|
116
|
+
try { text = fs.readFileSync(file, 'utf8'); } catch { continue; }
|
|
117
|
+
const parsed = parseFrontmatter(text);
|
|
118
|
+
const body = (parsed ? parsed.body : text.replace(/^\uFEFF/, '')).trim();
|
|
119
|
+
const name = (parsed?.meta.name || d.name).trim();
|
|
120
|
+
if (!body || !/^[\w.:-]+$/.test(name)) continue;
|
|
121
|
+
const description = parsed?.meta.description || body.split('\n').find((l) => l.trim() && !l.startsWith('#'))?.slice(0, 160) || name;
|
|
122
|
+
skills.set(name, { name, description, body, dir, scope, file });
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return skills;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// The text a skill expands to: its instructions with $ARGUMENTS filled in.
|
|
129
|
+
export function renderSkill(skill, args = '') {
|
|
130
|
+
// A function, not a string: in a replacement string `$&` and `$$` in the arguments would be expanded.
|
|
131
|
+
let body = skill.body.replace(/\$ARGUMENTS/g, () => args);
|
|
132
|
+
if (args && !skill.body.includes('$ARGUMENTS')) body += `\n\nARGUMENTS: ${args}`;
|
|
133
|
+
return `Base directory for this skill: ${skill.dir}\n\n${body}`;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// The text a custom command expands to: $ARGUMENTS and $1..$9 filled in. One pass with a function, so
|
|
137
|
+
// what the arguments contain (`$1`, `$&`, `$$`) is neither interpreted nor expanded a second time.
|
|
138
|
+
export function expandCommandBody(body, args = '') {
|
|
139
|
+
const argv = args.split(/\s+/).filter(Boolean);
|
|
140
|
+
let out = body.replace(/\$ARGUMENTS|\$(\d)/g, (m, n) => (n === undefined ? args : (argv[+n - 1] ?? '')));
|
|
141
|
+
if (!body.includes('$ARGUMENTS') && args) out += `\n\nARGUMENTS: ${args}`;
|
|
142
|
+
return out;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// !`command` in a command file is replaced by what `command` prints (run(command) -> text).
|
|
146
|
+
export async function expandShellEmbeds(body, run) {
|
|
147
|
+
let out = body;
|
|
148
|
+
for (const m of [...body.matchAll(/!`([^`]+)`/g)]) {
|
|
149
|
+
const output = await run(m[1]);
|
|
150
|
+
out = out.replace(m[0], () => output); // a function: the output may contain `$&` or `$$` (shell scripts do)
|
|
151
|
+
}
|
|
152
|
+
return out;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Custom slash commands: .claude/commands/*.md, .claude-pro/commands/*.md, ~/.claude-pro/commands/*.md
|
|
156
|
+
export function loadCustomCommands(cwd) {
|
|
157
|
+
const commands = new Map();
|
|
158
|
+
const dirs = [
|
|
159
|
+
[path.join(CONFIG_DIR, 'commands'), 'user'],
|
|
160
|
+
[path.join(cwd, '.claude', 'commands'), 'project'],
|
|
161
|
+
[path.join(cwd, '.claude-pro', 'commands'), 'project'],
|
|
162
|
+
];
|
|
163
|
+
const walk = (dir, prefix, scope) => {
|
|
164
|
+
let entries = [];
|
|
165
|
+
try { entries = fs.readdirSync(dir, { withFileTypes: true }); } catch { return; }
|
|
166
|
+
for (const e of entries) {
|
|
167
|
+
if (e.isDirectory()) { walk(path.join(dir, e.name), `${prefix}${e.name}:`, scope); continue; }
|
|
168
|
+
if (!e.name.endsWith('.md')) continue;
|
|
169
|
+
const file = path.join(dir, e.name);
|
|
170
|
+
let text;
|
|
171
|
+
try { text = fs.readFileSync(file, 'utf8'); } catch { continue; } // a broken link or a locked file must not stop the others
|
|
172
|
+
const parsed = parseFrontmatter(text);
|
|
173
|
+
const body = parsed ? parsed.body : text.replace(/^\uFEFF/, '');
|
|
174
|
+
const name = prefix + e.name.slice(0, -3);
|
|
175
|
+
commands.set(name, {
|
|
176
|
+
name,
|
|
177
|
+
description: parsed?.meta.description || body.split('\n').find((l) => l.trim())?.slice(0, 80) || `(${scope})`,
|
|
178
|
+
argumentHint: parsed?.meta['argument-hint'] || '',
|
|
179
|
+
body,
|
|
180
|
+
scope,
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
for (const [dir, scope] of dirs) walk(dir, '', scope);
|
|
185
|
+
return commands;
|
|
186
|
+
}
|