osai-agent 4.1.14 → 4.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/package.json +1 -1
- package/src/agent/context.js +1 -6
- package/src/agent/prompt.js +1 -3
- package/src/agent/react-loop.js +1 -6
- package/src/agent/subagent.js +1 -6
- package/src/commands/account.js +107 -0
- package/src/commands/admin.js +82 -0
- package/src/index.js +34 -0
- package/src/memory/store.js +1 -13
- package/src/parser/dependencies.js +1 -6
- package/src/parser/markdown.js +1 -7
- package/src/safety/check.js +1 -6
- package/src/services/executor.js +1 -6
- package/src/services/session.js +1 -4
- package/src/services/ssh.js +1 -3
- package/src/services/websocket.js +1 -7
- package/src/skills/loader.js +1 -5
- package/src/tools/browser.js +1 -7
- package/src/tools/local.js +2 -6
- package/src/tools/registry.js +1 -7
- package/src/tools/ssh.js +1 -3
- package/src/ui/components/ProviderMenu.js +16 -16
- package/src/utils/constants.js +1 -3
- package/src/utils/helpers.js +1 -3
- package/src/utils/logger.js +1 -3
- package/src/utils/sound.js +1 -3
package/README.md
CHANGED
|
@@ -167,6 +167,7 @@ Upgrade to Pro for higher daily limits (500 msgs/day, 30 req/min, 5 connections)
|
|
|
167
167
|
osai-agent config Show current configuration
|
|
168
168
|
osai-agent config set-os <os> Override OS detection
|
|
169
169
|
osai-agent skills Manage installed skills
|
|
170
|
+
osai-agent account delete Permanently delete your account and all data
|
|
170
171
|
osai-agent stop-subagent Stop a running sub-agent
|
|
171
172
|
osai-agent --version Show version
|
|
172
173
|
osai-agent --help Show help
|
package/package.json
CHANGED
package/src/agent/context.js
CHANGED
|
@@ -1,9 +1,4 @@
|
|
|
1
|
-
//
|
|
2
|
-
// OS AI Agent — Context Builder
|
|
3
|
-
// =============================================================================
|
|
4
|
-
// Builds structured context for the agent loop, including device information,
|
|
5
|
-
// OS detection, and device capabilities. Used primarily in network/SSH mode.
|
|
6
|
-
// =============================================================================
|
|
1
|
+
// Context builder — device info, OS, capabilities
|
|
7
2
|
|
|
8
3
|
/**
|
|
9
4
|
* Build a structured context object for the agent
|
package/src/agent/prompt.js
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
//
|
|
2
|
-
// OS AI Agent — Agent Prompt Builder (v4.0 — Coding Mode + Anti-Hallucination)
|
|
3
|
-
// =============================================================================
|
|
1
|
+
// Agent prompt builder — mode-specific prompts
|
|
4
2
|
|
|
5
3
|
import fs from 'fs/promises';
|
|
6
4
|
import path from 'path';
|
package/src/agent/react-loop.js
CHANGED
|
@@ -1,9 +1,4 @@
|
|
|
1
|
-
//
|
|
2
|
-
// OS AI Agent — Agent Loop (v4.0 — Coding Mode + Todos + Web Tools)
|
|
3
|
-
// =============================================================================
|
|
4
|
-
// Core agent loop: GOAL -> PLAN -> EXECUTE -> OBSERVE -> REFLECT -> REPEAT
|
|
5
|
-
// Supports GENERAL, NETWORK, and CODING modes with full tool dispatch.
|
|
6
|
-
// =============================================================================
|
|
1
|
+
// Agent loop — GOAL→PLAN→EXEC→OBSERVE→REFLECT
|
|
7
2
|
|
|
8
3
|
import {
|
|
9
4
|
executeLocal, readFile, writeFile, editFile, listDir, detectOS, getSystemInfo, resolvePath,
|
package/src/agent/subagent.js
CHANGED
|
@@ -1,9 +1,4 @@
|
|
|
1
|
-
//
|
|
2
|
-
// OS AI Agent — Subagent Runner (max 1 concurrent)
|
|
3
|
-
// =============================================================================
|
|
4
|
-
// Spawns a read-only child agent for exploration. Results are returned to the
|
|
5
|
-
// parent via structured [SUBAGENT_RESULT] tool output.
|
|
6
|
-
// =============================================================================
|
|
1
|
+
// Subagent runner — read-only child agent (max 1)
|
|
7
2
|
|
|
8
3
|
import { AgentLoop } from './react-loop.js';
|
|
9
4
|
import { SUBAGENT_MAX_ITERATIONS } from '../utils/constants.js';
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import Conf from 'conf';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import boxen from 'boxen';
|
|
4
|
+
import ora from 'ora';
|
|
5
|
+
import { createInterface } from 'node:readline';
|
|
6
|
+
import { rmSync, existsSync } from 'node:fs';
|
|
7
|
+
import { homedir } from 'node:os';
|
|
8
|
+
import { join } from 'node:path';
|
|
9
|
+
import { toHttpUrl, DEFAULT_SERVER_URL } from '../services/server-url.js';
|
|
10
|
+
import { APP_VERSION } from '../utils/constants.js';
|
|
11
|
+
|
|
12
|
+
export const deleteAccount = async ({ server: serverArg }) => {
|
|
13
|
+
const config = new Conf({ projectName: 'osai-agent' });
|
|
14
|
+
const token = config.get('token');
|
|
15
|
+
const serverUrl = serverArg || config.get('server') || DEFAULT_SERVER_URL;
|
|
16
|
+
const httpUrl = toHttpUrl(serverUrl);
|
|
17
|
+
|
|
18
|
+
const headerContent = [
|
|
19
|
+
` ${chalk.hex('#4a9eff').bold('OS AI AGENT')} ${chalk.gray(`v${APP_VERSION}`)}`,
|
|
20
|
+
'',
|
|
21
|
+
` ${chalk.hex('#8ab4d8')('Your AI sysadmin, network engineer & senior developer')}`,
|
|
22
|
+
'',
|
|
23
|
+
` ${token ? chalk.green('●') : chalk.red('○')} ${chalk.hex('#8ab4d8')('Auth:')} ${chalk.white(token ? 'Authenticated' : 'Not authenticated')}`,
|
|
24
|
+
].join('\n');
|
|
25
|
+
|
|
26
|
+
console.log(boxen(headerContent, {
|
|
27
|
+
padding: { left: 3, right: 3 },
|
|
28
|
+
margin: { top: 1, bottom: 1 },
|
|
29
|
+
borderStyle: 'round',
|
|
30
|
+
borderColor: '#4a9eff',
|
|
31
|
+
float: 'center',
|
|
32
|
+
}));
|
|
33
|
+
|
|
34
|
+
if (!token) {
|
|
35
|
+
console.log(chalk.red('\nYou need to be logged in to delete your account.'));
|
|
36
|
+
console.log(chalk.yellow('Run "osai-agent register" or "osai-agent login" first.\n'));
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
console.log(boxen(
|
|
41
|
+
chalk.hex('#f7768e').bold('⚠ WARNING') +
|
|
42
|
+
chalk.hex('#c0caf5')('\n\nThis will permanently delete your account and all associated data.') +
|
|
43
|
+
chalk.hex('#c0caf5')('\nThis includes: devices, logs, sessions, provider settings, pro key, and more.') +
|
|
44
|
+
chalk.hex('#ff9e64')('\n\nThis action CANNOT be undone.') +
|
|
45
|
+
chalk.hex('#9aa5ce')('\n\nYou will not be able to create a new account') +
|
|
46
|
+
chalk.hex('#9aa5ce')('\nwith the same email or from this machine for 24 hours.'),
|
|
47
|
+
{
|
|
48
|
+
padding: 2,
|
|
49
|
+
borderStyle: 'round',
|
|
50
|
+
borderColor: '#f7768e',
|
|
51
|
+
textAlignment: 'center',
|
|
52
|
+
}
|
|
53
|
+
));
|
|
54
|
+
|
|
55
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
56
|
+
const answer = await new Promise((resolve) => {
|
|
57
|
+
rl.question(chalk.hex('#ff9e64').bold('\nType "yes" to confirm: '), resolve);
|
|
58
|
+
});
|
|
59
|
+
rl.close();
|
|
60
|
+
|
|
61
|
+
if (answer.trim().toLowerCase() !== 'yes') {
|
|
62
|
+
console.log(chalk.yellow('\nAccount deletion cancelled.\n'));
|
|
63
|
+
process.exit(0);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const spinner = ora({ text: 'Deleting account...', color: 'red' }).start();
|
|
67
|
+
|
|
68
|
+
try {
|
|
69
|
+
const response = await fetch(`${httpUrl}/auth/account`, {
|
|
70
|
+
method: 'DELETE',
|
|
71
|
+
headers: {
|
|
72
|
+
'Content-Type': 'application/json',
|
|
73
|
+
'Authorization': `Bearer ${token}`,
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
if (!response.ok) {
|
|
78
|
+
const errorData = await response.json().catch(() => null);
|
|
79
|
+
const errorMsg = errorData?.error || response.statusText;
|
|
80
|
+
spinner.fail(`Failed to delete account: ${response.status} - ${errorMsg}`);
|
|
81
|
+
process.exit(1);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Clear local config
|
|
85
|
+
config.clear();
|
|
86
|
+
|
|
87
|
+
// Remove entire config directory
|
|
88
|
+
const configDir = join(homedir(), '.config', 'osai-agent');
|
|
89
|
+
if (existsSync(configDir)) {
|
|
90
|
+
try { rmSync(configDir, { recursive: true, force: true }); } catch {}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
spinner.succeed('Account deleted successfully');
|
|
94
|
+
|
|
95
|
+
console.log(boxen(
|
|
96
|
+
chalk.hex('#7aa2f7').bold(' Account Deleted') +
|
|
97
|
+
chalk.hex('#c0caf5')('\n\n All your data has been permanently removed.') +
|
|
98
|
+
chalk.hex('#9aa5ce')('\n You will be able to create a new account') +
|
|
99
|
+
chalk.hex('#9aa5ce')('\n with the same email or from this machine') +
|
|
100
|
+
chalk.hex('#9aa5ce')('\n after 24 hours.'),
|
|
101
|
+
{ padding: 2, borderStyle: 'round', borderColor: '#4a9eff', textAlignment: 'center' }
|
|
102
|
+
));
|
|
103
|
+
} catch (err) {
|
|
104
|
+
spinner.fail(`Failed to delete account: ${err.message}`);
|
|
105
|
+
process.exit(1);
|
|
106
|
+
}
|
|
107
|
+
};
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import ora from 'ora';
|
|
3
|
+
import { createInterface } from 'node:readline';
|
|
4
|
+
import { toHttpUrl, DEFAULT_SERVER_URL } from '../services/server-url.js';
|
|
5
|
+
import Conf from 'conf';
|
|
6
|
+
|
|
7
|
+
const promptSecret = () => new Promise((resolve) => {
|
|
8
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
9
|
+
rl.question(chalk.hex('#ff9e64')('Enter admin secret: '), (answer) => {
|
|
10
|
+
rl.close();
|
|
11
|
+
resolve(answer.trim());
|
|
12
|
+
});
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
const adminFetch = async (serverArg, path, method = 'GET', body = null) => {
|
|
16
|
+
const config = new Conf({ projectName: 'osai-agent' });
|
|
17
|
+
const serverUrl = serverArg || config.get('server') || DEFAULT_SERVER_URL;
|
|
18
|
+
const httpUrl = toHttpUrl(serverUrl);
|
|
19
|
+
|
|
20
|
+
const secret = await promptSecret();
|
|
21
|
+
if (!secret) {
|
|
22
|
+
console.log(chalk.red('Admin secret is required.'));
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const options = {
|
|
27
|
+
method,
|
|
28
|
+
headers: { 'Authorization': `Bearer ${secret}` },
|
|
29
|
+
};
|
|
30
|
+
if (body) {
|
|
31
|
+
options.headers['Content-Type'] = 'application/json';
|
|
32
|
+
options.body = JSON.stringify(body);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const response = await fetch(`${httpUrl}/auth${path}`, options);
|
|
36
|
+
const data = await response.json().catch(() => null);
|
|
37
|
+
|
|
38
|
+
if (!response.ok) {
|
|
39
|
+
console.log(chalk.red(`Error ${response.status}: ${data?.error || response.statusText}`));
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return data;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export const listUsers = async ({ server }) => {
|
|
47
|
+
const data = await adminFetch(server, '/admin/users');
|
|
48
|
+
const users = data.users || [];
|
|
49
|
+
|
|
50
|
+
if (users.length === 0) {
|
|
51
|
+
console.log(chalk.yellow('No users found.'));
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
console.log(chalk.hex('#4a9eff').bold(`\n Users (${users.length}):\n`));
|
|
56
|
+
for (const u of users) {
|
|
57
|
+
const statusBadge = u.status === 'disabled'
|
|
58
|
+
? chalk.red('disabled')
|
|
59
|
+
: chalk.green('active');
|
|
60
|
+
const planBadge = u.plan === 'pro' ? chalk.hex('#ff9e64')('pro') : chalk.gray('free');
|
|
61
|
+
const created = new Date(u.created_at).toLocaleDateString();
|
|
62
|
+
const machines = (u.machine_ids || []).length;
|
|
63
|
+
console.log(
|
|
64
|
+
` ${chalk.white(u.email)}` +
|
|
65
|
+
` ${statusBadge}` +
|
|
66
|
+
` ${planBadge}` +
|
|
67
|
+
` ${chalk.gray(`${machines} machine(s)`)}` +
|
|
68
|
+
` ${chalk.gray(`created ${created}`)}`
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
console.log();
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
export const disableUser = async ({ server, email }) => {
|
|
75
|
+
const data = await adminFetch(server, '/admin/disable-user', 'POST', { email });
|
|
76
|
+
const spinner = ora().succeed(chalk.green(`User disabled: ${data.email}`));
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
export const enableUser = async ({ server, email }) => {
|
|
80
|
+
const data = await adminFetch(server, '/admin/enable-user', 'POST', { email });
|
|
81
|
+
const spinner = ora().succeed(chalk.green(`User enabled: ${data.email}`));
|
|
82
|
+
};
|
package/src/index.js
CHANGED
|
@@ -25,6 +25,8 @@ import { manageSkills } from './commands/skills.js';
|
|
|
25
25
|
import { handleMcpCommand } from './commands/mcp.js';
|
|
26
26
|
import { stopSubagent } from './commands/stop-subagent.js';
|
|
27
27
|
import { claimProKey } from './commands/pro.js';
|
|
28
|
+
import { deleteAccount } from './commands/account.js';
|
|
29
|
+
import { listUsers, disableUser, enableUser } from './commands/admin.js';
|
|
28
30
|
import minimist from 'minimist';
|
|
29
31
|
import updateNotifier from 'update-notifier';
|
|
30
32
|
import { createRequire } from 'module';
|
|
@@ -133,6 +135,37 @@ switch (cmd) {
|
|
|
133
135
|
await claimProKey({ key: args.key || args._[1], server: args.server });
|
|
134
136
|
break;
|
|
135
137
|
|
|
138
|
+
case 'account':
|
|
139
|
+
if (args._[1] === 'delete') {
|
|
140
|
+
await deleteAccount({ server: args.server });
|
|
141
|
+
} else {
|
|
142
|
+
console.error('Usage: osai-agent account delete');
|
|
143
|
+
process.exit(1);
|
|
144
|
+
}
|
|
145
|
+
break;
|
|
146
|
+
|
|
147
|
+
case 'admin':
|
|
148
|
+
if (args._[1] === 'users') {
|
|
149
|
+
await listUsers({ server: args.server });
|
|
150
|
+
} else if (args._[1] === 'disable') {
|
|
151
|
+
if (!args._[2]) { console.error('Usage: osai-agent admin disable <email>'); process.exit(1); }
|
|
152
|
+
await disableUser({ server: args.server, email: args._[2] });
|
|
153
|
+
} else if (args._[1] === 'enable') {
|
|
154
|
+
if (!args._[2]) { console.error('Usage: osai-agent admin enable <email>'); process.exit(1); }
|
|
155
|
+
await enableUser({ server: args.server, email: args._[2] });
|
|
156
|
+
} else {
|
|
157
|
+
console.log();
|
|
158
|
+
console.log('Usage: osai-agent admin <subcommand> [args]');
|
|
159
|
+
console.log();
|
|
160
|
+
console.log('Subcommands:');
|
|
161
|
+
console.log(' users List all users');
|
|
162
|
+
console.log(' disable <email> Disable a user account');
|
|
163
|
+
console.log(' enable <email> Re-enable a user account');
|
|
164
|
+
console.log();
|
|
165
|
+
process.exit(1);
|
|
166
|
+
}
|
|
167
|
+
break;
|
|
168
|
+
|
|
136
169
|
default:
|
|
137
170
|
if (cmd) {
|
|
138
171
|
console.error(`Unknown command: ${cmd}`);
|
|
@@ -156,6 +189,7 @@ switch (cmd) {
|
|
|
156
189
|
console.log(' mcp Manage MCP servers');
|
|
157
190
|
console.log(' stop-subagent Stop a running subagent');
|
|
158
191
|
console.log(' pro Activate a pro access code');
|
|
192
|
+
console.log(' account delete Permanently delete your account and all data');
|
|
159
193
|
console.log();
|
|
160
194
|
process.exit(cmd ? 1 : 0);
|
|
161
195
|
}
|
package/src/memory/store.js
CHANGED
|
@@ -1,16 +1,4 @@
|
|
|
1
|
-
//
|
|
2
|
-
// OS AI Agent — Memory Store
|
|
3
|
-
// =============================================================================
|
|
4
|
-
// Lightweight JSON-based memory system that stores actions, results, and
|
|
5
|
-
// failures across sessions. Enables the agent to learn from past interactions.
|
|
6
|
-
// Implements a 6-layer memory model inspired by Claude Code's architecture:
|
|
7
|
-
// 1. System Prompt (static)
|
|
8
|
-
// 2. Session Messages (current conversation)
|
|
9
|
-
// 3. Compact History (auto-trimmed)
|
|
10
|
-
// 4. Project Knowledge (instructions.md)
|
|
11
|
-
// 5. Persistent Memory (this store - actions/failures/preferences)
|
|
12
|
-
// 6. Semantic Search (future — keyword-based for now)
|
|
13
|
-
// =============================================================================
|
|
1
|
+
// Memory store — persistent action/result history
|
|
14
2
|
import fs from 'fs/promises';
|
|
15
3
|
import path from 'path';
|
|
16
4
|
import os from 'os';
|
|
@@ -1,9 +1,4 @@
|
|
|
1
|
-
//
|
|
2
|
-
// OS AI Agent — Dependency Analysis Utilities
|
|
3
|
-
// =============================================================================
|
|
4
|
-
// Pure functions for extracting imports and exports from source code.
|
|
5
|
-
// Used by the GET_DEPENDENCIES tool and dependency auto-resolution.
|
|
6
|
-
// =============================================================================
|
|
1
|
+
// Dependency analysis — import/export extractor
|
|
7
2
|
|
|
8
3
|
/**
|
|
9
4
|
* Extract exported symbol names from JS/TS source content.
|
package/src/parser/markdown.js
CHANGED
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
//
|
|
2
|
-
// OS AI Agent — Markdown Renderer v4.0
|
|
3
|
-
// =============================================================================
|
|
4
|
-
// Two modes:
|
|
5
|
-
// renderMarkdown(text) — full buffered render (après réception complète)
|
|
6
|
-
// StreamMarkdown — classe stateful pour le streaming token-by-token
|
|
7
|
-
// =============================================================================
|
|
1
|
+
// Markdown renderer — buffered + streaming
|
|
8
2
|
|
|
9
3
|
import chalk from 'chalk';
|
|
10
4
|
|
package/src/safety/check.js
CHANGED
|
@@ -1,9 +1,4 @@
|
|
|
1
|
-
//
|
|
2
|
-
// OS AI Agent — Safety Check System (v4.0 — Coding Mode aware)
|
|
3
|
-
// =============================================================================
|
|
4
|
-
// Four-tier safety classification: READ, WRITE, DANGEROUS, ASK
|
|
5
|
-
// In CODING mode, WRITE tools auto-approved with --no-confirm.
|
|
6
|
-
// =============================================================================
|
|
1
|
+
// Safety checker — READ/WRITE/DANGEROUS/ASK tiers
|
|
7
2
|
|
|
8
3
|
const TIER = {
|
|
9
4
|
READ: 'READ',
|
package/src/services/executor.js
CHANGED
|
@@ -1,9 +1,4 @@
|
|
|
1
|
-
//
|
|
2
|
-
// OS AI Agent — Command Executor
|
|
3
|
-
// =============================================================================
|
|
4
|
-
// Unified command executor that dispatches to local or SSH based on device.
|
|
5
|
-
// Acts as a bridge between the agent loop and the tool system.
|
|
6
|
-
// =============================================================================
|
|
1
|
+
// Command executor — local or SSH dispatch
|
|
7
2
|
import { exec } from 'child_process';
|
|
8
3
|
import { connectSSH, execSSH, closeSSH } from './ssh.js';
|
|
9
4
|
import { DEFAULTS } from '../utils/constants.js';
|
package/src/services/session.js
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
//
|
|
2
|
-
// OS AI Agent — Session Manager
|
|
3
|
-
// Supports both LOCAL (JSON file) and CLOUD (MongoDB via server API) storage.
|
|
4
|
-
// =============================================================================
|
|
1
|
+
// Session manager — local JSON + cloud MongoDB
|
|
5
2
|
import fs from 'fs/promises';
|
|
6
3
|
import { mkdirSync, writeFileSync } from 'fs';
|
|
7
4
|
import path from 'path';
|
package/src/services/ssh.js
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
//
|
|
2
|
-
// OS AI Agent — SSH Connection Manager
|
|
3
|
-
// =============================================================================
|
|
1
|
+
// SSH connection manager
|
|
4
2
|
import { Client } from 'ssh2';
|
|
5
3
|
import { DEFAULTS } from '../utils/constants.js';
|
|
6
4
|
import { logger } from '../utils/logger.js';
|
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
//
|
|
2
|
-
// OS AI Agent — WebSocket Client (Standalone)
|
|
3
|
-
// =============================================================================
|
|
4
|
-
// Standalone WebSocket client with auto-reconnect and exponential backoff.
|
|
5
|
-
// Used as a lower-level utility that can be imported by the agent loop or
|
|
6
|
-
// other modules needing persistent WebSocket connections.
|
|
7
|
-
// =============================================================================
|
|
1
|
+
// WebSocket client — auto-reconnect + backoff
|
|
8
2
|
import WebSocket from 'ws';
|
|
9
3
|
import { DEFAULTS } from '../utils/constants.js';
|
|
10
4
|
import { logger } from '../utils/logger.js';
|
package/src/skills/loader.js
CHANGED
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
//
|
|
2
|
-
// OS AI Agent — Skills Loader
|
|
3
|
-
// =============================================================================
|
|
4
|
-
// Discovers and manages SKILL.md files from personal and project directories.
|
|
5
|
-
// =============================================================================
|
|
1
|
+
// Skills loader — discovers SKILL.md files
|
|
6
2
|
|
|
7
3
|
import fs from 'fs/promises';
|
|
8
4
|
import path from 'path';
|
package/src/tools/browser.js
CHANGED
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
//
|
|
2
|
-
// OS AI Agent — Browser Automation Module (Playwright + HTTP Fallback)
|
|
3
|
-
// =============================================================================
|
|
4
|
-
// Safe, stateless, per-request browser automation for the AI agent.
|
|
5
|
-
// Each call is fully isolated — launch → close in finally block.
|
|
6
|
-
// Falls back to HTTP fetch if Playwright/Chromium is unavailable.
|
|
7
|
-
// =============================================================================
|
|
1
|
+
// Browser automation — Playwright + HTTP fallback
|
|
8
2
|
|
|
9
3
|
import { logger } from '../utils/logger.js';
|
|
10
4
|
import { searchDDG, searchDDGHttp } from './search-providers.js';
|
package/src/tools/local.js
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
//
|
|
2
|
-
// OS AI Agent — Local Tool System (v4.0 — Coding Mode + Todos)
|
|
3
|
-
// =============================================================================
|
|
1
|
+
// Local tool system — command execution + file ops
|
|
4
2
|
import { exec, spawn } from 'child_process';
|
|
5
3
|
import { promisify } from 'util';
|
|
6
4
|
import fs from 'fs/promises';
|
|
@@ -937,9 +935,7 @@ export const validateLocalCommand = (command) => {
|
|
|
937
935
|
return { safe: true };
|
|
938
936
|
};
|
|
939
937
|
|
|
940
|
-
//
|
|
941
|
-
// NEW TOOLS — GLOB, GREP, GIT, READ_FILE_RANGE, ASK_USER, DIAG_POST_EDIT
|
|
942
|
-
// =============================================================================
|
|
938
|
+
// Glob, Grep, Git, ReadFileRange, AskUser, DiagPostEdit
|
|
943
939
|
|
|
944
940
|
import fastGlob from 'fast-glob';
|
|
945
941
|
import { execFile } from 'child_process';
|
package/src/tools/registry.js
CHANGED
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
//
|
|
2
|
-
// OS AI Agent — Tool Registry
|
|
3
|
-
// =============================================================================
|
|
4
|
-
// Central registry for all tools the agent can use. Each tool is an independent
|
|
5
|
-
// module with a standard interface: name, description, parameters, execute(),
|
|
6
|
-
// and safety tier.
|
|
7
|
-
// =============================================================================
|
|
1
|
+
// Tool registry — central tool catalog
|
|
8
2
|
|
|
9
3
|
import { logger } from '../utils/logger.js';
|
|
10
4
|
import { TOOLS, SAFETY_TIERS } from '../utils/constants.js';
|
package/src/tools/ssh.js
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
//
|
|
2
|
-
// OS AI Agent — SSH Tool (Connection Pool + Dispatch)
|
|
3
|
-
// =============================================================================
|
|
1
|
+
// SSH tool — connection pool + dispatch
|
|
4
2
|
import { connectSSH, execSSH, closeSSH } from '../services/ssh.js';
|
|
5
3
|
import { logger } from '../utils/logger.js';
|
|
6
4
|
|
|
@@ -544,7 +544,7 @@ export function ProviderMenu({ visible, onSelect, onCancel, serverUrl, token, cu
|
|
|
544
544
|
useInput((input, key) => {
|
|
545
545
|
if (!visible) return;
|
|
546
546
|
|
|
547
|
-
//
|
|
547
|
+
// MENU PHASE
|
|
548
548
|
if (phase === 'menu') {
|
|
549
549
|
if (key.escape) { resetAll(); onCancel(); return; }
|
|
550
550
|
if (key.upArrow) { setMenuCursor(c => (c > 0 ? c - 1 : filteredMenu.length - 1)); return; }
|
|
@@ -574,7 +574,7 @@ export function ProviderMenu({ visible, onSelect, onCancel, serverUrl, token, cu
|
|
|
574
574
|
return;
|
|
575
575
|
}
|
|
576
576
|
|
|
577
|
-
//
|
|
577
|
+
// CATALOG PHASE
|
|
578
578
|
if (phase === 'catalog') {
|
|
579
579
|
if (key.escape) { setPhase('menu'); setCatalogQuery(''); setCatalogCursor(0); return; }
|
|
580
580
|
if (key.upArrow) { setCatalogCursor(c => (c > 0 ? c - 1 : filteredCatalog.length - 1)); return; }
|
|
@@ -611,7 +611,7 @@ export function ProviderMenu({ visible, onSelect, onCancel, serverUrl, token, cu
|
|
|
611
611
|
return;
|
|
612
612
|
}
|
|
613
613
|
|
|
614
|
-
//
|
|
614
|
+
// BASE URL PHASE (local mode only)
|
|
615
615
|
if (phase === 'base_url') {
|
|
616
616
|
if (key.escape) { setPhase('catalog'); setLocalBaseUrlInput(''); setApiKeyInput(''); return; }
|
|
617
617
|
if (key.return) {
|
|
@@ -631,7 +631,7 @@ export function ProviderMenu({ visible, onSelect, onCancel, serverUrl, token, cu
|
|
|
631
631
|
return;
|
|
632
632
|
}
|
|
633
633
|
|
|
634
|
-
//
|
|
634
|
+
// CONFIGURED PHASE
|
|
635
635
|
if (phase === 'configured') {
|
|
636
636
|
if (key.escape) { resetAll(); return; }
|
|
637
637
|
if (key.upArrow) { setConfiguredCursor(c => (c > 0 ? c - 1 : filteredConfigured.length - 1)); return; }
|
|
@@ -648,7 +648,7 @@ export function ProviderMenu({ visible, onSelect, onCancel, serverUrl, token, cu
|
|
|
648
648
|
return;
|
|
649
649
|
}
|
|
650
650
|
|
|
651
|
-
//
|
|
651
|
+
// MODELS PHASE (full setup)
|
|
652
652
|
if (phase === 'models') {
|
|
653
653
|
if (modelsLoading) {
|
|
654
654
|
if (key.escape) { setPhase('catalog'); setModelsQuery(''); setModelsCursor(0); setSelectedProvider(null); setModelsData(null); return; }
|
|
@@ -669,7 +669,7 @@ export function ProviderMenu({ visible, onSelect, onCancel, serverUrl, token, cu
|
|
|
669
669
|
return;
|
|
670
670
|
}
|
|
671
671
|
|
|
672
|
-
//
|
|
672
|
+
// SWITCH MODELS PHASE (model selection for switch_model flow)
|
|
673
673
|
if (phase === 'switch_models') {
|
|
674
674
|
if (key.escape) { setPhase('configured'); setModelsQuery(''); setModelsCursor(0); setSelectedProvider(null); return; }
|
|
675
675
|
if (key.upArrow) { setModelsCursor(c => (c > 0 ? c - 1 : allModels.length - 1)); return; }
|
|
@@ -686,7 +686,7 @@ export function ProviderMenu({ visible, onSelect, onCancel, serverUrl, token, cu
|
|
|
686
686
|
return;
|
|
687
687
|
}
|
|
688
688
|
|
|
689
|
-
//
|
|
689
|
+
// API KEY PHASE (full setup: server mode after model select, local mode before model fetch)
|
|
690
690
|
if (phase === 'api_key') {
|
|
691
691
|
if (key.escape) {
|
|
692
692
|
if (isLocal) {
|
|
@@ -716,7 +716,7 @@ export function ProviderMenu({ visible, onSelect, onCancel, serverUrl, token, cu
|
|
|
716
716
|
return;
|
|
717
717
|
}
|
|
718
718
|
|
|
719
|
-
//
|
|
719
|
+
// UPDATE KEY INPUT PHASE
|
|
720
720
|
if (phase === 'update_key_input') {
|
|
721
721
|
if (key.escape) { setPhase('configured'); setApiKeyInput(''); setSettingError(null); return; }
|
|
722
722
|
if (key.return) { handleUpdateKeySubmit(); return; }
|
|
@@ -732,7 +732,7 @@ export function ProviderMenu({ visible, onSelect, onCancel, serverUrl, token, cu
|
|
|
732
732
|
const separator = '─'.repeat(52);
|
|
733
733
|
const { rows } = useWindowSize();
|
|
734
734
|
|
|
735
|
-
//
|
|
735
|
+
// SETTING UP VIEW
|
|
736
736
|
if (settingUp) {
|
|
737
737
|
return h(Box, { flexDirection: 'column', borderStyle: 'round', borderColor: '#2a2e3f', paddingX: 1, paddingY: 0, marginY: 1 },
|
|
738
738
|
h(Text, { color: '#7aa2f7', bold: true }, TITLE),
|
|
@@ -743,7 +743,7 @@ export function ProviderMenu({ visible, onSelect, onCancel, serverUrl, token, cu
|
|
|
743
743
|
);
|
|
744
744
|
}
|
|
745
745
|
|
|
746
|
-
//
|
|
746
|
+
// BASE URL INPUT (local mode)
|
|
747
747
|
if (phase === 'base_url') {
|
|
748
748
|
return h(Box, { flexDirection: 'column', borderStyle: 'round', borderColor: '#2a2e3f', paddingX: 1, paddingY: 0, marginY: 1 },
|
|
749
749
|
h(Box, { flexDirection: 'row', alignItems: 'center' },
|
|
@@ -766,7 +766,7 @@ export function ProviderMenu({ visible, onSelect, onCancel, serverUrl, token, cu
|
|
|
766
766
|
);
|
|
767
767
|
}
|
|
768
768
|
|
|
769
|
-
//
|
|
769
|
+
// API KEY VIEW
|
|
770
770
|
if (phase === 'api_key') {
|
|
771
771
|
const masked = apiKeyInput ? '\u2022'.repeat(apiKeyInput.length) : '';
|
|
772
772
|
return h(Box, { flexDirection: 'column', borderStyle: 'round', borderColor: '#2a2e3f', paddingX: 1, paddingY: 0, marginY: 1 },
|
|
@@ -794,7 +794,7 @@ export function ProviderMenu({ visible, onSelect, onCancel, serverUrl, token, cu
|
|
|
794
794
|
);
|
|
795
795
|
}
|
|
796
796
|
|
|
797
|
-
//
|
|
797
|
+
// UPDATE KEY INPUT VIEW
|
|
798
798
|
if (phase === 'update_key_input') {
|
|
799
799
|
const masked = apiKeyInput ? '\u2022'.repeat(apiKeyInput.length) : '';
|
|
800
800
|
return h(Box, { flexDirection: 'column', borderStyle: 'round', borderColor: '#2a2e3f', paddingX: 1, paddingY: 0, marginY: 1 },
|
|
@@ -822,7 +822,7 @@ export function ProviderMenu({ visible, onSelect, onCancel, serverUrl, token, cu
|
|
|
822
822
|
);
|
|
823
823
|
}
|
|
824
824
|
|
|
825
|
-
//
|
|
825
|
+
// MODELS VIEW (reused for both full setup and switch_model)
|
|
826
826
|
const isSwitchModels = phase === 'switch_models';
|
|
827
827
|
if (phase === 'models' || isSwitchModels) {
|
|
828
828
|
if (modelsLoading) {
|
|
@@ -882,7 +882,7 @@ export function ProviderMenu({ visible, onSelect, onCancel, serverUrl, token, cu
|
|
|
882
882
|
);
|
|
883
883
|
}
|
|
884
884
|
|
|
885
|
-
//
|
|
885
|
+
// CONFIGURED VIEW
|
|
886
886
|
if (phase === 'configured') {
|
|
887
887
|
if (configuredLoading) {
|
|
888
888
|
return h(Box, { flexDirection: 'column', borderStyle: 'round', borderColor: '#2a2e3f', paddingX: 1, paddingY: 0, marginY: 1 },
|
|
@@ -965,7 +965,7 @@ export function ProviderMenu({ visible, onSelect, onCancel, serverUrl, token, cu
|
|
|
965
965
|
);
|
|
966
966
|
}
|
|
967
967
|
|
|
968
|
-
//
|
|
968
|
+
// CATALOG VIEW
|
|
969
969
|
if (phase === 'catalog') {
|
|
970
970
|
if (catalogLoading) {
|
|
971
971
|
return h(Box, { flexDirection: 'column', borderStyle: 'round', borderColor: '#2a2e3f', paddingX: 1, paddingY: 0, marginY: 1 },
|
|
@@ -1055,7 +1055,7 @@ export function ProviderMenu({ visible, onSelect, onCancel, serverUrl, token, cu
|
|
|
1055
1055
|
);
|
|
1056
1056
|
}
|
|
1057
1057
|
|
|
1058
|
-
//
|
|
1058
|
+
// MENU VIEW
|
|
1059
1059
|
return h(Box, { flexDirection: 'column', borderStyle: 'round', borderColor: '#2a2e3f', paddingX: 1, paddingY: 0, marginY: 1 },
|
|
1060
1060
|
h(Box, { flexDirection: 'row', alignItems: 'center' },
|
|
1061
1061
|
h(Text, { color: '#7aa2f7', bold: true }, TITLE),
|
package/src/utils/constants.js
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
//
|
|
2
|
-
// OS AI Agent — Constants & Configuration
|
|
3
|
-
// =============================================================================
|
|
1
|
+
// Constants & configuration
|
|
4
2
|
|
|
5
3
|
export const APP_NAME = 'osai-agent';
|
|
6
4
|
import { createRequire } from 'module';
|
package/src/utils/helpers.js
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
//
|
|
2
|
-
// OS AI Agent — Shared Helpers
|
|
3
|
-
// =============================================================================
|
|
1
|
+
// Shared helpers
|
|
4
2
|
|
|
5
3
|
/**
|
|
6
4
|
* Estimate token count from text (rough: ~4 chars per token)
|
package/src/utils/logger.js
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
//
|
|
2
|
-
// OS AI Agent — Logger
|
|
3
|
-
// =============================================================================
|
|
1
|
+
// Logger
|
|
4
2
|
import chalk from 'chalk';
|
|
5
3
|
import { ENV_VARS } from './constants.js';
|
|
6
4
|
|
package/src/utils/sound.js
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
//
|
|
2
|
-
// OS AI Agent — System Sound Notification
|
|
3
|
-
// =============================================================================
|
|
1
|
+
// System sound notifications
|
|
4
2
|
|
|
5
3
|
/**
|
|
6
4
|
* Play a system beep sound (cross-platform: Windows, macOS, Linux)
|