crewly 1.20.349 → 1.20.351

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 (70) hide show
  1. package/config/skills/agent/core/complete-task/SKILL.md +6 -5
  2. package/config/skills/agent/core/complete-task/execute.sh +13 -4
  3. package/config/skills/agent/core/complete-task/execute.test.sh +7 -0
  4. package/config/skills/agent/core/report-status/SKILL.md +3 -3
  5. package/config/skills/agent/core/report-status/execute.sh +9 -5
  6. package/config/skills/agent/core/trace-read/SKILL.md +14 -0
  7. package/config/skills/agent/core/trace-read/execute.sh +25 -2
  8. package/config/skills/orchestrator/complete-task/SKILL.md +1 -1
  9. package/config/skills/orchestrator/complete-task/execute.sh +3 -2
  10. package/config/skills/orchestrator/render-verdict/SKILL.md +2 -1
  11. package/config/skills/orchestrator/render-verdict/execute.sh +8 -4
  12. package/config/skills/team-leader/verify-output/SKILL.md +8 -3
  13. package/config/skills/team-leader/verify-output/execute.sh +4 -3
  14. package/config/skills/team-leader/verify-output/execute.test.sh +2 -0
  15. package/dist/backend/backend/src/constants.d.ts +30 -5
  16. package/dist/backend/backend/src/constants.d.ts.map +1 -1
  17. package/dist/backend/backend/src/constants.js +32 -5
  18. package/dist/backend/backend/src/constants.js.map +1 -1
  19. package/dist/backend/backend/src/controllers/request/request.controller.d.ts +12 -0
  20. package/dist/backend/backend/src/controllers/request/request.controller.d.ts.map +1 -1
  21. package/dist/backend/backend/src/controllers/request/request.controller.js +48 -0
  22. package/dist/backend/backend/src/controllers/request/request.controller.js.map +1 -1
  23. package/dist/backend/backend/src/controllers/request/request.routes.d.ts +1 -0
  24. package/dist/backend/backend/src/controllers/request/request.routes.d.ts.map +1 -1
  25. package/dist/backend/backend/src/controllers/request/request.routes.js +4 -1
  26. package/dist/backend/backend/src/controllers/request/request.routes.js.map +1 -1
  27. package/dist/backend/backend/src/controllers/task-pool/task-pool.controller.d.ts +8 -5
  28. package/dist/backend/backend/src/controllers/task-pool/task-pool.controller.d.ts.map +1 -1
  29. package/dist/backend/backend/src/controllers/task-pool/task-pool.controller.js +91 -16
  30. package/dist/backend/backend/src/controllers/task-pool/task-pool.controller.js.map +1 -1
  31. package/dist/backend/backend/src/services/event-bus/event-to-workitem-bridge.service.d.ts.map +1 -1
  32. package/dist/backend/backend/src/services/event-bus/event-to-workitem-bridge.service.js +3 -1
  33. package/dist/backend/backend/src/services/event-bus/event-to-workitem-bridge.service.js.map +1 -1
  34. package/dist/backend/backend/src/services/messaging/agent-ask-ledger.service.d.ts +6 -0
  35. package/dist/backend/backend/src/services/messaging/agent-ask-ledger.service.d.ts.map +1 -1
  36. package/dist/backend/backend/src/services/messaging/agent-ask-ledger.service.js +9 -0
  37. package/dist/backend/backend/src/services/messaging/agent-ask-ledger.service.js.map +1 -1
  38. package/dist/backend/backend/src/services/task-pool/completion-evidence.service.d.ts +74 -5
  39. package/dist/backend/backend/src/services/task-pool/completion-evidence.service.d.ts.map +1 -1
  40. package/dist/backend/backend/src/services/task-pool/completion-evidence.service.js +187 -21
  41. package/dist/backend/backend/src/services/task-pool/completion-evidence.service.js.map +1 -1
  42. package/dist/backend/backend/src/services/v3/request-whereabouts.service.d.ts +88 -0
  43. package/dist/backend/backend/src/services/v3/request-whereabouts.service.d.ts.map +1 -0
  44. package/dist/backend/backend/src/services/v3/request-whereabouts.service.js +193 -0
  45. package/dist/backend/backend/src/services/v3/request-whereabouts.service.js.map +1 -0
  46. package/dist/backend/backend/src/types/v2/completion-evidence.types.d.ts +16 -0
  47. package/dist/backend/backend/src/types/v2/completion-evidence.types.d.ts.map +1 -1
  48. package/dist/backend/backend/src/types/v2/completion-evidence.types.js.map +1 -1
  49. package/dist/backend/backend/src/types/v2/work-item.types.d.ts +6 -0
  50. package/dist/backend/backend/src/types/v2/work-item.types.d.ts.map +1 -1
  51. package/dist/backend/backend/src/types/v2/work-item.types.js +6 -0
  52. package/dist/backend/backend/src/types/v2/work-item.types.js.map +1 -1
  53. package/dist/backend/build-info.json +2 -2
  54. package/dist/cli/backend/src/constants.d.ts +30 -5
  55. package/dist/cli/backend/src/constants.d.ts.map +1 -1
  56. package/dist/cli/backend/src/constants.js +32 -5
  57. package/dist/cli/backend/src/constants.js.map +1 -1
  58. package/dist/cli/backend/src/services/messaging/agent-ask-ledger.service.d.ts +6 -0
  59. package/dist/cli/backend/src/services/messaging/agent-ask-ledger.service.d.ts.map +1 -1
  60. package/dist/cli/backend/src/services/messaging/agent-ask-ledger.service.js +9 -0
  61. package/dist/cli/backend/src/services/messaging/agent-ask-ledger.service.js.map +1 -1
  62. package/dist/cli/backend/src/types/v2/work-item.types.d.ts +6 -0
  63. package/dist/cli/backend/src/types/v2/work-item.types.d.ts.map +1 -1
  64. package/dist/cli/backend/src/types/v2/work-item.types.js +6 -0
  65. package/dist/cli/backend/src/types/v2/work-item.types.js.map +1 -1
  66. package/frontend/dist/assets/{index-36b1788c.js → index-b1fc60ea.js} +65 -65
  67. package/frontend/dist/index.html +1 -1
  68. package/package.json +1 -1
  69. package/packages/crewly-agent/src/runtime/tool-registry.test.ts +26 -0
  70. package/packages/crewly-agent/src/runtime/tool-registry.ts +31 -4
