@mndrk/agx 1.4.20 → 1.4.22

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 (104) hide show
  1. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/BUILD_ID +1 -1
  2. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/app-build-manifest.json +29 -29
  3. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/app-path-routes-manifest.json +4 -4
  4. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/build-manifest.json +2 -2
  5. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/prerender-manifest.json +22 -22
  6. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  7. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/_not-found.html +1 -1
  8. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/_not-found.rsc +2 -2
  9. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/audit/route_client-reference-manifest.js +1 -1
  10. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/auth/[...nextauth]/route_client-reference-manifest.js +1 -1
  11. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/auth/daemon-secret/route_client-reference-manifest.js +1 -1
  12. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/auth/device/code/route_client-reference-manifest.js +1 -1
  13. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/auth/device/token/route_client-reference-manifest.js +1 -1
  14. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/auth/refresh/route_client-reference-manifest.js +1 -1
  15. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/auth/status/route_client-reference-manifest.js +1 -1
  16. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/learnings/route_client-reference-manifest.js +1 -1
  17. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/logs/stream/route_client-reference-manifest.js +1 -1
  18. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/orchestrator/tasks/[taskId]/cancel/route_client-reference-manifest.js +1 -1
  19. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/orchestrator/tasks/[taskId]/signal/route_client-reference-manifest.js +1 -1
  20. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/orchestrator/tasks/[taskId]/start/route_client-reference-manifest.js +1 -1
  21. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/orchestrator/tasks/[taskId]/status/route_client-reference-manifest.js +1 -1
  22. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/projects/[id]/route_client-reference-manifest.js +1 -1
  23. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  24. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/providers/route_client-reference-manifest.js +1 -1
  25. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/queue/complete/route_client-reference-manifest.js +1 -1
  26. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/queue/route_client-reference-manifest.js +1 -1
  27. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/stage-prompts/route_client-reference-manifest.js +1 -1
  28. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/tasks/[id]/comments/[commentId]/route_client-reference-manifest.js +1 -1
  29. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/tasks/[id]/comments/route_client-reference-manifest.js +1 -1
  30. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/tasks/[id]/heartbeat/route_client-reference-manifest.js +1 -1
  31. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/tasks/[id]/history/route_client-reference-manifest.js +1 -1
  32. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/tasks/[id]/logs/route_client-reference-manifest.js +1 -1
  33. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/tasks/[id]/route_client-reference-manifest.js +1 -1
  34. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/tasks/route_client-reference-manifest.js +1 -1
  35. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/tasks/stream/route_client-reference-manifest.js +1 -1
  36. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/user-settings/route_client-reference-manifest.js +1 -1
  37. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/workflows/[id]/nodes/route_client-reference-manifest.js +1 -1
  38. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/workflows/[id]/route_client-reference-manifest.js +1 -1
  39. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/workflows/route_client-reference-manifest.js +1 -1
  40. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/auth/callback/route_client-reference-manifest.js +1 -1
  41. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/auth/device/page.js +5 -5
  42. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/auth/device/page_client-reference-manifest.js +1 -1
  43. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/auth/device.html +1 -1
  44. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/auth/device.rsc +3 -3
  45. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/dashboard/page.js +8 -3
  46. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/dashboard/page_client-reference-manifest.js +1 -1
  47. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/dashboard.html +1 -1
  48. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/dashboard.rsc +3 -3
  49. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/index.html +1 -1
  50. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/index.rsc +2 -2
  51. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/login/page_client-reference-manifest.js +1 -1
  52. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/login.html +1 -1
  53. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/login.rsc +2 -2
  54. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/page_client-reference-manifest.js +1 -1
  55. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/projects/[slug]/page.js +4 -4
  56. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/projects/[slug]/page_client-reference-manifest.js +1 -1
  57. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/projects/[slug]/tasks/page_client-reference-manifest.js +1 -1
  58. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/projects/[slug]/workflow/page_client-reference-manifest.js +1 -1
  59. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  60. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/projects.html +1 -1
  61. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/projects.rsc +3 -3
  62. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  63. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/settings.html +1 -1
  64. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/settings.rsc +2 -2
  65. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app-paths-manifest.json +4 -4
  66. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/chunks/3009.js +5 -6
  67. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/chunks/6125.js +1 -1
  68. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/middleware-manifest.json +5 -5
  69. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/pages/404.html +1 -1
  70. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/pages/500.html +1 -1
  71. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/server-reference-manifest.js +1 -1
  72. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/server-reference-manifest.json +1 -1
  73. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/{9337-5d3c6b1828da8ec3.js → 9337-09000d8a6c85f40c.js} +1 -1
  74. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/9719-0fda94fde411f574.js +1 -0
  75. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/auth/device/page-e2c2560ec12b421d.js +1 -0
  76. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/dashboard/page-7437499eb05d5ce8.js +1 -0
  77. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/projects/[slug]/page-253ca8286e8f1d68.js +1 -0
  78. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/css/72371329e4c91108.css +1 -0
  79. package/index.js +212 -63
  80. package/lib/cli/cloud/aggregate.js +162 -0
  81. package/lib/cli/cloud/command.js +230 -0
  82. package/lib/cli/cloud/executeVerifySingle.js +293 -0
  83. package/lib/cli/cloud/executeVerifySwarm.js +302 -0
  84. package/lib/cli/cloud/index.js +68 -0
  85. package/lib/cli/cloud/iterations.js +155 -0
  86. package/lib/cli/cloud/persist.js +123 -0
  87. package/lib/cli/cloud/prompts.js +229 -0
  88. package/lib/cli/cloud/simpleLoops.js +203 -0
  89. package/lib/cli/cloud/taskLogger.js +159 -0
  90. package/lib/cli/cloudArtifacts.js +478 -0
  91. package/lib/cli/onboarding.js +23 -4
  92. package/lib/cli/runCli.js +205 -2200
  93. package/lib/cli/util.js +68 -1
  94. package/lib/cloud/client.js +3 -30
  95. package/lib/config/cloudConfig.js +110 -6
  96. package/lib/config/paths.js +1 -1
  97. package/package.json +1 -1
  98. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/9719-1d7bdd112db709cc.js +0 -1
  99. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/auth/device/page-1191b5d80fb53701.js +0 -1
  100. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/dashboard/page-2403721dcf6fac4f.js +0 -1
  101. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/projects/[slug]/page-e5b42f6a38ee1959.js +0 -1
  102. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/css/97623b2fc4a523a7.css +0 -1
  103. /package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/{_UEH0bf2vZJdfFbGlB9rM → M4AQWpnhTFqFD3HFlSHd9}/_buildManifest.js +0 -0
  104. /package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/{_UEH0bf2vZJdfFbGlB9rM → M4AQWpnhTFqFD3HFlSHd9}/_ssgManifest.js +0 -0
