@mndrk/agx 1.4.34 → 1.4.36

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.
Files changed (98) hide show
  1. package/README.md +12 -0
  2. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/BUILD_ID +1 -1
  3. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/app-build-manifest.json +47 -47
  4. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/app-path-routes-manifest.json +9 -9
  5. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/build-manifest.json +2 -2
  6. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/prerender-manifest.json +22 -22
  7. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  8. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/_not-found.html +1 -1
  9. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/_not-found.rsc +1 -1
  10. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/audit/route_client-reference-manifest.js +1 -1
  11. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/auth/[...nextauth]/route_client-reference-manifest.js +1 -1
  12. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/auth/daemon-secret/route_client-reference-manifest.js +1 -1
  13. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/auth/device/code/route_client-reference-manifest.js +1 -1
  14. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/auth/device/token/route_client-reference-manifest.js +1 -1
  15. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/auth/refresh/route_client-reference-manifest.js +1 -1
  16. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/auth/status/route_client-reference-manifest.js +1 -1
  17. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/domains/[id]/route_client-reference-manifest.js +1 -1
  18. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/domains/route_client-reference-manifest.js +1 -1
  19. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/health/route_client-reference-manifest.js +1 -1
  20. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/learnings/route_client-reference-manifest.js +1 -1
  21. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/logs/stream/route_client-reference-manifest.js +1 -1
  22. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/orchestrator/tasks/[taskId]/cancel/route_client-reference-manifest.js +1 -1
  23. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/orchestrator/tasks/[taskId]/signal/route_client-reference-manifest.js +1 -1
  24. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/orchestrator/tasks/[taskId]/start/route_client-reference-manifest.js +1 -1
  25. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/orchestrator/tasks/[taskId]/status/route_client-reference-manifest.js +1 -1
  26. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/projects/[id]/route_client-reference-manifest.js +1 -1
  27. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  28. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/providers/route_client-reference-manifest.js +1 -1
  29. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/queue/complete/route_client-reference-manifest.js +1 -1
  30. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/queue/route_client-reference-manifest.js +1 -1
  31. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/stage-prompts/route_client-reference-manifest.js +1 -1
  32. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/tasks/[id]/comments/[commentId]/route_client-reference-manifest.js +1 -1
  33. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/tasks/[id]/comments/route_client-reference-manifest.js +1 -1
  34. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/tasks/[id]/heartbeat/route_client-reference-manifest.js +1 -1
  35. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/tasks/[id]/history/route_client-reference-manifest.js +1 -1
  36. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/tasks/[id]/logs/route_client-reference-manifest.js +1 -1
  37. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/tasks/[id]/route_client-reference-manifest.js +1 -1
  38. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/tasks/route_client-reference-manifest.js +1 -1
  39. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/tasks/stream/route_client-reference-manifest.js +1 -1
  40. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/user-settings/route_client-reference-manifest.js +1 -1
  41. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/workflows/[id]/nodes/route_client-reference-manifest.js +1 -1
  42. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/workflows/[id]/route_client-reference-manifest.js +1 -1
  43. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/workflows/route_client-reference-manifest.js +1 -1
  44. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/auth/callback/route_client-reference-manifest.js +1 -1
  45. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/auth/device/page.js +5 -5
  46. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/auth/device/page_client-reference-manifest.js +1 -1
  47. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/auth/device.html +1 -1
  48. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/auth/device.rsc +2 -2
  49. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/dashboard/page_client-reference-manifest.js +1 -1
  50. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/dashboard.html +1 -1
  51. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/dashboard.rsc +1 -1
  52. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/index.html +1 -1
  53. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/index.rsc +1 -1
  54. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/login/page_client-reference-manifest.js +1 -1
  55. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/login.html +1 -1
  56. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/login.rsc +1 -1
  57. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/page_client-reference-manifest.js +1 -1
  58. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/projects/[slug]/page_client-reference-manifest.js +1 -1
  59. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/projects/[slug]/tasks/page_client-reference-manifest.js +1 -1
  60. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/projects/[slug]/workflow/page_client-reference-manifest.js +1 -1
  61. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  62. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/projects.html +1 -1
  63. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/projects.rsc +1 -1
  64. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  65. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/settings.html +1 -1
  66. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/settings.rsc +1 -1
  67. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app-paths-manifest.json +9 -9
  68. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/chunks/1240.js +1 -1
  69. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/chunks/6317.js +1 -1
  70. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/chunks/9773.js +1 -1
  71. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/functions-config-manifest.json +2 -2
  72. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/middleware-manifest.json +5 -5
  73. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/pages/404.html +1 -1
  74. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/pages/500.html +1 -1
  75. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/server-reference-manifest.js +1 -1
  76. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/server-reference-manifest.json +1 -1
  77. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/9719-0fda94fde411f574.js +1 -1
  78. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/auth/device/page-89af167d1fe0348d.js +1 -0
  79. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/dashboard/page-7437499eb05d5ce8.js +1 -1
  80. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/projects/[slug]/page-98b32955971a9b89.js +1 -1
  81. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/fallback/amp.js +1015 -0
  82. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/fallback/main-app.js +1893 -0
  83. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/fallback/main.js +1616 -0
  84. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/fallback/pages/_app.js +28 -0
  85. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/fallback/pages/_error.js +28 -0
  86. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/fallback/react-refresh.js +62 -0
  87. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/fallback/webpack.js +1368 -0
  88. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/polyfills.js +1 -0
  89. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/worker/index.js +1 -1
  90. package/lib/cli/cloudArtifacts.js +29 -23
  91. package/lib/cli/runCli.js +123 -31
  92. package/lib/project-cli.js +12 -0
  93. package/lib/prompts/cloudTask.js +144 -18
  94. package/lib/storage/locks.js +75 -37
  95. package/package.json +1 -1
  96. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/auth/device/page-af9fda9ec7668e77.js +0 -1
  97. /package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/{D_7sZpASpEwgzK6REgmIt → _sQ7ofTHOJaquTtqRSH9B}/_buildManifest.js +0 -0
  98. /package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/{D_7sZpASpEwgzK6REgmIt → _sQ7ofTHOJaquTtqRSH9B}/_ssgManifest.js +0 -0