@@ -1 +1 @@
1
- {"version":3,"file":"completion-evidence.service.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/task-pool/completion-evidence.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAOH,OAAO,EAGL,KAAK,eAAe,EACpB,KAAK,kBAAkB,EACxB,MAAM,6CAA6C,CAAC;AACrD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mCAAmC,CAAC;AAIlE,2DAA2D;AAC3D,MAAM,MAAM,uBAAuB,GAAG,MAAM,GAAG,SAAS,CAAC;AAEzD,4DAA4D;AAC5D,MAAM,MAAM,gBAAgB,GACxB;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,GAAG,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC9D;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,kBAAkB,CAAA;CAAE,GACjE;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,EAAE,kBAAkB,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAE5E,4CAA4C;AAC5C,MAAM,WAAW,oBAAoB;IACnC,gEAAgE;IAChE,IAAI,EAAE,uBAAuB,CAAC;IAC9B;;;OAGG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,oEAAoE;IACpE,UAAU,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACxD,iEAAiE;IACjE,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;GAOG;AACH,wBAAgB,8BAA8B,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,uBAAuB,CAI5G;AAiBD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,GAAG,IAAI,GAAG,MAAM,EAAE,CActF;AAiED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,eAAe,EAAE,GAAG,MAAM,CAEhE;AAED;;;;;;;;;GASG;AACH,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAAG,MAAM,CAS/F;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,gBAAgB,CACpC,WAAW,EAAE,OAAO,EACpB,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,GAAG,IAAI,EAC3C,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,gBAAgB,CAAC,CAwD3B"}
1
+ {"version":3,"file":"completion-evidence.service.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/task-pool/completion-evidence.service.ts"],"names":[],"mappings":"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"}
@@ -5,7 +5,8 @@
5
5
  * touches the WorkItem. The decision is one of:
6
6
  *
7
7
  * - `reject` (400): malformed evidence, an artifact path that does not exist
