taskmonkey-cli 0.5.2 → 0.7.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/bin/tm.js +9 -0
- package/package.json +1 -1
- package/src/commands/history.js +59 -0
- package/src/commands/sync.js +32 -8
- package/src/commands/watch.js +39 -9
package/bin/tm.js
CHANGED
|
@@ -9,6 +9,7 @@ import { watch } from '../src/commands/watch.js';
|
|
|
9
9
|
import { logs } from '../src/commands/logs.js';
|
|
10
10
|
import { chat } from '../src/commands/chat.js';
|
|
11
11
|
import { tasks } from '../src/commands/tasks.js';
|
|
12
|
+
import { history } from '../src/commands/history.js';
|
|
12
13
|
import { testChat } from '../src/commands/test-chat.js';
|
|
13
14
|
import { testConversations } from '../src/commands/test-conversations.js';
|
|
14
15
|
import { optimizePrompt } from '../src/commands/optimize-prompt.js';
|
|
@@ -41,6 +42,7 @@ program
|
|
|
41
42
|
program
|
|
42
43
|
.command('sync')
|
|
43
44
|
.description('Upload local config files to server')
|
|
45
|
+
.option('-d, --delete', 'Delete remote files that no longer exist locally')
|
|
44
46
|
.action(sync);
|
|
45
47
|
|
|
46
48
|
program
|
|
@@ -53,6 +55,13 @@ program
|
|
|
53
55
|
.description('Watch for file changes and auto-sync')
|
|
54
56
|
.action(watch);
|
|
55
57
|
|
|
58
|
+
program
|
|
59
|
+
.command('history')
|
|
60
|
+
.description('Show recent chat messages for a task (for debugging)')
|
|
61
|
+
.option('-t, --task <slug>', 'Monkey task slug (default: unified)')
|
|
62
|
+
.option('-n, --last <number>', 'Number of messages', '20')
|
|
63
|
+
.action(history);
|
|
64
|
+
|
|
56
65
|
program
|
|
57
66
|
.command('logs')
|
|
58
67
|
.description('Stream server logs')
|
package/package.json
CHANGED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import ora from 'ora';
|
|
3
|
+
import { createClient } from '../lib/api.js';
|
|
4
|
+
|
|
5
|
+
export async function history(options) {
|
|
6
|
+
const client = createClient();
|
|
7
|
+
|
|
8
|
+
const spinner = ora('Loading chat history...').start();
|
|
9
|
+
|
|
10
|
+
try {
|
|
11
|
+
const result = await client.get('/api/test/history', {
|
|
12
|
+
task: options.task || '',
|
|
13
|
+
last: options.last || '20',
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
spinner.stop();
|
|
17
|
+
|
|
18
|
+
if (result.count === 0) {
|
|
19
|
+
console.log(chalk.yellow('Keine Nachrichten gefunden.'));
|
|
20
|
+
console.log(chalk.gray(`Chat-ID: ${result.chat_id}`));
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
console.log(chalk.gray(`${result.chat_id} — ${result.count} Nachrichten\n`));
|
|
25
|
+
|
|
26
|
+
for (const msg of result.messages) {
|
|
27
|
+
const time = chalk.gray(msg.created);
|
|
28
|
+
const content = (msg.content || '').replace(/\n{3,}/g, '\n').trim();
|
|
29
|
+
|
|
30
|
+
switch (msg.role) {
|
|
31
|
+
case 'user':
|
|
32
|
+
console.log(`${time} ${chalk.green('USER')} ${content}`);
|
|
33
|
+
break;
|
|
34
|
+
case 'assistant':
|
|
35
|
+
// Check for tool_use
|
|
36
|
+
if (content.includes('[tool_use:')) {
|
|
37
|
+
const tools = content.match(/\[tool_use: ([^\]]+)\]/g) || [];
|
|
38
|
+
for (const t of tools) {
|
|
39
|
+
console.log(`${time} ${chalk.yellow('TOOL')} ${t}`);
|
|
40
|
+
}
|
|
41
|
+
} else {
|
|
42
|
+
console.log(`${time} ${chalk.cyan('AI')} ${content.substring(0, 200)}${content.length > 200 ? '...' : ''}`);
|
|
43
|
+
}
|
|
44
|
+
break;
|
|
45
|
+
case 'tool':
|
|
46
|
+
console.log(`${time} ${chalk.gray('RESULT')} ${content.substring(0, 150)}${content.length > 150 ? '...' : ''}`);
|
|
47
|
+
break;
|
|
48
|
+
case 'system':
|
|
49
|
+
console.log(`${time} ${chalk.magenta('SYS')} ${content.substring(0, 150)}`);
|
|
50
|
+
break;
|
|
51
|
+
default:
|
|
52
|
+
console.log(`${time} ${chalk.gray(msg.role.toUpperCase())} ${content.substring(0, 150)}`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
} catch (err) {
|
|
56
|
+
spinner.fail(err.message);
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
}
|
package/src/commands/sync.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { readdirSync, readFileSync
|
|
1
|
+
import { readdirSync, readFileSync } from 'fs';
|
|
2
2
|
import { join, relative } from 'path';
|
|
3
3
|
import chalk from 'chalk';
|
|
4
4
|
import ora from 'ora';
|
|
@@ -22,7 +22,7 @@ function collectFiles(dir, base = dir) {
|
|
|
22
22
|
return files;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
export async function sync() {
|
|
25
|
+
export async function sync(options = {}) {
|
|
26
26
|
const config = loadConfig();
|
|
27
27
|
if (!config) {
|
|
28
28
|
console.error(chalk.red('Not logged in. Run `tm login` first.'));
|
|
@@ -30,22 +30,46 @@ export async function sync() {
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
const tenantDir = join(config._configDir, config.tenant_path || '.');
|
|
33
|
+
const deleteRemote = options.delete || false;
|
|
33
34
|
|
|
34
35
|
const spinner = ora('Collecting files...').start();
|
|
35
36
|
|
|
36
|
-
const
|
|
37
|
-
const
|
|
37
|
+
const localFiles = collectFiles(tenantDir);
|
|
38
|
+
const localPaths = Object.keys(localFiles);
|
|
38
39
|
|
|
39
|
-
if (
|
|
40
|
+
if (localPaths.length === 0) {
|
|
40
41
|
spinner.warn('No .php files found');
|
|
41
42
|
return;
|
|
42
43
|
}
|
|
43
44
|
|
|
44
|
-
|
|
45
|
+
const client = createClient();
|
|
46
|
+
|
|
47
|
+
// Delete remote files that don't exist locally
|
|
48
|
+
if (deleteRemote) {
|
|
49
|
+
spinner.text = 'Comparing with server...';
|
|
50
|
+
try {
|
|
51
|
+
const remoteList = await client.get('/api/tenant/files');
|
|
52
|
+
const remotePaths = (remoteList.files || []).map(f => f.path);
|
|
53
|
+
const toDelete = remotePaths.filter(p => !localPaths.includes(p));
|
|
54
|
+
|
|
55
|
+
if (toDelete.length > 0) {
|
|
56
|
+
const result = await client.post('/api/tenant/delete-files', { files: toDelete });
|
|
57
|
+
spinner.stop();
|
|
58
|
+
console.log(chalk.red(`✗ ${result.deleted || 0} files deleted on server`));
|
|
59
|
+
for (const file of result.files || []) {
|
|
60
|
+
console.log(chalk.red(` - ${file}`));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
} catch (err) {
|
|
64
|
+
spinner.stop();
|
|
65
|
+
console.error(chalk.yellow(` Delete check failed: ${err.message}`));
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
spinner.text = `Syncing ${localPaths.length} files...`;
|
|
45
70
|
|
|
46
71
|
try {
|
|
47
|
-
const
|
|
48
|
-
const result = await client.post('/api/tenant/sync', { files });
|
|
72
|
+
const result = await client.post('/api/tenant/sync', { files: localFiles });
|
|
49
73
|
|
|
50
74
|
spinner.stop();
|
|
51
75
|
|
package/src/commands/watch.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import chokidar from 'chokidar';
|
|
2
2
|
import chalk from 'chalk';
|
|
3
3
|
import { loadConfig } from '../config.js';
|
|
4
|
+
import { createClient } from '../lib/api.js';
|
|
4
5
|
import { sync } from './sync.js';
|
|
5
|
-
import { join } from 'path';
|
|
6
|
+
import { join, relative } from 'path';
|
|
6
7
|
|
|
7
8
|
export async function watch() {
|
|
8
9
|
const config = loadConfig();
|
|
@@ -16,28 +17,57 @@ export async function watch() {
|
|
|
16
17
|
console.log(chalk.cyan('👀 Watching'), tenantDir);
|
|
17
18
|
console.log(chalk.gray(' Ctrl+C to stop\n'));
|
|
18
19
|
|
|
19
|
-
let
|
|
20
|
+
let syncTimer = null;
|
|
21
|
+
const pendingDeletes = [];
|
|
20
22
|
|
|
21
23
|
const watcher = chokidar.watch(join(tenantDir, '**/*.php'), {
|
|
22
24
|
ignoreInitial: true,
|
|
23
25
|
awaitWriteFinish: { stabilityThreshold: 300 },
|
|
24
26
|
});
|
|
25
27
|
|
|
26
|
-
watcher.on('
|
|
27
|
-
console.log(chalk.
|
|
28
|
+
watcher.on('add', (path) => {
|
|
29
|
+
console.log(chalk.green(` + ${relative(tenantDir, path)}`));
|
|
30
|
+
debouncedSync();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
watcher.on('change', (path) => {
|
|
34
|
+
console.log(chalk.yellow(` ~ ${relative(tenantDir, path)}`));
|
|
35
|
+
debouncedSync();
|
|
36
|
+
});
|
|
28
37
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
38
|
+
watcher.on('unlink', (path) => {
|
|
39
|
+
const relPath = relative(tenantDir, path);
|
|
40
|
+
console.log(chalk.red(` - ${relPath}`));
|
|
41
|
+
pendingDeletes.push(relPath);
|
|
42
|
+
debouncedSync();
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
function debouncedSync() {
|
|
46
|
+
if (syncTimer) clearTimeout(syncTimer);
|
|
47
|
+
syncTimer = setTimeout(async () => {
|
|
32
48
|
try {
|
|
49
|
+
// Delete files first
|
|
50
|
+
if (pendingDeletes.length > 0) {
|
|
51
|
+
const toDelete = [...pendingDeletes];
|
|
52
|
+
pendingDeletes.length = 0;
|
|
53
|
+
try {
|
|
54
|
+
const client = createClient();
|
|
55
|
+
const result = await client.post('/api/tenant/delete-files', { files: toDelete });
|
|
56
|
+
if (result.deleted > 0) {
|
|
57
|
+
console.log(chalk.red(` ✓ ${result.deleted} deleted on server`));
|
|
58
|
+
}
|
|
59
|
+
} catch (err) {
|
|
60
|
+
console.error(chalk.red(` Delete error: ${err.message}`));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// Then sync remaining files
|
|
33
64
|
await sync();
|
|
34
65
|
} catch (err) {
|
|
35
66
|
console.error(chalk.red(` Sync error: ${err.message}`));
|
|
36
67
|
}
|
|
37
68
|
}, 500);
|
|
38
|
-
}
|
|
69
|
+
}
|
|
39
70
|
|
|
40
|
-
// Keep process alive
|
|
41
71
|
process.on('SIGINT', () => {
|
|
42
72
|
watcher.close();
|
|
43
73
|
console.log(chalk.gray('\nStopped.'));
|