agent-mp 0.5.0 → 0.5.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/commands/repl.js +13 -11
- package/dist/utils/config.d.ts +7 -0
- package/dist/utils/config.js +50 -0
- package/package.json +1 -1
package/dist/commands/repl.js
CHANGED
|
@@ -7,7 +7,7 @@ import chalk from 'chalk';
|
|
|
7
7
|
import { execSync } from 'child_process';
|
|
8
8
|
import { CLI_REGISTRY } from '../types.js';
|
|
9
9
|
import { writeJson, ensureDir, readJson, listDir, fileExists } from '../utils/fs.js';
|
|
10
|
-
import { loadAuth, saveAuth, loadCliConfig, saveCliConfig, loadProjectConfig } from '../utils/config.js';
|
|
10
|
+
import { loadAuth, saveAuth, loadCliConfig, saveCliConfig, loadProjectConfig, resolveProjectDir } from '../utils/config.js';
|
|
11
11
|
import { log } from '../utils/logger.js';
|
|
12
12
|
import { AgentEngine, ExitError } from '../core/engine.js';
|
|
13
13
|
import { qwenLogin, qwenAuthStatus, QWEN_AGENT_HOME, fetchQwenModels } from '../utils/qwen-auth.js';
|
|
@@ -594,7 +594,7 @@ async function cmdStatus(fi) {
|
|
|
594
594
|
roleRows.push({ key: 'global fallback', value: `${cliConfig.fallback_global.cli}/${cliConfig.fallback_global.model}` });
|
|
595
595
|
}
|
|
596
596
|
sections.push({ title: 'Roles — full cmd', rows: roleRows });
|
|
597
|
-
const dir = process.cwd();
|
|
597
|
+
const dir = await resolveProjectDir(process.cwd());
|
|
598
598
|
try {
|
|
599
599
|
const config = await loadProjectConfig(dir);
|
|
600
600
|
const projectRows = [
|
|
@@ -711,7 +711,7 @@ function cmdHelp(fi) {
|
|
|
711
711
|
fi.println(renderSectionBox('Commands', commands));
|
|
712
712
|
}
|
|
713
713
|
async function cmdTasks(fi) {
|
|
714
|
-
const dir = process.cwd();
|
|
714
|
+
const dir = await resolveProjectDir(process.cwd());
|
|
715
715
|
const tasksDir = path.join(dir, '.agent', 'tasks');
|
|
716
716
|
const tasks = await listDir(tasksDir);
|
|
717
717
|
if (tasks.length === 0) {
|
|
@@ -858,13 +858,15 @@ export async function runRepl(resumeSession) {
|
|
|
858
858
|
const { activeCli } = init;
|
|
859
859
|
const rl = init.rl;
|
|
860
860
|
const session = resumeSession ?? newSession(process.cwd());
|
|
861
|
+
// Resolve actual project root (may be deeper than cwd)
|
|
862
|
+
const projectDir = await resolveProjectDir(process.cwd());
|
|
861
863
|
// Show project status and FORCE role configuration if missing
|
|
862
864
|
let hasRoles = false;
|
|
863
865
|
let welcomeRoles;
|
|
864
|
-
let welcomeProject = path.basename(
|
|
866
|
+
let welcomeProject = path.basename(projectDir);
|
|
865
867
|
let welcomeStack = 'generic';
|
|
866
868
|
try {
|
|
867
|
-
const config = await loadProjectConfig(
|
|
869
|
+
const config = await loadProjectConfig(projectDir);
|
|
868
870
|
welcomeProject = config.project;
|
|
869
871
|
welcomeStack = config.stack;
|
|
870
872
|
if (config.roles?.orchestrator?.cli && config.roles?.implementor?.cli && config.roles?.reviewer?.cli) {
|
|
@@ -915,8 +917,7 @@ export async function runRepl(resumeSession) {
|
|
|
915
917
|
process.stdout.write(renderHelpHint() + '\n\n');
|
|
916
918
|
// Print coordinator header BEFORE fi.setup() so no blank lines appear between them
|
|
917
919
|
try {
|
|
918
|
-
const
|
|
919
|
-
const config = await loadProjectConfig(dir);
|
|
920
|
+
const config = await loadProjectConfig(projectDir);
|
|
920
921
|
if (config.roles?.orchestrator?.cli) {
|
|
921
922
|
process.stdout.write('\n');
|
|
922
923
|
process.stdout.write(chalk.bold.cyan('═'.repeat(46)) + '\n');
|
|
@@ -990,7 +991,7 @@ export async function runRepl(resumeSession) {
|
|
|
990
991
|
await cmdStatus(fi);
|
|
991
992
|
break;
|
|
992
993
|
case 'run': {
|
|
993
|
-
const dir = process.cwd();
|
|
994
|
+
const dir = await resolveProjectDir(process.cwd());
|
|
994
995
|
const config = await loadProjectConfig(dir);
|
|
995
996
|
if (args[0] === 'orch' || args[0] === 'orchestrator') {
|
|
996
997
|
const task = args.slice(1).join(' ');
|
|
@@ -1027,7 +1028,7 @@ export async function runRepl(resumeSession) {
|
|
|
1027
1028
|
}
|
|
1028
1029
|
case 'explorer':
|
|
1029
1030
|
case 'exp': {
|
|
1030
|
-
const dir = process.cwd();
|
|
1031
|
+
const dir = await resolveProjectDir(process.cwd());
|
|
1031
1032
|
const config = await loadProjectConfig(dir);
|
|
1032
1033
|
const task = args.join(' ');
|
|
1033
1034
|
const engine = new AgentEngine(config, dir, gCoordinatorCmd, rl, fi, handleCmd);
|
|
@@ -1099,7 +1100,7 @@ export async function runRepl(resumeSession) {
|
|
|
1099
1100
|
session.messages.push({ role: 'user', content: trimmed, ts: new Date().toISOString() });
|
|
1100
1101
|
await saveSession(session);
|
|
1101
1102
|
try {
|
|
1102
|
-
const dir = process.cwd();
|
|
1103
|
+
const dir = await resolveProjectDir(process.cwd());
|
|
1103
1104
|
const config = await loadProjectConfig(dir);
|
|
1104
1105
|
if (!config.roles?.orchestrator?.cli) {
|
|
1105
1106
|
fi.println(chalk.red(' No roles configured. Run /config-multi first.'));
|
|
@@ -1141,7 +1142,8 @@ export async function runRole(role, arg, model) {
|
|
|
1141
1142
|
// In that case, skip REPL and run headless — no coordinator needed
|
|
1142
1143
|
const ROLE_BINS = new Set(['agent-orch', 'agent-impl', 'agent-rev', 'agent-explorer']);
|
|
1143
1144
|
const isNativeBin = ROLE_BINS.has(PKG_NAME);
|
|
1144
|
-
|
|
1145
|
+
// Resolve the actual project root (may be deeper than cwd)
|
|
1146
|
+
const dir = await resolveProjectDir(process.cwd());
|
|
1145
1147
|
let config;
|
|
1146
1148
|
try {
|
|
1147
1149
|
config = await loadProjectConfig(dir);
|
package/dist/utils/config.d.ts
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
import { AgentConfig } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Resolve the actual project root starting from a given directory.
|
|
4
|
+
* If .agent/config.json exists in the start dir, scan subdirectories
|
|
5
|
+
* for a deeper project root (indicated by common project files).
|
|
6
|
+
* Returns the deepest valid project root found, or the original dir.
|
|
7
|
+
*/
|
|
8
|
+
export declare function resolveProjectDir(startDir: string): Promise<string>;
|
|
2
9
|
export declare const PKG_NAME: string;
|
|
3
10
|
export declare const AGENT_HOME: string;
|
|
4
11
|
export declare const AUTH_FILE: string;
|
package/dist/utils/config.js
CHANGED
|
@@ -3,6 +3,56 @@ import * as fsSync from 'fs';
|
|
|
3
3
|
import * as path from 'path';
|
|
4
4
|
import * as os from 'os';
|
|
5
5
|
const KNOWN_PKGS = ['agent-mp', 'agent-orch', 'agent-impl', 'agent-rev', 'agent-explorer'];
|
|
6
|
+
// Files/dirs that indicate a directory is the real project root
|
|
7
|
+
const PROJECT_INDICATORS = [
|
|
8
|
+
'package.json', 'pyproject.toml', 'requirements.txt', 'setup.py', 'setup.cfg',
|
|
9
|
+
'Cargo.toml', 'go.mod', 'Gemfile', 'pom.xml', 'build.gradle', 'build.gradle.kts',
|
|
10
|
+
'CMakeLists.txt', 'Makefile', 'composer.json', 'mix.exs', 'pubspec.yaml',
|
|
11
|
+
'src', 'app', 'lib', 'main.py', 'app.py', 'index.js', 'index.ts',
|
|
12
|
+
'main.go', 'main.rs', 'lib.rs', 'app.js', 'app.ts',
|
|
13
|
+
];
|
|
14
|
+
/**
|
|
15
|
+
* Resolve the actual project root starting from a given directory.
|
|
16
|
+
* If .agent/config.json exists in the start dir, scan subdirectories
|
|
17
|
+
* for a deeper project root (indicated by common project files).
|
|
18
|
+
* Returns the deepest valid project root found, or the original dir.
|
|
19
|
+
*/
|
|
20
|
+
export async function resolveProjectDir(startDir) {
|
|
21
|
+
const hasAgentConfig = await fileExists(path.join(startDir, '.agent', 'config.json'));
|
|
22
|
+
if (!hasAgentConfig)
|
|
23
|
+
return startDir;
|
|
24
|
+
// Scan immediate subdirectories for a deeper project root
|
|
25
|
+
let bestDir = startDir;
|
|
26
|
+
let bestScore = 0;
|
|
27
|
+
try {
|
|
28
|
+
const entries = await fs.readdir(startDir, { withFileTypes: true });
|
|
29
|
+
for (const entry of entries) {
|
|
30
|
+
if (!entry.isDirectory() || entry.name.startsWith('.') || entry.name === 'node_modules')
|
|
31
|
+
continue;
|
|
32
|
+
const subDir = path.join(startDir, entry.name);
|
|
33
|
+
let score = 0;
|
|
34
|
+
for (const indicator of PROJECT_INDICATORS) {
|
|
35
|
+
if (await fileExists(path.join(subDir, indicator)))
|
|
36
|
+
score++;
|
|
37
|
+
}
|
|
38
|
+
if (score > bestScore) {
|
|
39
|
+
bestScore = score;
|
|
40
|
+
bestDir = subDir;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
catch { /* ignore */ }
|
|
45
|
+
return bestDir;
|
|
46
|
+
}
|
|
47
|
+
async function fileExists(p) {
|
|
48
|
+
try {
|
|
49
|
+
await fs.stat(p);
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
6
56
|
function resolvePackageName() {
|
|
7
57
|
// 1. Read package.json (reliable for both global installs and dev mode)
|
|
8
58
|
const __filename = new URL(import.meta.url).pathname;
|