@gajae-code/coding-agent 0.12.6 → 0.12.7

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/CHANGELOG.md +3 -1
  2. package/dist/types/async/job-manager.d.ts +36 -1
  3. package/dist/types/eval/backend.d.ts +2 -2
  4. package/dist/types/exec/bash-executor.d.ts +8 -10
  5. package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +0 -36
  6. package/dist/types/internal-urls/registry-helpers.d.ts +0 -18
  7. package/dist/types/sdk/bus/chat-daemon-control.d.ts +1 -3
  8. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +2 -4
  9. package/dist/types/sdk/host/host.d.ts +2 -23
  10. package/dist/types/sdk/host/reverse-leases.d.ts +4 -7
  11. package/dist/types/session/artifacts.d.ts +5 -8
  12. package/dist/types/session/client-bridge.d.ts +0 -14
  13. package/dist/types/session/internal/managed-session-storage.d.ts +2 -5
  14. package/dist/types/session/messages.d.ts +1 -4
  15. package/dist/types/session/session-manager.d.ts +4 -5
  16. package/dist/types/session/streaming-output.d.ts +0 -32
  17. package/dist/types/task/receipt.d.ts +1 -2
  18. package/dist/types/task/types.d.ts +43 -178
  19. package/dist/types/tools/bash.d.ts +1 -1
  20. package/dist/types/tools/fetch.d.ts +0 -3
  21. package/dist/types/tools/output-meta.d.ts +5 -37
  22. package/dist/types/tools/subagent.d.ts +15 -0
  23. package/dist/types/tools/todo-write.d.ts +3 -0
  24. package/dist/types/tools/tool-result.d.ts +0 -1
  25. package/package.json +8 -8
  26. package/src/async/job-manager.ts +430 -46
  27. package/src/cursor.ts +13 -20
  28. package/src/defaults/gjc/skills/ultragoal/SKILL.md +2 -3
  29. package/src/eval/backend.ts +2 -2
  30. package/src/exec/bash-executor.ts +151 -425
  31. package/src/gjc-runtime/ultragoal-runtime.ts +3 -280
  32. package/src/gjc-runtime/workflow-manifest.generated.json +1 -40
  33. package/src/gjc-runtime/workflow-manifest.ts +0 -12
  34. package/src/internal-urls/agent-protocol.ts +38 -98
  35. package/src/internal-urls/artifact-protocol.ts +17 -28
  36. package/src/internal-urls/docs-index.generated.ts +1 -1
  37. package/src/internal-urls/registry-helpers.ts +0 -62
  38. package/src/modes/acp/acp-agent.ts +0 -24
  39. package/src/modes/acp/acp-client-bridge.ts +11 -154
  40. package/src/prompts/tools/bash.md +2 -2
  41. package/src/sdk/acp/adapter.ts +9 -200
  42. package/src/sdk/bus/chat-daemon-control.ts +3 -5
  43. package/src/sdk/bus/index.ts +8 -324
  44. package/src/sdk/bus/telegram-daemon-contract.ts +2 -4
  45. package/src/sdk/host/host.ts +9 -187
  46. package/src/sdk/host/reverse-leases.ts +42 -249
  47. package/src/session/agent-session.ts +15 -178
  48. package/src/session/artifacts.ts +74 -211
  49. package/src/session/client-bridge.ts +0 -15
  50. package/src/session/internal/managed-session-storage.ts +5 -104
  51. package/src/session/messages.ts +7 -32
  52. package/src/session/session-manager.ts +21 -12
  53. package/src/session/streaming-output.ts +40 -198
  54. package/src/task/index.ts +230 -64
  55. package/src/task/receipt.ts +2 -4
  56. package/src/task/render.ts +0 -30
  57. package/src/task/types.ts +10 -34
  58. package/src/tools/bash.ts +239 -818
  59. package/src/tools/eval.ts +4 -99
  60. package/src/tools/fetch.ts +15 -77
  61. package/src/tools/find.ts +3 -7
  62. package/src/tools/output-meta.ts +114 -696
  63. package/src/tools/search.ts +4 -9
  64. package/src/tools/subagent.ts +97 -75
  65. package/src/tools/todo-write.ts +47 -0
  66. package/src/tools/tool-result.ts +0 -1
  67. package/dist/types/gjc-runtime/ultragoal-review-source.d.ts +0 -83
  68. package/dist/types/utils/artifact-id.d.ts +0 -2
  69. package/src/gjc-runtime/ultragoal-review-source.ts +0 -378
  70. package/src/utils/artifact-id.ts +0 -6
