@mndrk/agx 1.4.25 → 1.4.27
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/index.js +97 -15
- package/lib/cli/runCli.js +22 -4
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -322,6 +322,34 @@ async function postTaskComment(taskIdOrParams, contentMaybe) {
|
|
|
322
322
|
}
|
|
323
323
|
}
|
|
324
324
|
|
|
325
|
+
async function postLearning(taskId, content) {
|
|
326
|
+
if (!taskId || !content) return;
|
|
327
|
+
|
|
328
|
+
const cloudConfig = loadCloudConfigFile();
|
|
329
|
+
if (!cloudConfig?.apiUrl) return;
|
|
330
|
+
|
|
331
|
+
logExecutionFlow('postLearning', 'input', `taskId=${taskId}`);
|
|
332
|
+
|
|
333
|
+
try {
|
|
334
|
+
await fetch(`${cloudConfig.apiUrl}/api/learnings`, {
|
|
335
|
+
method: 'POST',
|
|
336
|
+
headers: {
|
|
337
|
+
'Content-Type': 'application/json',
|
|
338
|
+
...(cloudConfig?.token ? { 'Authorization': `Bearer ${cloudConfig.token}` } : {}),
|
|
339
|
+
'x-user-id': cloudConfig.userId || '',
|
|
340
|
+
},
|
|
341
|
+
body: JSON.stringify({
|
|
342
|
+
scope: 'task',
|
|
343
|
+
scope_id: taskId,
|
|
344
|
+
content: String(content).slice(0, 2000)
|
|
345
|
+
})
|
|
346
|
+
});
|
|
347
|
+
logExecutionFlow('postLearning', 'output', 'success');
|
|
348
|
+
} catch (err) {
|
|
349
|
+
logExecutionFlow('postLearning', 'output', `failed ${err?.message || err}`);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
325
353
|
function isLocalArtifactsEnabled() {
|
|
326
354
|
// Single cutover: always on, no opt-out.
|
|
327
355
|
return true;
|
|
@@ -372,6 +400,33 @@ function extractCloudTaskIdentity(task) {
|
|
|
372
400
|
return { taskId, taskSlug };
|
|
373
401
|
}
|
|
374
402
|
|
|
403
|
+
/**
|
|
404
|
+
* Extract the repo path from a task's project_context.
|
|
405
|
+
* Falls back to process.cwd() if no repo path is configured.
|
|
406
|
+
*/
|
|
407
|
+
function extractProjectRepoPath(task) {
|
|
408
|
+
// Check project_context.repos (returned by /api/queue with buildTaskContext)
|
|
409
|
+
const repos = task?.project_context?.repos;
|
|
410
|
+
if (Array.isArray(repos) && repos.length > 0) {
|
|
411
|
+
const firstRepo = repos[0];
|
|
412
|
+
if (firstRepo?.path && typeof firstRepo.path === 'string' && firstRepo.path.trim()) {
|
|
413
|
+
let repoPath = firstRepo.path.trim();
|
|
414
|
+
// Expand tilde to home directory
|
|
415
|
+
if (repoPath.startsWith('~/')) {
|
|
416
|
+
repoPath = path.join(os.homedir(), repoPath.slice(2));
|
|
417
|
+
} else if (repoPath === '~') {
|
|
418
|
+
repoPath = os.homedir();
|
|
419
|
+
}
|
|
420
|
+
// Validate the path exists before using it
|
|
421
|
+
if (fs.existsSync(repoPath)) {
|
|
422
|
+
return repoPath;
|
|
423
|
+
}
|
|
424
|
+
console.log(`${c.yellow}[daemon] repo path "${repoPath}" does not exist, using cwd${c.reset}`);
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
return process.cwd();
|
|
428
|
+
}
|
|
429
|
+
|
|
375
430
|
async function resolveLocalProjectSlugForCloudTask(storage, task) {
|
|
376
431
|
const { projectId, projectSlug, projectName } = extractCloudProjectIdentity(task);
|
|
377
432
|
const label = projectSlug || projectName || 'cloud';
|
|
@@ -1913,8 +1968,10 @@ async function finalizeRunSafe(storage, run, decision) {
|
|
|
1913
1968
|
} catch { }
|
|
1914
1969
|
}
|
|
1915
1970
|
|
|
1916
|
-
async function runSingleAgentExecuteVerifyLoop({ taskId, task, provider, model, logger, storage, projectSlug, taskSlug, stageLocal, initialPromptContext, cancellationWatcher }) {
|
|
1917
|
-
logExecutionFlow('runSingleAgentExecuteVerifyLoop', 'input', `taskId=${taskId}, provider=${provider}, model=${model}`);
|
|
1971
|
+
async function runSingleAgentExecuteVerifyLoop({ taskId, task, provider, model, logger, storage, projectSlug, taskSlug, stageLocal, initialPromptContext, cancellationWatcher, repoPath }) {
|
|
1972
|
+
logExecutionFlow('runSingleAgentExecuteVerifyLoop', 'input', `taskId=${taskId}, provider=${provider}, model=${model}, repoPath=${repoPath || 'cwd'}`);
|
|
1973
|
+
// Use provided repoPath or fall back to cwd
|
|
1974
|
+
const workingDir = repoPath || process.cwd();
|
|
1918
1975
|
const stageKey = task?.stage || 'unknown';
|
|
1919
1976
|
const stagePrompt = resolveStageObjective(task, stageKey, '');
|
|
1920
1977
|
const stageRequirement = buildStageRequirementPrompt({ stage: stageKey, stagePrompt });
|
|
@@ -1994,9 +2051,9 @@ async function runSingleAgentExecuteVerifyLoop({ taskId, task, provider, model,
|
|
|
1994
2051
|
await executeArtifacts.flush();
|
|
1995
2052
|
|
|
1996
2053
|
// VERIFY (local commands)
|
|
1997
|
-
const verifyCommands = detectVerifyCommands({ cwd:
|
|
1998
|
-
const gitSummary = getGitSummary({ cwd:
|
|
1999
|
-
const verifyResults = await runVerifyCommands(verifyCommands, { cwd:
|
|
2054
|
+
const verifyCommands = detectVerifyCommands({ cwd: workingDir });
|
|
2055
|
+
const gitSummary = getGitSummary({ cwd: workingDir });
|
|
2056
|
+
const verifyResults = await runVerifyCommands(verifyCommands, { cwd: workingDir, max_output_chars: 20000 });
|
|
2000
2057
|
|
|
2001
2058
|
const verifyRun = await storage.createRun({
|
|
2002
2059
|
projectSlug,
|
|
@@ -2167,8 +2224,10 @@ async function runSingleAgentExecuteVerifyLoop({ taskId, task, provider, model,
|
|
|
2167
2224
|
return { code: 1, decision: lastDecision, lastRun, runIndexEntry: lastRunEntry };
|
|
2168
2225
|
}
|
|
2169
2226
|
|
|
2170
|
-
async function runSwarmExecuteVerifyLoop({ taskId, task, logger, storage, projectSlug, taskSlug, stageLocal, initialPromptContext, cancellationWatcher }) {
|
|
2171
|
-
logExecutionFlow('runSwarmExecuteVerifyLoop', 'input', `taskId=${taskId}`);
|
|
2227
|
+
async function runSwarmExecuteVerifyLoop({ taskId, task, logger, storage, projectSlug, taskSlug, stageLocal, initialPromptContext, cancellationWatcher, repoPath }) {
|
|
2228
|
+
logExecutionFlow('runSwarmExecuteVerifyLoop', 'input', `taskId=${taskId}, repoPath=${repoPath || 'cwd'}`);
|
|
2229
|
+
// Use provided repoPath or fall back to cwd
|
|
2230
|
+
const workingDir = repoPath || process.cwd();
|
|
2172
2231
|
const stageKey = task?.stage || 'unknown';
|
|
2173
2232
|
const stagePrompt = resolveStageObjective(task, stageKey, '');
|
|
2174
2233
|
const stageRequirement = buildStageRequirementPrompt({ stage: stageKey, stagePrompt });
|
|
@@ -2253,9 +2312,9 @@ async function runSwarmExecuteVerifyLoop({ taskId, task, logger, storage, projec
|
|
|
2253
2312
|
await executeArtifacts.flush();
|
|
2254
2313
|
|
|
2255
2314
|
// VERIFY (local commands)
|
|
2256
|
-
const verifyCommands = detectVerifyCommands({ cwd:
|
|
2257
|
-
const gitSummary = getGitSummary({ cwd:
|
|
2258
|
-
const verifyResults = await runVerifyCommands(verifyCommands, { cwd:
|
|
2315
|
+
const verifyCommands = detectVerifyCommands({ cwd: workingDir });
|
|
2316
|
+
const gitSummary = getGitSummary({ cwd: workingDir });
|
|
2317
|
+
const verifyResults = await runVerifyCommands(verifyCommands, { cwd: workingDir, max_output_chars: 20000 });
|
|
2259
2318
|
|
|
2260
2319
|
const verifyRun = await storage.createRun({
|
|
2261
2320
|
projectSlug,
|
|
@@ -4945,8 +5004,12 @@ async function checkOnboarding() {
|
|
|
4945
5004
|
taskSlug = await resolveLocalTaskSlugForCloudTask(storage, projectSlug, task);
|
|
4946
5005
|
|
|
4947
5006
|
const cloudProject = extractCloudProjectIdentity(task);
|
|
5007
|
+
const taskRepoPath = extractProjectRepoPath(task);
|
|
5008
|
+
if (taskRepoPath !== process.cwd()) {
|
|
5009
|
+
console.log(`${c.cyan}[daemon] using project repo path: ${taskRepoPath}${c.reset}`);
|
|
5010
|
+
}
|
|
4948
5011
|
await storage.writeProjectState(projectSlug, {
|
|
4949
|
-
repo_path:
|
|
5012
|
+
repo_path: taskRepoPath,
|
|
4950
5013
|
cloud: {
|
|
4951
5014
|
project_id: cloudProject.projectId,
|
|
4952
5015
|
project_slug: cloudProject.projectSlug,
|
|
@@ -5030,6 +5093,7 @@ async function checkOnboarding() {
|
|
|
5030
5093
|
stageLocal,
|
|
5031
5094
|
initialPromptContext: fullPromptContext,
|
|
5032
5095
|
cancellationWatcher,
|
|
5096
|
+
repoPath: taskRepoPath,
|
|
5033
5097
|
});
|
|
5034
5098
|
} else {
|
|
5035
5099
|
loopResult = await runSingleAgentExecuteVerifyLoop({
|
|
@@ -5044,6 +5108,7 @@ async function checkOnboarding() {
|
|
|
5044
5108
|
stageLocal,
|
|
5045
5109
|
initialPromptContext: fullPromptContext,
|
|
5046
5110
|
cancellationWatcher,
|
|
5111
|
+
repoPath: taskRepoPath,
|
|
5047
5112
|
});
|
|
5048
5113
|
}
|
|
5049
5114
|
|
|
@@ -6378,18 +6443,21 @@ async function checkOnboarding() {
|
|
|
6378
6443
|
process.exit(0);
|
|
6379
6444
|
}
|
|
6380
6445
|
|
|
6381
|
-
// agx retry <taskId> [--task <id>] [--swarm]
|
|
6446
|
+
// agx retry <taskId> [--task <id>] [--swarm] [--async]
|
|
6382
6447
|
if (cmd === 'retry' || (cmd === 'task' && args[1] === 'retry')) {
|
|
6383
6448
|
const runArgs = cmd === 'task' ? args.slice(1) : args;
|
|
6384
6449
|
retryFlowActive = true;
|
|
6385
6450
|
logExecutionFlow('retry command', 'input', `cmd=${cmd}, args=${runArgs.slice(1).join(' ')}`);
|
|
6386
6451
|
let taskId = null;
|
|
6387
6452
|
let forceSwarm = false;
|
|
6453
|
+
let asyncMode = false;
|
|
6388
6454
|
for (let i = 1; i < runArgs.length; i++) {
|
|
6389
6455
|
if (runArgs[i] === '--task' || runArgs[i] === '-t') {
|
|
6390
6456
|
taskId = runArgs[++i];
|
|
6391
6457
|
} else if (runArgs[i] === '--swarm') {
|
|
6392
6458
|
forceSwarm = true;
|
|
6459
|
+
} else if (runArgs[i] === '--async' || runArgs[i] === '-a') {
|
|
6460
|
+
asyncMode = true;
|
|
6393
6461
|
}
|
|
6394
6462
|
}
|
|
6395
6463
|
if (!taskId) {
|
|
@@ -6397,12 +6465,26 @@ async function checkOnboarding() {
|
|
|
6397
6465
|
}
|
|
6398
6466
|
if (!taskId) {
|
|
6399
6467
|
logExecutionFlow('retry command', 'output', 'missing task id');
|
|
6400
|
-
console.log(`${c.yellow}Usage:${c.reset} agx retry <taskId> [--task <id>] [--swarm]`);
|
|
6401
|
-
console.log(`${c.dim} or:${c.reset} agx task retry <taskId> [--task <id>] [--swarm]`);
|
|
6468
|
+
console.log(`${c.yellow}Usage:${c.reset} agx retry <taskId> [--task <id>] [--swarm] [--async]`);
|
|
6469
|
+
console.log(`${c.dim} or:${c.reset} agx task retry <taskId> [--task <id>] [--swarm] [--async]`);
|
|
6470
|
+
console.log(`${c.dim}--async: Reset status and let daemon handle (non-blocking)${c.reset}`);
|
|
6402
6471
|
process.exit(1);
|
|
6403
6472
|
}
|
|
6404
6473
|
|
|
6405
6474
|
try {
|
|
6475
|
+
// Async mode: just reset task status, daemon will pick it up
|
|
6476
|
+
if (asyncMode) {
|
|
6477
|
+
const resolvedId = await resolveTaskId(taskId);
|
|
6478
|
+
await cloudRequest('PATCH', `/api/tasks/${resolvedId}`, {
|
|
6479
|
+
status: 'queued',
|
|
6480
|
+
started_at: null,
|
|
6481
|
+
completed_at: null,
|
|
6482
|
+
});
|
|
6483
|
+
console.log(`${c.green}✓${c.reset} Task ${resolvedId.slice(0, 8)} queued for retry`);
|
|
6484
|
+
console.log(`${c.dim}Daemon will pick it up shortly${c.reset}`);
|
|
6485
|
+
process.exit(0);
|
|
6486
|
+
}
|
|
6487
|
+
|
|
6406
6488
|
const exitCode = await runTaskInline(taskId, { resetFirst: true, forceSwarm });
|
|
6407
6489
|
process.exit(exitCode);
|
|
6408
6490
|
} catch (err) {
|
|
@@ -7421,7 +7503,7 @@ PROVIDERS:
|
|
|
7421
7503
|
CLOUD:
|
|
7422
7504
|
agx new "<task>" Create task in cloud
|
|
7423
7505
|
agx run <id|slug|#> Claim and run a task
|
|
7424
|
-
agx retry <id|slug|#> Reset + retry a task
|
|
7506
|
+
agx retry <id|slug|#> Reset + retry a task (--async for non-blocking)
|
|
7425
7507
|
agx status Show cloud status
|
|
7426
7508
|
agx complete <taskId> Mark task stage complete
|
|
7427
7509
|
agx project assign <project> --task <task> Assign task to project
|
package/lib/cli/runCli.js
CHANGED
|
@@ -1485,18 +1485,21 @@ async function checkOnboarding() {
|
|
|
1485
1485
|
process.exit(0);
|
|
1486
1486
|
}
|
|
1487
1487
|
|
|
1488
|
-
// agx retry <taskId> [--task <id>] [--swarm]
|
|
1488
|
+
// agx retry <taskId> [--task <id>] [--swarm] [--async]
|
|
1489
1489
|
if (cmd === 'retry' || (cmd === 'task' && args[1] === 'retry')) {
|
|
1490
1490
|
const runArgs = cmd === 'task' ? args.slice(1) : args;
|
|
1491
1491
|
retryFlowActive = true;
|
|
1492
1492
|
logExecutionFlow('retry command', 'input', `cmd=${cmd}, args=${runArgs.slice(1).join(' ')}`);
|
|
1493
1493
|
let taskId = null;
|
|
1494
1494
|
let forceSwarm = false;
|
|
1495
|
+
let asyncMode = false;
|
|
1495
1496
|
for (let i = 1; i < runArgs.length; i++) {
|
|
1496
1497
|
if (runArgs[i] === '--task' || runArgs[i] === '-t') {
|
|
1497
1498
|
taskId = runArgs[++i];
|
|
1498
1499
|
} else if (runArgs[i] === '--swarm') {
|
|
1499
1500
|
forceSwarm = true;
|
|
1501
|
+
} else if (runArgs[i] === '--async' || runArgs[i] === '-a') {
|
|
1502
|
+
asyncMode = true;
|
|
1500
1503
|
}
|
|
1501
1504
|
}
|
|
1502
1505
|
if (!taskId) {
|
|
@@ -1504,12 +1507,27 @@ async function checkOnboarding() {
|
|
|
1504
1507
|
}
|
|
1505
1508
|
if (!taskId) {
|
|
1506
1509
|
logExecutionFlow('retry command', 'output', 'missing task id');
|
|
1507
|
-
console.log(`${c.yellow}Usage:${c.reset} agx retry <taskId> [--task <id>] [--swarm]`);
|
|
1508
|
-
console.log(`${c.dim} or:${c.reset} agx task retry <taskId> [--task <id>] [--swarm]`);
|
|
1510
|
+
console.log(`${c.yellow}Usage:${c.reset} agx retry <taskId> [--task <id>] [--swarm] [--async]`);
|
|
1511
|
+
console.log(`${c.dim} or:${c.reset} agx task retry <taskId> [--task <id>] [--swarm] [--async]`);
|
|
1512
|
+
console.log(`${c.dim}--async: Reset status and let daemon handle (non-blocking)${c.reset}`);
|
|
1509
1513
|
process.exit(1);
|
|
1510
1514
|
}
|
|
1511
1515
|
|
|
1512
1516
|
try {
|
|
1517
|
+
// Async mode: just reset task status, daemon will pick it up
|
|
1518
|
+
logExecutionFlow('retry command', 'processing', `asyncMode=${asyncMode}, taskId=${taskId}`);
|
|
1519
|
+
if (asyncMode) {
|
|
1520
|
+
const resolvedId = await resolveTaskId(taskId);
|
|
1521
|
+
await cloudRequest('PATCH', `/api/tasks/${resolvedId}`, {
|
|
1522
|
+
status: 'queued',
|
|
1523
|
+
started_at: null,
|
|
1524
|
+
completed_at: null,
|
|
1525
|
+
});
|
|
1526
|
+
console.log(`${c.green}✓${c.reset} Task ${resolvedId.slice(0, 8)} queued for retry`);
|
|
1527
|
+
console.log(`${c.dim}Daemon will pick it up shortly${c.reset}`);
|
|
1528
|
+
process.exit(0);
|
|
1529
|
+
}
|
|
1530
|
+
|
|
1513
1531
|
const exitCode = await runTaskInline(taskId, { resetFirst: true, forceSwarm });
|
|
1514
1532
|
process.exit(exitCode);
|
|
1515
1533
|
} catch (err) {
|
|
@@ -2500,7 +2518,7 @@ PROVIDERS:
|
|
|
2500
2518
|
CLOUD:
|
|
2501
2519
|
agx new "<task>" Create task in cloud
|
|
2502
2520
|
agx run <id|slug|#> Claim and run a task
|
|
2503
|
-
agx retry <id|slug|#> Reset + retry a task
|
|
2521
|
+
agx retry <id|slug|#> Reset + retry a task (--async for non-blocking)
|
|
2504
2522
|
agx status Show cloud status
|
|
2505
2523
|
agx complete <taskId> Mark task stage complete
|
|
2506
2524
|
agx project assign <project> --task <task> Assign task to project
|