@@ -0,0 +1,478 @@
1
+ /* eslint-disable no-console */
2
+ 'use strict';
3
+
4
+ const crypto = require('crypto');
5
+ const fs = require('fs');
6
+ const os = require('os');
7
+ const path = require('path');
8
+
9
+ function isLocalArtifactsEnabled() {
10
+ // Single cutover: always on, no opt-out.
11
+ return true;
12
+ }
13
+
14
+ function mapCloudStageToLocalStage(stage) {
15
+ const raw = String(stage || '').toLowerCase().trim();
16
+ if (raw === 'plan' || raw === 'execute' || raw === 'verify' || raw === 'resume') return raw;
17
+ if (raw === 'ideation' || raw === 'planning') return 'plan';
18
+ if (raw === 'verification') return 'verify';
19
+ return 'execute';
20
+ }
21
+
22
+ function shortStableHex(value, len = 6) {
23
+ const v = String(value || '');
24
+ if (!v) return crypto.randomBytes(Math.max(2, Math.ceil(len / 2))).toString('hex').slice(0, len);
25
+ return crypto.createHash('sha1').update(v).digest('hex').slice(0, len);
26
+ }
27
+
28
+ function extractCloudProjectIdentity(task) {
29
+ const projectObj = task?.project && typeof task.project === 'object' ? task.project : null;
30
+ const projectId =
31
+ task?.project_id ||
32
+ task?.projectId ||
33
+ projectObj?.id ||
34
+ projectObj?.project_id ||
35
+ null;
36
+
37
+ const projectSlug =
38
+ task?.project_slug ||
39
+ projectObj?.slug ||
40
+ projectObj?.project_slug ||
41
+ (typeof task?.project === 'string' ? task.project : null) ||
42
+ null;
43
+
44
+ const projectName =
45
+ task?.project_name ||
46
+ projectObj?.name ||
47
+ projectObj?.project_name ||
48
+ null;
49
+
50
+ return {
51
+ projectId: projectId ? String(projectId) : null,
52
+ projectSlug: projectSlug ? String(projectSlug) : null,
53
+ projectName: projectName ? String(projectName) : null
54
+ };
55
+ }
56
+
57
+ function extractCloudTaskIdentity(task) {
58
+ const taskId = task?.id ? String(task.id).trim() : '';
59
+ const taskSlug = task?.slug ? String(task.slug).trim() : '';
60
+ return { taskId, taskSlug };
61
+ }
62
+
63
+ async function resolveLocalProjectSlugForCloudTask(storage, task) {
64
+ const { projectId, projectSlug, projectName } = extractCloudProjectIdentity(task);
65
+ const label = projectSlug || projectName || 'cloud';
66
+ const base = storage.slugify(label, { maxLength: 64 });
67
+ const baseState = await storage.readProjectState(base);
68
+
69
+ if (!baseState) {
70
+ return base;
71
+ }
72
+
73
+ const baseCloudId = baseState?.cloud?.project_id ? String(baseState.cloud.project_id) : null;
74
+ if (!baseCloudId && projectId) {
75
+ return base;
76
+ }
77
+ if (baseCloudId && projectId && baseCloudId === projectId) {
78
+ return base;
79
+ }
80
+
81
+ const suffix = projectId ? shortStableHex(projectId, 6) : shortStableHex(`${label}:${process.cwd()}:${Date.now()}`, 6);
82
+ const trimmedBase = storage.slugify(label, { maxLength: 64 - (1 + suffix.length) });
83
+ let candidate = `${trimmedBase}-${suffix}`;
84
+
85
+ for (let i = 0; i < 200; i += 1) {
86
+ const s = await storage.readProjectState(candidate);
87
+ if (!s) return candidate;
88
+ const cid = s?.cloud?.project_id ? String(s.cloud.project_id) : null;
89
+ if (projectId && cid === projectId) return candidate;
90
+ candidate = `${trimmedBase}-${suffix}-${i + 1}`;
91
+ }
92
+
93
+ return `${trimmedBase}-${suffix}-${crypto.randomBytes(2).toString('hex')}`;
94
+ }
95
+
96
+ async function resolveLocalTaskSlugForCloudTask(storage, projectSlug, task) {
97
+ const { taskId, taskSlug: cloudTaskSlug } = extractCloudTaskIdentity(task);
98
+ const label = cloudTaskSlug || taskId;
99
+ const desired = storage.slugify(label, { maxLength: 64 });
100
+
101
+ const existing = await storage.readTaskState(projectSlug, desired);
102
+ if (!existing) return desired;
103
+
104
+ const existingCloudTaskId = existing?.cloud?.task_id ? String(existing.cloud.task_id) : null;
105
+ if (!existingCloudTaskId && taskId) return desired;
106
+ if (existingCloudTaskId && taskId && existingCloudTaskId === taskId) return desired;
107
+
108
+ const suffix = taskId ? shortStableHex(taskId, 6) : shortStableHex(`${label}:${Date.now()}`, 6);
109
+ const trimmedBase = storage.slugify(label, { maxLength: 64 - (1 + suffix.length) });
110
+ let candidate = `${trimmedBase}-${suffix}`;
111
+
112
+ for (let i = 0; i < 200; i += 1) {
113
+ const st = await storage.readTaskState(projectSlug, candidate);
114
+ if (!st) return candidate;
115
+ const cid = st?.cloud?.task_id ? String(st.cloud.task_id) : null;
116
+ if (taskId && cid === taskId) return candidate;
117
+ candidate = `${trimmedBase}-${suffix}-${i + 1}`;
118
+ }
119
+
120
+ return `${trimmedBase}-${suffix}-${crypto.randomBytes(2).toString('hex')}`;
121
+ }
122
+
123
+ function renderWorkingSetMarkdownFromCloudTask(task) {
124
+ const currentPlan = typeof task?.current_plan === 'string' ? task.current_plan.trim() : '';
125
+ const openBlockers = Array.isArray(task?.open_blockers) ? task.open_blockers.filter(Boolean).map(String) : [];
126
+ const nextAction = typeof task?.next_action === 'string' ? task.next_action.trim() : '';
127
+
128
+ if (!currentPlan && openBlockers.length === 0 && !nextAction) return '';
129
+
130
+ const lines = ['# Working Set', ''];
131
+ if (currentPlan) {
132
+ lines.push('## Current Plan', '', currentPlan.trim(), '');
133
+ }
134
+ if (openBlockers.length > 0) {
135
+ lines.push('## Open Blockers', '');
136
+ for (const blocker of openBlockers) lines.push(`- ${blocker}`);
137
+ lines.push('');
138
+ }
139
+ if (nextAction) {
140
+ lines.push('## Next Action', '', nextAction.trim(), '');
141
+ }
142
+ return lines.join('\n').trim() + '\n';
143
+ }
144
+
145
+ function createDaemonArtifactsRecorder({ storage, run, taskId }) {
146
+ const promptParts = [];
147
+ const outputParts = [];
148
+
149
+ const pushSection = (arr, title, text) => {
150
+ if (!text) return;
151
+ arr.push(`# ${title}`.trim(), '');
152
+ arr.push(String(text).trim(), '');
153
+ arr.push('---', '');
154
+ };
155
+
156
+ return {
157
+ get runPath() {
158
+ return run?.paths?.root || null;
159
+ },
160
+ recordPrompt(title, text) {
161
+ pushSection(promptParts, title, text);
162
+ },
163
+ recordOutput(title, text) {
164
+ pushSection(outputParts, title, text);
165
+ },
166
+ async recordEngineTrace(meta, traceEvent) {
167
+ if (!storage || !run?.paths?.events || !traceEvent) return;
168
+ const safeMeta = meta && typeof meta === 'object' ? meta : {};
169
+
170
+ try {
171
+ if (traceEvent.phase === 'start') {
172
+ await storage.appendEvent(
173
+ run.paths.events,
174
+ storage.engineCallStartedEvent({
175
+ trace_id: traceEvent.id,
176
+ label: traceEvent.label,
177
+ provider: safeMeta.provider || null,
178
+ model: safeMeta.model || null,
179
+ role: safeMeta.role || null,
180
+ pid: traceEvent.pid ?? null,
181
+ args: traceEvent.args,
182
+ timeout_ms: traceEvent.timeout_ms,
183
+ started_at: traceEvent.started_at,
184
+ })
185
+ );
186
+ return;
187
+ }
188
+
189
+ if (traceEvent.phase === 'exit' || traceEvent.phase === 'error' || traceEvent.phase === 'timeout') {
190
+ await storage.appendEvent(
191
+ run.paths.events,
192
+ storage.engineCallCompletedEvent({
193
+ trace_id: traceEvent.id,
194
+ label: traceEvent.label,
195
+ provider: safeMeta.provider || null,
196
+ model: safeMeta.model || null,
197
+ role: safeMeta.role || null,
198
+ phase: traceEvent.phase,
199
+ exit_code: traceEvent.exit_code ?? null,
200
+ duration_ms: traceEvent.duration_ms,
201
+ finished_at: traceEvent.finished_at,
202
+ stdout_tail: traceEvent.stdout_tail,
203
+ stderr_tail: traceEvent.stderr_tail,
204
+ error: traceEvent.error,
205
+ })
206
+ );
207
+ }
208
+ } catch {
209
+ // Never let trace/event writing break daemon execution.
210
+ }
211
+ },
212
+ async flush() {
213
+ const promptText = promptParts.join('\n').trim() + '\n';
214
+ const outputText = outputParts.join('\n').trim() + '\n';
215
+
216
+ if (promptText.trim()) {
217
+ const totalBytes = Buffer.byteLength(promptText, 'utf8');
218
+ const event = storage.promptBuiltEvent({ sections: { daemon: totalBytes }, total_bytes: totalBytes });
219
+ await storage.writePrompt(run, promptText, event);
220
+ }
221
+
222
+ if (outputText.trim()) {
223
+ await storage.writeOutput(run, outputText);
224
+ }
225
+
226
+ await storage.appendEvent(run.paths.events, { t: 'DAEMON_ARTIFACTS_FLUSHED', task_id: taskId });
227
+ }
228
+ };
229
+ }
230
+
231
+ function localArtifactKey(filePath) {
232
+ const host = os.hostname();
233
+ const p = String(filePath || '');
234
+ if (!p) return `local://${host}/`;
235
+ return `local://${host}${p.startsWith('/') ? '' : '/'}${p}`;
236
+ }
237
+
238
+ async function buildLocalRunIndexEntry(storage, run, status) {
239
+ if (!storage || !run?.paths?.root) return null;
240
+
241
+ const maxShaBytes = Number(process.env.AGX_LOCAL_ARTIFACT_SHA_MAX_BYTES || 5 * 1024 * 1024);
242
+ const shaMax = Number.isFinite(maxShaBytes) && maxShaBytes > 0 ? maxShaBytes : 5 * 1024 * 1024;
243
+
244
+ const sha256File = async (filePath) => {
245
+ const stat = await fs.promises.stat(filePath);
246
+ if (stat.size > shaMax) {
247
+ return { bytes: stat.size, sha256: undefined };
248
+ }
249
+
250
+ return new Promise((resolve, reject) => {
251
+ const hash = crypto.createHash('sha256');
252
+ const stream = fs.createReadStream(filePath);
253
+ stream.on('data', (chunk) => hash.update(chunk));
254
+ stream.on('error', reject);
255
+ stream.on('end', () => resolve({ bytes: stat.size, sha256: hash.digest('hex') }));
256
+ });
257
+ };
258
+
259
+ const tryRef = async (kind, filePath) => {
260
+ try {
261
+ const { bytes, sha256 } = await sha256File(filePath);
262
+ return { kind, key: localArtifactKey(filePath), bytes, sha256 };
263
+ } catch {
264
+ return null;
265
+ }
266
+ };
267
+
268
+ const meta = await storage.readJsonSafe(run.paths.meta);
269
+ const createdAt = meta?.created_at || new Date().toISOString();
270
+
271
+ const manifest = [];
272
+ manifest.push({ kind: 'artifact', key: localArtifactKey(run.paths.root) });
273
+
274
+ const promptRef = await tryRef('prompt', run.paths.prompt);
275
+ if (promptRef) manifest.push(promptRef);
276
+
277
+ const outputRef = await tryRef('output', run.paths.output);
278
+ if (outputRef) manifest.push(outputRef);
279
+
280
+ const eventsRef = await tryRef('events', run.paths.events);
281
+ if (eventsRef) manifest.push(eventsRef);
282
+
283
+ const decisionRef = await tryRef('artifact', run.paths.decision);
284
+ if (decisionRef) manifest.push({ ...decisionRef, kind: 'artifact' });
285
+
286
+ return {
287
+ run_id: run.run_id,
288
+ stage: run.stage,
289
+ engine: meta?.engine || meta?.provider || meta?.engine_name || run.engine || 'unknown',
290
+ model: meta?.model || null,
291
+ status: String(status || 'unknown'),
292
+ created_at: createdAt,
293
+ artifact_manifest: manifest,
294
+ };
295
+ }
296
+
297
+ function saveAugmentedPrompt(content, debug = false) {
298
+ if (!content) return;
299
+ const CONFIG_DIR = path.join(process.env.HOME || process.env.USERPROFILE, '.agx');
300
+ const AUGMENTED_PROMPT_FILE = path.join(CONFIG_DIR, 'augmented-prompt.txt');
301
+ try {
302
+ fs.mkdirSync(CONFIG_DIR, { recursive: true });
303
+ fs.writeFileSync(AUGMENTED_PROMPT_FILE, `${content}\n`, 'utf8');
304
+ } catch (err) {
305
+ if (debug) {
306
+ console.error(`Failed to write augmented prompt to ${AUGMENTED_PROMPT_FILE}:`, err?.message || err);
307
+ }
308
+ }
309
+ }
310
+
311
+ function extractSection(markdown, heading) {
312
+ if (!markdown) return '';
313
+ const pattern = new RegExp(`^##\\s+${heading}\\s*$`, 'im');
314
+ const match = pattern.exec(markdown);
315
+ if (!match) return '';
316
+ const start = match.index + match[0].length;
317
+ const rest = markdown.slice(start);
318
+ const next = rest.search(/^##\s+/im);
319
+ const section = next === -1 ? rest : rest.slice(0, next);
320
+ return section.trim();
321
+ }
322
+
323
+ function buildFullDaemonPromptContext(task, options = {}) {
324
+ const comments = Array.isArray(options.comments) ? options.comments : [];
325
+ const provider = options.provider || task?.engine || task?.provider || 'unknown';
326
+ const model = options.model || task?.model || null;
327
+ const iterationPrompt = options.iterationPrompt || '';
328
+
329
+ const plan = extractSection(task?.content, 'Plan');
330
+ const todo = extractSection(task?.content, 'Todo') || extractSection(task?.content, 'TODO');
331
+ const checkpoints = extractSection(task?.content, 'Checkpoints');
332
+ const learnings = extractSection(task?.content, 'Learnings');
333
+
334
+ const stageKey = task?.stage || 'unknown';
335
+ const stagePrompt = typeof options.resolveStageObjective === 'function'
336
+ ? options.resolveStageObjective(task, stageKey, '')
337
+ : '';
338
+ const stageRequirement = typeof options.buildStageRequirementPrompt === 'function'
339
+ ? options.buildStageRequirementPrompt({ stage: stageKey, stagePrompt })
340
+ : '';
341
+
342
+ const commentsSection = comments.length > 0
343
+ ? comments.map((c) => `${c.author || 'user'}: ${c.content || ''}`).join('\n')
344
+ : '(no comments yet)';
345
+
346
+ let prompt = `## Cloud Task Context
347
+
348
+ You are continuing a cloud task. Here is the current state:
349
+
350
+ Task ID: ${task?.id || 'unknown'}
351
+ Title: ${task?.title || 'Untitled'}
352
+ Stage: ${task?.stage || 'ideation'}
353
+ Stage Objective: ${stagePrompt}
354
+ Stage Completion Requirement (guidance): ${stageRequirement}
355
+ Provider: ${provider}${model ? `/${model}` : ''}
356
+
357
+ User Request:
358
+ """
359
+ ${task?.title || ''}
360
+ ${task?.content || ''}
361
+ ---
362
+ Task Thread:
363
+ ${commentsSection}
364
+ """
365
+
366
+ ## Extracted State
367
+
368
+ Goal: ${task?.title || 'Untitled'}
369
+ Plan: ${plan || '(none)'}
370
+ Todo: ${todo || '(none)'}
371
+ Checkpoints: ${checkpoints || '(none)'}
372
+ Learnings: ${learnings || '(none)'}
373
+
374
+ ## Instructions
375
+
376
+ Continue working on this task. Use the cloud API to sync progress.
377
+ Respect the Stage Completion Requirement before using [complete] or [done].
378
+
379
+ To update the task:
380
+ - [done] - Mark task complete
381
+ - [complete: message] - Complete current stage
382
+ - [log: message] - Add a log entry
383
+ - [checkpoint: message] - Save progress checkpoint
384
+ - [learn: insight] - Record a learning
385
+ - [plan: text] - Update plan
386
+ - [todo: text] - Update todo list
387
+ `;
388
+
389
+ if (iterationPrompt) {
390
+ prompt += `\nYour specific task for this iteration: ${iterationPrompt}\n`;
391
+ }
392
+
393
+ return prompt;
394
+ }
395
+
396
+ function parseFrontmatterFromContent(content) {
397
+ if (!content) return {};
398
+ const match = content.match(/^---\n([\s\S]*?)\n---\n/);
399
+ if (!match) return {};
400
+ const frontmatter = {};
401
+ const lines = match[1].split('\n');
402
+ for (const line of lines) {
403
+ const colonIndex = line.indexOf(':');
404
+ if (colonIndex > 0) {
405
+ const key = line.slice(0, colonIndex).trim();
406
+ const value = line.slice(colonIndex + 1).trim();
407
+ if (key) frontmatter[key] = value;
408
+ }
409
+ }
410
+ return frontmatter;
411
+ }
412
+
413
+ function normalizeTicketType(value) {
414
+ if (typeof value !== 'string') return 'task';
415
+ const normalized = value.trim().toLowerCase();
416
+ if (!normalized) return 'task';
417
+ if (normalized === 'spike' || normalized === 'spikes') return 'spike';
418
+ return 'task';
419
+ }
420
+
421
+ function resolveTaskTicketType(task) {
422
+ const frontmatter = parseFrontmatterFromContent(task?.content || '');
423
+ const candidates = [
424
+ task?.ticket_type,
425
+ task?.type,
426
+ task?.issue_type,
427
+ task?.kind,
428
+ frontmatter.ticket_type,
429
+ frontmatter.type,
430
+ frontmatter.issue_type,
431
+ frontmatter.kind,
432
+ ];
433
+ for (const candidate of candidates) {
434
+ const resolved = normalizeTicketType(candidate);
435
+ if (resolved === 'spike') return 'spike';
436
+ }
437
+
438
+ const title = String(task?.title || '').trim().toLowerCase();
439
+ if (title.startsWith('spike:') || title.startsWith('[spike]')) {
440
+ return 'spike';
441
+ }
442
+ return 'task';
443
+ }
444
+
445
+ function parseList(value) {
446
+ if (!value || typeof value !== 'string') return [];
447
+ const trimmed = value.trim();
448
+ if (!trimmed) return [];
449
+ if (trimmed.startsWith('[') && trimmed.endsWith(']')) {
450
+ try {
451
+ const parsed = JSON.parse(trimmed);
452
+ if (Array.isArray(parsed)) {
453
+ return parsed.map((v) => String(v).trim()).filter(Boolean);
454
+ }
455
+ } catch { }
456
+ }
457
+ return trimmed
458
+ .split(',')
459
+ .map((v) => v.trim())
460
+ .filter(Boolean);
461
+ }
462
+
463
+ module.exports = {
464
+ isLocalArtifactsEnabled,
465
+ mapCloudStageToLocalStage,
466
+ extractCloudProjectIdentity,
467
+ extractCloudTaskIdentity,
468
+ resolveLocalProjectSlugForCloudTask,
469
+ resolveLocalTaskSlugForCloudTask,
470
+ renderWorkingSetMarkdownFromCloudTask,
471
+ createDaemonArtifactsRecorder,
472
+ buildLocalRunIndexEntry,
473
+ saveAugmentedPrompt,
474
+ buildFullDaemonPromptContext,
475
+ resolveTaskTicketType,
476
+ parseList,
477
+ };
478
+
@@ -3,6 +3,7 @@
3
3
 
4
4
  const { c } = require('../ui/colors');
5
5
  const { loadConfig, saveConfig, prompt } = require('./configStore');
6
+ const { loadCloudConfigFile, saveCloudConfigFile, DEFAULT_API_URL } = require('../config/cloudConfig');
6
7
  const {
7
8
  PROVIDERS,
8
9
  detectProviders,
@@ -177,6 +178,9 @@ async function showConfigStatus() {
177
178
  if (config?.settingsMeta?.changedAt) {
178
179
  console.log(` Settings changed: ${c.dim}${config.settingsMeta.changedAt}${c.reset} (${config.settingsMeta.provenance || 'unknown'})`);
179
180
  }
181
+ const cloudConfig = loadCloudConfigFile();
182
+ const cloudUrl = cloudConfig?.apiUrl || DEFAULT_API_URL;
183
+ console.log(` Backend URL: ${c.cyan}${cloudUrl}${c.reset}`);
180
184
  } else {
181
185
  console.log(` ${c.yellow}Not configured${c.reset} - run ${c.cyan}agx init${c.reset}`);
182
186
  }
@@ -195,8 +199,9 @@ async function runConfigMenu() {
195
199
  console.log(` ${c.cyan}1${c.reset}) Install a new provider`);
196
200
  console.log(` ${c.cyan}2${c.reset}) Login to a provider`);
197
201
  console.log(` ${c.cyan}3${c.reset}) Change default provider`);
198
- console.log(` ${c.cyan}4${c.reset}) Show status`);
199
- console.log(` ${c.cyan}5${c.reset}) Run full setup wizard`);
202
+ console.log(` ${c.cyan}4${c.reset}) Set backend URL`);
203
+ console.log(` ${c.cyan}5${c.reset}) Show status`);
204
+ console.log(` ${c.cyan}6${c.reset}) Run full setup wizard`);
200
205
  console.log(` ${c.cyan}q${c.reset}) Quit`);
201
206
 
202
207
  const choice = await prompt('\nChoice: ');
@@ -256,10 +261,24 @@ async function runConfigMenu() {
256
261
  }
257
262
  break;
258
263
  }
259
- case '4':
260
- await showConfigStatus();
264
+ case '4': {
265
+ const cloudConfig = loadCloudConfigFile();
266
+ const currentUrl = cloudConfig?.apiUrl || DEFAULT_API_URL;
267
+ console.log(`\n Current backend URL: ${c.cyan}${currentUrl}${c.reset}`);
268
+ const newUrl = await prompt(`\n New URL [${c.dim}${currentUrl}${c.reset}]: `);
269
+ if (newUrl && newUrl.trim()) {
270
+ const updated = { ...(cloudConfig || {}), apiUrl: newUrl.trim() };
271
+ saveCloudConfigFile(updated);
272
+ console.log(`\n${c.green}✓${c.reset} Backend URL set to ${c.cyan}${newUrl.trim()}${c.reset}`);
273
+ } else {
274
+ console.log(`\n${c.dim}Keeping current URL${c.reset}`);
275
+ }
261
276
  break;
277
+ }
262
278
  case '5':
279
+ await showConfigStatus();
280
+ break;
281
+ case '6':
263
282
  await runOnboarding();
264
283
  break;
265
284
  case 'q':