contextmate 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/LICENSE +21 -0
- package/README.md +142 -0
- package/dist/src/adapters/base.d.ts +32 -0
- package/dist/src/adapters/base.d.ts.map +1 -0
- package/dist/src/adapters/base.js +49 -0
- package/dist/src/adapters/base.js.map +1 -0
- package/dist/src/adapters/claude.d.ts +30 -0
- package/dist/src/adapters/claude.d.ts.map +1 -0
- package/dist/src/adapters/claude.js +534 -0
- package/dist/src/adapters/claude.js.map +1 -0
- package/dist/src/adapters/index.d.ts +7 -0
- package/dist/src/adapters/index.d.ts.map +1 -0
- package/dist/src/adapters/index.js +16 -0
- package/dist/src/adapters/index.js.map +1 -0
- package/dist/src/adapters/openclaw.d.ts +15 -0
- package/dist/src/adapters/openclaw.d.ts.map +1 -0
- package/dist/src/adapters/openclaw.js +198 -0
- package/dist/src/adapters/openclaw.js.map +1 -0
- package/dist/src/bin/contextmate.d.ts +3 -0
- package/dist/src/bin/contextmate.d.ts.map +1 -0
- package/dist/src/bin/contextmate.js +4 -0
- package/dist/src/bin/contextmate.js.map +1 -0
- package/dist/src/cli/adapter.d.ts +3 -0
- package/dist/src/cli/adapter.d.ts.map +1 -0
- package/dist/src/cli/adapter.js +187 -0
- package/dist/src/cli/adapter.js.map +1 -0
- package/dist/src/cli/daemon.d.ts +3 -0
- package/dist/src/cli/daemon.d.ts.map +1 -0
- package/dist/src/cli/daemon.js +212 -0
- package/dist/src/cli/daemon.js.map +1 -0
- package/dist/src/cli/files.d.ts +3 -0
- package/dist/src/cli/files.d.ts.map +1 -0
- package/dist/src/cli/files.js +158 -0
- package/dist/src/cli/files.js.map +1 -0
- package/dist/src/cli/index.d.ts +3 -0
- package/dist/src/cli/index.d.ts.map +1 -0
- package/dist/src/cli/index.js +20 -0
- package/dist/src/cli/index.js.map +1 -0
- package/dist/src/cli/init.d.ts +3 -0
- package/dist/src/cli/init.d.ts.map +1 -0
- package/dist/src/cli/init.js +88 -0
- package/dist/src/cli/init.js.map +1 -0
- package/dist/src/cli/log.d.ts +3 -0
- package/dist/src/cli/log.d.ts.map +1 -0
- package/dist/src/cli/log.js +141 -0
- package/dist/src/cli/log.js.map +1 -0
- package/dist/src/cli/mcp.d.ts +3 -0
- package/dist/src/cli/mcp.d.ts.map +1 -0
- package/dist/src/cli/mcp.js +186 -0
- package/dist/src/cli/mcp.js.map +1 -0
- package/dist/src/cli/status.d.ts +3 -0
- package/dist/src/cli/status.d.ts.map +1 -0
- package/dist/src/cli/status.js +107 -0
- package/dist/src/cli/status.js.map +1 -0
- package/dist/src/config.d.ts +42 -0
- package/dist/src/config.d.ts.map +1 -0
- package/dist/src/config.js +93 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/crypto/auth.d.ts +4 -0
- package/dist/src/crypto/auth.d.ts.map +1 -0
- package/dist/src/crypto/auth.js +21 -0
- package/dist/src/crypto/auth.js.map +1 -0
- package/dist/src/crypto/encrypt.d.ts +9 -0
- package/dist/src/crypto/encrypt.d.ts.map +1 -0
- package/dist/src/crypto/encrypt.js +39 -0
- package/dist/src/crypto/encrypt.js.map +1 -0
- package/dist/src/crypto/index.d.ts +4 -0
- package/dist/src/crypto/index.d.ts.map +1 -0
- package/dist/src/crypto/index.js +4 -0
- package/dist/src/crypto/index.js.map +1 -0
- package/dist/src/crypto/keys.d.ts +9 -0
- package/dist/src/crypto/keys.d.ts.map +1 -0
- package/dist/src/crypto/keys.js +43 -0
- package/dist/src/crypto/keys.js.map +1 -0
- package/dist/src/mcp/embeddings.d.ts +16 -0
- package/dist/src/mcp/embeddings.d.ts.map +1 -0
- package/dist/src/mcp/embeddings.js +237 -0
- package/dist/src/mcp/embeddings.js.map +1 -0
- package/dist/src/mcp/index.d.ts +10 -0
- package/dist/src/mcp/index.d.ts.map +1 -0
- package/dist/src/mcp/index.js +6 -0
- package/dist/src/mcp/index.js.map +1 -0
- package/dist/src/mcp/rerank.d.ts +14 -0
- package/dist/src/mcp/rerank.d.ts.map +1 -0
- package/dist/src/mcp/rerank.js +47 -0
- package/dist/src/mcp/rerank.js.map +1 -0
- package/dist/src/mcp/scope.d.ts +26 -0
- package/dist/src/mcp/scope.d.ts.map +1 -0
- package/dist/src/mcp/scope.js +71 -0
- package/dist/src/mcp/scope.js.map +1 -0
- package/dist/src/mcp/search.d.ts +18 -0
- package/dist/src/mcp/search.d.ts.map +1 -0
- package/dist/src/mcp/search.js +110 -0
- package/dist/src/mcp/search.js.map +1 -0
- package/dist/src/mcp/server.d.ts +15 -0
- package/dist/src/mcp/server.d.ts.map +1 -0
- package/dist/src/mcp/server.js +340 -0
- package/dist/src/mcp/server.js.map +1 -0
- package/dist/src/sync/client.d.ts +25 -0
- package/dist/src/sync/client.d.ts.map +1 -0
- package/dist/src/sync/client.js +109 -0
- package/dist/src/sync/client.js.map +1 -0
- package/dist/src/sync/engine.d.ts +21 -0
- package/dist/src/sync/engine.d.ts.map +1 -0
- package/dist/src/sync/engine.js +304 -0
- package/dist/src/sync/engine.js.map +1 -0
- package/dist/src/sync/index.d.ts +6 -0
- package/dist/src/sync/index.d.ts.map +1 -0
- package/dist/src/sync/index.js +6 -0
- package/dist/src/sync/index.js.map +1 -0
- package/dist/src/sync/state.d.ts +33 -0
- package/dist/src/sync/state.d.ts.map +1 -0
- package/dist/src/sync/state.js +146 -0
- package/dist/src/sync/state.js.map +1 -0
- package/dist/src/sync/watcher.d.ts +14 -0
- package/dist/src/sync/watcher.d.ts.map +1 -0
- package/dist/src/sync/watcher.js +74 -0
- package/dist/src/sync/watcher.js.map +1 -0
- package/dist/src/sync/websocket.d.ts +22 -0
- package/dist/src/sync/websocket.d.ts.map +1 -0
- package/dist/src/sync/websocket.js +103 -0
- package/dist/src/sync/websocket.js.map +1 -0
- package/dist/src/types.d.ts +63 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +2 -0
- package/dist/src/types.js.map +1 -0
- package/dist/src/utils/paths.d.ts +9 -0
- package/dist/src/utils/paths.d.ts.map +1 -0
- package/dist/src/utils/paths.js +24 -0
- package/dist/src/utils/paths.js.map +1 -0
- package/package.json +61 -0
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import { readFile, readdir, access, stat, unlink, copyFile, mkdir } from 'node:fs/promises';
|
|
2
|
+
import { join, relative, dirname } from 'node:path';
|
|
3
|
+
import { homedir } from 'node:os';
|
|
4
|
+
import { BaseAdapter } from './base.js';
|
|
5
|
+
export class OpenClawAdapter extends BaseAdapter {
|
|
6
|
+
get name() {
|
|
7
|
+
return 'openclaw';
|
|
8
|
+
}
|
|
9
|
+
async detect() {
|
|
10
|
+
const workspacePath = join(homedir(), '.openclaw', 'workspace');
|
|
11
|
+
try {
|
|
12
|
+
await access(workspacePath);
|
|
13
|
+
return workspacePath;
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
async import(workspacePath) {
|
|
20
|
+
const result = { imported: [], skipped: [], errors: [] };
|
|
21
|
+
const filesToImport = await this.discoverFiles(workspacePath);
|
|
22
|
+
for (const filePath of filesToImport) {
|
|
23
|
+
const relativeSrc = relative(workspacePath, filePath);
|
|
24
|
+
const vaultRelative = join('openclaw', relativeSrc);
|
|
25
|
+
try {
|
|
26
|
+
const sourceContent = await readFile(filePath, 'utf-8');
|
|
27
|
+
// Check if file already exists in vault with same content
|
|
28
|
+
const vaultDest = join(this.vaultPath, vaultRelative);
|
|
29
|
+
try {
|
|
30
|
+
const existingContent = await readFile(vaultDest, 'utf-8');
|
|
31
|
+
if (existingContent === sourceContent) {
|
|
32
|
+
result.skipped.push(vaultRelative);
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
// File doesn't exist in vault yet
|
|
38
|
+
}
|
|
39
|
+
await this.copyToVault(filePath, vaultRelative);
|
|
40
|
+
result.imported.push(vaultRelative);
|
|
41
|
+
}
|
|
42
|
+
catch (err) {
|
|
43
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
44
|
+
result.errors.push(`${relativeSrc}: ${message}`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return result;
|
|
48
|
+
}
|
|
49
|
+
async createSymlinks(workspacePath) {
|
|
50
|
+
const result = { created: [], errors: [] };
|
|
51
|
+
const filesToLink = await this.discoverFiles(workspacePath);
|
|
52
|
+
for (const filePath of filesToLink) {
|
|
53
|
+
const relativeSrc = relative(workspacePath, filePath);
|
|
54
|
+
const vaultRelative = join('openclaw', relativeSrc);
|
|
55
|
+
const vaultPath = join(this.vaultPath, vaultRelative);
|
|
56
|
+
try {
|
|
57
|
+
if (!(await this.isSymlink(filePath))) {
|
|
58
|
+
await this.backupFile(filePath, 'openclaw');
|
|
59
|
+
}
|
|
60
|
+
await this.safeSymlink(vaultPath, filePath);
|
|
61
|
+
result.created.push(relativeSrc);
|
|
62
|
+
}
|
|
63
|
+
catch (err) {
|
|
64
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
65
|
+
result.errors.push(`${relativeSrc}: ${message}`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return result;
|
|
69
|
+
}
|
|
70
|
+
async verifySymlinks(workspacePath) {
|
|
71
|
+
const valid = [];
|
|
72
|
+
const broken = [];
|
|
73
|
+
const filesToCheck = await this.discoverFiles(workspacePath);
|
|
74
|
+
for (const filePath of filesToCheck) {
|
|
75
|
+
const relativeSrc = relative(workspacePath, filePath);
|
|
76
|
+
if (await this.isSymlink(filePath)) {
|
|
77
|
+
try {
|
|
78
|
+
await stat(filePath);
|
|
79
|
+
valid.push(relativeSrc);
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
broken.push(relativeSrc);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
broken.push(relativeSrc);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return { valid, broken };
|
|
90
|
+
}
|
|
91
|
+
async removeSymlinks(workspacePath) {
|
|
92
|
+
const filesToRestore = await this.discoverVaultFiles();
|
|
93
|
+
for (const vaultRelative of filesToRestore) {
|
|
94
|
+
const relativeSrc = vaultRelative.replace(/^openclaw\//, '');
|
|
95
|
+
const originalPath = join(workspacePath, relativeSrc);
|
|
96
|
+
if (!(await this.isSymlink(originalPath))) {
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
await unlink(originalPath);
|
|
100
|
+
// Try to restore from backup
|
|
101
|
+
const backupPath = join(this.backupsPath, 'openclaw', relative('/', originalPath));
|
|
102
|
+
try {
|
|
103
|
+
await mkdir(dirname(originalPath), { recursive: true });
|
|
104
|
+
await copyFile(backupPath, originalPath);
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
// No backup -- move vault file back
|
|
108
|
+
const vaultFilePath = join(this.vaultPath, vaultRelative);
|
|
109
|
+
try {
|
|
110
|
+
await copyFile(vaultFilePath, originalPath);
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
// Vault file also missing
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
async discoverFiles(workspacePath) {
|
|
119
|
+
const files = [];
|
|
120
|
+
const topLevelFiles = ['MEMORY.md', 'IDENTITY.md', 'USER.md', 'SOUL.md'];
|
|
121
|
+
for (const name of topLevelFiles) {
|
|
122
|
+
const filePath = join(workspacePath, name);
|
|
123
|
+
try {
|
|
124
|
+
await access(filePath);
|
|
125
|
+
files.push(filePath);
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
// File doesn't exist
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
// skills/*/SKILL.md
|
|
132
|
+
try {
|
|
133
|
+
const skillsDir = join(workspacePath, 'skills');
|
|
134
|
+
const skillNames = await readdir(skillsDir);
|
|
135
|
+
for (const name of skillNames) {
|
|
136
|
+
const skillPath = join(skillsDir, name);
|
|
137
|
+
const s = await stat(skillPath);
|
|
138
|
+
if (s.isDirectory()) {
|
|
139
|
+
const skillFile = join(skillPath, 'SKILL.md');
|
|
140
|
+
try {
|
|
141
|
+
await access(skillFile);
|
|
142
|
+
files.push(skillFile);
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
// No SKILL.md
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
// No skills directory
|
|
152
|
+
}
|
|
153
|
+
// memory/*.md
|
|
154
|
+
try {
|
|
155
|
+
const memoryDir = join(workspacePath, 'memory');
|
|
156
|
+
const memoryNames = await readdir(memoryDir);
|
|
157
|
+
for (const name of memoryNames) {
|
|
158
|
+
if (name.endsWith('.md')) {
|
|
159
|
+
const memPath = join(memoryDir, name);
|
|
160
|
+
const s = await stat(memPath);
|
|
161
|
+
if (s.isFile()) {
|
|
162
|
+
files.push(memPath);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
catch {
|
|
168
|
+
// No memory directory
|
|
169
|
+
}
|
|
170
|
+
return files;
|
|
171
|
+
}
|
|
172
|
+
async discoverVaultFiles() {
|
|
173
|
+
const files = [];
|
|
174
|
+
const openclawVault = join(this.vaultPath, 'openclaw');
|
|
175
|
+
const walkDir = async (dir, baseDir) => {
|
|
176
|
+
try {
|
|
177
|
+
const names = await readdir(dir);
|
|
178
|
+
for (const name of names) {
|
|
179
|
+
const fullPath = join(dir, name);
|
|
180
|
+
const s = await stat(fullPath);
|
|
181
|
+
if (s.isDirectory()) {
|
|
182
|
+
await walkDir(fullPath, baseDir);
|
|
183
|
+
}
|
|
184
|
+
else if (s.isFile() && name.endsWith('.md')) {
|
|
185
|
+
const rel = relative(baseDir, fullPath);
|
|
186
|
+
files.push(join('openclaw', rel));
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
catch {
|
|
191
|
+
// Directory doesn't exist or not readable
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
await walkDir(openclawVault, openclawVault);
|
|
195
|
+
return files;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
//# sourceMappingURL=openclaw.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openclaw.js","sourceRoot":"","sources":["../../../src/adapters/openclaw.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contextmate.d.ts","sourceRoot":"","sources":["../../../src/bin/contextmate.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contextmate.js","sourceRoot":"","sources":["../../../src/bin/contextmate.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC1C,OAAO,CAAC,KAAK,EAAE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../../src/cli/adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA0NpC,eAAO,MAAM,cAAc,SAGqC,CAAC"}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import { loadConfig, saveConfig, getConfigPath } from '../config.js';
|
|
4
|
+
import { getAdapter } from '../adapters/index.js';
|
|
5
|
+
import { getBackupsPath } from '../utils/paths.js';
|
|
6
|
+
import { access } from 'node:fs/promises';
|
|
7
|
+
async function isInitialized() {
|
|
8
|
+
try {
|
|
9
|
+
await access(getConfigPath());
|
|
10
|
+
return true;
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function countByPrefix(items, prefix) {
|
|
17
|
+
return items.filter((i) => i.startsWith(prefix)).length;
|
|
18
|
+
}
|
|
19
|
+
function createAdapterSubcommands(agentName, displayName) {
|
|
20
|
+
const cmd = new Command(agentName).description(`Manage ${displayName} adapter`);
|
|
21
|
+
cmd
|
|
22
|
+
.command('init')
|
|
23
|
+
.description(`Import and symlink ${displayName} workspace`)
|
|
24
|
+
.action(async () => {
|
|
25
|
+
try {
|
|
26
|
+
if (!(await isInitialized())) {
|
|
27
|
+
console.error(chalk.red('ContextMate is not initialized. Run "contextmate init" first.'));
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
const config = await loadConfig();
|
|
31
|
+
const adapter = getAdapter(agentName, {
|
|
32
|
+
vaultPath: config.vault.path,
|
|
33
|
+
backupsPath: getBackupsPath(),
|
|
34
|
+
});
|
|
35
|
+
// Detect workspace
|
|
36
|
+
console.log(chalk.dim(`Detecting ${displayName} workspace...`));
|
|
37
|
+
const workspacePath = await adapter.detect();
|
|
38
|
+
if (!workspacePath) {
|
|
39
|
+
console.error(chalk.red(`Could not detect ${displayName} workspace.`));
|
|
40
|
+
if (agentName === 'openclaw') {
|
|
41
|
+
console.error(chalk.dim(' Expected at: ~/.openclaw/workspace'));
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
console.error(chalk.dim(' Expected at: ~/.claude'));
|
|
45
|
+
}
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
console.log(` Found: ${workspacePath}`);
|
|
49
|
+
// Import files
|
|
50
|
+
console.log(chalk.dim('Importing files to vault...'));
|
|
51
|
+
const importResult = await adapter.import(workspacePath);
|
|
52
|
+
if (agentName === 'claude') {
|
|
53
|
+
const skills = countByPrefix(importResult.imported, 'skills/');
|
|
54
|
+
const rules = countByPrefix(importResult.imported, 'claude/rules/');
|
|
55
|
+
const claudeMd = importResult.imported.includes('claude/CLAUDE.md') ? 1 : 0;
|
|
56
|
+
const memories = countByPrefix(importResult.imported, 'claude/projects/');
|
|
57
|
+
console.log(` Found: ${skills} skills, ${rules} rules, ${memories} project memory files` +
|
|
58
|
+
(claudeMd ? ', CLAUDE.md' : ''));
|
|
59
|
+
}
|
|
60
|
+
console.log(` ${chalk.green(`${importResult.imported.length} imported`)}, ` +
|
|
61
|
+
`${chalk.dim(`${importResult.skipped.length} skipped`)}`);
|
|
62
|
+
if (importResult.errors.length > 0) {
|
|
63
|
+
for (const err of importResult.errors) {
|
|
64
|
+
console.log(` ${chalk.red('Error:')} ${err}`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
// Create symlinks
|
|
68
|
+
console.log(chalk.dim('Creating symlinks...'));
|
|
69
|
+
const symlinkResult = await adapter.createSymlinks(workspacePath);
|
|
70
|
+
console.log(` ${chalk.green(`${symlinkResult.created.length} symlinks created`)}`);
|
|
71
|
+
if (symlinkResult.errors.length > 0) {
|
|
72
|
+
for (const err of symlinkResult.errors) {
|
|
73
|
+
console.log(` ${chalk.red('Error:')} ${err}`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
// Update config
|
|
77
|
+
if (agentName === 'openclaw') {
|
|
78
|
+
config.adapters.openclaw.enabled = true;
|
|
79
|
+
config.adapters.openclaw.workspacePath = workspacePath;
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
config.adapters.claude.enabled = true;
|
|
83
|
+
config.adapters.claude.claudeDir = workspacePath;
|
|
84
|
+
}
|
|
85
|
+
await saveConfig(config);
|
|
86
|
+
console.log('');
|
|
87
|
+
console.log(chalk.green(`${displayName} adapter initialized successfully.`));
|
|
88
|
+
}
|
|
89
|
+
catch (err) {
|
|
90
|
+
console.error(chalk.red(`Error: ${err instanceof Error ? err.message : String(err)}`));
|
|
91
|
+
process.exit(1);
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
cmd
|
|
95
|
+
.command('status')
|
|
96
|
+
.description(`Show ${displayName} symlink status`)
|
|
97
|
+
.action(async () => {
|
|
98
|
+
try {
|
|
99
|
+
if (!(await isInitialized())) {
|
|
100
|
+
console.error(chalk.red('ContextMate is not initialized. Run "contextmate init" first.'));
|
|
101
|
+
process.exit(1);
|
|
102
|
+
}
|
|
103
|
+
const config = await loadConfig();
|
|
104
|
+
const adapter = getAdapter(agentName, {
|
|
105
|
+
vaultPath: config.vault.path,
|
|
106
|
+
backupsPath: getBackupsPath(),
|
|
107
|
+
});
|
|
108
|
+
const isEnabled = agentName === 'openclaw'
|
|
109
|
+
? config.adapters.openclaw.enabled
|
|
110
|
+
: config.adapters.claude.enabled;
|
|
111
|
+
if (!isEnabled) {
|
|
112
|
+
console.log(chalk.dim(`${displayName} adapter is not enabled.`));
|
|
113
|
+
console.log(chalk.dim(`Run "contextmate adapter ${agentName} init" to set it up.`));
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
const workspacePath = agentName === 'openclaw'
|
|
117
|
+
? config.adapters.openclaw.workspacePath
|
|
118
|
+
: config.adapters.claude.claudeDir;
|
|
119
|
+
const result = await adapter.verifySymlinks(workspacePath);
|
|
120
|
+
console.log('');
|
|
121
|
+
console.log(chalk.bold(`${displayName} Adapter Status`));
|
|
122
|
+
console.log(chalk.dim('─'.repeat(40)));
|
|
123
|
+
console.log(` Workspace: ${workspacePath}`);
|
|
124
|
+
console.log(` Valid symlinks: ${chalk.green(String(result.valid.length))}`);
|
|
125
|
+
console.log(` Broken symlinks: ${chalk.red(String(result.broken.length))}`);
|
|
126
|
+
if (result.broken.length > 0) {
|
|
127
|
+
console.log('');
|
|
128
|
+
console.log(chalk.red(' Broken:'));
|
|
129
|
+
for (const b of result.broken) {
|
|
130
|
+
console.log(` - ${b}`);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
console.log('');
|
|
134
|
+
}
|
|
135
|
+
catch (err) {
|
|
136
|
+
console.error(chalk.red(`Error: ${err instanceof Error ? err.message : String(err)}`));
|
|
137
|
+
process.exit(1);
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
cmd
|
|
141
|
+
.command('remove')
|
|
142
|
+
.description(`Remove ${displayName} symlinks and restore originals`)
|
|
143
|
+
.action(async () => {
|
|
144
|
+
try {
|
|
145
|
+
if (!(await isInitialized())) {
|
|
146
|
+
console.error(chalk.red('ContextMate is not initialized. Run "contextmate init" first.'));
|
|
147
|
+
process.exit(1);
|
|
148
|
+
}
|
|
149
|
+
const config = await loadConfig();
|
|
150
|
+
const adapter = getAdapter(agentName, {
|
|
151
|
+
vaultPath: config.vault.path,
|
|
152
|
+
backupsPath: getBackupsPath(),
|
|
153
|
+
});
|
|
154
|
+
const isEnabled = agentName === 'openclaw'
|
|
155
|
+
? config.adapters.openclaw.enabled
|
|
156
|
+
: config.adapters.claude.enabled;
|
|
157
|
+
if (!isEnabled) {
|
|
158
|
+
console.log(chalk.dim(`${displayName} adapter is not enabled.`));
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
const workspacePath = agentName === 'openclaw'
|
|
162
|
+
? config.adapters.openclaw.workspacePath
|
|
163
|
+
: config.adapters.claude.claudeDir;
|
|
164
|
+
console.log(chalk.dim('Removing symlinks and restoring originals...'));
|
|
165
|
+
await adapter.removeSymlinks(workspacePath);
|
|
166
|
+
// Update config
|
|
167
|
+
if (agentName === 'openclaw') {
|
|
168
|
+
config.adapters.openclaw.enabled = false;
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
config.adapters.claude.enabled = false;
|
|
172
|
+
}
|
|
173
|
+
await saveConfig(config);
|
|
174
|
+
console.log(chalk.green(`${displayName} adapter removed.`));
|
|
175
|
+
}
|
|
176
|
+
catch (err) {
|
|
177
|
+
console.error(chalk.red(`Error: ${err instanceof Error ? err.message : String(err)}`));
|
|
178
|
+
process.exit(1);
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
return cmd;
|
|
182
|
+
}
|
|
183
|
+
export const adapterCommand = new Command('adapter')
|
|
184
|
+
.description('Manage agent adapters')
|
|
185
|
+
.addCommand(createAdapterSubcommands('openclaw', 'OpenClaw'))
|
|
186
|
+
.addCommand(createAdapterSubcommands('claude', 'Claude Code'));
|
|
187
|
+
//# sourceMappingURL=adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../../../src/cli/adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../../../src/cli/daemon.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAiOpC,eAAO,MAAM,aAAa,SAIK,CAAC"}
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import * as readline from 'node:readline/promises';
|
|
4
|
+
import { stdin, stdout } from 'node:process';
|
|
5
|
+
import { readFile, writeFile, unlink, access } from 'node:fs/promises';
|
|
6
|
+
import { join } from 'node:path';
|
|
7
|
+
import { hexToBytes } from '@noble/hashes/utils';
|
|
8
|
+
import { loadConfig, getConfigPath } from '../config.js';
|
|
9
|
+
import { getPidFilePath } from '../utils/paths.js';
|
|
10
|
+
import { deriveMasterKey, deriveVaultKey, decryptString } from '../crypto/index.js';
|
|
11
|
+
import { SyncEngine } from '../sync/index.js';
|
|
12
|
+
async function isInitialized() {
|
|
13
|
+
try {
|
|
14
|
+
await access(getConfigPath());
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function isPidRunning(pid) {
|
|
22
|
+
try {
|
|
23
|
+
process.kill(pid, 0);
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
async function readPassphrase(prompt) {
|
|
31
|
+
const rl = readline.createInterface({ input: stdin, output: stdout });
|
|
32
|
+
const answer = await rl.question(prompt);
|
|
33
|
+
rl.close();
|
|
34
|
+
return answer;
|
|
35
|
+
}
|
|
36
|
+
const startCommand = new Command('start')
|
|
37
|
+
.description('Start the sync daemon')
|
|
38
|
+
.option('--foreground', 'Run in the foreground (default for MVP)')
|
|
39
|
+
.action(async () => {
|
|
40
|
+
try {
|
|
41
|
+
if (!(await isInitialized())) {
|
|
42
|
+
console.error(chalk.red('ContextMate is not initialized. Run "contextmate init" first.'));
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
const config = await loadConfig();
|
|
46
|
+
const pidFile = getPidFilePath(config);
|
|
47
|
+
// Check if already running
|
|
48
|
+
try {
|
|
49
|
+
await access(pidFile);
|
|
50
|
+
const pidStr = await readFile(pidFile, 'utf-8');
|
|
51
|
+
const pid = parseInt(pidStr.trim(), 10);
|
|
52
|
+
if (isPidRunning(pid)) {
|
|
53
|
+
console.error(chalk.red(`Daemon is already running (PID: ${pid}).`));
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
56
|
+
// Stale PID file, remove it
|
|
57
|
+
await unlink(pidFile);
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
// No PID file or already cleaned up
|
|
61
|
+
}
|
|
62
|
+
// Load credentials
|
|
63
|
+
const credentialsPath = join(config.data.path, 'credentials.json');
|
|
64
|
+
let credentialsRaw;
|
|
65
|
+
try {
|
|
66
|
+
credentialsRaw = await readFile(credentialsPath, 'utf-8');
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
console.error(chalk.red('No credentials found. Run "contextmate init" first.'));
|
|
70
|
+
process.exit(1);
|
|
71
|
+
}
|
|
72
|
+
const credentials = JSON.parse(credentialsRaw);
|
|
73
|
+
// Prompt for passphrase
|
|
74
|
+
const passphrase = await readPassphrase(chalk.bold('Enter passphrase: '));
|
|
75
|
+
if (!passphrase) {
|
|
76
|
+
console.error(chalk.red('Error: Passphrase cannot be empty.'));
|
|
77
|
+
process.exit(1);
|
|
78
|
+
}
|
|
79
|
+
// Derive keys
|
|
80
|
+
console.log(chalk.dim('Deriving encryption keys...'));
|
|
81
|
+
const salt = hexToBytes(credentials.salt);
|
|
82
|
+
const masterKey = await deriveMasterKey(passphrase, salt);
|
|
83
|
+
const vaultKey = deriveVaultKey(masterKey);
|
|
84
|
+
// Verify passphrase by trying to decrypt the stored master key
|
|
85
|
+
try {
|
|
86
|
+
const encryptedMasterKeyBytes = hexToBytes(credentials.encryptedMasterKey);
|
|
87
|
+
decryptString(encryptedMasterKeyBytes, vaultKey);
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
console.error(chalk.red('Error: Invalid passphrase.'));
|
|
91
|
+
process.exit(1);
|
|
92
|
+
}
|
|
93
|
+
// Write PID file
|
|
94
|
+
await writeFile(pidFile, String(process.pid), 'utf-8');
|
|
95
|
+
// Start sync engine (foreground)
|
|
96
|
+
console.log(chalk.green(`Daemon started (PID: ${process.pid})`));
|
|
97
|
+
console.log(chalk.dim('Press Ctrl+C to stop.'));
|
|
98
|
+
const engine = new SyncEngine(config, vaultKey);
|
|
99
|
+
await engine.start();
|
|
100
|
+
// Handle graceful shutdown
|
|
101
|
+
const shutdown = async () => {
|
|
102
|
+
console.log(chalk.dim('\nStopping daemon...'));
|
|
103
|
+
await engine.stop();
|
|
104
|
+
try {
|
|
105
|
+
await unlink(pidFile);
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
// Already removed
|
|
109
|
+
}
|
|
110
|
+
console.log(chalk.green('Daemon stopped.'));
|
|
111
|
+
process.exit(0);
|
|
112
|
+
};
|
|
113
|
+
process.on('SIGINT', () => void shutdown());
|
|
114
|
+
process.on('SIGTERM', () => void shutdown());
|
|
115
|
+
}
|
|
116
|
+
catch (err) {
|
|
117
|
+
console.error(chalk.red(`Error: ${err instanceof Error ? err.message : String(err)}`));
|
|
118
|
+
process.exit(1);
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
const stopCommand = new Command('stop')
|
|
122
|
+
.description('Stop the sync daemon')
|
|
123
|
+
.action(async () => {
|
|
124
|
+
try {
|
|
125
|
+
if (!(await isInitialized())) {
|
|
126
|
+
console.error(chalk.red('ContextMate is not initialized. Run "contextmate init" first.'));
|
|
127
|
+
process.exit(1);
|
|
128
|
+
}
|
|
129
|
+
const config = await loadConfig();
|
|
130
|
+
const pidFile = getPidFilePath(config);
|
|
131
|
+
let pidStr;
|
|
132
|
+
try {
|
|
133
|
+
pidStr = await readFile(pidFile, 'utf-8');
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
console.log(chalk.dim('Daemon is not running.'));
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
const pid = parseInt(pidStr.trim(), 10);
|
|
140
|
+
if (!isPidRunning(pid)) {
|
|
141
|
+
console.log(chalk.dim('Daemon is not running (stale PID file).'));
|
|
142
|
+
await unlink(pidFile);
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
// Send SIGTERM
|
|
146
|
+
process.kill(pid, 'SIGTERM');
|
|
147
|
+
console.log(chalk.dim(`Sent SIGTERM to PID ${pid}...`));
|
|
148
|
+
// Wait for process to exit (up to 10 seconds)
|
|
149
|
+
let stopped = false;
|
|
150
|
+
for (let i = 0; i < 20; i++) {
|
|
151
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
152
|
+
if (!isPidRunning(pid)) {
|
|
153
|
+
stopped = true;
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (stopped) {
|
|
158
|
+
try {
|
|
159
|
+
await unlink(pidFile);
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
// Already removed by the daemon
|
|
163
|
+
}
|
|
164
|
+
console.log(chalk.green('Daemon stopped.'));
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
console.log(chalk.yellow(`Daemon (PID: ${pid}) did not stop within 10 seconds.`));
|
|
168
|
+
console.log(chalk.dim(`You may need to kill it manually: kill ${pid}`));
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
catch (err) {
|
|
172
|
+
console.error(chalk.red(`Error: ${err instanceof Error ? err.message : String(err)}`));
|
|
173
|
+
process.exit(1);
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
const statusSubCommand = new Command('status')
|
|
177
|
+
.description('Check daemon status')
|
|
178
|
+
.action(async () => {
|
|
179
|
+
try {
|
|
180
|
+
if (!(await isInitialized())) {
|
|
181
|
+
console.error(chalk.red('ContextMate is not initialized. Run "contextmate init" first.'));
|
|
182
|
+
process.exit(1);
|
|
183
|
+
}
|
|
184
|
+
const config = await loadConfig();
|
|
185
|
+
const pidFile = getPidFilePath(config);
|
|
186
|
+
let pidStr;
|
|
187
|
+
try {
|
|
188
|
+
pidStr = await readFile(pidFile, 'utf-8');
|
|
189
|
+
}
|
|
190
|
+
catch {
|
|
191
|
+
console.log(chalk.dim('Daemon is not running.'));
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
const pid = parseInt(pidStr.trim(), 10);
|
|
195
|
+
if (isPidRunning(pid)) {
|
|
196
|
+
console.log(chalk.green(`Daemon is running (PID: ${pid}).`));
|
|
197
|
+
}
|
|
198
|
+
else {
|
|
199
|
+
console.log(chalk.red(`Daemon is not running (stale PID file, PID: ${pid}).`));
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
catch (err) {
|
|
203
|
+
console.error(chalk.red(`Error: ${err instanceof Error ? err.message : String(err)}`));
|
|
204
|
+
process.exit(1);
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
export const daemonCommand = new Command('daemon')
|
|
208
|
+
.description('Manage the sync daemon')
|
|
209
|
+
.addCommand(startCommand)
|
|
210
|
+
.addCommand(stopCommand)
|
|
211
|
+
.addCommand(statusSubCommand);
|
|
212
|
+
//# sourceMappingURL=daemon.js.map
|