@mndrk/agx 1.4.26 → 1.4.28

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 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: process.cwd() });
1998
- const gitSummary = getGitSummary({ cwd: process.cwd() });
1999
- const verifyResults = await runVerifyCommands(verifyCommands, { cwd: process.cwd(), max_output_chars: 20000 });
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: process.cwd() });
2257
- const gitSummary = getGitSummary({ cwd: process.cwd() });
2258
- const verifyResults = await runVerifyCommands(verifyCommands, { cwd: process.cwd(), max_output_chars: 20000 });
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: process.cwd(),
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
 
@@ -29,10 +29,15 @@ function buildCloudTaskTerminalPatch({ decision, newStage, nowIso } = {}) {
29
29
  return { status: 'completed', completed_at: now };
30
30
  }
31
31
 
32
- if (d === 'done') return { status: 'completed', completed_at: now };
32
+ // NOTE: decision "done" means the CURRENT STAGE is complete, not the entire task.
33
+ // Only mark task as completed when stage reaches "done" (handled above).
34
+ // Do NOT mark completed just because decision is "done" - that prematurely
35
+ // ends tasks stuck in ideation/planning/execution.
33
36
  if (d === 'failed') return { status: 'failed', completed_at: now };
34
37
  if (d === 'blocked') return { status: 'blocked' };
35
38
 
39
+ // For "done" and "not_done" decisions, let the stage machine handle transitions.
40
+ // The task status will be updated by the orchestrator based on stage progression.
36
41
  return null;
37
42
  }
38
43
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mndrk/agx",
3
- "version": "1.4.26",
3
+ "version": "1.4.28",
4
4
  "description": "Autonomous AI Agent Orchestrator for Claude, Gemini, and Ollama",
5
5
  "main": "lib/index.js",
6
6
  "exports": {