package/lib/cli/runCli.js CHANGED
@@ -40,7 +40,11 @@ const { spawnCloudTaskProcess } = require('../proc/spawnCloudTaskProcess');
40
40
  const { scheduleTermination } = require('../proc/killProcessTree');
41
41
  const { getProcessManager } = require('../proc/ProcessManager');
42
42
  const { createCloudClient } = require('../cloud/client');
43
- const { buildContinueCloudTaskPrompt, buildNewAutonomousCloudTaskPrompt } = require('../prompts/cloudTask');
43
+ const {
44
+ buildContinueCloudTaskPrompt,
45
+ buildNewAutonomousCloudTaskPrompt,
46
+ buildCloudTaskPromptFromContext,
47
+ } = require('../prompts/cloudTask');
44
48
  const {
45
49
  resolveStageObjective,
46
50
  buildStageRequirementPrompt,
@@ -67,6 +71,20 @@ const { handleSkillCommand } = require('./skills');
67
71
  const { runOnboarding, showConfigStatus, runConfigMenu } = require('./onboarding');
68
72
  const { runInteractiveMenu } = require('./interactiveMenu');
69
73
  const cloudArtifacts = require('./cloudArtifacts');
74
+ const fallbackExtractSection = (markdown, heading) => {
75
+ if (!markdown) return '';
76
+ const pattern = new RegExp(`^##\\s+${heading}\\s*$`, 'im');
77
+ const match = pattern.exec(markdown);
78
+ if (!match) return '';
79
+ const start = match.index + match[0].length;
80
+ const rest = markdown.slice(start);
81
+ const next = rest.search(/^##\\s+/im);
82
+ const section = next === -1 ? rest : rest.slice(0, next);
83
+ return section.trim();
84
+ };
85
+ const extractSection = typeof cloudArtifacts.extractSection === 'function'
86
+ ? cloudArtifacts.extractSection
87
+ : fallbackExtractSection;
70
88
  const {
71
89
  sleep,
72
90
  appendTail,
@@ -134,7 +152,6 @@ const {
134
152
  createDaemonArtifactsRecorder,
135
153
  buildLocalRunIndexEntry,
136
154
  saveAugmentedPrompt,
137
- extractSection,
138
155
  buildFullDaemonPromptContext,
139
156
  resolveTaskTicketType,
140
157
  parseList,
@@ -770,8 +787,25 @@ async function checkOnboarding() {
770
787
  let decisionPayload;
771
788
  try {
772
789
  if (localArtifacts) {
773
- projectSlug = await resolveLocalProjectSlugForCloudTask(storage, task);
774
- taskSlug = await resolveLocalTaskSlugForCloudTask(storage, projectSlug, task);
790
+ try {
791
+ projectSlug = await resolveLocalProjectSlugForCloudTask(storage, task);
792
+ } catch {
793
+ projectSlug = null;
794
+ }
795
+ if (!projectSlug || typeof projectSlug !== 'string') {
796
+ projectSlug = storage.slugify(
797
+ (task?.project_slug || task?.project?.slug || task?.project_name || task?.project?.name || 'cloud'),
798
+ { maxLength: 64 }
799
+ ) || 'cloud';
800
+ }
801
+ try {
802
+ taskSlug = await resolveLocalTaskSlugForCloudTask(storage, projectSlug, task);
803
+ } catch {
804
+ taskSlug = null;
805
+ }
806
+ if (!taskSlug || typeof taskSlug !== 'string') {
807
+ taskSlug = storage.slugify(task?.slug || taskId || 'untitled', { maxLength: 64 }) || 'untitled';
808
+ }
775
809
 
776
810
  const cloudProject = extractCloudProjectIdentity(task);
777
811
  await storage.writeProjectState(projectSlug, {
@@ -1127,7 +1161,7 @@ async function checkOnboarding() {
1127
1161
  // Local-first command handlers live in lib/commands/local.js.
1128
1162
 
1129
1163
  // ============================================================
1130
- // agx new "<goal>" [--provider c|g|o|x] [--run] [--json]
1164
+ // agx new "<goal>" [--provider c|g|o|x] [--project <slug>] [--run] [--json]
1131
1165
  // Creates a new task via cloud API
1132
1166
  // ============================================================
1133
1167
  if (cmd === 'new') {
@@ -1157,6 +1191,11 @@ async function checkOnboarding() {
1157
1191
  if (modelIdx !== -1 && args[modelIdx + 1]) {
1158
1192
  model = args[modelIdx + 1];
1159
1193
  }
1194
+ let projectSlug = null;
1195
+ const projectIdx = args.findIndex(a => a === '--project');
1196
+ if (projectIdx !== -1 && args[projectIdx + 1]) {
1197
+ projectSlug = args[projectIdx + 1];
1198
+ }
1160
1199
  let ticketType = null;
1161
1200
  const ticketTypeIdx = args.findIndex(a => a === '--type' || a === '--ticket-type');
1162
1201
  if (ticketTypeIdx !== -1 && args[ticketTypeIdx + 1]) {
@@ -1171,12 +1210,13 @@ async function checkOnboarding() {
1171
1210
  }
1172
1211
 
1173
1212
  // Extract goal text (filter out flags)
1174
- const flagsToRemove = ['--json', '--run', '-r', '--provider', '-P', '--model', '-m', '--type', '--ticket-type'];
1213
+ const flagsToRemove = ['--json', '--run', '-r', '--provider', '-P', '--model', '-m', '--project', '--type', '--ticket-type'];
1175
1214
  const goalParts = [];
1176
1215
  for (let i = 1; i < args.length; i++) {
1177
1216
  if (flagsToRemove.includes(args[i])) {
1178
1217
  if (args[i] === '--provider' || args[i] === '-P') i++;
1179
1218
  if (args[i] === '--model' || args[i] === '-m') i++;
1219
+ if (args[i] === '--project') i++;
1180
1220
  if (args[i] === '--type' || args[i] === '--ticket-type') i++;
1181
1221
  continue;
1182
1222
  }
@@ -1186,18 +1226,37 @@ async function checkOnboarding() {
1186
1226
 
1187
1227
  if (!goalText) {
1188
1228
  if (jsonMode) {
1189
- console.log(JSON.stringify({ error: 'missing_goal', usage: 'agx new "<goal>" [--provider c] [--type spike|task] [--run]' }));
1229
+ console.log(JSON.stringify({ error: 'missing_goal', usage: 'agx new "<goal>" [--provider c] [--project <slug>] [--type spike|task] [--run]' }));
1190
1230
  } else {
1191
- console.log(`${c.red}Usage:${c.reset} agx new "<goal>" [--provider c|g|o|x] [--type spike|task] [--run]`);
1231
+ console.log(`${c.red}Usage:${c.reset} agx new "<goal>" [--provider c|g|o|x] [--project <slug>] [--type spike|task] [--run]`);
1192
1232
  }
1193
1233
  process.exit(1);
1194
1234
  }
1195
1235
 
1196
1236
  try {
1237
+ let projectId = null;
1238
+ if (projectSlug) {
1239
+ try {
1240
+ const project = await resolveProjectByIdentifier(projectSlug);
1241
+ projectId = project?.id || null;
1242
+ } catch (err) {
1243
+ const slug = projectSlug.trim();
1244
+ const projectErr = `Project ${slug} not found. Run agx project list to see available projects.`;
1245
+ if (jsonMode) {
1246
+ console.log(JSON.stringify({ error: projectErr }));
1247
+ } else {
1248
+ console.log(`${c.red}${projectErr}${c.reset}`);
1249
+ }
1250
+ process.exit(1);
1251
+ }
1252
+ }
1253
+
1197
1254
  // Create task via cloud API
1198
1255
  const frontmatter = ['status: queued', 'stage: ideation'];
1199
1256
  frontmatter.push(`engine: ${provider}`);
1200
1257
  frontmatter.push(`provider: ${provider}`);
1258
+ if (projectSlug) frontmatter.push(`project: ${projectSlug}`);
1259
+ if (projectId) frontmatter.push(`project_id: ${projectId}`);
1201
1260
  if (model) frontmatter.push(`model: ${model}`);
1202
1261
  if (ticketType) frontmatter.push(`type: ${ticketType}`);
1203
1262
 
@@ -1374,6 +1433,17 @@ async function checkOnboarding() {
1374
1433
  process.exit(1);
1375
1434
  }
1376
1435
 
1436
+ if (projectSlug) {
1437
+ try {
1438
+ const project = await resolveProjectByIdentifier(projectSlug);
1439
+ projectId = project?.id || projectId;
1440
+ } catch (err) {
1441
+ const slug = projectSlug.trim();
1442
+ console.log(`${c.red}Project ${slug} not found. Run agx project list to see available projects.${c.reset}`);
1443
+ process.exit(1);
1444
+ }
1445
+ }
1446
+
1377
1447
  // Build markdown content
1378
1448
  const frontmatter = ['status: queued', 'stage: ideation'];
1379
1449
  if (projectSlug) frontmatter.push(`project: ${projectSlug}`);
@@ -2886,29 +2956,51 @@ EXAMPLES:
2886
2956
  }
2887
2957
 
2888
2958
  // Build augmented prompt with task context
2889
- const plan = cloudArtifacts.extractSection(task.content, 'Plan');
2890
- const todo = cloudArtifacts.extractSection(task.content, 'Todo') || cloudArtifacts.extractSection(task.content, 'TODO');
2891
- const checkpoints = cloudArtifacts.extractSection(task.content, 'Checkpoints');
2892
- const learnings = cloudArtifacts.extractSection(task.content, 'Learnings');
2893
-
2894
- const stageKey = task?.stage || 'unknown';
2895
- const stagePrompt = resolveStageObjective(task, stageKey, '');
2896
- const stageRequirement = buildStageRequirementPrompt({ stage: stageKey, stagePrompt });
2897
- const runContext = {
2898
- run_root: process.env.AGX_RUN_ROOT || '',
2899
- plan_dir: process.env.AGX_RUN_PLAN_DIR || '',
2900
- artifacts_dir: process.env.AGX_RUN_ARTIFACTS_DIR || '',
2901
- };
2902
-
2903
- const augmentedPrompt = buildContinueCloudTaskPrompt({
2904
- task,
2905
- taskComments,
2906
- finalPrompt,
2907
- stagePrompt,
2908
- stageRequirement,
2909
- extracted: { plan, todo, checkpoints, learnings },
2910
- runContext,
2911
- });
2959
+ let hasTaskPrompt = typeof task?.prompt === 'string' && task.prompt.trim();
2960
+ if (!hasTaskPrompt) {
2961
+ const inferredPrompt = buildCloudTaskPromptFromContext(task);
2962
+ if (inferredPrompt) {
2963
+ task.prompt = inferredPrompt;
2964
+ hasTaskPrompt = true;
2965
+ }
2966
+ }
2967
+ let plan = '';
2968
+ let todo = '';
2969
+ let checkpoints = '';
2970
+ let learnings = '';
2971
+ let stagePrompt = '';
2972
+ let stageRequirement = '';
2973
+
2974
+ if (!hasTaskPrompt) {
2975
+ const sectionExtractor = (typeof extractSection === 'function')
2976
+ ? extractSection
2977
+ : fallbackExtractSection;
2978
+
2979
+ plan = sectionExtractor(task.content, 'Plan');
2980
+ todo = sectionExtractor(task.content, 'Todo') || sectionExtractor(task.content, 'TODO');
2981
+ checkpoints = sectionExtractor(task.content, 'Checkpoints');
2982
+ learnings = sectionExtractor(task.content, 'Learnings');
2983
+
2984
+ const stageKey = task?.stage || 'unknown';
2985
+ stagePrompt = resolveStageObjective(task, stageKey, '');
2986
+ stageRequirement = buildStageRequirementPrompt({ stage: stageKey, stagePrompt });
2987
+ }
2988
+
2989
+ const runContext = {
2990
+ run_root: process.env.AGX_RUN_ROOT || '',
2991
+ plan_dir: process.env.AGX_RUN_PLAN_DIR || '',
2992
+ artifacts_dir: process.env.AGX_RUN_ARTIFACTS_DIR || '',
2993
+ };
2994
+
2995
+ const augmentedPrompt = buildContinueCloudTaskPrompt({
2996
+ task,
2997
+ taskComments,
2998
+ finalPrompt,
2999
+ stagePrompt,
3000
+ stageRequirement,
3001
+ extracted: { plan, todo, checkpoints, learnings },
3002
+ runContext,
3003
+ });
2912
3004
 
2913
3005
  const promptIndex = translatedArgs.indexOf(finalPrompt);
2914
3006
  if (promptIndex !== -1) {
@@ -83,20 +83,32 @@ function collectProjectFlags(argv = []) {
83
83
  switch (arg) {
84
84
  case '--name':
85
85
  case '-n':
86
+ if (typeof value === 'undefined') {
87
+ throw new Error('Missing value for --name');
88
+ }
86
89
  parsed.name = value;
87
90
  i++;
88
91
  break;
89
92
  case '--slug':
93
+ if (typeof value === 'undefined') {
94
+ throw new Error('Missing value for --slug');
95
+ }
90
96
  parsed.slug = value;
91
97
  i++;
92
98
  break;
93
99
  case '--description':
94
100
  case '--desc':
101
+ if (typeof value === 'undefined') {
102
+ throw new Error('Missing value for --description');
103
+ }
95
104
  parsed.description = value;
96
105
  i++;
97
106
  break;
98
107
  case '--ci':
99
108
  case '--ci-info':
109
+ if (typeof value === 'undefined') {
110
+ throw new Error('Missing value for --ci');
111
+ }
100
112
  parsed.ci_cd_info = value;
101
113
  i++;
102
114
  break;
@@ -59,7 +59,8 @@ function buildContinueCloudTaskPrompt({
59
59
  const planDir = typeof runContext?.plan_dir === 'string' ? runContext.plan_dir.trim() : '';
60
60
  const artifactsDir = typeof runContext?.artifacts_dir === 'string' ? runContext.artifacts_dir.trim() : '';
61
61
 
62
- let augmentedPrompt = task?.prompt || `## Cloud Task Context
62
+ const hasTaskPrompt = typeof task?.prompt === 'string' && task.prompt.trim();
63
+ let augmentedPrompt = hasTaskPrompt ? task.prompt.trim() : `## Cloud Task Context
63
64
 
64
65
  You are continuing a cloud task. Here is the current state:
65
66
 
@@ -88,31 +89,77 @@ Learnings: ${learnings || '(none)'}
88
89
 
89
90
  `;
90
91
 
91
- if (!task?.prompt && task?.engine) {
92
+ if (!hasTaskPrompt && task?.engine) {
92
93
  augmentedPrompt += `Engine: ${task.engine}\n`;
93
94
  }
94
95
 
95
- augmentedPrompt += `
96
- ## Instructions
96
+ augmentedPrompt += `\n\n${buildLegacyInstructionFooter({
97
+ runContext: { runRoot, planDir, artifactsDir },
98
+ finalPrompt,
99
+ })}`;
97
100
 
98
- Continue working on this task. Use the cloud API to sync progress.
99
- Respect the Stage Completion Requirement before using [complete] or [done].
101
+ return augmentedPrompt;
102
+ }
100
103
 
101
- ${(runRoot || planDir || artifactsDir) ? `\nLocal run paths (scratch space):\n- Run root: ${runRoot || '(unset)'}\n- Plan dir: ${planDir || '(unset)'}\n- Artifacts dir: ${artifactsDir || '(unset)'}\n\nPrefer writing scratch planning docs under the run's Plan dir to avoid polluting the repo.\n` : ''}
104
+ function buildCloudTaskPromptFromContext(task) {
105
+ if (!task || typeof task !== 'object') return '';
102
106
 
103
- To update the task:
104
- - [done] - Mark task complete
105
- - [complete: message] - Complete current stage
106
- - [log: message] - Add a log entry
107
- - [checkpoint: message] - Save progress checkpoint
108
- - [learn: insight] - Record a learning
109
- - [plan: text] - Update plan
110
- - [todo: text] - Update todo list
107
+ const stagePrompt = task.stage_prompt || task.stagePrompt || '';
108
+ const comments = Array.isArray(task.comments) ? task.comments : [];
109
+ const learnings = task.learnings || { task: [], project: [], global: [] };
110
+ const projectContext = task.project_context || null;
111
111
 
112
- ${finalPrompt ? `Your specific task: ${finalPrompt}` : ''}
113
- `;
112
+ const description = (task.description || extractBodyFromContent(task.content || '')).trim();
113
+ const provider = task.resolved_provider || task.provider || task.engine || 'unspecified';
114
+ const model = task.resolved_model || task.model || '';
115
+ const swarm = task.resolved_swarm ?? task.swarm ?? false;
116
+ const swarmModels = Array.isArray(task.resolved_swarm_models)
117
+ ? task.resolved_swarm_models
118
+ : Array.isArray(task.swarm_models)
119
+ ? task.swarm_models
120
+ : [];
114
121
 
115
- return augmentedPrompt;
122
+ const metaLines = [
123
+ `Title: ${task.title || 'Untitled'}`,
124
+ `Slug: ${task.slug || 'unspecified'}`,
125
+ `Stage: ${task.stage || 'ideation'}`,
126
+ `Project: ${task.project || 'none'}`,
127
+ `Engine: ${task.engine || provider || 'unspecified'}`,
128
+ `Provider: ${provider}`,
129
+ `Model: ${model}`,
130
+ `Swarm: ${swarm ? 'true' : 'false'}`,
131
+ `Swarm Models: ${swarmModels.length ? swarmModels.map((m) => `${m.provider}:${m.model}`).join(', ') : 'none'}`,
132
+ ];
133
+
134
+ const commentLines = comments
135
+ .filter((comment) => isPromptRelevantComment(comment?.content))
136
+ .map((comment) => {
137
+ const when = comment?.created_at ? new Date(comment.created_at).toISOString() : 'unknown-time';
138
+ const author = comment?.author_type === 'agent' ? 'agent' : 'user';
139
+ return `[${when}] (${author}) ${comment?.content || ''}`;
140
+ });
141
+
142
+ const projectSections = projectContext?.project
143
+ ? [
144
+ `PROJECT CONTEXT\n${formatProjectMetadata(projectContext.project)}`,
145
+ `REPOSITORY MAP\n${formatRepoLines(projectContext.repos || [])}`,
146
+ `PROJECT LEARNINGS\n${formatList(projectContext.learnings || [], '(none)')}`,
147
+ ]
148
+ : [];
149
+
150
+ const sections = [
151
+ stagePrompt ? `STAGE PROMPT\n${stagePrompt}` : null,
152
+ 'EXECUTION RULES\n- Do not use AGX MCP tools or AGX MCP servers for this task.\n- Complete work using local edits, shell commands, and allowed HTTP APIs only.',
153
+ `TASK META\n${metaLines.join('\n')}`,
154
+ `TASK\n${description || '(empty)'}`,
155
+ `COMMENTS\n${formatList(commentLines, '(none)')}`,
156
+ ...projectSections,
157
+ `LEARNINGS (task)\n${formatList((learnings.task || []).map((l) => l.content || ''), '(none)')}`,
158
+ `LEARNINGS (project)\n${formatList((learnings.project || []).map((l) => l.content || ''), '(none)')}`,
159
+ `LEARNINGS (global)\n${formatList((learnings.global || []).map((l) => l.content || ''), '(none)')}`,
160
+ ].filter(Boolean);
161
+
162
+ return sections.join('\n\n');
116
163
  }
117
164
 
118
165
  function buildNewAutonomousCloudTaskPrompt({
@@ -158,4 +205,83 @@ Goal: ${finalPrompt}
158
205
  module.exports = {
159
206
  buildContinueCloudTaskPrompt,
160
207
  buildNewAutonomousCloudTaskPrompt,
208
+ buildLegacyInstructionFooter,
209
+ buildCloudTaskPromptFromContext,
161
210
  };
211
+
212
+ function buildLegacyInstructionFooter({ runContext, finalPrompt } = {}) {
213
+ const runRoot = typeof runContext?.runRoot === 'string' ? runContext.runRoot.trim() : '';
214
+ const planDir = typeof runContext?.planDir === 'string' ? runContext.planDir.trim() : '';
215
+ const artifactsDir = typeof runContext?.artifactsDir === 'string' ? runContext.artifactsDir.trim() : '';
216
+
217
+ return `## Instructions
218
+
219
+ Continue working on this task. Use the cloud API to sync progress.
220
+ Respect the Stage Completion Requirement before using [complete] or [done].
221
+
222
+ ${(runRoot || planDir || artifactsDir) ? `\nLocal run paths (scratch space):\n- Run root: ${runRoot || '(unset)'}\n- Plan dir: ${planDir || '(unset)'}\n- Artifacts dir: ${artifactsDir || '(unset)'}\n\nPrefer writing scratch planning docs under the run's Plan dir to avoid polluting the repo.\n` : ''}
223
+
224
+ To update the task:
225
+ - [done] - Mark task complete
226
+ - [complete: message] - Complete current stage
227
+ - [log: message] - Add a log entry
228
+ - [checkpoint: message] - Save progress checkpoint
229
+ - [learn: insight] - Record a learning
230
+ - [plan: text] - Update plan
231
+ - [todo: text] - Update todo list
232
+
233
+ ${finalPrompt ? `Your specific task: ${finalPrompt}` : ''}`.trim();
234
+ }
235
+
236
+ function extractBodyFromContent(content) {
237
+ if (!content) return '';
238
+ const match = String(content).match(/^---\n[\s\S]*?\n---\n([\s\S]*)$/);
239
+ return (match ? match[1] : content).trim();
240
+ }
241
+
242
+ function isPromptRelevantComment(content) {
243
+ const normalized = String(content || '').trim();
244
+ if (!normalized) return false;
245
+ if (normalized.startsWith('[execution/')) return false;
246
+ if (normalized.startsWith('Execution result from agx')) return false;
247
+ return true;
248
+ }
249
+
250
+ function formatList(items, emptyLabel) {
251
+ const safe = Array.isArray(items) ? items.filter(Boolean) : [];
252
+ if (!safe.length) return emptyLabel;
253
+ return safe.map((item) => `- ${item}`).join('\n');
254
+ }
255
+
256
+ function formatProjectMetadata(project) {
257
+ if (!project) return '(none)';
258
+ const lines = [];
259
+ if (project.name) lines.push(`Name: ${project.name}`);
260
+ if (project.slug) lines.push(`Slug: ${project.slug}`);
261
+ if (project.description) lines.push(`Description: ${project.description}`);
262
+ if (project.ci_cd_info) lines.push(`CI/CD: ${project.ci_cd_info}`);
263
+ if (project.workflow_id) lines.push(`Workflow: ${project.workflow_id}`);
264
+ if (project.metadata && typeof project.metadata === 'object' && !Array.isArray(project.metadata)) {
265
+ const entries = Object.entries(project.metadata);
266
+ if (entries.length) {
267
+ lines.push('Metadata:');
268
+ entries.forEach(([key, value]) => {
269
+ lines.push(`- ${key}: ${value}`);
270
+ });
271
+ }
272
+ }
273
+ return lines.length ? lines.join('\n') : '(none)';
274
+ }
275
+
276
+ function formatRepoLines(repos) {
277
+ if (!Array.isArray(repos) || repos.length === 0) return '(none)';
278
+ return repos
279
+ .map((repo) => {
280
+ const parts = [repo?.name || '(unnamed repo)'];
281
+ if (repo?.path) parts.push(`path: ${repo.path}`);
282
+ if (repo?.git_url) parts.push(`git_url: ${repo.git_url}`);
283
+ if (repo?.notes) parts.push(`notes: ${repo.notes}`);
284
+ return `- ${parts.join(' | ')}`;
285
+ })
286
+ .join('\n');
287
+ }
@@ -29,6 +29,50 @@ const LOCK_STALE_MS = process.env.AGX_LOCK_STALE_MS
29
29
  // Process start time - used to detect PID reuse
30
30
  const PROCESS_STARTED_AT = Date.now();
31
31
 
32
+ // ============================================================
33
+ // Lock Registry — track all held locks for cleanup on exit
34
+ // ============================================================
35
+
36
+ /** @type {Set<LockHandle>} */
37
+ const _heldLocks = new Set();
38
+ let _exitHandlerRegistered = false;
39
+
40
+ function _registerExitHandler() {
41
+ if (_exitHandlerRegistered) return;
42
+ _exitHandlerRegistered = true;
43
+
44
+ // Synchronous cleanup on exit — best-effort delete of lock files.
45
+ // This fires for normal exit, SIGINT, SIGTERM — but NOT SIGKILL.
46
+ const cleanup = () => {
47
+ for (const handle of _heldLocks) {
48
+ if (handle.released) continue;
49
+ try {
50
+ // Verify ownership before deleting (sync read + unlink)
51
+ const raw = fs.readFileSync(handle.lockPath, 'utf8');
52
+ const lock = JSON.parse(raw);
53
+ if (lock.pid === handle.pid && lock.at === handle.at) {
54
+ fs.unlinkSync(handle.lockPath);
55
+ }
56
+ } catch {
57
+ // Best-effort — ignore errors during shutdown
58
+ }
59
+ handle.released = true;
60
+ }
61
+ _heldLocks.clear();
62
+ };
63
+
64
+ process.on('exit', cleanup);
65
+
66
+ // For signals, run cleanup then re-raise so the process actually exits
67
+ for (const sig of ['SIGINT', 'SIGTERM']) {
68
+ process.on(sig, () => {
69
+ cleanup();
70
+ // Re-raise signal with default handler
71
+ process.kill(process.pid, sig);
72
+ });
73
+ }
74
+ }
75
+
32
76
  // ============================================================
33
77
  // Lock Management
34
78
  // ============================================================
@@ -80,48 +124,37 @@ async function acquireTaskLock(taskRootPath, options = {}) {
80
124
  const lockPath = path.join(taskRootPath, '.lock');
81
125
  const force = options.force || false;
82
126
 
83
- // Check existing lock
127
+ // Proactively clean stale locks before attempting acquisition
128
+ // This handles the common case where a previous process died without cleanup
84
129
  const existingLock = await readJsonSafe(lockPath);
85
130
 
86
131
  if (existingLock && !force) {
87
- // First check: is this our own lock from a previous run that wasn't released?
88
- // This handles the case where the same process crashed/restarted mid-task.
89
- if (existingLock.pid === process.pid) {
90
- // Same PID - check if it's truly from this process instance
91
- if (!isCurrentProcessLock(existingLock)) {
92
- // Lock is from a previous instance of this PID (PID was reused)
93
- // or from before this process started - safe to take over
94
- // This is the key fix: we clean up our own stale locks
95
- } else {
96
- // Lock is from current process instance - we already hold it
97
- // This shouldn't happen in normal operation, but return the existing lock
98
- // Actually, this would be a programming error, so let's throw
99
- throw new Error(
100
- `Lock already held by this process instance. ` +
101
- `This indicates a logic error - lock should be released before re-acquiring.`
102
- );
103
- }
104
- } else {
105
- // Different PID - check if the process is still alive and lock is fresh
106
- const isAlive = isProcessAlive(existingLock.pid);
107
- const isStale = isLockStale(existingLock);
108
-
109
- if (isAlive && !isStale) {
110
- // Also check process start time if available
111
- const startTimeValid = !existingLock.startedAt ||
112
- isProcessStartTimeValid(existingLock.pid, existingLock.startedAt);
113
-
114
- if (startTimeValid) {
115
- throw new Error(
116
- `Task is locked by process ${existingLock.pid} since ${existingLock.at}. ` +
117
- `Use --force to override if you're sure the lock is stale.`
118
- );
119
- }
120
- // Process has same PID but different start time (PID reuse) - lock is stale
132
+ const { valid, reason } = isLockValid(existingLock);
133
+ if (!valid) {
134
+ // Lock is stale/dead — clean it up silently
135
+ try { await fs.promises.unlink(lockPath); } catch (e) {
136
+ if (e.code !== 'ENOENT') throw e;
121
137
  }
138
+ // Fall through to acquire below
139
+ }
140
+ }
141
+
142
+ // Re-read after potential cleanup
143
+ const currentLock = existingLock ? await readJsonSafe(lockPath) : null;
122
144
 
123
- // Lock is stale or process is dead - we can take it
145
+ if (currentLock && !force) {
146
+ // If we get here, the lock survived the stale cleanup above — it's genuinely held.
147
+ if (currentLock.pid === process.pid && isCurrentProcessLock(currentLock)) {
148
+ throw new Error(
149
+ `Lock already held by this process instance. ` +
150
+ `This indicates a logic error - lock should be released before re-acquiring.`
151
+ );
124
152
  }
153
+ // Lock is held by a live process — reject
154
+ throw new Error(
155
+ `Task is locked by process ${currentLock.pid} since ${currentLock.at}. ` +
156
+ `Use --force to override if you're sure the lock is stale.`
157
+ );
125
158
  }
126
159
 
127
160
  const now = new Date().toISOString();
@@ -156,6 +189,10 @@ async function acquireTaskLock(taskRootPath, options = {}) {
156
189
  released: false,
157
190
  };
158
191
 
192
+ // Track for cleanup on process exit
193
+ _heldLocks.add(handle);
194
+ _registerExitHandler();
195
+
159
196
  return handle;
160
197
  }
161
198
 
@@ -212,7 +249,8 @@ async function releaseTaskLock(handle) {
212
249
  }
213
250
 
214
251
  handle.released = true;
215
-
252
+ _heldLocks.delete(handle);
253
+
216
254
  // Return status for debugging (callers typically ignore this)
217
255
  return { deleted, ownershipVerified };
218
256
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mndrk/agx",
3
- "version": "1.4.34",
3
+ "version": "1.4.36",
4
4
  "description": "Autonomous AI Agent Orchestrator for Claude, Gemini, and Ollama",
5
5
  "main": "lib/index.js",
6
6
  "exports": {
@@ -1 +0,0 @@
1
- (self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[8008],{63:(e,t,r)=>{"use strict";var s=r(7260);r.o(s,"usePathname")&&r.d(t,{usePathname:function(){return s.usePathname}}),r.o(s,"useRouter")&&r.d(t,{useRouter:function(){return s.useRouter}}),r.o(s,"useSearchParams")&&r.d(t,{useSearchParams:function(){return s.useSearchParams}})},926:(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),!function(e,t){for(var r in t)Object.defineProperty(e,r,{enumerable:!0,get:t[r]})}(t,{callServer:function(){return s.callServer},createServerReference:function(){return c.createServerReference},findSourceMapURL:function(){return n.findSourceMapURL}});let s=r(1209),n=r(5153),c=r(7197)},5109:(e,t,r)=>{Promise.resolve().then(r.bind(r,9053))},9053:(e,t,r)=>{"use strict";r.r(t),r.d(t,{default:()=>u});var s=r(5155),n=r(2115),c=r(63),a=r(926);let l=(0,a.createServerReference)("402af22e910eb71e0867f901bdd4e9ceaeb0263b84",a.callServer,void 0,a.findSourceMapURL,"approveDeviceCode");function o(){let e=(0,c.useSearchParams)(),t=(0,c.useRouter)(),r=e.get("user_code")||"",[a,o]=(0,n.useState)(r),[u,i]=(0,n.useState)(!1),[d,f]=(0,n.useState)(null),[x,h]=(0,n.useState)(!1);(0,n.useEffect)(()=>{if(x){let e=setTimeout(()=>{t.push("/projects")},3e3);return()=>clearTimeout(e)}},[x,t]);let m=async e=>{e.preventDefault(),i(!0),f(null);try{let e=await l(a);if(!e.success)throw Error(e.error);h(!0)}catch(e){f(e.message)}finally{i(!1)}};return x?(0,s.jsx)("div",{className:"flex flex-col items-center justify-center min-h-screen bg-neutral-900 text-white p-4",children:(0,s.jsxs)("div",{className:"max-w-md w-full bg-neutral-800 p-8 rounded-xl shadow-2xl text-center",children:[(0,s.jsx)("h1",{className:"text-3xl font-bold mb-4 text-green-400",children:"Success!"}),(0,s.jsx)("p",{className:"text-gray-300 mb-2",children:"You have successfully authenticated your device."}),(0,s.jsx)("p",{className:"text-gray-400 text-sm mb-6 italic",children:"Redirecting to projects in a few seconds..."}),(0,s.jsx)("button",{onClick:()=>t.push("/projects"),className:"w-full py-3 px-4 bg-white text-black font-semibold rounded-lg hover:bg-gray-200 transition-colors",children:"Go to Projects"})]})}):(0,s.jsx)("div",{className:"flex flex-col items-center justify-center min-h-screen bg-neutral-900 text-white p-4",children:(0,s.jsxs)("div",{className:"max-w-md w-full bg-neutral-800 p-8 rounded-xl shadow-2xl",children:[(0,s.jsx)("h1",{className:"text-2xl font-bold mb-6 text-center",children:"Connect Device"}),(0,s.jsx)("p",{className:"text-gray-400 mb-8 text-center text-sm",children:"Enter the code displayed on your device to authorize it."}),(0,s.jsxs)("form",{onSubmit:m,className:"space-y-6",children:[(0,s.jsxs)("div",{children:[(0,s.jsx)("label",{htmlFor:"code",className:"block text-sm font-medium text-gray-400 mb-2",children:"Device Code"}),(0,s.jsx)("input",{type:"text",id:"code",value:a,onChange:e=>o(e.target.value.toUpperCase()),placeholder:"BCDF-XXXX",className:"w-full px-4 py-3 bg-neutral-900 border border-neutral-700 rounded-lg text-white placeholder-neutral-600 focus:outline-none focus:ring-2 focus:ring-blue-500 font-mono text-center tracking-widest text-lg uppercase",required:!0})]}),d&&(0,s.jsx)("div",{className:"p-3 bg-red-900/50 border border-red-800 rounded-lg text-red-200 text-center text-sm",children:d}),(0,s.jsx)("button",{type:"submit",disabled:u,className:"w-full py-3 px-4 bg-white text-black font-semibold rounded-lg hover:bg-gray-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-white transition-colors disabled:opacity-50 disabled:cursor-not-allowed",children:u?"Verifying...":"Authorize Device"})]})]})})}function u(){return(0,s.jsx)(n.Suspense,{fallback:(0,s.jsx)("div",{children:"Loading..."}),children:(0,s.jsx)(o,{})})}}},e=>{e.O(0,[8441,1255,7358],()=>e(e.s=5109)),_N_E=e.O()}]);