8
- * (or a relative path with no project/worktree to resolve it against), a
8
+ * (or a relative path with no project/worktree to resolve it against), an
9
+ * empty file, a file last modified before the WorkItem was created (#1313), a
9
10
  * command that exited non-zero, or — in `enforce` mode — no evidence.
10
11
  * - `block`: a `blocked` entry. The worker could not finish, so the item is
11
12
  * recorded as blocked (same path as `POST /task-pool/block/:id`), not done.
@@ -23,6 +24,23 @@ import { fileURLToPath } from 'url';
23
24
  import { COMPLETION_EVIDENCE_CONSTANTS, WORKTREE_CONSTANTS } from '../../constants.js';
24
25
  import { validateCompletionEvidence, } from '../../types/v2/completion-evidence.types.js';
25
26
  const C = COMPLETION_EVIDENCE_CONSTANTS;
27
+ /**
28
+ * Whether a WorkItem of this type must carry evidence to complete (#1312).
29
+ * Deliverables (delegate, project_task, review) and items with no type do;
30
+ * harness bookkeeping types (triage, replans, retros, notifications) do not.
31
+ *
32
+ * @param type - The WorkItem's type, if known
33
+ * @returns True when a completion without evidence is refused in enforce mode
34
+ *
35
+ * @example
36
+ * ```typescript
37
+ * evidenceRequiredFor('delegate'); // true
38
+ * evidenceRequiredFor('goal_replan'); // false
39
+ * ```
40
+ */
41
+ export function evidenceRequiredFor(type) {
42
+ return !type || C.REQUIRED_FOR_TYPES.includes(type);
43
+ }
26
44
  /**
27
45
  * The rollout mode in effect: `CREWLY_EVIDENCE_MODE` when it is `warn` or
28
46
  * `enforce`, else {@link COMPLETION_EVIDENCE_CONSTANTS.EVIDENCE_ENFORCEMENT_MODE}.
@@ -38,18 +56,18 @@ export function resolveEvidenceEnforcementMode(env = process.env) {
38
56
  return C.EVIDENCE_ENFORCEMENT_MODE;
39
57
  }
40
58
  /**
41
- * Default existence check.
59
+ * Default file check.
42
60
  *
43
61
  * @param p - Absolute path
44
- * @returns True when something exists at `p`
62
+ * @returns Its stat, or null when nothing exists at `p`
45
63
  */
46
- async function defaultPathExists(p) {
64
+ async function defaultStatPath(p) {
47
65
  try {
48
- await fs.stat(p);
49
- return true;
66
+ const st = await fs.stat(p);
67
+ return { isDirectory: st.isDirectory(), sizeBytes: st.size, mtimeMs: st.mtimeMs };
50
68
  }
51
69
  catch {
52
- return false;
70
+ return null;
53
71
  }
54
72
  }
55
73
  /**
@@ -77,12 +95,14 @@ export function artifactBaseDirs(workItem) {
77
95
  return [...new Set(bases)];
78
96
  }
79
97
  /**
80
- * Check one artifact: http(s) URLs pass without fetching; local paths must exist.
98
+ * Check one artifact: http(s) URLs pass without fetching; local paths must
99
+ * exist, and a file must be non-empty and modified no earlier than
100
+ * `notBeforeMs` (#1313). Directories only need to exist.
81
101
  *
82
102
  * @param artifact - The artifact entry
83
103
  * @param bases - Directories for relative paths
84
- * @param options - Existence check and home directory
85
- * @returns ok, or the problem with this artifact
104
+ * @param options - File check, home directory, and the oldest acceptable mtime (null: no age check)
105
+ * @returns ok (with the stat of a local artifact), or the problem with this artifact
86
106
  */
87
107
  async function checkArtifact(artifact, bases, options) {
88
108
  const raw = artifact.path;
@@ -112,9 +132,8 @@ async function checkArtifact(artifact, bases, options) {
112
132
  local = raw;
113
133
  }
114
134
  if (path.isAbsolute(local)) {
115
- return (await options.pathExists(local))
116
- ? { ok: true }
117
- : { ok: false, code: C.CODES.ARTIFACT_NOT_FOUND, problem: `"${raw}" does not exist` };
135
+ const st = await options.statPath(local);
136
+ return st ? judgeFile(raw, st, options.notBeforeMs) : { ok: false, code: C.CODES.ARTIFACT_NOT_FOUND, problem: `"${raw}" does not exist` };
118
137
  }
119
138
  if (bases.length === 0) {
120
139
  return {
@@ -124,8 +143,9 @@ async function checkArtifact(artifact, bases, options) {
124
143
  };
125
144
  }
126
145
  for (const base of bases) {
127
- if (await options.pathExists(path.resolve(base, local)))
128
- return { ok: true };
146
+ const st = await options.statPath(path.resolve(base, local));
147
+ if (st)
148
+ return judgeFile(raw, st, options.notBeforeMs);
129
149
  }
130
150
  return {
131
151
  ok: false,
@@ -133,6 +153,40 @@ async function checkArtifact(artifact, bases, options) {
133
153
  problem: `"${raw}" does not exist (looked in ${bases.join(', ')})`,
134
154
  };
135
155
  }
156
+ /**
157
+ * An existing local artifact: a file must have content and be newer than the
158
+ * WorkItem (a placeholder or an earlier task's output is not evidence).
159
+ *
160
+ * @param raw - The path as sent
161
+ * @param st - Its stat
162
+ * @param notBeforeMs - Oldest acceptable mtime, or null for no age check
163
+ * @returns The check
164
+ */
165
+ function judgeFile(raw, st, notBeforeMs) {
166
+ if (st.isDirectory)
167
+ return { ok: true, stat: st };
168
+ if (st.sizeBytes <= 0)
169
+ return { ok: false, code: C.CODES.ARTIFACT_EMPTY, problem: `"${raw}" is empty (0 bytes)` };
170
+ if (notBeforeMs !== null && st.mtimeMs < notBeforeMs) {
171
+ return {
172
+ ok: false,
173
+ code: C.CODES.ARTIFACT_STALE,
174
+ problem: `"${raw}" was last changed ${new Date(st.mtimeMs).toISOString()}, before this WorkItem existed, so it is not this task's output; attach what this task produced, or a command that shows the work`,
175
+ };
176
+ }
177
+ return { ok: true, stat: st };
178
+ }
179
+ /**
180
+ * The oldest mtime a file artifact may have: the WorkItem's creation minus
181
+ * {@link COMPLETION_EVIDENCE_CONSTANTS.STALE_GRACE_MS}.
182
+ *
183
+ * @param workItem - The WorkItem (null or no createdAt: no age check)
184
+ * @returns Epoch ms, or null
185
+ */
186
+ export function artifactNotBefore(workItem) {
187
+ const created = workItem?.createdAt ? Date.parse(workItem.createdAt) : NaN;
188
+ return Number.isFinite(created) ? created - C.STALE_GRACE_MS : null;
189
+ }
136
190
  /**
137
191
  * The blocked reason recorded on the WorkItem for `blocked` entries.
138
192
  *
@@ -156,11 +210,16 @@ export function describeEvidenceForReviewer(output) {
156
210
  const v = validateCompletionEvidence(output?.['evidence']);
157
211
  const evidence = v.ok ? v.evidence : [];
158
212
  if (evidence.length === 0) {
159
- return 'Evidence: NONE — marked done without artifacts or commands (accepted only in evidence warn mode). Check the work directly or send it back asking for evidence.';
213
+ return 'Evidence: NONE — marked done without artifacts or commands (accepted only in evidence warn mode). Check the work directly (a check with "entry": null) or send it back asking for evidence.';
160
214
  }
161
215
  const artifacts = evidence.filter((e) => e.type === 'artifact').length;
162
216
  const commands = evidence.filter((e) => e.type === 'command').length;
163
- return `Evidence: ${artifacts} artifact(s), ${commands} command(s) — read them first (verify-output shows them, or GET /api/task-pool/items/<id> → output.evidence).`;
217
+ // Numbered so the reviewer's checks can name each entry (#1314).
218
+ const lines = evidence.map((e, i) => ` [${i}] ${e.type === 'artifact' ? `artifact ${e.path}` : e.type === 'command' ? `command \`${e.command}\` → exit ${e.exitCode}` : `blocked at ${e.step}`}`.slice(0, 300));
219
+ const shown = lines.slice(0, C.REVIEW_LISTED_ENTRIES);
220
+ if (lines.length > shown.length)
221
+ shown.push(` … and ${lines.length - shown.length} more (verify-output lists them all)`);
222
+ return `Evidence: ${artifacts} artifact(s), ${commands} command(s) — open or re-run them and record each check:\n${shown.join('\n')}`;
164
223
  }
165
224
  /**
166
225
  * Decide what a completion does from its evidence block.
@@ -189,12 +248,12 @@ export async function decideCompletion(rawEvidence, workItem, options) {
189
248
  action: 'reject',
190
249
  status: 400,
191
250
  code: C.CODES.MISSING,
192
- error: `complete requires evidence: "done" needs at least one artifact that exists or command with its exit code. ${C.SHAPE_HINT}`,
251
+ error: `complete requires evidence: "done" needs at least one artifact that exists or command with its exit code. Nothing was completed. ${C.SHAPE_HINT}`,
193
252
  };
194
253
  }
195
254
  return {
196
255
  action: 'complete',
197
- warning: `Completed WITHOUT evidence. This is accepted for now but will be rejected in the next release. ${C.SHAPE_HINT}`,
256
+ warning: `Completed WITHOUT evidence. Accepted only because ${C.ENV_MODE}=warn; by default this is rejected. ${C.SHAPE_HINT}`,
198
257
  };
199
258
  }
200
259
  const validation = validateCompletionEvidence(rawEvidence);
@@ -215,7 +274,11 @@ export async function decideCompletion(rawEvidence, workItem, options) {
215
274
  };
216
275
  }
217
276
  const bases = artifactBaseDirs(workItem);
218
- const fsOptions = { pathExists: options.pathExists ?? defaultPathExists, homeDir: options.homeDir ?? os.homedir() };
277
+ const fsOptions = {
278
+ statPath: options.statPath ?? defaultStatPath,
279
+ homeDir: options.homeDir ?? os.homedir(),
280
+ notBeforeMs: artifactNotBefore(workItem),
281
+ };
219
282
  const problems = [];
220
283
  for (let i = 0; i < evidence.length; i++) {
221
284
  const e = evidence[i];
@@ -224,15 +287,118 @@ export async function decideCompletion(rawEvidence, workItem, options) {
224
287
  const check = await checkArtifact(e, bases, fsOptions);
225
288
  if (!check.ok)
226
289
  problems.push({ code: check.code, text: `evidence[${i}] artifact ${check.problem}` });
290
+ // Recorded so the reviewer sees what was checked (#1313).
291
+ else if (check.stat && !check.stat.isDirectory)
292
+ evidence[i] = { ...e, sizeBytes: check.stat.sizeBytes, mtime: new Date(check.stat.mtimeMs).toISOString() };
227
293
  }
228
294
  if (problems.length > 0) {
229
295
  return {
230
296
  action: 'reject',
231
297
  status: 400,
232
298
  code: problems[0].code,
233
- error: `${problems.map((p) => p.text).join('; ')}. Artifacts must exist on this machine (or be http(s) URLs).`,
299
+ error: `${problems.map((p) => p.text).join('; ')}. Artifacts must exist on this machine (or be http(s) URLs), and files must be non-empty and made for this task.`,
234
300
  };
235
301
  }
236
302
  return { action: 'complete', evidence };
237
303
  }
304
+ /**
305
+ * Why one raw check entry is not a {@link ReviewCheck}, or null when it is.
306
+ *
307
+ * @param raw - One entry of `result.checks`
308
+ * @param evidenceCount - Number of entries in the worker's evidence
309
+ * @returns A problem description, or null
310
+ */
311
+ function checkProblem(raw, evidenceCount) {
312
+ if (!raw || typeof raw !== 'object' || Array.isArray(raw))
313
+ return 'must be an object';
314
+ const c = raw;
315
+ const entry = c['entry'];
316
+ if (entry !== null && entry !== undefined) {
317
+ if (typeof entry !== 'number' || !Number.isInteger(entry))
318
+ return '"entry" must be an evidence index or null';
319
+ if (entry < 0 || entry >= evidenceCount)
320
+ return `"entry" ${entry} is not in the worker's evidence (it has ${evidenceCount} entr${evidenceCount === 1 ? 'y' : 'ies'})`;
321
+ }
322
+ if (typeof c['did'] !== 'string' || !c['did'].trim())
323
+ return '"did" must say what you did';
324
+ if (c['did'].length > C.MAX_FIELD_CHARS)
325
+ return `"did" is longer than ${C.MAX_FIELD_CHARS} characters`;
326
+ if (!C.CHECK_OUTCOMES.includes(c['outcome']))
327
+ return '"outcome" must be "pass" or "fail"';
328
+ return null;
329
+ }
330
+ /**
331
+ * Decide whether a reviewer's accept of a worker's delivery may go through
332
+ * (#1314): it must record, per worker evidence entry it looked at, what it
333
+ * did. A rubber-stamp accept was indistinguishable from a real check.
334
+ *
335
+ * Rules (rejections are not affected; only accepts are checked):
336
+ * - `checks` is a non-empty array of `{entry, did, outcome}`;
337
+ * - when the worker sent evidence, at least one check names an entry of it;
338
+ * without evidence, a check with `entry: null` (a direct look) is enough;
339
+ * - a check with `outcome: "fail"` cannot be accepted — send it back.
340
+ *
341
+ * In `warn` mode a missing record is accepted and flagged `unchecked`;
342
+ * malformed or failed checks are refused in both modes.
343
+ *
344
+ * @param rawChecks - `body.result.checks` as received (any value)
345
+ * @param workerEvidence - The worker's `output.evidence` (any value)
346
+ * @param mode - Rollout mode ({@link resolveEvidenceEnforcementMode})
347
+ * @returns The decision; never throws
348
+ *
349
+ * @example
350
+ * ```typescript
351
+ * const d = decideReviewAccept(result.checks, source.output?.evidence, resolveEvidenceEnforcementMode());
352
+ * if (d.action === 'reject') return res.status(d.status).json({ error: d.error, code: d.code });
353
+ * ```
354
+ */
355
+ export function decideReviewAccept(rawChecks, workerEvidence, mode) {
356
+ const ev = validateCompletionEvidence(workerEvidence);
357
+ const evidenceCount = ev.ok ? ev.evidence.length : 0;
358
+ const missing = rawChecks === undefined || rawChecks === null || (Array.isArray(rawChecks) && rawChecks.length === 0);
359
+ if (missing) {
360
+ const what = evidenceCount > 0 ? `the worker sent ${evidenceCount} evidence entr${evidenceCount === 1 ? 'y' : 'ies'}` : 'the worker sent no evidence';
361
+ if (mode === 'warn') {
362
+ return { action: 'accept_unchecked', warning: `Accepted WITHOUT a check record (${what}); flagged unchecked. ${C.CHECKS_HINT}` };
363
+ }
364
+ return {
365
+ action: 'reject',
366
+ status: 400,
367
+ code: C.CODES.REVIEW_UNCHECKED,
368
+ error: `accepting a review requires a record of what you checked; ${what}. Nothing was accepted. ${C.CHECKS_HINT}`,
369
+ };
370
+ }
371
+ if (!Array.isArray(rawChecks)) {
372
+ return { action: 'reject', status: 400, code: C.CODES.REVIEW_CHECKS_MALFORMED, error: `checks must be an array. ${C.CHECKS_HINT}` };
373
+ }
374
+ if (rawChecks.length > C.MAX_ENTRIES) {
375
+ return { action: 'reject', status: 400, code: C.CODES.REVIEW_CHECKS_MALFORMED, error: `checks has ${rawChecks.length} entries; at most ${C.MAX_ENTRIES} are accepted` };
376
+ }
377
+ const checks = [];
378
+ for (let i = 0; i < rawChecks.length; i++) {
379
+ const problem = checkProblem(rawChecks[i], evidenceCount);
380
+ if (problem)
381
+ return { action: 'reject', status: 400, code: C.CODES.REVIEW_CHECKS_MALFORMED, error: `checks[${i}]: ${problem}. ${C.CHECKS_HINT}` };
382
+ const c = rawChecks[i];
383
+ checks.push({ entry: typeof c['entry'] === 'number' ? c['entry'] : null, did: c['did'].trim(), outcome: c['outcome'] });
384
+ }
385
+ if (evidenceCount > 0 && !checks.some((c) => c.entry !== null)) {
386
+ return {
387
+ action: 'reject',
388
+ status: 400,
389
+ code: C.CODES.REVIEW_UNCHECKED,
390
+ error: `the worker sent ${evidenceCount} evidence entr${evidenceCount === 1 ? 'y' : 'ies'} but no check names one: open or re-run at least one and record it. ${C.CHECKS_HINT}`,
391
+ };
392
+ }
393
+ const failed = checks.flatMap((c, i) => (c.outcome === 'fail' ? [`checks[${i}] (${c.did})`] : []));
394
+ if (failed.length > 0) {
395
+ return {
396
+ action: 'reject',
397
+ status: 400,
398
+ code: C.CODES.REVIEW_CHECK_FAILED,
399
+ error: `${failed.join('; ')} failed: a failed check cannot be accepted. Send it back with {"verdict":"rejected","feedback":"<what is wrong>"}.`,
400
+ };
401
+ }
402
+ return { action: 'accept', checks };
403
+ }
238
404
  //# sourceMappingURL=completion-evidence.service.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"completion-evidence.service.js","sourceRoot":"","sources":["../../../../../../backend/src/services/task-pool/completion-evidence.service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"completion-evidence.service.js","sourceRoot":"","sources":["../../../../../../backend/src/services/task-pool/completion-evidence.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Where a Request is right now: who holds it, doing what, since when.
3
+ *
4
+ * On 2026-10-14 an owner request went Ella → Pia → Dex, Dex finished, and
5
+ * the result sat in Dex's terminal for seven hours. Reconstructing that took
6
+ * reading three agents' transcripts. Everything needed was already recorded:
7
+ * the Request's open WorkItems (holder = `target`, time = `statusChangedAt`)
8
+ * and the agent ask ledger (a holder that handed the work to another agent
9
+ * with a plain message). This module joins them into one answer.
10
+ *
11
+ * Pure: the caller passes the Request, its WorkItems and the open asks.
12
+ *
13
+ * @module services/v3/request-whereabouts.service
14
+ */
15
+ import type { Request } from '../../types/v2/request.types.js';
16
+ import type { WorkItem } from '../../types/v2/work-item.types.js';
17
+ import type { AgentAsk } from '../messaging/agent-ask-ledger.service.js';
18
+ /** What a holder is doing with the request. */
19
+ export type HolderState = 'working' | 'queued' | 'blocked' | 'awaiting_review' | 'waiting_on_agent' | 'waiting_on_owner' | 'handling';
20
+ /** One place the request is held. */
21
+ export interface RequestHolder {
22
+ /** Agent session, or `owner` */
23
+ session: string;
24
+ /** What it is doing */
25
+ state: HolderState;
26
+ /** Since when (ISO 8601) */
27
+ since: string;
28
+ /** How long, in ms, at `now` */
29
+ forMs: number;
30
+ /** The WorkItem behind it, when there is one */
31
+ workItemId?: string;
32
+ /** That WorkItem's title, or the ask excerpt */
33
+ what?: string;
34
+ /** Who handed it here (an ask's sender) */
35
+ from?: string;
36
+ /** Why it is blocked */
37
+ blockedReason?: string;
38
+ }
39
+ /** The answer to "where is this request now?". */
40
+ export interface RequestWhereabouts {
41
+ requestId: string;
42
+ ticketNumber?: number;
43
+ title: string;
44
+ status: Request['status'];
45
+ /** True when the request is done or cancelled */
46
+ finished: boolean;
47
+ /** When it finished (ISO), if it did */
48
+ finishedAt?: string;
49
+ /** Where it is held now, longest-held first */
50
+ holders: RequestHolder[];
51
+ /** One line for a person */
52
+ summary: string;
53
+ }
54
+ /**
55
+ * Format a duration for a person: "45m", "2h 10m", "3d 4h".
56
+ *
57
+ * @param ms - Duration
58
+ * @returns Short text
59
+ */
60
+ export declare function formatDuration(ms: number): string;
61
+ /**
62
+ * Compute where a request is now.
63
+ *
64
+ * Rules:
65
+ * - finished request → no holders;
66
+ * - each open WorkItem of the request (by `requestId` or `workItemIds`) is a
67
+ * holder: its `target` (running/queued/blocked) or, once the worker is done,
68
+ * its reviewer (awaiting_review). Review items themselves are folded in;
69
+ * - a holder that handed the work to another agent with a plain message (an
70
+ * open ask newer than the holder's own start) is `waiting_on_agent`, and
71
+ * the asked agent is a holder too (followed up to {@link MAX_ASK_HOPS});
72
+ * - no open WorkItem: the request's `assignee`/`ownerAgent` handles it, or the
73
+ * owner when the request waits on a confirmation or follow-up.
74
+ *
75
+ * @param request - The Request
76
+ * @param workItems - WorkItems to search (the pool, or a subset)
77
+ * @param openAsks - Open agent-to-agent asks (from the ledger)
78
+ * @param now - Current time (epoch ms)
79
+ * @returns The whereabouts
80
+ *
81
+ * @example
82
+ * ```typescript
83
+ * const w = computeWhereabouts(request, await pool.getAllItems(), ledger.openAsks(), Date.now());
84
+ * w.summary; // "With Dex (working on "Replicate the video") for 2h 10m"
85
+ * ```
86
+ */
87
+ export declare function computeWhereabouts(request: Request, workItems: WorkItem[], openAsks: AgentAsk[], now: number): RequestWhereabouts;
88
+ //# sourceMappingURL=request-whereabouts.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-whereabouts.service.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/v3/request-whereabouts.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iCAAiC,CAAC;AAC/D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mCAAmC,CAAC;AAElE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0CAA0C,CAAC;AAEzE,+CAA+C;AAC/C,MAAM,MAAM,WAAW,GACpB,SAAS,GACT,QAAQ,GACR,SAAS,GACT,iBAAiB,GACjB,kBAAkB,GAClB,kBAAkB,GAClB,UAAU,CAAC;AAEd,qCAAqC;AACrC,MAAM,WAAW,aAAa;IAC7B,gCAAgC;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,uBAAuB;IACvB,KAAK,EAAE,WAAW,CAAC;IACnB,4BAA4B;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,gCAAgC;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,gDAAgD;IAChD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gDAAgD;IAChD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,2CAA2C;IAC3C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,wBAAwB;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,kDAAkD;AAClD,MAAM,WAAW,kBAAkB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC1B,iDAAiD;IACjD,QAAQ,EAAE,OAAO,CAAC;IAClB,wCAAwC;IACxC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,+CAA+C;IAC/C,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,4BAA4B;IAC5B,OAAO,EAAE,MAAM,CAAC;CAChB;AAcD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAMjD;AAsBD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,kBAAkB,CAwEjI"}
@@ -0,0 +1,193 @@
1
+ /**
2
+ * Where a Request is right now: who holds it, doing what, since when.
3
+ *
4
+ * On 2026-10-14 an owner request went Ella → Pia → Dex, Dex finished, and
5
+ * the result sat in Dex's terminal for seven hours. Reconstructing that took
6
+ * reading three agents' transcripts. Everything needed was already recorded:
7
+ * the Request's open WorkItems (holder = `target`, time = `statusChangedAt`)
8
+ * and the agent ask ledger (a holder that handed the work to another agent
9
+ * with a plain message). This module joins them into one answer.
10
+ *
11
+ * Pure: the caller passes the Request, its WorkItems and the open asks.
12
+ *
13
+ * @module services/v3/request-whereabouts.service
14
+ */
15
+ import { WORK_ITEM_REVIEWER_KEY } from '../../types/v2/work-item.types.js';
16
+ /** WorkItem statuses that still hold a request. */
17
+ const OPEN_STATUSES = new Set(['queued', 'scheduled', 'proposed', 'accepted', 'running', 'blocked', 'escalated', 'done_by_worker']);
18
+ /** Request statuses that wait on the owner. */
19
+ const OWNER_WAIT_STATUSES = new Set(['waiting_confirmation', 'awaiting_followup']);
20
+ /** Most hops followed along agent-to-agent asks. */
21
+ const MAX_ASK_HOPS = 4;
22
+ /** Request statuses that are final. */
23
+ const FINISHED_STATUSES = new Set(['done', 'cancelled']);
24
+ /**
25
+ * Format a duration for a person: "45m", "2h 10m", "3d 4h".
26
+ *
27
+ * @param ms - Duration
28
+ * @returns Short text
29
+ */
30
+ export function formatDuration(ms) {
31
+ const m = Math.max(0, Math.floor(ms / 60_000));
32
+ if (m < 60)
33
+ return `${m}m`;
34
+ const h = Math.floor(m / 60);
35
+ if (h < 48)
36
+ return `${h}h ${m % 60}m`;
37
+ return `${Math.floor(h / 24)}d ${h % 24}h`;
38
+ }
39
+ /**
40
+ * The state and holder a WorkItem implies.
41
+ *
42
+ * @param wi - An open WorkItem
43
+ * @param reviewItems - Review WorkItems by the id they verify
44
+ * @returns Holder session and state
45
+ */
46
+ function holderOf(wi, reviewItems) {
47
+ if (wi.status === 'done_by_worker') {
48
+ const reviewer = (typeof wi.metadata?.[WORK_ITEM_REVIEWER_KEY] === 'string' ? wi.metadata[WORK_ITEM_REVIEWER_KEY] : undefined)
49
+ ?? reviewItems.get(wi.id)?.target
50
+ ?? 'unassigned';
51
+ return { session: reviewer, state: 'awaiting_review' };
52
+ }
53
+ const session = wi.target ?? 'unassigned';
54
+ if (wi.status === 'running')
55
+ return { session, state: 'working' };
56
+ if (wi.status === 'blocked' || wi.status === 'escalated')
57
+ return { session, state: 'blocked' };
58
+ return { session, state: 'queued' };
59
+ }
60
+ /**
61
+ * Compute where a request is now.
62
+ *
63
+ * Rules:
64
+ * - finished request → no holders;
65
+ * - each open WorkItem of the request (by `requestId` or `workItemIds`) is a
66
+ * holder: its `target` (running/queued/blocked) or, once the worker is done,
67
+ * its reviewer (awaiting_review). Review items themselves are folded in;
68
+ * - a holder that handed the work to another agent with a plain message (an
69
+ * open ask newer than the holder's own start) is `waiting_on_agent`, and
70
+ * the asked agent is a holder too (followed up to {@link MAX_ASK_HOPS});
71
+ * - no open WorkItem: the request's `assignee`/`ownerAgent` handles it, or the
72
+ * owner when the request waits on a confirmation or follow-up.
73
+ *
74
+ * @param request - The Request
75
+ * @param workItems - WorkItems to search (the pool, or a subset)
76
+ * @param openAsks - Open agent-to-agent asks (from the ledger)
77
+ * @param now - Current time (epoch ms)
78
+ * @returns The whereabouts
79
+ *
80
+ * @example
81
+ * ```typescript
82
+ * const w = computeWhereabouts(request, await pool.getAllItems(), ledger.openAsks(), Date.now());
83
+ * w.summary; // "With Dex (working on "Replicate the video") for 2h 10m"
84
+ * ```
85
+ */
86
+ export function computeWhereabouts(request, workItems, openAsks, now) {
87
+ const base = {
88
+ requestId: request.id,
89
+ ...(request.ticketNumber ? { ticketNumber: request.ticketNumber } : {}),
90
+ title: request.title,
91
+ status: request.status,
92
+ };
93
+ if (FINISHED_STATUSES.has(request.status)) {
94
+ const at = request.completedAt ?? request.updatedAt;
95
+ return { ...base, finished: true, finishedAt: at, holders: [], summary: `${request.status === 'done' ? 'Done' : 'Cancelled'}${at ? ` at ${at}` : ''}.` };
96
+ }
97
+ const linked = new Set(request.workItemIds ?? []);
98
+ const mine = workItems.filter((wi) => wi.requestId === request.id || linked.has(wi.id));
99
+ const reviewItems = new Map();
100
+ for (const wi of mine) {
101
+ const of = wi.metadata?.['verifyOf'];
102
+ if (wi.type === 'review' && typeof of === 'string')
103
+ reviewItems.set(of, wi);
104
+ }
105
+ const holders = [];
106
+ const seen = new Set();
107
+ const add = (h) => {
108
+ const key = `${h.session}|${h.workItemId ?? ''}|${h.state}`;
109
+ if (seen.has(key))
110
+ return;
111
+ seen.add(key);
112
+ holders.push({ ...h, forMs: Math.max(0, now - Date.parse(h.since)) });
113
+ };
114
+ for (const wi of mine) {
115
+ if (!OPEN_STATUSES.has(wi.status))
116
+ continue;
117
+ // A review item is shown through the item it reviews.
118
+ if (wi.type === 'review' && typeof wi.metadata?.['verifyOf'] === 'string' && mine.some((m) => m.id === wi.metadata?.['verifyOf']))
119
+ continue;
120
+ const { session, state } = holderOf(wi, reviewItems);
121
+ add({
122
+ session,
123
+ state,
124
+ since: wi.statusChangedAt ?? wi.startedAt ?? wi.createdAt,
125
+ workItemId: wi.id,
126
+ what: wi.title,
127
+ ...(wi.blockedReason ? { blockedReason: wi.blockedReason } : {}),
128
+ });
129
+ }
130
+ if (holders.length === 0) {
131
+ if (OWNER_WAIT_STATUSES.has(request.status)) {
132
+ add({ session: 'owner', state: 'waiting_on_owner', since: request.updatedAt, what: request.title });
133
+ }
134
+ else {
135
+ const agent = request.assignee ?? request.ownerAgent;
136
+ if (agent)
137
+ add({ session: agent, state: 'handling', since: request.updatedAt, what: request.title });
138
+ }
139
+ }
140
+ // Follow plain-message hand-offs: a holder that asked another agent after
141
+ // it took the work is waiting on that agent.
142
+ let frontier = holders.filter((h) => h.session !== 'owner').map((h) => ({ session: h.session, sinceMs: Date.parse(h.since) }));
143
+ for (let hop = 0; hop < MAX_ASK_HOPS && frontier.length > 0; hop++) {
144
+ const next = [];
145
+ for (const f of frontier) {
146
+ const asks = openAsks.filter((a) => a.sender === f.session && a.deliveredAt >= f.sinceMs);
147
+ if (asks.length === 0)
148
+ continue;
149
+ for (const h of holders)
150
+ if (h.session === f.session && h.state !== 'awaiting_review')
151
+ h.state = 'waiting_on_agent';
152
+ for (const a of asks) {
153
+ const since = new Date(a.deliveredAt).toISOString();
154
+ add({ session: a.target, state: 'working', since, what: a.excerpt, from: a.sender });
155
+ next.push({ session: a.target, sinceMs: a.deliveredAt });
156
+ }
157
+ }
158
+ frontier = next;
159
+ }
160
+ holders.sort((a, b) => b.forMs - a.forMs);
161
+ return { ...base, finished: false, holders, summary: summarize(holders) };
162
+ }
163
+ /**
164
+ * One line for a person: where the request is, longest-held first.
165
+ *
166
+ * @param holders - Holders, sorted
167
+ * @returns Summary text
168
+ */
169
+ function summarize(holders) {
170
+ const active = holders.filter((h) => h.state !== 'waiting_on_agent');
171
+ if (active.length === 0) {
172
+ return holders.length === 0 ? 'Nobody holds it: no open work item, no assignee.' : 'Handed on, but nobody is working on it.';
173
+ }
174
+ const phrase = {
175
+ working: 'working on',
176
+ queued: 'queued:',
177
+ blocked: 'blocked on',
178
+ awaiting_review: 'reviewing',
179
+ waiting_on_agent: 'waiting on another agent for',
180
+ waiting_on_owner: 'waiting on you for',
181
+ handling: 'handling',
182
+ };
183
+ return active
184
+ .slice(0, 3)
185
+ .map((h) => {
186
+ const who = h.session === 'owner' ? 'You' : h.session;
187
+ const what = h.what ? ` "${h.what.slice(0, 80)}"` : '';
188
+ const via = h.from ? `, from ${h.from}` : '';
189
+ return `${who} (${phrase[h.state]}${what}${via}) for ${formatDuration(h.forMs)}`;
190
+ })
191
+ .join('; ') + (active.length > 3 ? `; and ${active.length - 3} more` : '') + '.';
192
+ }
193
+ //# sourceMappingURL=request-whereabouts.service.js.map