morpheus-cli 0.8.9 → 0.9.1
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/dist/channels/discord.js +133 -6
- package/dist/channels/telegram.js +23 -17
- package/dist/http/api.js +2 -3
- package/dist/runtime/__tests__/keymaker.test.js +5 -2
- package/dist/runtime/apoc.js +7 -7
- package/dist/{devkit/registry.js → runtime/devkit-instrument.js} +5 -29
- package/dist/runtime/keymaker.js +6 -5
- package/dist/runtime/memory/sati/service.js +1 -1
- package/dist/runtime/memory/sqlite.js +31 -124
- package/dist/runtime/neo.js +1 -1
- package/dist/runtime/oracle.js +30 -52
- package/dist/runtime/smiths/delegator.js +2 -2
- package/dist/runtime/trinity.js +1 -1
- package/dist/ui/assets/{AuditDashboard-5sA8Sd8S.js → AuditDashboard-nVV9KKFp.js} +1 -1
- package/dist/ui/assets/Chat-ChsmnZzq.js +41 -0
- package/dist/ui/assets/{Chronos-BAjeLobF.js → Chronos-kgO7IkEj.js} +1 -1
- package/dist/ui/assets/{ConfirmationModal-fvgnOWTY.js → ConfirmationModal-D1BYPXJ4.js} +1 -1
- package/dist/ui/assets/{Dashboard-Ca5mSefz.js → Dashboard-DWB5NwQn.js} +1 -1
- package/dist/ui/assets/{DeleteConfirmationModal-A8EmnHoa.js → DeleteConfirmationModal-CgIMbyB7.js} +1 -1
- package/dist/ui/assets/{Logs-CYu7se7R.js → Logs-DGdRnEFi.js} +1 -1
- package/dist/ui/assets/{MCPManager-DsDA_ZVT.js → MCPManager-BDjWMRRX.js} +1 -1
- package/dist/ui/assets/{ModelPricing-DnSm_Nh-.js → ModelPricing-DAk1sS7D.js} +1 -1
- package/dist/ui/assets/{Notifications-CiljQzvM.js → Notifications-DMEq6EZR.js} +1 -1
- package/dist/ui/assets/{SatiMemories-rnO2b0LG.js → SatiMemories-BxicQE35.js} +1 -1
- package/dist/ui/assets/{SessionAudit-Dfvhge3Z.js → SessionAudit-CKJQf9LU.js} +1 -1
- package/dist/ui/assets/{Settings-OQlHAJoy.js → Settings-CulMd4Qr.js} +1 -1
- package/dist/ui/assets/{Skills-Crsybug0.js → Skills-DPoqYa8Y.js} +1 -1
- package/dist/ui/assets/{Smiths-wm90jRDT.js → Smiths-Clamjlph.js} +1 -1
- package/dist/ui/assets/{Tasks-C5FMu_Yu.js → Tasks-BfTkhB1J.js} +1 -1
- package/dist/ui/assets/{TrinityDatabases-BzYfecKI.js → TrinityDatabases-BmM1S9aQ.js} +1 -1
- package/dist/ui/assets/{UsageStats-CBo2vW2n.js → UsageStats-aAu2DFlb.js} +1 -1
- package/dist/ui/assets/{WebhookManager-0tDFkfHd.js → WebhookManager-DdnRSWl9.js} +1 -1
- package/dist/ui/assets/{audit-B-F8XPLi.js → audit-CqszEkOd.js} +1 -1
- package/dist/ui/assets/{chronos-BvMxfBQH.js → chronos-CPwFWid9.js} +1 -1
- package/dist/ui/assets/{config-DteVgNGR.js → config-D0DePxKu.js} +1 -1
- package/dist/ui/assets/{index-Cwqr-n0Y.js → index-BxVeRyTh.js} +2 -2
- package/dist/ui/assets/index-OLhpm8I7.css +1 -0
- package/dist/ui/assets/{mcp-DxzodOdH.js → mcp-Gjc3IZpO.js} +1 -1
- package/dist/ui/assets/{skills--hAyQnmG.js → skills-B5DnmnHW.js} +1 -1
- package/dist/ui/assets/{stats-Cibaisqd.js → stats-BAse7jj0.js} +1 -1
- package/dist/ui/index.html +2 -2
- package/dist/ui/sw.js +1 -1
- package/package.json +6 -4
- package/dist/devkit/adapters/shell.js +0 -80
- package/dist/devkit/index.js +0 -11
- package/dist/devkit/tools/browser.js +0 -825
- package/dist/devkit/tools/filesystem.js +0 -235
- package/dist/devkit/tools/git.js +0 -226
- package/dist/devkit/tools/network.js +0 -165
- package/dist/devkit/tools/packages.js +0 -73
- package/dist/devkit/tools/processes.js +0 -130
- package/dist/devkit/tools/shell.js +0 -106
- package/dist/devkit/tools/system.js +0 -132
- package/dist/devkit/types.js +0 -1
- package/dist/devkit/utils.js +0 -45
- package/dist/ui/assets/Chat-CjxeAQmd.js +0 -41
- package/dist/ui/assets/index-DcfyUdLI.css +0 -1
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import { tool } from '@langchain/core/tools';
|
|
2
|
-
import { z } from 'zod';
|
|
3
|
-
import { ShellAdapter } from '../adapters/shell.js';
|
|
4
|
-
import { truncateOutput, isCommandAllowed } from '../utils.js';
|
|
5
|
-
import { registerToolFactory } from '../registry.js';
|
|
6
|
-
export function createPackageTools(ctx) {
|
|
7
|
-
const shell = ShellAdapter.create();
|
|
8
|
-
async function run(binary, args, timeout_ms) {
|
|
9
|
-
if (!isCommandAllowed(binary, ctx.allowed_commands)) {
|
|
10
|
-
return `'${binary}' is not in the allowed_commands list.`;
|
|
11
|
-
}
|
|
12
|
-
const result = await shell.run(binary, args, {
|
|
13
|
-
cwd: ctx.working_dir,
|
|
14
|
-
timeout_ms: timeout_ms ?? ctx.timeout_ms ?? 120_000,
|
|
15
|
-
});
|
|
16
|
-
return truncateOutput(result.stdout + (result.stderr ? '\n' + result.stderr : ''));
|
|
17
|
-
}
|
|
18
|
-
return [
|
|
19
|
-
tool(async ({ packages, save_dev, timeout_ms }) => {
|
|
20
|
-
const args = ['install'];
|
|
21
|
-
if (packages?.length)
|
|
22
|
-
args.push(...packages);
|
|
23
|
-
if (save_dev)
|
|
24
|
-
args.push('--save-dev');
|
|
25
|
-
return run('npm', args, timeout_ms);
|
|
26
|
-
}, {
|
|
27
|
-
name: 'npm_install',
|
|
28
|
-
description: 'Install npm packages. Runs "npm install [packages]".',
|
|
29
|
-
schema: z.object({
|
|
30
|
-
packages: z.array(z.string()).optional().describe('Specific packages to install, omit to install all from package.json'),
|
|
31
|
-
save_dev: z.boolean().optional().describe('Install as devDependency'),
|
|
32
|
-
timeout_ms: z.number().optional(),
|
|
33
|
-
}),
|
|
34
|
-
}),
|
|
35
|
-
tool(async ({ script, args, timeout_ms }) => {
|
|
36
|
-
const npmArgs = ['run', script];
|
|
37
|
-
if (args?.length)
|
|
38
|
-
npmArgs.push('--', ...args);
|
|
39
|
-
return run('npm', npmArgs, timeout_ms);
|
|
40
|
-
}, {
|
|
41
|
-
name: 'npm_run',
|
|
42
|
-
description: 'Run an npm script defined in package.json.',
|
|
43
|
-
schema: z.object({
|
|
44
|
-
script: z.string().describe('Script name from package.json'),
|
|
45
|
-
args: z.array(z.string()).optional().describe('Additional arguments after --'),
|
|
46
|
-
timeout_ms: z.number().optional(),
|
|
47
|
-
}),
|
|
48
|
-
}),
|
|
49
|
-
tool(async ({ packages, upgrade, timeout_ms }) => {
|
|
50
|
-
const args = [upgrade ? 'install' : 'install', '--upgrade', ...packages];
|
|
51
|
-
return run('pip3', packages.length ? ['install', ...packages] : ['install', '-r', 'requirements.txt'], timeout_ms);
|
|
52
|
-
}, {
|
|
53
|
-
name: 'pip_install',
|
|
54
|
-
description: 'Install Python packages with pip3.',
|
|
55
|
-
schema: z.object({
|
|
56
|
-
packages: z.array(z.string()).default([]).describe('Package names, omit to use requirements.txt'),
|
|
57
|
-
upgrade: z.boolean().optional().describe('Upgrade packages if already installed'),
|
|
58
|
-
timeout_ms: z.number().optional(),
|
|
59
|
-
}),
|
|
60
|
-
}),
|
|
61
|
-
tool(async ({ args, timeout_ms }) => {
|
|
62
|
-
return run('cargo', ['build', ...(args ?? [])], timeout_ms);
|
|
63
|
-
}, {
|
|
64
|
-
name: 'cargo_build',
|
|
65
|
-
description: 'Build a Rust project using cargo.',
|
|
66
|
-
schema: z.object({
|
|
67
|
-
args: z.array(z.string()).optional().describe('Additional cargo build arguments'),
|
|
68
|
-
timeout_ms: z.number().optional(),
|
|
69
|
-
}),
|
|
70
|
-
}),
|
|
71
|
-
];
|
|
72
|
-
}
|
|
73
|
-
registerToolFactory(createPackageTools, 'packages');
|
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
import { tool } from '@langchain/core/tools';
|
|
2
|
-
import { z } from 'zod';
|
|
3
|
-
import os from 'os';
|
|
4
|
-
import { ShellAdapter } from '../adapters/shell.js';
|
|
5
|
-
import { truncateOutput } from '../utils.js';
|
|
6
|
-
import { registerToolFactory } from '../registry.js';
|
|
7
|
-
import { platform } from 'os';
|
|
8
|
-
export function createProcessTools(ctx) {
|
|
9
|
-
const shell = ShellAdapter.create();
|
|
10
|
-
const isWindows = platform() === 'win32';
|
|
11
|
-
return [
|
|
12
|
-
tool(async ({ filter }) => {
|
|
13
|
-
let result;
|
|
14
|
-
if (isWindows) {
|
|
15
|
-
result = await shell.run('tasklist', filter ? ['/FI', `IMAGENAME eq ${filter}*`] : [], {
|
|
16
|
-
cwd: ctx.working_dir, timeout_ms: 10_000,
|
|
17
|
-
});
|
|
18
|
-
}
|
|
19
|
-
else {
|
|
20
|
-
result = await shell.run('ps', ['aux'], { cwd: ctx.working_dir, timeout_ms: 10_000 });
|
|
21
|
-
if (filter && result.exitCode === 0) {
|
|
22
|
-
result.stdout = result.stdout
|
|
23
|
-
.split('\n')
|
|
24
|
-
.filter((l, i) => i === 0 || l.toLowerCase().includes(filter.toLowerCase()))
|
|
25
|
-
.join('\n');
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
return truncateOutput(result.stdout || result.stderr);
|
|
29
|
-
}, {
|
|
30
|
-
name: 'list_processes',
|
|
31
|
-
description: 'List running processes, optionally filtered by name.',
|
|
32
|
-
schema: z.object({
|
|
33
|
-
filter: z.string().optional().describe('Filter by process name (partial match)'),
|
|
34
|
-
}),
|
|
35
|
-
}),
|
|
36
|
-
tool(async ({ pid, name }) => {
|
|
37
|
-
let result;
|
|
38
|
-
if (isWindows) {
|
|
39
|
-
const filter = pid ? `/FI "PID eq ${pid}"` : `/FI "IMAGENAME eq ${name}*"`;
|
|
40
|
-
result = await shell.run('tasklist', ['/FI', filter.replace(/"/g, '').split(' ').join(' ')], {
|
|
41
|
-
cwd: ctx.working_dir, timeout_ms: 5_000,
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
else {
|
|
45
|
-
const query = pid ? String(pid) : name ?? '';
|
|
46
|
-
result = await shell.run('ps', ['-p', query, '-o', 'pid,ppid,cmd,%cpu,%mem'], {
|
|
47
|
-
cwd: ctx.working_dir, timeout_ms: 5_000,
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
return truncateOutput(result.stdout || result.stderr);
|
|
51
|
-
}, {
|
|
52
|
-
name: 'get_process',
|
|
53
|
-
description: 'Get info about a specific process by PID or name.',
|
|
54
|
-
schema: z.object({
|
|
55
|
-
pid: z.number().int().optional().describe('Process ID'),
|
|
56
|
-
name: z.string().optional().describe('Process name'),
|
|
57
|
-
}),
|
|
58
|
-
}),
|
|
59
|
-
tool(async ({ pid, force }) => {
|
|
60
|
-
let result;
|
|
61
|
-
if (isWindows) {
|
|
62
|
-
const args = ['taskkill', '/PID', String(pid)];
|
|
63
|
-
if (force)
|
|
64
|
-
args.push('/F');
|
|
65
|
-
result = await shell.run('taskkill', ['/PID', String(pid), ...(force ? ['/F'] : [])], {
|
|
66
|
-
cwd: ctx.working_dir, timeout_ms: 10_000,
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
else {
|
|
70
|
-
const signal = force ? '-9' : '-15';
|
|
71
|
-
result = await shell.run('kill', [signal, String(pid)], {
|
|
72
|
-
cwd: ctx.working_dir, timeout_ms: 10_000,
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
return JSON.stringify({
|
|
76
|
-
success: result.exitCode === 0,
|
|
77
|
-
stdout: result.stdout.trim(),
|
|
78
|
-
stderr: result.stderr.trim(),
|
|
79
|
-
});
|
|
80
|
-
}, {
|
|
81
|
-
name: 'kill_process',
|
|
82
|
-
description: 'Kill a process by PID. Use force=true for SIGKILL.',
|
|
83
|
-
schema: z.object({
|
|
84
|
-
pid: z.number().int().describe('Process ID to kill'),
|
|
85
|
-
force: z.boolean().optional().describe('Force kill (SIGKILL / /F), default false'),
|
|
86
|
-
}),
|
|
87
|
-
}),
|
|
88
|
-
tool(async () => {
|
|
89
|
-
const cpus = os.cpus();
|
|
90
|
-
return JSON.stringify({
|
|
91
|
-
platform: os.platform(),
|
|
92
|
-
arch: os.arch(),
|
|
93
|
-
release: os.release(),
|
|
94
|
-
hostname: os.hostname(),
|
|
95
|
-
cpus: cpus.length,
|
|
96
|
-
cpu_model: cpus[0]?.model ?? 'unknown',
|
|
97
|
-
total_memory_mb: Math.round(os.totalmem() / 1024 / 1024),
|
|
98
|
-
free_memory_mb: Math.round(os.freemem() / 1024 / 1024),
|
|
99
|
-
uptime_seconds: Math.round(os.uptime()),
|
|
100
|
-
load_avg: os.loadavg(),
|
|
101
|
-
home_dir: os.homedir(),
|
|
102
|
-
tmp_dir: os.tmpdir(),
|
|
103
|
-
});
|
|
104
|
-
}, {
|
|
105
|
-
name: 'system_info',
|
|
106
|
-
description: 'Get system information (OS, CPU, RAM, uptime).',
|
|
107
|
-
schema: z.object({}),
|
|
108
|
-
}),
|
|
109
|
-
tool(async ({ name, all }) => {
|
|
110
|
-
if (all)
|
|
111
|
-
return JSON.stringify(process.env);
|
|
112
|
-
if (name)
|
|
113
|
-
return JSON.stringify({ [name]: process.env[name] ?? null });
|
|
114
|
-
// Return non-sensitive vars
|
|
115
|
-
const safe = Object.fromEntries(Object.entries(process.env).filter(([k]) => !k.toLowerCase().includes('key') &&
|
|
116
|
-
!k.toLowerCase().includes('token') &&
|
|
117
|
-
!k.toLowerCase().includes('secret') &&
|
|
118
|
-
!k.toLowerCase().includes('password')));
|
|
119
|
-
return truncateOutput(JSON.stringify(safe, null, 2));
|
|
120
|
-
}, {
|
|
121
|
-
name: 'env_read',
|
|
122
|
-
description: 'Read environment variables. Sensitive keys (API_KEY, TOKEN, etc.) are filtered unless all=true.',
|
|
123
|
-
schema: z.object({
|
|
124
|
-
name: z.string().optional().describe('Specific env var name'),
|
|
125
|
-
all: z.boolean().optional().describe('Include all vars including sensitive ones'),
|
|
126
|
-
}),
|
|
127
|
-
}),
|
|
128
|
-
];
|
|
129
|
-
}
|
|
130
|
-
registerToolFactory(createProcessTools, 'processes');
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
import { tool } from '@langchain/core/tools';
|
|
2
|
-
import { z } from 'zod';
|
|
3
|
-
import fs from 'fs-extra';
|
|
4
|
-
import path from 'path';
|
|
5
|
-
import os from 'os';
|
|
6
|
-
import { randomUUID } from 'crypto';
|
|
7
|
-
import { ShellAdapter } from '../adapters/shell.js';
|
|
8
|
-
import { truncateOutput, isCommandAllowed, isWithinDir } from '../utils.js';
|
|
9
|
-
import { registerToolFactory } from '../registry.js';
|
|
10
|
-
export function createShellTools(ctx) {
|
|
11
|
-
const shell = ShellAdapter.create();
|
|
12
|
-
return [
|
|
13
|
-
tool(async ({ command, args, timeout_ms, cwd }) => {
|
|
14
|
-
if (!isCommandAllowed(command, ctx.allowed_commands)) {
|
|
15
|
-
return JSON.stringify({
|
|
16
|
-
success: false,
|
|
17
|
-
error: `Command '${command}' is not in the allowed_commands list for this project. Allowed: [${ctx.allowed_commands.join(', ')}]`,
|
|
18
|
-
});
|
|
19
|
-
}
|
|
20
|
-
// Enforce sandbox_dir: override cwd to stay within sandbox
|
|
21
|
-
let effectiveCwd = cwd ?? ctx.working_dir;
|
|
22
|
-
if (ctx.sandbox_dir) {
|
|
23
|
-
const resolvedCwd = path.isAbsolute(effectiveCwd) ? effectiveCwd : path.resolve(ctx.sandbox_dir, effectiveCwd);
|
|
24
|
-
if (!isWithinDir(resolvedCwd, ctx.sandbox_dir)) {
|
|
25
|
-
return JSON.stringify({
|
|
26
|
-
success: false,
|
|
27
|
-
error: `Working directory '${resolvedCwd}' is outside the sandbox directory '${ctx.sandbox_dir}'. Operation denied.`,
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
effectiveCwd = resolvedCwd;
|
|
31
|
-
}
|
|
32
|
-
const result = await shell.run(command, args ?? [], {
|
|
33
|
-
cwd: effectiveCwd,
|
|
34
|
-
timeout_ms: timeout_ms ?? ctx.timeout_ms ?? 30_000,
|
|
35
|
-
});
|
|
36
|
-
return JSON.stringify({
|
|
37
|
-
success: result.exitCode === 0,
|
|
38
|
-
stdout: truncateOutput(result.stdout),
|
|
39
|
-
stderr: truncateOutput(result.stderr),
|
|
40
|
-
exitCode: result.exitCode,
|
|
41
|
-
timedOut: result.timedOut,
|
|
42
|
-
});
|
|
43
|
-
}, {
|
|
44
|
-
name: 'run_command',
|
|
45
|
-
description: 'Run a shell command. The command binary must be in the project allowlist.',
|
|
46
|
-
schema: z.object({
|
|
47
|
-
command: z.string().describe('Command/binary to run'),
|
|
48
|
-
args: z.array(z.string()).optional().describe('Arguments array'),
|
|
49
|
-
timeout_ms: z.number().optional().describe('Override timeout in milliseconds'),
|
|
50
|
-
cwd: z.string().optional().describe('Override working directory'),
|
|
51
|
-
}),
|
|
52
|
-
}),
|
|
53
|
-
tool(async ({ script, language, timeout_ms }) => {
|
|
54
|
-
const lang = language ?? 'bash';
|
|
55
|
-
const ext = lang === 'python' ? 'py' : lang === 'node' ? 'js' : 'sh';
|
|
56
|
-
const tmpFile = path.join(os.tmpdir(), `morpheus-script-${randomUUID()}.${ext}`);
|
|
57
|
-
try {
|
|
58
|
-
await fs.writeFile(tmpFile, script, 'utf8');
|
|
59
|
-
const binaryMap = {
|
|
60
|
-
bash: 'bash',
|
|
61
|
-
python: 'python3',
|
|
62
|
-
node: 'node',
|
|
63
|
-
sh: 'sh',
|
|
64
|
-
};
|
|
65
|
-
const binary = binaryMap[lang] ?? lang;
|
|
66
|
-
if (!isCommandAllowed(binary, ctx.allowed_commands)) {
|
|
67
|
-
return JSON.stringify({
|
|
68
|
-
success: false,
|
|
69
|
-
error: `Script runtime '${binary}' is not in the allowed_commands list.`,
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
const result = await shell.run(binary, [tmpFile], {
|
|
73
|
-
cwd: ctx.working_dir,
|
|
74
|
-
timeout_ms: timeout_ms ?? ctx.timeout_ms ?? 60_000,
|
|
75
|
-
});
|
|
76
|
-
return JSON.stringify({
|
|
77
|
-
success: result.exitCode === 0,
|
|
78
|
-
stdout: truncateOutput(result.stdout),
|
|
79
|
-
stderr: truncateOutput(result.stderr),
|
|
80
|
-
exitCode: result.exitCode,
|
|
81
|
-
timedOut: result.timedOut,
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
finally {
|
|
85
|
-
await fs.remove(tmpFile).catch(() => { });
|
|
86
|
-
}
|
|
87
|
-
}, {
|
|
88
|
-
name: 'run_script',
|
|
89
|
-
description: 'Write and execute an inline script (bash, python, node, sh).',
|
|
90
|
-
schema: z.object({
|
|
91
|
-
script: z.string().describe('Script content to execute'),
|
|
92
|
-
language: z.enum(['bash', 'python', 'node', 'sh']).optional().describe('Script language, default bash'),
|
|
93
|
-
timeout_ms: z.number().optional(),
|
|
94
|
-
}),
|
|
95
|
-
}),
|
|
96
|
-
tool(async ({ binary }) => {
|
|
97
|
-
const location = await shell.which(binary);
|
|
98
|
-
return JSON.stringify({ found: Boolean(location), path: location });
|
|
99
|
-
}, {
|
|
100
|
-
name: 'which',
|
|
101
|
-
description: 'Find the location of a binary in the system PATH.',
|
|
102
|
-
schema: z.object({ binary: z.string() }),
|
|
103
|
-
}),
|
|
104
|
-
];
|
|
105
|
-
}
|
|
106
|
-
registerToolFactory(createShellTools, 'shell');
|
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
import { tool } from '@langchain/core/tools';
|
|
2
|
-
import { z } from 'zod';
|
|
3
|
-
import { ShellAdapter } from '../adapters/shell.js';
|
|
4
|
-
import { registerToolFactory } from '../registry.js';
|
|
5
|
-
import { platform } from 'os';
|
|
6
|
-
export function createSystemTools(ctx) {
|
|
7
|
-
const shell = ShellAdapter.create();
|
|
8
|
-
const isWindows = platform() === 'win32';
|
|
9
|
-
const isMac = platform() === 'darwin';
|
|
10
|
-
return [
|
|
11
|
-
tool(async ({ title, message, urgency }) => {
|
|
12
|
-
try {
|
|
13
|
-
if (isWindows) {
|
|
14
|
-
// PowerShell toast notification
|
|
15
|
-
const ps = `[Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType=WindowsRuntime] | Out-Null; $template = [Windows.UI.Notifications.ToastNotificationManager]::GetTemplateContent([Windows.UI.Notifications.ToastTemplateType]::ToastText02); $template.GetElementsByTagName('text')[0].AppendChild($template.CreateTextNode('${title}')); $template.GetElementsByTagName('text')[1].AppendChild($template.CreateTextNode('${message}')); [Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier('Morpheus').Show([Windows.UI.Notifications.ToastNotification]::new($template))`;
|
|
16
|
-
await shell.run('powershell', ['-Command', ps], { cwd: ctx.working_dir, timeout_ms: 5_000 });
|
|
17
|
-
}
|
|
18
|
-
else if (isMac) {
|
|
19
|
-
await shell.run('osascript', ['-e', `display notification "${message}" with title "${title}"`], {
|
|
20
|
-
cwd: ctx.working_dir, timeout_ms: 5_000,
|
|
21
|
-
});
|
|
22
|
-
}
|
|
23
|
-
else {
|
|
24
|
-
// Linux — notify-send
|
|
25
|
-
const args = [title, message];
|
|
26
|
-
if (urgency)
|
|
27
|
-
args.unshift(`-u`, urgency);
|
|
28
|
-
await shell.run('notify-send', args, { cwd: ctx.working_dir, timeout_ms: 5_000 });
|
|
29
|
-
}
|
|
30
|
-
return JSON.stringify({ success: true });
|
|
31
|
-
}
|
|
32
|
-
catch (err) {
|
|
33
|
-
return JSON.stringify({ success: false, error: err.message });
|
|
34
|
-
}
|
|
35
|
-
}, {
|
|
36
|
-
name: 'notify',
|
|
37
|
-
description: 'Send a desktop notification.',
|
|
38
|
-
schema: z.object({
|
|
39
|
-
title: z.string(),
|
|
40
|
-
message: z.string(),
|
|
41
|
-
urgency: z.enum(['low', 'normal', 'critical']).optional().describe('Linux urgency level'),
|
|
42
|
-
}),
|
|
43
|
-
}),
|
|
44
|
-
tool(async () => {
|
|
45
|
-
try {
|
|
46
|
-
let result;
|
|
47
|
-
if (isWindows) {
|
|
48
|
-
result = await shell.run('powershell', ['-Command', 'Get-Clipboard'], {
|
|
49
|
-
cwd: ctx.working_dir, timeout_ms: 5_000,
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
else if (isMac) {
|
|
53
|
-
result = await shell.run('pbpaste', [], { cwd: ctx.working_dir, timeout_ms: 5_000 });
|
|
54
|
-
}
|
|
55
|
-
else {
|
|
56
|
-
result = await shell.run('xclip', ['-selection', 'clipboard', '-o'], {
|
|
57
|
-
cwd: ctx.working_dir, timeout_ms: 5_000,
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
return JSON.stringify({ success: result.exitCode === 0, content: result.stdout });
|
|
61
|
-
}
|
|
62
|
-
catch (err) {
|
|
63
|
-
return JSON.stringify({ success: false, error: err.message });
|
|
64
|
-
}
|
|
65
|
-
}, {
|
|
66
|
-
name: 'read_clipboard',
|
|
67
|
-
description: 'Read the current clipboard contents.',
|
|
68
|
-
schema: z.object({}),
|
|
69
|
-
}),
|
|
70
|
-
tool(async ({ content }) => {
|
|
71
|
-
try {
|
|
72
|
-
let result;
|
|
73
|
-
if (isWindows) {
|
|
74
|
-
result = await shell.run('powershell', ['-Command', `Set-Clipboard -Value '${content.replace(/'/g, "''")}'`], {
|
|
75
|
-
cwd: ctx.working_dir, timeout_ms: 5_000,
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
else if (isMac) {
|
|
79
|
-
result = await shell.run('sh', ['-c', `printf '%s' '${content.replace(/'/g, "'\\''")}' | pbcopy`], {
|
|
80
|
-
cwd: ctx.working_dir, timeout_ms: 5_000,
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
else {
|
|
84
|
-
result = await shell.run('sh', ['-c', `printf '%s' '${content.replace(/'/g, "'\\''")}' | xclip -selection clipboard`], {
|
|
85
|
-
cwd: ctx.working_dir, timeout_ms: 5_000,
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
return JSON.stringify({ success: result.exitCode === 0 });
|
|
89
|
-
}
|
|
90
|
-
catch (err) {
|
|
91
|
-
return JSON.stringify({ success: false, error: err.message });
|
|
92
|
-
}
|
|
93
|
-
}, {
|
|
94
|
-
name: 'write_clipboard',
|
|
95
|
-
description: 'Write content to the clipboard.',
|
|
96
|
-
schema: z.object({ content: z.string() }),
|
|
97
|
-
}),
|
|
98
|
-
tool(async ({ url }) => {
|
|
99
|
-
try {
|
|
100
|
-
const open = isWindows ? 'start' : isMac ? 'open' : 'xdg-open';
|
|
101
|
-
const result = await shell.run(isWindows ? 'cmd' : open, isWindows ? ['/c', 'start', url] : [url], {
|
|
102
|
-
cwd: ctx.working_dir, timeout_ms: 5_000,
|
|
103
|
-
});
|
|
104
|
-
return JSON.stringify({ success: result.exitCode === 0, url });
|
|
105
|
-
}
|
|
106
|
-
catch (err) {
|
|
107
|
-
return JSON.stringify({ success: false, error: err.message });
|
|
108
|
-
}
|
|
109
|
-
}, {
|
|
110
|
-
name: 'open_url',
|
|
111
|
-
description: 'Open a URL in the default browser.',
|
|
112
|
-
schema: z.object({ url: z.string() }),
|
|
113
|
-
}),
|
|
114
|
-
tool(async ({ file_path }) => {
|
|
115
|
-
try {
|
|
116
|
-
const open = isWindows ? 'start' : isMac ? 'open' : 'xdg-open';
|
|
117
|
-
const result = await shell.run(isWindows ? 'cmd' : open, isWindows ? ['/c', 'start', '""', file_path] : [file_path], {
|
|
118
|
-
cwd: ctx.working_dir, timeout_ms: 5_000,
|
|
119
|
-
});
|
|
120
|
-
return JSON.stringify({ success: result.exitCode === 0, file_path });
|
|
121
|
-
}
|
|
122
|
-
catch (err) {
|
|
123
|
-
return JSON.stringify({ success: false, error: err.message });
|
|
124
|
-
}
|
|
125
|
-
}, {
|
|
126
|
-
name: 'open_file',
|
|
127
|
-
description: 'Open a file with the default application.',
|
|
128
|
-
schema: z.object({ file_path: z.string() }),
|
|
129
|
-
}),
|
|
130
|
-
];
|
|
131
|
-
}
|
|
132
|
-
registerToolFactory(createSystemTools, 'system');
|
package/dist/devkit/types.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export const MAX_OUTPUT_BYTES = 50 * 1024; // 50 KB
|
package/dist/devkit/utils.js
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import path from 'path';
|
|
2
|
-
import { MAX_OUTPUT_BYTES } from './types.js';
|
|
3
|
-
/**
|
|
4
|
-
* Truncates a string to MAX_OUTPUT_BYTES (50 KB) if needed.
|
|
5
|
-
* Returns a UTF-8-safe truncation with a note when truncated.
|
|
6
|
-
*/
|
|
7
|
-
export function truncateOutput(output) {
|
|
8
|
-
const bytes = Buffer.byteLength(output, 'utf8');
|
|
9
|
-
if (bytes <= MAX_OUTPUT_BYTES)
|
|
10
|
-
return output;
|
|
11
|
-
const truncated = Buffer.from(output).subarray(0, MAX_OUTPUT_BYTES).toString('utf8');
|
|
12
|
-
return truncated + `\n\n[OUTPUT TRUNCATED: ${bytes} bytes total, showing first ${MAX_OUTPUT_BYTES} bytes]`;
|
|
13
|
-
}
|
|
14
|
-
/**
|
|
15
|
-
* Returns true if filePath is inside dir (or equal to dir).
|
|
16
|
-
* Both paths are resolved before comparison.
|
|
17
|
-
*/
|
|
18
|
-
export function isWithinDir(filePath, dir) {
|
|
19
|
-
const resolved = path.resolve(filePath);
|
|
20
|
-
const resolvedDir = path.resolve(dir);
|
|
21
|
-
return resolved === resolvedDir || resolved.startsWith(resolvedDir + path.sep);
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Extracts the binary base name from a command string.
|
|
25
|
-
* Handles full paths (/usr/bin/node, C:\bin\node.exe) and plain names.
|
|
26
|
-
*/
|
|
27
|
-
export function extractBinaryName(command) {
|
|
28
|
-
// Take first token (before any space), then get the basename, strip extension
|
|
29
|
-
const firstToken = command.split(/\s+/)[0] ?? command;
|
|
30
|
-
const base = path.basename(firstToken);
|
|
31
|
-
return base.replace(/\.(exe|cmd|bat|sh|ps1)$/i, '').toLowerCase();
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Checks if a command is allowed based on the allowlist.
|
|
35
|
-
* Empty allowlist means ALL commands are allowed (Merovingian mode).
|
|
36
|
-
*/
|
|
37
|
-
export function isCommandAllowed(command, allowedCommands) {
|
|
38
|
-
if (allowedCommands.length === 0)
|
|
39
|
-
return true;
|
|
40
|
-
const binary = extractBinaryName(command);
|
|
41
|
-
return allowedCommands.some(allowed => {
|
|
42
|
-
const allowedBinary = extractBinaryName(allowed);
|
|
43
|
-
return allowedBinary === binary;
|
|
44
|
-
});
|
|
45
|
-
}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import{j as e,A as B,m as L}from"./vendor-motion-C3CZ8ZlO.js";import{c as U,r as l}from"./vendor-react-DikRIOlj.js";import{s as H,t as F,u as X,v as Q,X as W,w as V,x as Y,y as Z,z as ee,E as re,q as G,F as K,r as q,G as $,m as te,M as ae,I as T,J as se,U as ie,K as ne}from"./vendor-icons-BVuQI-6R.js";import{h as oe,g as le,i as de,c as A}from"./index-Cwqr-n0Y.js";import{M as ce,r as xe}from"./vendor-markdown-BN_Np5Ta.js";import{C as me}from"./ConfirmationModal-fvgnOWTY.js";import"./vendor-utils-D4NnWbOU.js";function he(r){const n=Date.now()-r;return n<6e4?"just now":n<36e5?`${Math.floor(n/6e4)}m ago`:n<864e5?`${Math.floor(n/36e5)}h ago`:n<6048e5?`${Math.floor(n/864e5)}d ago`:new Date(r).toLocaleDateString()}const pe=({sessions:r,activeSessionId:n,onSelectSession:i,onCreateSession:d,onArchiveSession:p,onDeleteSession:x,onRenameSession:c,isOpen:u,toggleSidebar:m})=>{const v=U(),[g,b]=l.useState(null),[w,k]=l.useState(""),z=l.useRef(null);l.useEffect(()=>{g&&z.current&&z.current.focus()},[g]);const I=(o,S)=>{o.stopPropagation(),b(S.id),k(S.title||"Untitled Session")},D=o=>{o?.stopPropagation(),g&&w.trim()&&(c(g,w.trim()),b(null))},N=o=>{o?.stopPropagation(),b(null)},_=o=>{o.key==="Enter"?D():o.key==="Escape"&&N()};return u?e.jsxs("div",{className:"w-72 bg-white dark:bg-black border-r border-gray-300 dark:border-matrix-primary flex flex-col h-full shrink-0 transition-colors duration-300",children:[e.jsxs("div",{className:"flex items-center justify-between px-4 py-3 border-b border-gray-300 dark:border-matrix-primary shrink-0",children:[e.jsx("span",{className:"text-sm font-semibold text-gray-800 dark:text-matrix-highlight",children:"Sessions"}),e.jsx("button",{onClick:m,className:"p-1.5 rounded-lg hover:bg-gray-100 dark:hover:bg-matrix-primary/20 text-gray-400 dark:text-matrix-secondary/60 transition-colors",title:"Collapse sidebar",children:e.jsx(X,{size:16})})]}),e.jsx("div",{className:"px-3 py-2.5 shrink-0",children:e.jsxs("button",{onClick:d,className:"w-full flex items-center justify-center gap-2 bg-azure-primary text-white dark:bg-matrix-highlight dark:text-black py-2 px-4 rounded-xl hover:bg-azure-secondary dark:hover:bg-matrix-secondary transition-colors text-sm font-medium shadow-sm",children:[e.jsx(F,{size:16}),"New Chat"]})}),e.jsxs("div",{className:"flex-1 overflow-y-auto px-2 pb-3 space-y-0.5",children:[r.length===0&&e.jsx("div",{className:"text-center text-gray-400 dark:text-matrix-secondary/40 mt-12 text-sm px-4",children:"No sessions yet. Start a new chat!"}),r.map(o=>{const S=n===o.id,E=g===o.id;return e.jsxs("div",{onClick:()=>!E&&i(o.id),className:`
|
|
2
|
-
group relative flex items-center gap-2 px-3 py-2.5 rounded-xl cursor-pointer transition-all
|
|
3
|
-
${S?"bg-azure-primary/10 dark:bg-matrix-primary/15 text-azure-primary dark:text-matrix-highlight":"hover:bg-gray-100 dark:hover:bg-matrix-primary/10 text-gray-700 dark:text-matrix-secondary"}
|
|
4
|
-
`,children:[e.jsx("div",{className:"flex-1 min-w-0",children:E?e.jsx("div",{onClick:a=>a.stopPropagation(),children:e.jsx("input",{ref:z,type:"text",value:w,onChange:a=>k(a.target.value),onKeyDown:_,className:"w-full text-sm px-1.5 py-0.5 bg-white dark:bg-black border border-azure-primary dark:border-matrix-highlight rounded-lg focus:outline-none dark:text-matrix-highlight"})}):e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"text-sm font-medium truncate leading-snug",children:o.title||"Untitled Session"}),e.jsx("div",{className:"text-xs text-gray-400 dark:text-matrix-secondary/50 mt-0.5",children:he(o.started_at)})]})}),e.jsx("div",{className:`flex items-center gap-0.5 shrink-0 transition-opacity ${S||E?"opacity-100":"opacity-0 group-hover:opacity-100"}`,onClick:a=>a.stopPropagation(),children:E?e.jsxs(e.Fragment,{children:[e.jsx("button",{onClick:D,className:"p-1.5 rounded-lg text-emerald-600 hover:bg-emerald-50 dark:text-emerald-400 dark:hover:bg-emerald-900/20 transition-colors",title:"Save",children:e.jsx(Q,{size:13})}),e.jsx("button",{onClick:N,className:"p-1.5 rounded-lg text-red-500 hover:bg-red-50 dark:text-red-400 dark:hover:bg-red-900/20 transition-colors",title:"Cancel",children:e.jsx(W,{size:13})})]}):e.jsxs(e.Fragment,{children:[e.jsx("button",{onClick:a=>I(a,o),className:"p-1.5 rounded-lg text-gray-400 hover:text-blue-500 hover:bg-blue-50 dark:text-matrix-secondary/50 dark:hover:text-blue-400 dark:hover:bg-blue-900/20 transition-colors",title:"Rename",children:e.jsx(V,{size:13})}),e.jsx("button",{onClick:()=>v(`/sessions/${o.id}/audit`),className:"p-1.5 rounded-lg text-gray-400 hover:text-violet-500 hover:bg-violet-50 dark:text-matrix-secondary/50 dark:hover:text-violet-400 dark:hover:bg-violet-900/20 transition-colors",title:"Audit",children:e.jsx(Y,{size:13})}),e.jsx("button",{onClick:()=>p(o.id),className:"p-1.5 rounded-lg text-gray-400 hover:text-amber-500 hover:bg-amber-50 dark:text-matrix-secondary/50 dark:hover:text-amber-400 dark:hover:bg-amber-900/20 transition-colors",title:"Archive",children:e.jsx(Z,{size:13})}),e.jsx("button",{onClick:()=>x(o.id),className:"p-1.5 rounded-lg text-gray-400 hover:text-red-500 hover:bg-red-50 dark:text-matrix-secondary/50 dark:hover:text-red-400 dark:hover:bg-red-900/20 transition-colors",title:"Delete",children:e.jsx(ee,{size:13})})]})})]},o.id)})]})]}):e.jsxs("div",{className:"w-14 bg-white dark:bg-black border-r border-gray-300 dark:border-matrix-primary flex flex-col items-center py-3 gap-3 shrink-0 transition-colors duration-300",children:[e.jsx("button",{onClick:m,className:"p-2 rounded-lg hover:bg-gray-100 dark:hover:bg-matrix-primary/20 text-gray-400 dark:text-matrix-secondary/60 transition-colors",title:"Expand sidebar",children:e.jsx(H,{size:18})}),e.jsx("div",{className:"w-8 h-px bg-gray-200 dark:bg-matrix-primary/20"}),e.jsx("button",{onClick:d,className:"p-2.5 bg-azure-primary text-white dark:bg-matrix-highlight dark:text-black rounded-xl hover:bg-azure-secondary dark:hover:bg-matrix-secondary shadow-sm transition-colors",title:"New chat",children:e.jsx(F,{size:18})})]})};function P(r){if(r==null)return"";if(typeof r=="string")try{return JSON.stringify(JSON.parse(r),null,2)}catch{return r}try{return JSON.stringify(r,null,2)}catch{return String(r)}}const ge=({group:r})=>{const[n,i]=l.useState(!1),d=r.result!==null,p=r.result?.content??"",x=p.startsWith("Error")||p.startsWith("❌");return e.jsxs("div",{className:"rounded-lg border border-gray-300 dark:border-matrix-primary/70 bg-white dark:bg-black overflow-hidden text-sm mb-1",children:[e.jsxs("button",{onClick:()=>i(!n),className:"w-full flex items-center gap-2 px-3 py-1.5 text-left hover:bg-gray-50 dark:hover:bg-zinc-900/60 transition-colors",children:[e.jsx(re,{size:12,className:"text-amber-500 dark:text-amber-400/80 flex-shrink-0"}),e.jsx("span",{className:"flex-1 font-mono text-xs text-gray-600 dark:text-matrix-secondary/80 truncate",children:r.call.name}),d?x?e.jsx(G,{size:12,className:"text-red-500 dark:text-red-400 flex-shrink-0"}):e.jsx(K,{size:12,className:"text-emerald-500 dark:text-emerald-400 flex-shrink-0"}):e.jsx(q,{size:12,className:"text-gray-400 animate-spin flex-shrink-0"}),e.jsx($,{size:12,className:`text-gray-400 dark:text-matrix-secondary/40 flex-shrink-0 transition-transform duration-200 ${n?"rotate-180":""}`})]}),e.jsx(B,{initial:!1,children:n&&e.jsx(L.div,{initial:{height:0,opacity:0},animate:{height:"auto",opacity:1},exit:{height:0,opacity:0},transition:{duration:.15,ease:"easeInOut"},className:"overflow-hidden",children:e.jsxs("div",{className:"px-3 pb-2.5 pt-1 border-t border-gray-100 dark:border-matrix-primary/20 space-y-2",children:[Object.keys(r.call.args??{}).length>0&&e.jsxs("div",{children:[e.jsx("div",{className:"text-[10px] text-gray-400 dark:text-matrix-secondary/40 uppercase tracking-wider mb-1",children:"args"}),e.jsx("pre",{className:"text-xs font-mono text-gray-600 dark:text-matrix-secondary/80 whitespace-pre-wrap break-all bg-gray-50 dark:bg-zinc-900 rounded-md p-2 border border-gray-100 dark:border-matrix-primary/20 max-h-36 overflow-y-auto",children:P(r.call.args)})]}),d&&e.jsxs("div",{children:[e.jsx("div",{className:"text-[10px] text-gray-400 dark:text-matrix-secondary/40 uppercase tracking-wider mb-1",children:"result"}),e.jsx("pre",{className:"text-xs font-mono text-gray-600 dark:text-matrix-secondary/80 whitespace-pre-wrap break-all bg-gray-50 dark:bg-zinc-900 rounded-md p-2 border border-gray-100 dark:border-matrix-primary/20 max-h-44 overflow-y-auto",children:P(p)})]})]})})})]})},ue={apoc_delegate:{label:"Apoc",emoji:"🧑🔬",colorClass:"text-amber-600 dark:text-amber-400",bgClass:"bg-amber-50 dark:bg-amber-900/10"},neo_delegate:{label:"Neo",emoji:"🥷",colorClass:"text-violet-600 dark:text-violet-400",bgClass:"bg-violet-50 dark:bg-violet-900/10"},trinity_delegate:{label:"Trinity",emoji:"👩💻",colorClass:"text-teal-600 dark:text-teal-400",bgClass:"bg-teal-50 dark:bg-teal-900/10"},smith_delegate:{label:"Smith",emoji:"🕶️",colorClass:"text-gray-500 dark:text-gray-400",bgClass:"bg-gray-50 dark:bg-zinc-900"}};function O(r){return r?.task??r?.prompt??""}function be(r){if(typeof r!="string")return String(r);try{return JSON.stringify(JSON.parse(r),null,2)}catch{return r}}const ye=({group:r})=>{const[n,i]=l.useState(!1),d=ue[r.call.name]??{label:r.call.name,emoji:"🤖",colorClass:"text-gray-500",bgClass:"bg-gray-50 dark:bg-zinc-900"},p=r.result!==null,x=r.result?.content??"",c=x.startsWith("❌")||x.toLowerCase().startsWith("error"),u=O(r.call.args).slice(0,100),m=r.call.args?.smith??null;return e.jsxs("div",{className:`rounded-lg border border-gray-300 dark:border-matrix-primary/70 overflow-hidden text-sm mb-1 ${d.bgClass}`,children:[e.jsxs("button",{onClick:()=>i(!n),className:"w-full flex items-center gap-2.5 px-3 py-2 text-left hover:brightness-95 dark:hover:brightness-110 transition-all",children:[e.jsx("span",{className:"text-base flex-shrink-0 leading-none",children:d.emoji}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsxs("div",{className:`text-xs font-semibold ${d.colorClass}`,children:[d.label,m?` · ${m}`:""]}),u&&e.jsx("div",{className:"text-xs text-gray-500 dark:text-matrix-secondary/60 truncate mt-0.5",children:u})]}),p?c?e.jsx(G,{size:14,className:"text-red-500 dark:text-red-400 flex-shrink-0"}):e.jsx(K,{size:14,className:"text-emerald-500 dark:text-emerald-400 flex-shrink-0"}):e.jsx(q,{size:14,className:"text-gray-400 animate-spin flex-shrink-0"}),e.jsx($,{size:13,className:`text-gray-400 dark:text-matrix-secondary/40 flex-shrink-0 transition-transform duration-200 ${n?"rotate-180":""}`})]}),e.jsx(B,{initial:!1,children:n&&e.jsx(L.div,{initial:{height:0,opacity:0},animate:{height:"auto",opacity:1},exit:{height:0,opacity:0},transition:{duration:.18,ease:"easeInOut"},className:"overflow-hidden",children:e.jsxs("div",{className:"px-3 pb-2.5 pt-1 border-t border-gray-200 dark:border-matrix-primary/20 space-y-2",children:[O(r.call.args)&&e.jsxs("div",{children:[e.jsx("div",{className:"text-[10px] text-gray-400 dark:text-matrix-secondary/40 uppercase tracking-wider mb-1",children:"task"}),e.jsx("p",{className:"text-xs text-gray-600 dark:text-matrix-secondary/80 bg-white dark:bg-black rounded-md p-2 border border-gray-100 dark:border-matrix-primary/20 whitespace-pre-wrap",children:O(r.call.args)})]}),p&&e.jsxs("div",{children:[e.jsx("div",{className:"text-[10px] text-gray-400 dark:text-matrix-secondary/40 uppercase tracking-wider mb-1",children:"result"}),e.jsx("pre",{className:"text-xs font-mono text-gray-600 dark:text-matrix-secondary/80 whitespace-pre-wrap break-all bg-white dark:bg-black rounded-md p-2 border border-gray-100 dark:border-matrix-primary/20 max-h-56 overflow-y-auto",children:be(x)})]})]})})})]})};function fe(r){return r==null||r===0?null:r<1e3?`${r}ms`:`${(r/1e3).toFixed(1)}s`}function R(r){return r>=1e3?`${(r/1e3).toFixed(1)}k`:String(r)}const ke=({message:r})=>{const n=r.usage_metadata,i=n?.input_tokens??n?.prompt_tokens??0,d=n?.output_tokens??n?.completion_tokens??0,p=i>0||d>0,x=fe(r.duration_ms),c=r.model,u=r.sati_memories_count??null;if(!p&&!x&&!c&&u==null)return null;const m=c?(c.includes(":")?c.split(":").pop():c)?.split("-").slice(0,4).join("-")??c:null;return e.jsxs("div",{className:"mt-2 pt-1.5 border-t border-gray-100 dark:border-matrix-primary/20 flex flex-wrap items-center gap-x-3 gap-y-0.5",children:[m&&e.jsx("span",{className:"text-[11px] font-mono text-gray-400 dark:text-matrix-secondary/40 truncate max-w-[180px]",title:c??"",children:m}),p&&e.jsxs("span",{className:"text-[11px] font-mono text-gray-400 dark:text-matrix-secondary/40",children:["↑",R(i)," ↓",R(d)]}),x&&e.jsx("span",{className:"text-[11px] font-mono text-gray-400 dark:text-matrix-secondary/40",children:x}),u!=null&&u>0&&e.jsxs("span",{className:"flex items-center gap-1 text-[11px] font-mono text-purple-400 dark:text-purple-400/70",children:[e.jsx(te,{size:10}),u]})]})},je=[{name:"apoc",emoji:"🧑🔬",description:"Filesystem, shell & git",color:"amber"},{name:"keymaker",emoji:"🗝️",description:"Quick inline tasks",color:"purple"},{name:"neo",emoji:"🥷",description:"MCP tool orchestration",color:"violet"},{name:"trinity",emoji:"👩💻",description:"Database specialist",color:"teal"}],J={amber:"bg-amber-100 text-amber-800 border-amber-300 dark:bg-amber-900/30 dark:text-amber-300 dark:border-amber-700/60",purple:"bg-purple-100 text-purple-800 border-purple-300 dark:bg-purple-900/30 dark:text-purple-300 dark:border-purple-700/60",violet:"bg-violet-100 text-violet-800 border-violet-300 dark:bg-violet-900/30 dark:text-violet-300 dark:border-violet-700/60",teal:"bg-teal-100 text-teal-800 border-teal-300 dark:bg-teal-900/30 dark:text-teal-300 dark:border-teal-700/60",gray:"bg-zinc-100 text-zinc-700 border-zinc-300 dark:bg-zinc-800 dark:text-zinc-300 dark:border-zinc-600"};function ve(r){try{return JSON.stringify(JSON.parse(r),null,2)}catch{return r}}function we(r){return r.session_id?.startsWith("sati-evaluation-")===!0||r.tool_name?.toLowerCase().includes("sati")===!0}const Ne=({message:r})=>{const[n,i]=l.useState(!1),d=we(r),p=d?r.tool_name==="sati_evaluation_output"?"Sati · memory update":"Sati · analysis":r.tool_name??"tool result";return e.jsxs("details",{open:n,onToggle:x=>i(x.target.open),className:"w-full",children:[e.jsxs("summary",{className:"list-none cursor-pointer select-none flex items-center gap-2 text-xs text-gray-400 dark:text-matrix-secondary/40 hover:text-gray-500 dark:hover:text-matrix-secondary/60 transition-colors py-0.5",children:[e.jsx("div",{className:"flex-1 h-px bg-gray-200 dark:bg-matrix-primary/20"}),e.jsxs("span",{className:"flex items-center gap-1.5 whitespace-nowrap px-2",children:[e.jsx("span",{children:d?"🧠":"🔧"}),e.jsx("span",{children:p}),e.jsx($,{size:11,className:`transition-transform duration-200 ${n?"rotate-180":""}`})]}),e.jsx("div",{className:"flex-1 h-px bg-gray-200 dark:bg-matrix-primary/20"})]}),n&&e.jsx("pre",{className:"mt-2 px-3 py-2.5 whitespace-pre-wrap break-all text-xs font-mono text-gray-600 dark:text-matrix-secondary/80 border border-gray-300 dark:border-matrix-primary/60 rounded-lg bg-gray-50 dark:bg-zinc-900 max-h-48 overflow-y-auto",children:ve(r.content)})]})},Se={table:({children:r})=>e.jsx("div",{className:"my-2 overflow-x-auto rounded-lg border border-gray-200 dark:border-matrix-primary/60",children:e.jsx("table",{className:"min-w-full text-xs border-collapse",children:r})}),thead:({children:r})=>e.jsx("thead",{className:"bg-gray-100 dark:bg-zinc-900 text-gray-600 dark:text-matrix-secondary/70",children:r}),tbody:({children:r})=>e.jsx("tbody",{className:"divide-y divide-gray-100 dark:divide-matrix-primary/20",children:r}),tr:({children:r})=>e.jsx("tr",{className:"hover:bg-gray-50 dark:hover:bg-zinc-900/60 transition-colors",children:r}),th:({children:r})=>e.jsx("th",{className:"px-3 py-2 text-left font-semibold whitespace-nowrap border-b border-gray-200 dark:border-matrix-primary/40",children:r}),td:({children:r})=>e.jsx("td",{className:"px-3 py-2 text-gray-700 dark:text-matrix-secondary align-top",children:r})},Ce=({messages:r,onSendMessage:n,isLoading:i,activeSessionId:d,activeSession:p,onToggleSidebar:x})=>{const[c,u]=l.useState(""),[m,v]=l.useState([]),[g,b]=l.useState(null),[w,k]=l.useState(0),[z,I]=l.useState([]),D=l.useRef(null),N=l.useRef(null);l.useEffect(()=>{D.current?.scrollIntoView({behavior:"smooth"})},[r,i]),l.useEffect(()=>{const t=N.current;t&&(t.style.height="auto",t.style.height=t.scrollHeight+"px")},[c]),l.useEffect(()=>{oe.get("/smiths").then(t=>I(t.smiths.map(s=>({name:s.name,emoji:"🕶️",description:"Remote Smith agent",color:"gray"})))).catch(()=>{})},[]);const _=[...je,...z],o=g?_.filter(t=>t.name.toLowerCase().startsWith(g.query.toLowerCase())):[],S=t=>{if(!g)return;const s=c.slice(0,g.startIdx),f=c.slice(g.startIdx+1+g.query.length),M=(s+f).replace(/ +/g," ").trim();u(M),v(j=>j.includes(t)?j:[...j,t]),b(null),k(0),setTimeout(()=>N.current?.focus(),0)},E=t=>{v(s=>s.filter(f=>f!==t))},a=t=>{const s=t.target.value;u(s);const f=t.target.selectionStart??s.length,j=s.slice(0,f).match(/@(\w*)$/);j?(b({query:j[1],startIdx:f-j[0].length}),k(0)):b(null)},h=()=>{if(!(c.trim()||m.length>0)||i)return;const s=[...m.map(f=>`@${f}`),c.trim()].filter(Boolean);n(s.join(" ")),u(""),v([]),b(null),N.current&&(N.current.style.height="auto")},y=t=>{if(g&&o.length>0){if(t.key==="ArrowDown"){t.preventDefault(),k(s=>(s+1)%o.length);return}if(t.key==="ArrowUp"){t.preventDefault(),k(s=>(s-1+o.length)%o.length);return}if(t.key==="Tab"||t.key==="Enter"){t.preventDefault(),S(o[w].name);return}if(t.key==="Escape"){t.preventDefault(),b(null);return}}t.key==="Enter"&&!t.shiftKey&&(t.preventDefault(),h())},C=t=>_.find(s=>s.name===t)??{name:t,emoji:"🤖",description:"",color:"gray"};return e.jsxs("div",{className:"flex-1 flex flex-col h-full bg-white dark:bg-black overflow-hidden transition-colors duration-300",children:[x&&e.jsxs("div",{className:"md:hidden flex items-center gap-3 px-4 py-3 shrink-0 bg-white dark:bg-black border-b border-gray-300 dark:border-matrix-primary",children:[e.jsx("button",{onClick:x,className:"p-2 -ml-1 rounded-lg hover:bg-gray-100 dark:hover:bg-matrix-primary/20 text-gray-500 dark:text-matrix-secondary transition-colors","aria-label":"Open sessions",children:e.jsx(ae,{size:20})}),e.jsx("span",{className:"text-sm font-semibold text-gray-800 dark:text-matrix-highlight truncate flex-1",children:p?.title??(d?"Chat":"Morpheus")})]}),d?e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"flex-1 overflow-y-auto min-h-0 px-4 py-5 space-y-4",children:[le(r).map(t=>{const{message:s,toolGroups:f}=t;if(s.type==="tool")return e.jsx("div",{className:"px-2 py-0.5",children:e.jsx(Ne,{message:s})},t.index);const M=s.type==="human";return e.jsxs("div",{className:`flex items-end gap-2.5 ${M?"justify-end":"justify-start"}`,children:[!M&&e.jsx("div",{className:"w-7 h-7 rounded-full flex-shrink-0 flex items-center justify-center bg-azure-primary/10 text-azure-primary dark:bg-matrix-primary/20 dark:text-matrix-highlight mb-0.5",children:e.jsx(T,{size:14})}),e.jsxs("div",{className:`
|
|
5
|
-
max-w-[85%] md:max-w-[72%] min-w-0
|
|
6
|
-
${M?"bg-azure-primary text-white dark:text-white/80 dark:bg-matrix-primary rounded-2xl rounded-br-sm px-4 py-2.5":"bg-gray-50 dark:bg-zinc-900 border border-gray-300 dark:border-matrix-primary/60 text-gray-800 dark:text-matrix-secondary rounded-2xl rounded-bl-sm px-4 py-3"}
|
|
7
|
-
`,children:[M&&e.jsxs(e.Fragment,{children:[s.audio_duration_seconds!=null&&e.jsxs("div",{className:"flex items-center gap-1 mb-1.5 text-white/70 dark:text-white/50",children:[e.jsx(se,{size:11}),e.jsxs("span",{className:"text-[10px] font-mono tracking-wide",children:["voice · ",s.audio_duration_seconds,"s"]})]}),e.jsx("p",{className:"text-sm leading-relaxed whitespace-pre-wrap break-words",children:s.content})]}),s.type==="ai"&&e.jsxs(e.Fragment,{children:[f&&f.length>0&&e.jsx("div",{className:"mb-2.5 space-y-1",children:f.map(j=>de(j.call.name)?e.jsx(ye,{group:j},j.call.id):e.jsx(ge,{group:j},j.call.id))}),s.content&&e.jsx("div",{className:`
|
|
8
|
-
prose prose-sm dark:prose-invert max-w-none
|
|
9
|
-
prose-p:my-1.5 prose-p:leading-relaxed
|
|
10
|
-
prose-headings:my-2 prose-headings:font-semibold
|
|
11
|
-
prose-ul:my-1.5 prose-ol:my-1.5 prose-li:my-0.5
|
|
12
|
-
prose-pre:my-2 prose-pre:rounded-lg prose-pre:text-xs
|
|
13
|
-
prose-code:text-[0.8em] prose-code:px-1 prose-code:py-0.5 prose-code:rounded prose-code:font-mono
|
|
14
|
-
prose-table:my-0 prose-thead:border-0 prose-tbody:border-0
|
|
15
|
-
prose-tr:border-0 prose-th:p-0 prose-td:p-0
|
|
16
|
-
dark:prose-p:text-matrix-secondary
|
|
17
|
-
dark:prose-headings:text-matrix-highlight
|
|
18
|
-
dark:prose-strong:text-matrix-highlight
|
|
19
|
-
dark:prose-li:text-matrix-secondary
|
|
20
|
-
dark:prose-code:text-matrix-highlight dark:prose-code:bg-black/60
|
|
21
|
-
dark:prose-pre:bg-black dark:prose-pre:border dark:prose-pre:border-matrix-primary/30
|
|
22
|
-
`,children:e.jsx(ce,{remarkPlugins:[xe],components:Se,children:s.content})}),e.jsx(ke,{message:s})]})]}),M&&e.jsx("div",{className:"w-7 h-7 rounded-full flex-shrink-0 flex items-center justify-center bg-gray-200 dark:bg-matrix-primary/30 text-gray-500 dark:text-matrix-secondary mb-0.5",children:e.jsx(ie,{size:14})})]},t.index)}),i&&e.jsxs("div",{className:"flex items-end gap-2.5 justify-start",children:[e.jsx("div",{className:"w-7 h-7 rounded-full flex-shrink-0 flex items-center justify-center bg-azure-primary/10 text-azure-primary dark:bg-matrix-primary/20 dark:text-matrix-highlight mb-0.5",children:e.jsx(T,{size:14})}),e.jsxs("div",{className:"bg-gray-50 dark:bg-zinc-900 border border-gray-300 dark:border-matrix-primary/60 rounded-2xl rounded-bl-sm px-4 py-3 flex items-center gap-1.5",children:[e.jsx("span",{className:"w-1.5 h-1.5 rounded-full bg-azure-primary dark:bg-matrix-highlight animate-bounce",style:{animationDelay:"0ms"}}),e.jsx("span",{className:"w-1.5 h-1.5 rounded-full bg-azure-primary dark:bg-matrix-highlight animate-bounce",style:{animationDelay:"160ms"}}),e.jsx("span",{className:"w-1.5 h-1.5 rounded-full bg-azure-primary dark:bg-matrix-highlight animate-bounce",style:{animationDelay:"320ms"}})]})]}),e.jsx("div",{ref:D})]}),e.jsx("div",{className:"shrink-0 px-4 pt-3 pb-4 bg-white dark:bg-black border-t border-gray-300 dark:border-matrix-primary",children:e.jsxs("div",{className:"max-w-3xl mx-auto relative",children:[g&&o.length>0&&e.jsxs("div",{className:"absolute bottom-full left-0 right-0 mb-2 z-50 bg-white dark:bg-zinc-900 border border-gray-300 dark:border-matrix-primary rounded-xl shadow-xl overflow-hidden",children:[e.jsx("div",{className:"px-3 py-1.5 border-b border-gray-100 dark:border-matrix-primary/40 flex items-center gap-1.5",children:e.jsx("span",{className:"text-[10px] font-semibold uppercase tracking-wider text-gray-400 dark:text-matrix-secondary/50",children:"Agents"})}),e.jsx("ul",{className:"max-h-52 overflow-y-auto py-1",children:o.map((t,s)=>e.jsx("li",{children:e.jsxs("button",{type:"button",onMouseDown:f=>{f.preventDefault(),S(t.name)},onMouseEnter:()=>k(s),className:`
|
|
23
|
-
w-full flex items-center gap-3 px-3 py-2 text-left transition-colors
|
|
24
|
-
${s===w?"bg-azure-primary/10 dark:bg-matrix-primary/20":"hover:bg-gray-50 dark:hover:bg-matrix-primary/10"}
|
|
25
|
-
`,children:[e.jsx("span",{className:"text-base leading-none",children:t.emoji}),e.jsxs("span",{className:"flex-1 min-w-0",children:[e.jsxs("span",{className:"block text-sm font-medium text-gray-800 dark:text-matrix-highlight",children:["@",t.name]}),e.jsx("span",{className:"block text-xs text-gray-400 dark:text-matrix-secondary/50 truncate",children:t.description})]}),s===w&&e.jsx("kbd",{className:"flex-shrink-0 text-[10px] px-1.5 py-0.5 rounded bg-gray-100 dark:bg-black text-gray-500 dark:text-matrix-secondary/60 font-mono border border-gray-200 dark:border-matrix-primary/40",children:"Tab"})]})},t.name))})]}),m.length>0&&e.jsx("div",{className:"flex flex-wrap gap-1.5 mb-2",children:m.map(t=>{const s=C(t),f=J[s.color]??J.gray;return e.jsxs("span",{className:`inline-flex items-center gap-1 pl-2 pr-1 py-0.5 rounded-full text-xs font-medium border ${f}`,children:[e.jsx("span",{className:"leading-none",children:s.emoji}),e.jsxs("span",{children:["@",t]}),e.jsx("button",{type:"button",onClick:()=>E(t),className:"ml-0.5 rounded-full p-0.5 hover:bg-black/10 dark:hover:bg-white/10 transition-colors","aria-label":`Remove @${t}`,children:e.jsx(W,{size:10})})]},t)})}),e.jsxs("form",{onSubmit:t=>{t.preventDefault(),h()},className:"flex items-end gap-2",children:[e.jsx("textarea",{ref:N,value:c,onChange:a,onKeyDown:y,placeholder:"Message Morpheus… (type @ to mention an agent)",rows:1,disabled:i,className:`
|
|
26
|
-
flex-1 resize-none max-h-40 overflow-y-auto
|
|
27
|
-
bg-gray-100 dark:bg-zinc-900
|
|
28
|
-
border border-gray-300 dark:border-matrix-primary/60
|
|
29
|
-
rounded-xl px-4 py-3
|
|
30
|
-
text-sm leading-relaxed
|
|
31
|
-
text-gray-800 dark:text-matrix-secondary
|
|
32
|
-
placeholder-gray-400 dark:placeholder-matrix-secondary/40
|
|
33
|
-
focus:outline-none focus:ring-2 focus:ring-azure-primary dark:focus:ring-matrix-highlight focus:border-transparent
|
|
34
|
-
disabled:opacity-50
|
|
35
|
-
transition-all duration-200
|
|
36
|
-
`}),e.jsx("button",{type:"submit",disabled:!c.trim()&&m.length===0||i,className:"flex-shrink-0 p-3 rounded-xl bg-azure-primary text-white dark:bg-matrix-secondary dark:text-black hover:bg-azure-secondary dark:hover:bg-matrix-highlight disabled:opacity-40 disabled:cursor-not-allowed transition-colors shadow-sm",children:e.jsx(ne,{size:18})})]}),e.jsx("p",{className:"mt-1.5 text-center text-[11px] text-gray-300 dark:text-matrix-secondary/25 select-none",children:"Enter to send · Shift+Enter for newline · @ to mention an agent"})]})})]}):e.jsxs("div",{className:"flex-1 flex flex-col items-center justify-center gap-5 p-8 text-center",children:[e.jsx("div",{className:"w-16 h-16 rounded-2xl bg-azure-primary/10 dark:bg-matrix-primary/10 flex items-center justify-center",children:e.jsx(T,{size:30,className:"text-azure-primary/60 dark:text-matrix-highlight/50"})}),e.jsxs("div",{className:"space-y-1.5",children:[e.jsx("h3",{className:"text-base font-semibold text-gray-700 dark:text-matrix-highlight",children:"Morpheus is ready"}),e.jsx("p",{className:"text-sm text-gray-400 dark:text-matrix-secondary/60 max-w-[240px] leading-relaxed",children:"Select a session from the sidebar or start a new chat."})]})]})]})},Te=()=>{const[r,n]=l.useState([]),[i,d]=l.useState(null),[p,x]=l.useState([]),[c,u]=l.useState(!1),[m,v]=l.useState(()=>typeof window<"u"?window.innerWidth>=768:!0),g=l.useRef(!1);l.useEffect(()=>{g.current=c},[c]),l.useEffect(()=>{if(!i)return;const a=setInterval(async()=>{if(!g.current)try{const y=(await A.getMessages(i)).filter(C=>C.type!=="system");x(C=>{if(y.length!==C.length)return y;const t=y.at(-1)?.created_at??0,s=C.at(-1)?.created_at??0;return t>s?y:C})}catch{}},3e3);return()=>clearInterval(a)},[i]);const[b,w]=l.useState({isOpen:!1,title:"",description:"",onConfirm:()=>{}}),k=async()=>{try{const a=await A.getSessions();return n(a),a}catch(a){return console.error("Failed to load sessions:",a),[]}};l.useEffect(()=>{k().then(a=>{if(!a.length)return;const h=sessionStorage.getItem("morpheus.chat.uiSessionId"),y=h&&a.find(C=>C.id===h)?h:a[0].id;d(y)})},[]),l.useEffect(()=>{i?(z(i),sessionStorage.setItem("morpheus.chat.uiSessionId",i)):x([])},[i]);const z=async a=>{try{const h=await A.getMessages(a);x(h.filter(y=>y.type!=="system"))}catch(h){console.error("Failed to load messages:",h)}},I=async()=>{try{const a=await A.createSession();await k(),d(a.id),window.innerWidth<768&&v(!1)}catch(a){console.error("Failed to create session:",a)}},D=a=>{d(a),window.innerWidth<768&&v(!1)},N=async a=>{if(!i)return;const h={type:"human",content:a};x(y=>[...y,h]),u(!0);try{await A.sendMessage(i,a),await z(i),await k()}catch(y){console.error("Failed to send message:",y)}finally{u(!1)}},_=a=>{w({isOpen:!0,title:"Archive Session",description:"Are you sure you want to archive this session? It will be moved to the archives.",confirmJson:"Archive",onConfirm:async()=>{try{await A.archiveSession(a),i===a&&d(null),await k()}catch(h){console.error("Failed to archive session:",h)}}})},o=a=>{w({isOpen:!0,title:"Delete Session",description:"Are you sure you want to DELETE this session? This action cannot be undone.",confirmJson:"Delete",variant:"destructive",onConfirm:async()=>{try{await A.deleteSession(a),i===a&&d(null),await k()}catch(h){console.error("Failed to delete session:",h)}}})},S=async(a,h)=>{try{await A.renameSession(a,h),await k()}catch(y){console.error("Failed to rename session:",y)}},E=r.find(a=>a.id===i)??null;return e.jsxs("div",{className:"flex h-full w-full overflow-hidden bg-white dark:bg-black relative",children:[m&&e.jsx("div",{className:"fixed inset-0 bg-black/40 z-20 md:hidden",onClick:()=>v(!1)}),e.jsx("div",{className:`
|
|
37
|
-
fixed top-16 bottom-0 left-0 z-40 flex
|
|
38
|
-
md:relative md:inset-auto md:z-auto md:translate-x-0
|
|
39
|
-
transition-transform duration-300 ease-out
|
|
40
|
-
${m?"translate-x-0":"-translate-x-full"}
|
|
41
|
-
`,children:e.jsx(pe,{sessions:r,activeSessionId:i,onSelectSession:D,onCreateSession:I,onArchiveSession:_,onDeleteSession:o,onRenameSession:S,isOpen:m,toggleSidebar:()=>v(!m)})}),e.jsx("div",{className:"flex-1 flex flex-col h-full overflow-hidden min-w-0",children:e.jsx(Ce,{messages:p,onSendMessage:N,isLoading:c,activeSessionId:i,activeSession:E,onToggleSidebar:()=>v(!m)})}),e.jsx(me,{isOpen:b.isOpen,onClose:()=>w(a=>({...a,isOpen:!1})),onConfirm:b.onConfirm,title:b.title,description:b.description,confirmJson:b.confirmJson,variant:b.variant})]})};export{Te as ChatPage};
|