package/src/tools/eval.ts CHANGED
@@ -11,17 +11,8 @@ import type { RenderResultOptions } from "../extensibility/custom-tools/types";
11
11
  import { truncateToVisualLines } from "../modes/components/visual-truncate";
12
12
  import { getMarkdownTheme, type Theme } from "../modes/theme/theme";
13
13
  import evalDescription from "../prompts/tools/eval.md" with { type: "text" };
14
- import {
15
- DEFAULT_ARTIFACT_MAX_BYTES,
16
- DEFAULT_MAX_BYTES,
17
- OutputSink,
18
- type OutputSummary,
19
- TailBuffer,
20
- type TerminalArtifactPublisher,
21
- truncateHeadBytes,
22
- } from "../session/streaming-output";
14
+ import { DEFAULT_MAX_BYTES, OutputSink, type OutputSummary, TailBuffer } from "../session/streaming-output";
23
15
  import { getTreeBranch, getTreeContinuePrefix, renderCodeCell } from "../tui";
24
- import { isValidArtifactId } from "../utils/artifact-id";
25
16
  import { resolveEvalBackends, type ToolSession } from ".";
26
17
  import {
27
18
  formatStyledTruncationWarning,
@@ -172,55 +163,6 @@ interface ResolvedEvalCell {
172
163
  resolved: ResolvedBackend;
173
164
  }
174
165
 
175
- const EVAL_ARTIFACT_ALLOCATION_WAIT_MS = 500;
176
- const EVAL_ARTIFACT_ALLOCATION_LIMIT = 64;
177
- const pendingEvalArtifactAllocations = new Set<Promise<unknown>>();
178
-
179
- async function allocateEvalArtifact(
180
- session: ToolSession,
181
- signal?: AbortSignal,
182
- ): Promise<{ path?: string; id?: string; diagnostic?: string }> {
183
- if (!session.allocateOutputArtifact) return {};
184
- if (signal?.aborted) throw new ToolAbortError();
185
- if (pendingEvalArtifactAllocations.size >= EVAL_ARTIFACT_ALLOCATION_LIMIT) {
186
- return { diagnostic: "pending Eval artifact allocation limit reached" };
187
- }
188
- const allocation = Promise.resolve().then(() => session.allocateOutputArtifact!("eval"));
189
- pendingEvalArtifactAllocations.add(allocation);
190
- void allocation.then(
191
- () => pendingEvalArtifactAllocations.delete(allocation),
192
- () => pendingEvalArtifactAllocations.delete(allocation),
193
- );
194
- const aborted = Promise.withResolvers<{ status: "aborted" }>();
195
- const onAbort = () => aborted.resolve({ status: "aborted" });
196
- signal?.addEventListener("abort", onAbort, { once: true });
197
- try {
198
- const outcome = await Promise.race([
199
- allocation.then(
200
- value => ({ status: "ok" as const, value }),
201
- error => ({
202
- status: "failed" as const,
203
- diagnostic: error instanceof Error ? error.message : String(error),
204
- }),
205
- ),
206
- Bun.sleep(EVAL_ARTIFACT_ALLOCATION_WAIT_MS).then(() => ({
207
- status: "timeout" as const,
208
- diagnostic: `did not settle within ${EVAL_ARTIFACT_ALLOCATION_WAIT_MS}ms`,
209
- })),
210
- aborted.promise,
211
- ]);
212
- if (outcome.status === "aborted") throw new ToolAbortError();
213
- if (outcome.status !== "ok") return { diagnostic: outcome.diagnostic.slice(0, 512) };
214
- const { path, id } = outcome.value ?? {};
215
- if (!path || !isValidArtifactId(id)) {
216
- return { diagnostic: "artifact storage is unavailable or returned an invalid artifact id" };
217
- }
218
- return { path, id };
219
- } finally {
220
- signal?.removeEventListener("abort", onAbort);
221
- }
222
- }
223
-
224
166
  function uniqueEvalLanguages(cells: ResolvedEvalCell[]): EvalLanguage[] {
225
167
  return [...new Set(cells.map(cell => cell.resolved.backend.id))];
226
168
  }
@@ -323,12 +265,10 @@ export class EvalTool implements AgentTool<typeof evalSchema> {
323
265
  const sessionAbortController = new AbortController();
324
266
  let outputSink: OutputSink | undefined;
325
267
  let outputSummary: OutputSummary | undefined;
326
- let artifactAllocationDiagnostic: string | undefined;
327
268
  let outputDumped = false;
328
269
  const finalizeOutput = async (): Promise<OutputSummary | undefined> => {
329
270
  if (outputDumped || !outputSink) return outputSummary;
330
271
  outputSummary = await outputSink.dump();
331
- if (artifactAllocationDiagnostic) outputSummary.artifactFailureDiagnostic = artifactAllocationDiagnostic;
332
272
  outputDumped = true;
333
273
  return outputSummary;
334
274
  };
@@ -394,34 +334,11 @@ export class EvalTool implements AgentTool<typeof evalSchema> {
394
334
 
395
335
  const sessionFile = session.getSessionFile?.() ?? undefined;
396
336
  const kernelOwnerId = session.getEvalKernelOwnerId?.() ?? undefined;
397
- const artifactManager = session.getArtifactManager?.();
398
- const managedArtifactPublisher: TerminalArtifactPublisher | undefined = artifactManager?.getManagedStore()
399
- ? Object.assign(
400
- async (content: string) => {
401
- const contentBytes = Buffer.byteLength(content, "utf8");
402
- const artifactId = await artifactManager.save(content, "eval");
403
- if (contentBytes <= DEFAULT_ARTIFACT_MAX_BYTES) {
404
- return { status: "published" as const, artifactId };
405
- }
406
- const retainedBytes = truncateHeadBytes(content, DEFAULT_ARTIFACT_MAX_BYTES).bytes;
407
- return {
408
- status: "published" as const,
409
- artifactId,
410
- omittedBytes: contentBytes - retainedBytes,
411
- };
412
- },
413
- { owner: artifactManager },
414
- )
415
- : undefined;
416
- const allocation = managedArtifactPublisher ? {} : await allocateEvalArtifact(session, signal);
417
- artifactAllocationDiagnostic = allocation.diagnostic;
418
- const { path: artifactPath, id: artifactId } = allocation;
419
- if (signal?.aborted) throw new ToolAbortError();
337
+ const { path: artifactPath, id: artifactId } = (await session.allocateOutputArtifact?.("eval")) ?? {};
420
338
  session.assertEvalExecutionAllowed?.();
421
339
  outputSink = new OutputSink({
422
340
  artifactPath,
423
341
  artifactId,
424
- artifactPublisher: managedArtifactPublisher,
425
342
  headBytes: resolveOutputSinkHeadBytes(session.settings),
426
343
  maxColumns: resolveOutputMaxColumns(session.settings),
427
344
  onChunk: chunk => {
@@ -459,6 +376,8 @@ export class EvalTool implements AgentTool<typeof evalSchema> {
459
376
  session,
460
377
  deadlineMs,
461
378
  reset: cell.reset,
379
+ artifactPath,
380
+ artifactId,
462
381
  onChunk: chunk => {
463
382
  outputSink!.push(chunk);
464
383
  },
@@ -626,7 +545,6 @@ async function summarizeFinal(
626
545
  const outputBytes = Buffer.byteLength(combinedOutput, "utf-8");
627
546
  const missingLines = Math.max(0, rawSummary.totalLines - rawSummary.outputLines);
628
547
  const missingBytes = Math.max(0, rawSummary.totalBytes - rawSummary.outputBytes);
629
- const artifactRepresentationIncomplete = rawSummary.output !== combinedOutput || rawSummary.artifactId !== undefined;
630
548
  return {
631
549
  output: combinedOutput,
632
550
  truncated: rawSummary.truncated,
@@ -635,19 +553,6 @@ async function summarizeFinal(
635
553
  outputLines,
636
554
  outputBytes,
637
555
  artifactId: rawSummary.artifactId,
638
- artifactVerified: rawSummary.artifactVerified,
639
- artifactTruncatedBytes: rawSummary.artifactTruncatedBytes,
640
- sourceTruncatedBytes: rawSummary.sourceTruncatedBytes,
641
- sourceCaptureIncomplete:
642
- rawSummary.sourceCaptureIncomplete === true || artifactRepresentationIncomplete || undefined,
643
- headRange: rawSummary.headRange,
644
- tailRange: rawSummary.tailRange,
645
- elidedBytes: rawSummary.elidedBytes,
646
- elidedLines: rawSummary.elidedLines,
647
- columnDroppedBytes: rawSummary.columnDroppedBytes,
648
- columnTruncatedLines: rawSummary.columnTruncatedLines,
649
- columnMax: rawSummary.columnMax,
650
- artifactFailureDiagnostic: rawSummary.artifactFailureDiagnostic,
651
556
  };
652
557
  }
653
558
 
@@ -10,15 +10,9 @@ import type { RenderResultOptions } from "../extensibility/custom-tools/types";
10
10
  import { type Theme, theme } from "../modes/theme/theme";
11
11
  import type { ToolSession } from "../sdk";
12
12
  import type { AgentStorage } from "../session/agent-storage";
13
- import {
14
- DEFAULT_ARTIFACT_MAX_BYTES,
15
- DEFAULT_MAX_BYTES,
16
- type TruncationDirection,
17
- truncateContent,
18
- } from "../session/streaming-output";
13
+ import { DEFAULT_MAX_BYTES, type TruncationDirection, truncateContent } from "../session/streaming-output";
19
14
  import { renderStatusLine } from "../tui";
20
15
  import { CachedOutputBlock } from "../tui/output-block";
21
- import { isValidArtifactId } from "../utils/artifact-id";
22
16
  import { formatDimensionNote, resizeImage } from "../utils/image-resize";
23
17
  import { parseHtmlLazy } from "../utils/linkedom";
24
18
  import { INSANE_NOTES } from "../web/insane/bridge";
@@ -28,7 +22,7 @@ import type { RenderResult } from "../web/scrapers/types";
28
22
  import { finalizeOutput, loadPage, looksLikeHtml, MAX_OUTPUT_CHARS } from "../web/scrapers/types";
29
23
  import { convertWithMarkit, fetchBinary } from "../web/scrapers/utils";
30
24
  import { applyListLimit } from "./list-limit";
31
- import { formatArtifactEvidenceNotice, type OutputMeta } from "./output-meta";
25
+ import { formatStyledArtifactReference, type OutputMeta } from "./output-meta";
32
26
  import { formatExpandHint, getDomain, replaceTabs } from "./render-utils";
33
27
  import { ToolAbortError, ToolError } from "./tool-errors";
34
28
  import { toolResult } from "./tool-result";
@@ -1150,9 +1144,6 @@ export interface ReadUrlToolDetails {
1150
1144
 
1151
1145
  interface ReadUrlCacheEntry {
1152
1146
  artifactId?: string;
1153
- artifactVerified?: boolean;
1154
- artifactFailureDiagnostic?: string;
1155
- artifactStorageIncomplete?: boolean;
1156
1147
  details: ReadUrlToolDetails;
1157
1148
  image?: FetchImagePayload;
1158
1149
  /** Complete URL output, including its preamble and body. */
@@ -1189,7 +1180,7 @@ async function materializeReadUrlCacheEntry(
1189
1180
  entry: ReadUrlCacheEntry,
1190
1181
  ): Promise<ReadUrlCacheEntry | null> {
1191
1182
  if (entry.output.length > 0) return entry;
1192
- if (isValidArtifactId(entry.artifactId) && entry.artifactVerified === true) {
1183
+ if (entry.artifactId) {
1193
1184
  const artifactOutput = await readArtifactOutput(session, entry.artifactId);
1194
1185
  if (artifactOutput !== null) {
1195
1186
  // Artifacts retain their trust-boundary wrapper. Keep the raw preamble
@@ -1197,7 +1188,6 @@ async function materializeReadUrlCacheEntry(
1197
1188
  return {
1198
1189
  ...entry,
1199
1190
  output: artifactOutput,
1200
- artifactVerified: true,
1201
1191
  ...(entry.wrappedPreambleChars !== undefined ? { wrappedPreambleChars: entry.wrappedPreambleChars } : {}),
1202
1192
  };
1203
1193
  }
@@ -1205,60 +1195,17 @@ async function materializeReadUrlCacheEntry(
1205
1195
  return null;
1206
1196
  }
1207
1197
 
1208
- const READ_URL_ARTIFACT_WAIT_MS = 500;
1209
- const READ_URL_ARTIFACT_PENDING_LIMIT = 64;
1210
- const pendingReadUrlArtifactWrites = new Set<Promise<unknown>>();
1211
-
1212
- async function persistReadUrlArtifact(
1213
- session: ToolSession,
1214
- output: string,
1215
- ): Promise<{ artifactId?: string; diagnostic?: string; storageIncomplete?: boolean }> {
1216
- if (pendingReadUrlArtifactWrites.size >= READ_URL_ARTIFACT_PENDING_LIMIT) {
1217
- return { diagnostic: "pending URL artifact persistence limit reached" };
1218
- }
1219
- const promise = Promise.resolve().then(async () => {
1220
- const wrapped = wrapUntrustedContent(output);
1221
- const artifactManager = session.getArtifactManager?.();
1222
- if (artifactManager?.getManagedStore()) {
1223
- const artifactId = await artifactManager.save(wrapped, "read");
1224
- const contentBytes = Buffer.byteLength(wrapped, "utf8");
1225
- return {
1226
- artifactId,
1227
- storageIncomplete: contentBytes > DEFAULT_ARTIFACT_MAX_BYTES || undefined,
1228
- };
1229
- }
1230
- const { path: artifactPath, id } = (await session.allocateOutputArtifact?.("read")) ?? {};
1231
- if (!artifactPath || !isValidArtifactId(id)) {
1232
- return { diagnostic: "artifact storage is unavailable or returned an invalid artifact id" };
1233
- }
1234
- await Bun.write(artifactPath, wrapped);
1235
- return { artifactId: id };
1236
- });
1237
- pendingReadUrlArtifactWrites.add(promise);
1238
- void promise.then(
1239
- () => pendingReadUrlArtifactWrites.delete(promise),
1240
- () => pendingReadUrlArtifactWrites.delete(promise),
1241
- );
1242
- return Promise.race([
1243
- promise.catch(error => ({
1244
- diagnostic: error instanceof Error ? error.message.slice(0, 512) : String(error).slice(0, 512),
1245
- })),
1246
- Bun.sleep(READ_URL_ARTIFACT_WAIT_MS).then(() => ({
1247
- diagnostic: `did not settle within ${READ_URL_ARTIFACT_WAIT_MS}ms`,
1248
- })),
1249
- ]);
1198
+ async function persistReadUrlArtifact(session: ToolSession, output: string): Promise<string | undefined> {
1199
+ const { path: artifactPath, id } = (await session.allocateOutputArtifact?.("read")) ?? {};
1200
+ if (!artifactPath) return undefined;
1201
+ await Bun.write(artifactPath, wrapUntrustedContent(output));
1202
+ return id;
1250
1203
  }
1251
1204
 
1252
1205
  async function ensureReadUrlCacheArtifact(session: ToolSession, entry: ReadUrlCacheEntry): Promise<ReadUrlCacheEntry> {
1253
- if (isValidArtifactId(entry.artifactId) && entry.artifactVerified === true) return entry;
1254
- const persisted = await persistReadUrlArtifact(session, entry.output);
1255
- return {
1256
- ...entry,
1257
- artifactId: persisted.artifactId,
1258
- artifactVerified: persisted.artifactId !== undefined,
1259
- artifactFailureDiagnostic: persisted.diagnostic,
1260
- artifactStorageIncomplete: persisted.storageIncomplete,
1261
- };
1206
+ if (entry.artifactId) return entry;
1207
+ const artifactId = await persistReadUrlArtifact(session, entry.output);
1208
+ return artifactId ? { ...entry, artifactId } : entry;
1262
1209
  }
1263
1210
 
1264
1211
  function cacheReadUrlEntry(session: ToolSession, requestedUrl: string, raw: boolean, entry: ReadUrlCacheEntry): void {
@@ -1283,13 +1230,10 @@ async function buildReadUrlCacheEntry(
1283
1230
  const storage = session.settings.getStorage();
1284
1231
  const result = await renderUrl(url, effectiveTimeout, raw, session.settings, signal, storage);
1285
1232
  const built = buildUrlReadOutput(result, result.content);
1286
- const persistedArtifact = options?.ensureArtifact ? await persistReadUrlArtifact(session, built.output) : {};
1233
+ const artifactId = options?.ensureArtifact ? await persistReadUrlArtifact(session, built.output) : undefined;
1287
1234
 
1288
1235
  return {
1289
- artifactId: persistedArtifact.artifactId,
1290
- artifactVerified: persistedArtifact.artifactId !== undefined,
1291
- artifactFailureDiagnostic: persistedArtifact.diagnostic,
1292
- artifactStorageIncomplete: persistedArtifact.storageIncomplete,
1236
+ artifactId,
1293
1237
  details: {
1294
1238
  kind: "url",
1295
1239
  url: result.url,
@@ -1427,7 +1371,7 @@ export async function executeReadUrl(
1427
1371
  direction: effectiveDirection,
1428
1372
  });
1429
1373
  const needsArtifact = truncation.truncated;
1430
- if (needsArtifact && (!isValidArtifactId(cacheEntry.artifactId) || cacheEntry.artifactVerified !== true)) {
1374
+ if (needsArtifact && !cacheEntry.artifactId) {
1431
1375
  cacheEntry = await ensureReadUrlCacheArtifact(session, cacheEntry);
1432
1376
  cacheReadUrlEntry(session, params.path, params.raw ?? false, cacheEntry);
1433
1377
  }
@@ -1454,9 +1398,6 @@ export async function executeReadUrl(
1454
1398
  resultBuilder.truncation(truncation, {
1455
1399
  direction: effectiveDirection === "both" ? "middle" : effectiveDirection === "last" ? "tail" : "head",
1456
1400
  artifactId: cacheEntry.artifactId,
1457
- artifactVerified: cacheEntry.artifactVerified === true || undefined,
1458
- artifactFailureDiagnostic: cacheEntry.artifactFailureDiagnostic,
1459
- sourceCaptureIncomplete: cacheEntry.details.truncated || cacheEntry.artifactStorageIncomplete || undefined,
1460
1401
  ...(effectiveDirection !== "head" ? { maxBytes: DEFAULT_MAX_BYTES } : {}),
1461
1402
  });
1462
1403
  } else if (cacheEntry.details.truncated) {
@@ -1560,10 +1501,7 @@ export function renderReadUrlResult(
1560
1501
  metadataLines.push(`${uiTheme.fg("muted", "Chars:")} ${charCount}`);
1561
1502
  if (truncated) {
1562
1503
  metadataLines.push(uiTheme.fg("warning", `${uiTheme.status.warning} Output truncated`));
1563
- if (truncation?.artifactId && truncation.artifactVerified === true) {
1564
- const artifactNotice = formatArtifactEvidenceNotice(truncation);
1565
- if (artifactNotice) metadataLines.push(uiTheme.fg("warning", artifactNotice));
1566
- }
1504
+ if (truncation?.artifactId) metadataLines.push(formatStyledArtifactReference(truncation.artifactId, uiTheme));
1567
1505
  }
1568
1506
  if (hasNotes) {
1569
1507
  metadataLines.push(`${uiTheme.fg("muted", "Notes:")} ${details.notes.join("; ")}`);
package/src/tools/find.ts CHANGED
@@ -14,7 +14,7 @@ import { type TruncationResult, truncateHead } from "../session/streaming-output
14
14
  import { Ellipsis, fileHyperlink, renderFileList, renderStatusLine, renderTreeList, truncateToWidth } from "../tui";
15
15
  import type { ToolSession } from ".";
16
16
  import { applyListLimit } from "./list-limit";
17
- import { formatArtifactEvidenceNotice, type OutputMeta } from "./output-meta";
17
+ import { formatFullOutputReference, type OutputMeta } from "./output-meta";
18
18
  import {
19
19
  formatPathRelativeToCwd,
20
20
  hasGlobPathChars,
@@ -510,12 +510,8 @@ export const findToolRenderer = {
510
510
  if (details?.resultLimitReached) truncationReasons.push(`limit ${details.resultLimitReached} results`);
511
511
  if (limits?.resultLimit) truncationReasons.push(`limit ${limits.resultLimit.reached} results`);
512
512
  if (truncation) truncationReasons.push(truncation.truncatedBy === "lines" ? "line limit" : "size limit");
513
- const artifactEvidence = details?.meta?.truncation
514
- ? formatArtifactEvidenceNotice(details.meta.truncation)
515
- : truncation && "artifactId" in truncation
516
- ? formatArtifactEvidenceNotice(truncation as NonNullable<OutputMeta["truncation"]>)
517
- : undefined;
518
- if (artifactEvidence) truncationReasons.push(artifactEvidence);
513
+ const artifactId = truncation && "artifactId" in truncation ? truncation.artifactId : undefined;
514
+ if (artifactId) truncationReasons.push(formatFullOutputReference(artifactId));
519
515
 
520
516
  const extraLines: string[] = [];
521
517
  if (truncationReasons.length > 0) {