codexmate 0.0.48 → 0.0.50
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 +2 -0
- package/README.zh.md +2 -0
- package/cli/agents-files.js +97 -28
- package/cli.js +10 -2
- package/package.json +2 -1
- package/skills/codexmate-project-context-recovery/SKILL.md +64 -0
- package/skills/codexmate-project-context-recovery/scripts/search_sessions.py +549 -0
- package/web-ui/app.js +28 -1
- package/web-ui/logic.agents-diff.mjs +6 -0
- package/web-ui/modules/app.methods.agents.mjs +82 -16
- package/web-ui/modules/i18n/locales/en.mjs +12 -6
- package/web-ui/modules/i18n/locales/ja.mjs +12 -6
- package/web-ui/modules/i18n/locales/vi.mjs +12 -2
- package/web-ui/modules/i18n/locales/zh-tw.mjs +12 -6
- package/web-ui/modules/i18n/locales/zh.mjs +12 -6
- package/web-ui/partials/index/layout-header.html +5 -5
- package/web-ui/partials/index/modal-config-template-agents.html +2 -2
- package/web-ui/partials/index/panel-prompts.html +24 -2
- package/web-ui/res/web-ui-render.precompiled.js +47 -11
- package/web-ui/styles/modals-core.css +34 -0
- package/web-ui/styles/titles-cards.css +2 -2
package/README.md
CHANGED
|
@@ -58,6 +58,7 @@ Unlike simple wrappers, Codex Mate acts as a **Local Agent Bridge**:
|
|
|
58
58
|
- **Claude Provider Bridge**: Connect Claude Code to OpenAI Chat Completions-compatible providers and Ollama through the built-in local Claude-compatible proxy.
|
|
59
59
|
- **OpenCode Provider Control**: Manage OpenCode provider/model selection with a CodexMate-owned provider store under `~/.codexmate`, projecting only the active provider into native OpenCode config to avoid polluting or deleting user-owned settings.
|
|
60
60
|
- **Skills Marketplace**: A local-first market to share and import skills between different agent apps.
|
|
61
|
+
- **Prompt File Editor**: Unified editor for global and project-level `CLAUDE.md` and `AGENTS.md` with auto-detection of project paths.
|
|
61
62
|
- **Task Orchestrator**: Plan and execute complex tasks with dependency tracking.
|
|
62
63
|
|
|
63
64
|
---
|
|
@@ -76,6 +77,7 @@ Unlike simple wrappers, Codex Mate acts as a **Local Agent Bridge**:
|
|
|
76
77
|
| **Claude Provider Bridge** | ✅ | Connect Claude Code to OpenAI Chat Completions-compatible providers and Ollama via the built-in Claude-compatible proxy |
|
|
77
78
|
| **OpenCode Provider Store** | ✅ | Keep multiple OpenCode providers in `~/.codexmate` while projecting only the selected provider to native OpenCode config |
|
|
78
79
|
| **Prompt Templates** | ✅ | Reusable prompt plugins with variables |
|
|
80
|
+
| **Prompt File Editor** | ✅ | Edit global and project-level CLAUDE.md / AGENTS.md with auto-detect and path switching |
|
|
79
81
|
| **MCP Integration** | ✅ | Expose local tools and resources via MCP stdio |
|
|
80
82
|
| **Auto Update** | ✅ | Quick update CLI via `codexmate update` |
|
|
81
83
|
|
package/README.zh.md
CHANGED
|
@@ -58,6 +58,7 @@
|
|
|
58
58
|
- **Claude Provider 桥接**:通过内建本地 Claude 兼容代理,让 Claude Code 接入 OpenAI Chat Completions 兼容 provider 与 Ollama。
|
|
59
59
|
- **OpenCode Provider 控制**:在 `~/.codexmate` 下维护 CodexMate 自有的 OpenCode 多 provider 存储,只将当前选中的 provider 投影到 OpenCode 原生配置,避免污染或误删用户已有配置。
|
|
60
60
|
- **Skills 市场**:本地优先的市场,支持在不同的智能体应用之间共享和导入 Skills。
|
|
61
|
+
- **提示词文件编辑器**:统一编辑全局和项目级 `CLAUDE.md` 与 `AGENTS.md`,支持项目路径自动检测。
|
|
61
62
|
- **任务编排器**:支持带有依赖跟踪的复杂任务规划与执行。
|
|
62
63
|
|
|
63
64
|
---
|
|
@@ -76,6 +77,7 @@
|
|
|
76
77
|
| **Claude Provider 桥接** | ✅ | 通过内建 Claude 兼容代理,让 Claude Code 接入 OpenAI Chat Completions 兼容 provider 与 Ollama |
|
|
77
78
|
| **OpenCode Provider 存储** | ✅ | 在 `~/.codexmate` 中保留多个 OpenCode provider,只将当前选中的 provider 投影到 OpenCode 原生配置 |
|
|
78
79
|
| **提示词模板** | ✅ | 支持变量的可复用提示词插件 |
|
|
80
|
+
| **提示词文件编辑器** | ✅ | 编辑全局和项目级 CLAUDE.md / AGENTS.md,支持自动检测与路径切换 |
|
|
79
81
|
| **MCP 集成** | ✅ | 通过 MCP stdio 暴露本地工具与资源 |
|
|
80
82
|
| **自动更新** | ✅ | 通过 `codexmate update` 快速更新 CLI |
|
|
81
83
|
|
package/cli/agents-files.js
CHANGED
|
@@ -53,57 +53,119 @@ function createAgentsFileController(deps = {}) {
|
|
|
53
53
|
return { ok: true, dirPath };
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
function
|
|
57
|
-
|
|
56
|
+
function detectProjectClaudeMdDir(baseDir) {
|
|
57
|
+
if (typeof baseDir !== 'string' || !baseDir.trim()) {
|
|
58
|
+
return { error: 'project path is required' };
|
|
59
|
+
}
|
|
60
|
+
const root = baseDir.trim();
|
|
61
|
+
const rootPath = path.join(root, CLAUDE_MD_FILE_NAME);
|
|
62
|
+
const dotDirPath = path.join(root, '.claude', CLAUDE_MD_FILE_NAME);
|
|
63
|
+
try {
|
|
64
|
+
if (fs.statSync(rootPath).isFile()) {
|
|
65
|
+
return { path: rootPath, source: 'root', dir: root };
|
|
66
|
+
}
|
|
67
|
+
} catch (_) {}
|
|
68
|
+
try {
|
|
69
|
+
if (fs.statSync(dotDirPath).isFile()) {
|
|
70
|
+
return { path: dotDirPath, source: 'dotdir', dir: path.join(root, '.claude') };
|
|
71
|
+
}
|
|
72
|
+
} catch (_) {}
|
|
73
|
+
return { path: rootPath, source: 'root', dir: root };
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function validateClaudeMdBaseDir(filePath) {
|
|
77
|
+
const dirPath = path.dirname(filePath);
|
|
78
|
+
try {
|
|
79
|
+
const stat = fs.statSync(dirPath);
|
|
80
|
+
if (!stat.isDirectory()) {
|
|
81
|
+
return { error: 'project directory is not a directory: ' + dirPath };
|
|
82
|
+
}
|
|
83
|
+
} catch (e) {
|
|
84
|
+
return { error: 'project directory does not exist: ' + dirPath };
|
|
85
|
+
}
|
|
86
|
+
return { ok: true, dirPath };
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function resolveClaudeMdFilePath(params = {}) {
|
|
90
|
+
const baseDir = typeof params.baseDir === 'string' && params.baseDir.trim()
|
|
91
|
+
? params.baseDir.trim()
|
|
92
|
+
: '';
|
|
93
|
+
if (!baseDir) {
|
|
94
|
+
return { filePath: path.join(CLAUDE_DIR, CLAUDE_MD_FILE_NAME), isProject: false };
|
|
95
|
+
}
|
|
96
|
+
var detected = detectProjectClaudeMdDir(baseDir);
|
|
97
|
+
if (detected.error) {
|
|
98
|
+
return { filePath: path.join(CLAUDE_DIR, CLAUDE_MD_FILE_NAME), isProject: false, detectionError: detected.error };
|
|
99
|
+
}
|
|
100
|
+
return { filePath: detected.path, isProject: true, detectionSource: detected.source, projectPath: baseDir };
|
|
58
101
|
}
|
|
59
102
|
|
|
60
103
|
function readClaudeMdFile(params = {}) {
|
|
61
|
-
|
|
62
|
-
|
|
104
|
+
var resolved = resolveClaudeMdFilePath(params);
|
|
105
|
+
var filePath = resolved.filePath;
|
|
106
|
+
var lineEndingFallback = os.EOL === '\r\n' ? '\r\n' : '\n';
|
|
107
|
+
var base = {
|
|
108
|
+
path: filePath,
|
|
109
|
+
lineEnding: lineEndingFallback
|
|
110
|
+
};
|
|
111
|
+
if (resolved.isProject) {
|
|
112
|
+
base.detectionSource = resolved.detectionSource;
|
|
113
|
+
base.projectPath = resolved.projectPath;
|
|
114
|
+
}
|
|
115
|
+
if (resolved.detectionError) {
|
|
116
|
+
base.detectionError = resolved.detectionError;
|
|
117
|
+
}
|
|
118
|
+
if (resolved.isProject) {
|
|
119
|
+
var dirCheck = validateClaudeMdBaseDir(filePath);
|
|
120
|
+
if (dirCheck.error) {
|
|
121
|
+
return { error: dirCheck.error };
|
|
122
|
+
}
|
|
123
|
+
}
|
|
63
124
|
if (!fs.existsSync(filePath)) {
|
|
64
|
-
return {
|
|
65
|
-
exists: false,
|
|
66
|
-
path: filePath,
|
|
67
|
-
content: '',
|
|
68
|
-
lineEnding: lineEndingFallback
|
|
69
|
-
};
|
|
125
|
+
return Object.assign({ exists: false, content: '' }, base);
|
|
70
126
|
}
|
|
71
127
|
if (params.metaOnly) {
|
|
72
|
-
return {
|
|
73
|
-
exists: true,
|
|
74
|
-
path: filePath,
|
|
75
|
-
content: '',
|
|
76
|
-
lineEnding: lineEndingFallback
|
|
77
|
-
};
|
|
128
|
+
return Object.assign({ exists: true, content: '' }, base);
|
|
78
129
|
}
|
|
79
130
|
try {
|
|
80
|
-
|
|
81
|
-
|
|
131
|
+
var raw = fs.readFileSync(filePath, 'utf-8');
|
|
132
|
+
var result = {
|
|
82
133
|
exists: true,
|
|
83
134
|
path: filePath,
|
|
84
135
|
content: stripUtf8Bom(raw),
|
|
85
136
|
lineEnding: detectLineEnding(raw)
|
|
86
137
|
};
|
|
138
|
+
if (resolved.isProject) {
|
|
139
|
+
result.detectionSource = resolved.detectionSource;
|
|
140
|
+
result.projectPath = resolved.projectPath;
|
|
141
|
+
}
|
|
142
|
+
return result;
|
|
87
143
|
} catch (e) {
|
|
88
|
-
return { error:
|
|
144
|
+
return { error: 'read CLAUDE.md failed: ' + e.message };
|
|
89
145
|
}
|
|
90
146
|
}
|
|
91
147
|
|
|
92
148
|
function applyClaudeMdFile(params = {}) {
|
|
93
|
-
|
|
94
|
-
|
|
149
|
+
var resolved = resolveClaudeMdFilePath(params);
|
|
150
|
+
var filePath = resolved.filePath;
|
|
151
|
+
var content = typeof params.content === 'string' ? params.content : '';
|
|
95
152
|
if (content.length > 2 * 1024 * 1024) {
|
|
96
|
-
return { error: '
|
|
153
|
+
return { error: 'content too large (max 2MB)' };
|
|
97
154
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
155
|
+
var lineEnding = params.lineEnding === '\r\n' ? '\r\n' : '\n';
|
|
156
|
+
var normalized = normalizeLineEnding(content, lineEnding);
|
|
157
|
+
var finalContent = ensureUtf8Bom(normalized);
|
|
101
158
|
try {
|
|
102
|
-
ensureDir(
|
|
159
|
+
ensureDir(path.dirname(filePath));
|
|
103
160
|
fs.writeFileSync(filePath, finalContent, 'utf-8');
|
|
104
|
-
|
|
161
|
+
var result = { success: true, path: filePath };
|
|
162
|
+
if (resolved.isProject) {
|
|
163
|
+
result.projectPath = resolved.projectPath;
|
|
164
|
+
result.detectionSource = resolved.detectionSource;
|
|
165
|
+
}
|
|
166
|
+
return result;
|
|
105
167
|
} catch (e) {
|
|
106
|
-
return { error:
|
|
168
|
+
return { error: 'write CLAUDE.md failed: ' + e.message };
|
|
107
169
|
}
|
|
108
170
|
}
|
|
109
171
|
|
|
@@ -181,6 +243,11 @@ function createAgentsFileController(deps = {}) {
|
|
|
181
243
|
let readResult;
|
|
182
244
|
if (context === 'claude-md') {
|
|
183
245
|
readResult = readClaudeMdFile({ metaOnly });
|
|
246
|
+
} else if (context === 'claude-project') {
|
|
247
|
+
if (!params.baseDir || !String(params.baseDir).trim()) {
|
|
248
|
+
return { error: 'project path is required for claude-project context' };
|
|
249
|
+
}
|
|
250
|
+
readResult = readClaudeMdFile({ ...params, metaOnly });
|
|
184
251
|
} else if (context === 'openclaw') {
|
|
185
252
|
readResult = readOpenclawAgentsFile({ metaOnly });
|
|
186
253
|
} else if (context === 'openclaw-workspace') {
|
|
@@ -215,6 +282,8 @@ function createAgentsFileController(deps = {}) {
|
|
|
215
282
|
return {
|
|
216
283
|
resolveAgentsFilePath,
|
|
217
284
|
validateAgentsBaseDir,
|
|
285
|
+
detectProjectClaudeMdDir,
|
|
286
|
+
validateClaudeMdBaseDir,
|
|
218
287
|
resolveClaudeMdFilePath,
|
|
219
288
|
readClaudeMdFile,
|
|
220
289
|
applyClaudeMdFile,
|
package/cli.js
CHANGED
|
@@ -1828,6 +1828,8 @@ async function fetchProviderModels(providerName, overrides = {}) {
|
|
|
1828
1828
|
const {
|
|
1829
1829
|
resolveAgentsFilePath,
|
|
1830
1830
|
validateAgentsBaseDir,
|
|
1831
|
+
detectProjectClaudeMdDir,
|
|
1832
|
+
validateClaudeMdBaseDir,
|
|
1831
1833
|
resolveClaudeMdFilePath,
|
|
1832
1834
|
readClaudeMdFile,
|
|
1833
1835
|
applyClaudeMdFile,
|
|
@@ -11876,10 +11878,16 @@ function createWebServer({ htmlPath, assetsDir, webDir, host, port, openBrowser
|
|
|
11876
11878
|
case 'apply-claude-md-file':
|
|
11877
11879
|
result = applyClaudeMdFile(params || {});
|
|
11878
11880
|
if (result && !result.error) {
|
|
11879
|
-
const
|
|
11880
|
-
|
|
11881
|
+
const mdBaseDir = params && params.baseDir ? String(params.baseDir).trim() : '';
|
|
11882
|
+
const mdTarget = mdBaseDir
|
|
11883
|
+
? path.join(mdBaseDir, 'CLAUDE.md')
|
|
11884
|
+
: ((params && params.targetPath) ? String(params.targetPath) : 'CLAUDE.md');
|
|
11885
|
+
notifyWebhook('claude-md-edit', 'CLAUDE.md modified: ' + mdTarget, { targetPath: mdTarget, projectPath: mdBaseDir }).catch(function () { });
|
|
11881
11886
|
}
|
|
11882
11887
|
break;
|
|
11888
|
+
case 'detect-project-claude-md':
|
|
11889
|
+
result = detectProjectClaudeMdDir((params && params.baseDir) || '');
|
|
11890
|
+
break;
|
|
11883
11891
|
case 'preview-agents-diff':
|
|
11884
11892
|
result = buildAgentsDiff(params || {});
|
|
11885
11893
|
break;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codexmate",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.50",
|
|
4
4
|
"description": "Codex/Claude Code/OpenClaw 配置、会话与任务编排 CLI + Web 工具",
|
|
5
5
|
"main": "cli.js",
|
|
6
6
|
"bin": {
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
"cli.js",
|
|
11
11
|
"cli/",
|
|
12
12
|
"plugins/",
|
|
13
|
+
"skills/",
|
|
13
14
|
"web-ui.html",
|
|
14
15
|
"lib/",
|
|
15
16
|
"web-ui/",
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: codexmate-project-context-recovery
|
|
3
|
+
description: Recovers project handoff context from local Codex, Claude Code, Gemini, CodeBuddy, and codexmate-derived sessions. Use when the user asks what happened in prior project/PR/branch/file/error work, needs a handoff brief, wants old decisions or validations recovered, or asks to summarize cross-session project activity with evidence.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Codexmate Project Context Recovery
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
Use this skill to build an evidence-first project handoff brief from local agent sessions. It is not semantic memory or a live GitHub source of truth. It works best with hard identifiers: `owner/repo`, branch names, file paths, commit hashes, exact errors, PR/issue numbers plus repo filters, or unique commands.
|
|
11
|
+
|
|
12
|
+
Old sessions are historical evidence. Mutable facts such as PR state, CI, releases, deployments, and current files still require live checks before action.
|
|
13
|
+
|
|
14
|
+
## Quick Start
|
|
15
|
+
|
|
16
|
+
Generate a context brief first. Resolve `scripts/search_sessions.py` relative to this skill directory; after npm installation the full package path is `node_modules/codexmate/skills/codexmate-project-context-recovery/scripts/search_sessions.py`.
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
python3 scripts/search_sessions.py "SakuraByteCore/codexmate feat/task-orchestration-tab" --mode brief --source all --path-filter codexmate --match all --format text --limit 8
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Use plain search when you need raw candidates:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
python3 scripts/search_sessions.py "exact error text" --mode search --source all --path-filter codexmate --format text --limit 10
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Workflow
|
|
29
|
+
|
|
30
|
+
1. **Confirm the object**: repo/project, PR/issue number, branch, file path, command, exact error text, person, or date range. If multiple projects match, state the chosen object before searching.
|
|
31
|
+
2. **Prefer hard identifiers**: exact `owner/repo`, short repo name, PR/issue number with repo filter, branch, file path, commit hash, exact error, then user wording.
|
|
32
|
+
3. **Generate a brief**: use `--mode brief`; add `--path-filter` for project/worktree isolation; use `--match all` when the query has strong identifiers.
|
|
33
|
+
4. **Check confidence**: `high` means multiple hard signals appeared; `medium/weak` means re-query with stronger identifiers before relying on it; `none` means no hits were found.
|
|
34
|
+
5. **Use the brief as a handoff**: extract timeline, decisions, validations, risks, files, commands, commits, and top evidence sessions.
|
|
35
|
+
6. **Live-check mutable facts**: before commenting, merging, releasing, or claiming current status, check GitHub/current files directly.
|
|
36
|
+
|
|
37
|
+
## What Good Output Looks Like
|
|
38
|
+
|
|
39
|
+
- **Target Object:** repo / PR / branch / file / error
|
|
40
|
+
- **Context Brief:** confidence, top sources, timeline, repos/branches/PRs/files
|
|
41
|
+
- **Historical Evidence:** session source/id/path + snippets
|
|
42
|
+
- **Handoff Summary:** decisions, validations, risks, commands, commits
|
|
43
|
+
- **Live Verification:** PR/check/review/release/current-file facts that still need live verification
|
|
44
|
+
|
|
45
|
+
## Optional codexmate MCP Path
|
|
46
|
+
|
|
47
|
+
If codexmate MCP is configured and healthy, use it to inspect strong candidates:
|
|
48
|
+
|
|
49
|
+
- `codexmate.session.list` with `source`, `query`, `queryScope: "all"`, `limit`, and `forceRefresh: true`.
|
|
50
|
+
- `codexmate.session.detail` for candidate session inspection.
|
|
51
|
+
- `codexmate.session.export` only when a markdown export is useful.
|
|
52
|
+
|
|
53
|
+
If MCP is unavailable, do not block; run `scripts/search_sessions.py`.
|
|
54
|
+
|
|
55
|
+
## Limits
|
|
56
|
+
|
|
57
|
+
- Generic natural-language queries can be noisy.
|
|
58
|
+
- Short PR numbers without repo/path filters are weak signals.
|
|
59
|
+
- Session logs may contain stale, failed, or speculative work.
|
|
60
|
+
- The brief should guide investigation; it must not replace current repo/GitHub verification.
|
|
61
|
+
|
|
62
|
+
## Privacy
|
|
63
|
+
|
|
64
|
+
Share only context relevant to the current task. Do not quote credentials, unrelated personal details, private memory, or large transcript chunks. In group chats, summarize narrowly and avoid exposing unrelated sessions.
|