@gajae-code/coding-agent 0.6.4 → 0.6.5

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 (120) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/types/cli/migrate-cli.d.ts +20 -0
  3. package/dist/types/commands/migrate.d.ts +33 -0
  4. package/dist/types/config/keybindings.d.ts +4 -0
  5. package/dist/types/gjc-runtime/deep-interview-recorder.d.ts +2 -0
  6. package/dist/types/gjc-runtime/deep-interview-runtime.d.ts +2 -2
  7. package/dist/types/gjc-runtime/goal-mode-request.d.ts +1 -1
  8. package/dist/types/gjc-runtime/session-layout.d.ts +59 -0
  9. package/dist/types/gjc-runtime/session-resolution.d.ts +47 -0
  10. package/dist/types/gjc-runtime/state-graph.d.ts +1 -1
  11. package/dist/types/gjc-runtime/state-runtime.d.ts +5 -4
  12. package/dist/types/gjc-runtime/state-schema.d.ts +2 -0
  13. package/dist/types/gjc-runtime/state-writer.d.ts +36 -7
  14. package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +7 -4
  15. package/dist/types/gjc-runtime/workflow-command-ref.d.ts +1 -1
  16. package/dist/types/gjc-runtime/workflow-manifest.d.ts +1 -1
  17. package/dist/types/harness-control-plane/storage.d.ts +2 -1
  18. package/dist/types/hooks/skill-state.d.ts +12 -4
  19. package/dist/types/migrate/action-planner.d.ts +11 -0
  20. package/dist/types/migrate/adapters/claude-code.d.ts +2 -0
  21. package/dist/types/migrate/adapters/codex.d.ts +5 -0
  22. package/dist/types/migrate/adapters/index.d.ts +45 -0
  23. package/dist/types/migrate/adapters/opencode.d.ts +2 -0
  24. package/dist/types/migrate/executor.d.ts +2 -0
  25. package/dist/types/migrate/mcp-mapper.d.ts +20 -0
  26. package/dist/types/migrate/report.d.ts +18 -0
  27. package/dist/types/migrate/skill-normalizer.d.ts +27 -0
  28. package/dist/types/migrate/types.d.ts +126 -0
  29. package/dist/types/modes/components/custom-editor.d.ts +1 -1
  30. package/dist/types/modes/shared/agent-wire/unattended-audit.d.ts +1 -1
  31. package/dist/types/research-plan/index.d.ts +1 -0
  32. package/dist/types/research-plan/ledger.d.ts +33 -0
  33. package/dist/types/rlm/artifacts.d.ts +1 -1
  34. package/dist/types/runtime-mcp/config-writer.d.ts +26 -0
  35. package/dist/types/skill-state/active-state.d.ts +6 -11
  36. package/dist/types/skill-state/canonical-skills.d.ts +3 -0
  37. package/dist/types/skill-state/workflow-hud.d.ts +2 -0
  38. package/dist/types/task/spawn-gate.d.ts +1 -10
  39. package/package.json +7 -7
  40. package/src/cli/migrate-cli.ts +106 -0
  41. package/src/cli.ts +1 -0
  42. package/src/commands/deep-interview.ts +2 -2
  43. package/src/commands/migrate.ts +46 -0
  44. package/src/commands/state.ts +2 -1
  45. package/src/commands/team.ts +7 -3
  46. package/src/coordinator-mcp/policy.ts +10 -2
  47. package/src/defaults/gjc/extensions/grok-cli-vendor/biome.json +0 -1
  48. package/src/defaults/gjc/skills/deep-interview/SKILL.md +28 -24
  49. package/src/defaults/gjc/skills/ralplan/SKILL.md +8 -4
  50. package/src/defaults/gjc/skills/team/SKILL.md +51 -47
  51. package/src/defaults/gjc/skills/ultragoal/SKILL.md +17 -13
  52. package/src/extensibility/custom-commands/loader.ts +0 -7
  53. package/src/extensibility/gjc-plugins/injection.ts +23 -4
  54. package/src/extensibility/gjc-plugins/state.ts +16 -1
  55. package/src/gjc-runtime/deep-interview-recorder.ts +43 -18
  56. package/src/gjc-runtime/deep-interview-runtime.ts +49 -23
  57. package/src/gjc-runtime/goal-mode-request.ts +26 -11
  58. package/src/gjc-runtime/launch-tmux.ts +6 -1
  59. package/src/gjc-runtime/ralplan-runtime.ts +79 -50
  60. package/src/gjc-runtime/session-layout.ts +180 -0
  61. package/src/gjc-runtime/session-resolution.ts +217 -0
  62. package/src/gjc-runtime/state-graph.ts +1 -2
  63. package/src/gjc-runtime/state-migrations.ts +1 -0
  64. package/src/gjc-runtime/state-runtime.ts +230 -121
  65. package/src/gjc-runtime/state-schema.ts +2 -0
  66. package/src/gjc-runtime/state-writer.ts +289 -41
  67. package/src/gjc-runtime/team-runtime.ts +43 -19
  68. package/src/gjc-runtime/tmux-sessions.ts +7 -1
  69. package/src/gjc-runtime/ultragoal-guard.ts +45 -2
  70. package/src/gjc-runtime/ultragoal-runtime.ts +121 -41
  71. package/src/gjc-runtime/workflow-command-ref.ts +1 -2
  72. package/src/gjc-runtime/workflow-manifest.ts +1 -2
  73. package/src/harness-control-plane/storage.ts +14 -4
  74. package/src/hooks/native-skill-hook.ts +38 -12
  75. package/src/hooks/skill-state.ts +178 -83
  76. package/src/internal-urls/docs-index.generated.ts +6 -4
  77. package/src/migrate/action-planner.ts +318 -0
  78. package/src/migrate/adapters/claude-code.ts +39 -0
  79. package/src/migrate/adapters/codex.ts +70 -0
  80. package/src/migrate/adapters/index.ts +277 -0
  81. package/src/migrate/adapters/opencode.ts +52 -0
  82. package/src/migrate/executor.ts +81 -0
  83. package/src/migrate/mcp-mapper.ts +152 -0
  84. package/src/migrate/report.ts +104 -0
  85. package/src/migrate/skill-normalizer.ts +80 -0
  86. package/src/migrate/types.ts +163 -0
  87. package/src/modes/bridge/bridge-mode.ts +2 -2
  88. package/src/modes/components/custom-editor.ts +30 -20
  89. package/src/modes/rpc/rpc-mode.ts +2 -2
  90. package/src/modes/shared/agent-wire/unattended-audit.ts +3 -2
  91. package/src/prompts/agents/init.md +1 -1
  92. package/src/prompts/system/plan-mode-active.md +1 -1
  93. package/src/prompts/tools/ast-grep.md +1 -1
  94. package/src/prompts/tools/search.md +1 -1
  95. package/src/prompts/tools/task.md +1 -2
  96. package/src/research-plan/index.ts +1 -0
  97. package/src/research-plan/ledger.ts +177 -0
  98. package/src/rlm/artifacts.ts +12 -3
  99. package/src/rlm/index.ts +7 -0
  100. package/src/runtime-mcp/config-writer.ts +46 -0
  101. package/src/session/agent-session.ts +15 -21
  102. package/src/setup/hermes-setup.ts +1 -1
  103. package/src/skill-state/active-state.ts +72 -108
  104. package/src/skill-state/canonical-skills.ts +4 -0
  105. package/src/skill-state/deep-interview-mutation-guard.ts +28 -109
  106. package/src/skill-state/workflow-hud.ts +4 -2
  107. package/src/skill-state/workflow-state-contract.ts +3 -3
  108. package/src/task/agents.ts +1 -22
  109. package/src/task/index.ts +1 -41
  110. package/src/task/spawn-gate.ts +1 -38
  111. package/src/task/types.ts +1 -1
  112. package/src/tools/ask.ts +34 -12
  113. package/src/tools/computer.ts +58 -4
  114. package/dist/types/extensibility/custom-commands/bundled/review/index.d.ts +0 -10
  115. package/src/extensibility/custom-commands/bundled/review/index.ts +0 -456
  116. package/src/prompts/agents/explore.md +0 -58
  117. package/src/prompts/agents/plan.md +0 -49
  118. package/src/prompts/agents/reviewer.md +0 -141
  119. package/src/prompts/agents/task.md +0 -16
  120. package/src/prompts/review-request.md +0 -70
package/src/task/index.ts CHANGED
@@ -55,7 +55,7 @@ import { assertNoRawTaskFields, buildTaskReceipt, buildTaskRoiSummary } from "./
55
55
  import { renderResult, renderCall as renderTaskCall } from "./render";
56
56
  import { reconcileSpawnRoi } from "./roi-reconciliation";
57
57
  import { getTaskSimpleModeCapabilities, type TaskSimpleMode } from "./simple-mode";
58
- import { DEFAULT_SPAWN_THRESHOLD, evaluateReviewerExploreGate, evaluateSpawnGate } from "./spawn-gate";
58
+ import { DEFAULT_SPAWN_THRESHOLD, evaluateSpawnGate } from "./spawn-gate";
59
59
  import {
60
60
  applyNestedPatches,
61
61
  captureBaseline,
@@ -359,7 +359,6 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
359
359
  readonly renderResult = renderResult;
360
360
  readonly #discoveredAgents: AgentDefinition[];
361
361
  readonly #blockedAgent: string | undefined;
362
- readonly #spawningAgentType: string | undefined;
363
362
 
364
363
  get parameters(): TaskToolSchemaInstance {
365
364
  const isolationEnabled = this.session.settings.get("task.isolation.mode") !== "none";
@@ -391,7 +390,6 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
391
390
  discoveredAgents: AgentDefinition[],
392
391
  ) {
393
392
  this.#blockedAgent = $env.PI_BLOCKED_AGENT;
394
- this.#spawningAgentType = session.currentAgentType;
395
393
  this.#discoveredAgents = discoveredAgents;
396
394
  }
397
395
 
@@ -478,23 +476,6 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
478
476
  };
479
477
  }
480
478
 
481
- const reviewerExploreDecision = evaluateReviewerExploreGate({
482
- spawningAgentType: this.#spawningAgentType,
483
- targetAgent: params.agent,
484
- plan: params.spawnPlan,
485
- });
486
- if (reviewerExploreDecision.outcome === "rejected") {
487
- return {
488
- content: [
489
- {
490
- type: "text",
491
- text: `Task spawn gate rejected reviewer->explore: ${reviewerExploreDecision.reason}. Provide spawnPlan fields: ${reviewerExploreDecision.missingFields.join(", ")}.`,
492
- },
493
- ],
494
- details: { projectAgentsDir: null, results: [], totalDurationMs: 0 },
495
- };
496
- }
497
-
498
479
  const manager = AsyncJobManager.instance();
499
480
  if (!manager) {
500
481
  return {
@@ -1083,27 +1064,6 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
1083
1064
  };
1084
1065
  }
1085
1066
 
1086
- const reviewerExploreDecision = evaluateReviewerExploreGate({
1087
- spawningAgentType: this.#spawningAgentType,
1088
- targetAgent: agentName,
1089
- plan: params.spawnPlan,
1090
- });
1091
- if (reviewerExploreDecision.outcome === "rejected") {
1092
- return {
1093
- content: [
1094
- {
1095
- type: "text",
1096
- text: `Task spawn gate rejected reviewer->explore: ${reviewerExploreDecision.reason}. Provide spawnPlan fields: ${reviewerExploreDecision.missingFields.join(", ")}.`,
1097
- },
1098
- ],
1099
- details: {
1100
- projectAgentsDir,
1101
- results: [],
1102
- totalDurationMs: Date.now() - startTime,
1103
- },
1104
- };
1105
- }
1106
-
1107
1067
  let repoRoot: string | null = null;
1108
1068
  let baseline: WorktreeBaseline | null = null;
1109
1069
  if (isIsolated) {
@@ -1,7 +1,7 @@
1
1
  /** The hard, locked batch threshold enforced by the runtime gate. */
2
2
  export const DEFAULT_SPAWN_THRESHOLD = 4;
3
3
 
4
- /** The justification a large batch or reviewer-spawned explorer must supply to pass the hard gate. */
4
+ /** The justification a large batch must supply to pass the hard gate. */
5
5
  export interface SpawnPlanReceipt {
6
6
  whyParallel: string;
7
7
  whyNotLocal: string;
@@ -17,15 +17,6 @@ export interface SpawnGateRequest {
17
17
  plan?: SpawnPlanReceipt;
18
18
  }
19
19
 
20
- export interface ReviewerExploreGateRequest {
21
- /** Agent type/name doing the spawning, when known. */
22
- spawningAgentType?: string | null;
23
- /** Target agent type/name requested by the task call. */
24
- targetAgent: string;
25
- /** The spawn-plan receipt, when provided. */
26
- plan?: SpawnPlanReceipt;
27
- }
28
-
29
20
  export type SpawnGateOutcome = "allowed" | "rejected";
30
21
 
31
22
  export interface SpawnGateDecision {
@@ -102,31 +93,3 @@ export function decide(childCount: number, threshold: number, plan: SpawnPlanRec
102
93
  export function evaluateSpawnGate(request: SpawnGateRequest): SpawnGateDecision {
103
94
  return decide(request.childCount, DEFAULT_SPAWN_THRESHOLD, request.plan);
104
95
  }
105
-
106
- export function evaluateReviewerExploreGate(request: ReviewerExploreGateRequest): SpawnGateDecision {
107
- if (request.spawningAgentType !== "reviewer" || request.targetAgent !== "explore") {
108
- return {
109
- outcome: "allowed",
110
- reason: "reviewer->explore gate does not apply",
111
- planRequired: false,
112
- missingFields: [],
113
- };
114
- }
115
-
116
- const missingFields = findMissingPlanFields(request.plan);
117
- if (missingFields.length > 0) {
118
- return {
119
- outcome: "rejected",
120
- reason: `reviewer->explore spawn requires a complete spawn-plan receipt (${missingFields.join(", ")})`,
121
- planRequired: true,
122
- missingFields,
123
- };
124
- }
125
-
126
- return {
127
- outcome: "allowed",
128
- reason: "reviewer->explore spawn has a complete spawn-plan receipt",
129
- planRequired: true,
130
- missingFields: [],
131
- };
132
- }
package/src/task/types.ts CHANGED
@@ -72,7 +72,7 @@ const spawnPlanSchema = z
72
72
  expectedReceiptShape: z.string(),
73
73
  maxInlineTokens: z.number(),
74
74
  })
75
- .describe("justification required before spawning more than four tasks or reviewer-spawned explore tasks");
75
+ .describe("justification required before spawning more than four tasks");
76
76
 
77
77
  const createTaskItemSchema = (_contextEnabled: boolean) =>
78
78
  z.object({
package/src/tools/ask.ts CHANGED
@@ -34,7 +34,7 @@ import {
34
34
  renderDeepInterviewAskQuestion,
35
35
  } from "../deep-interview/render-middleware";
36
36
  import type { RenderResultOptions } from "../extensibility/custom-tools/types";
37
- import { appendOrMergeDeepInterviewRound } from "../gjc-runtime/deep-interview-recorder";
37
+ import { appendOrMergeDeepInterviewRound, syncDeepInterviewRecorderHud } from "../gjc-runtime/deep-interview-recorder";
38
38
  import { deepInterviewStatePath } from "../gjc-runtime/deep-interview-runtime";
39
39
  import { gateAnswerToResult, questionToGate } from "../modes/shared/agent-wire/deep-interview-gate";
40
40
  import { getMarkdownTheme, type Theme, theme } from "../modes/theme/theme";
@@ -104,6 +104,30 @@ export interface AskToolDetails {
104
104
  const OTHER_OPTION = "Other (type your own)";
105
105
  const RECOMMENDED_SUFFIX = " (Recommended)";
106
106
  const DEEP_INTERVIEW_SELECTOR_SCROLL_TITLE_ROWS = Number.MAX_SAFE_INTEGER;
107
+ const DEEP_INTERVIEW_RECORDER_AWAIT_TIMEOUT_MS = 250;
108
+
109
+ function errorMessage(error: unknown): string {
110
+ return error instanceof Error ? error.message : String(error);
111
+ }
112
+
113
+ async function awaitDeepInterviewRecorderPersistence(persistence: Promise<void>): Promise<void> {
114
+ let timeout: ReturnType<typeof setTimeout> | undefined;
115
+ try {
116
+ await Promise.race([
117
+ persistence,
118
+ new Promise<never>((_resolve, reject) => {
119
+ timeout = setTimeout(
120
+ () => reject(new Error(`timed out after ${DEEP_INTERVIEW_RECORDER_AWAIT_TIMEOUT_MS}ms`)),
121
+ DEEP_INTERVIEW_RECORDER_AWAIT_TIMEOUT_MS,
122
+ );
123
+ }),
124
+ ]);
125
+ } catch (error) {
126
+ logger.warn(`ask: deep-interview round recording failed: ${errorMessage(error)}`);
127
+ } finally {
128
+ if (timeout) clearTimeout(timeout);
129
+ }
130
+ }
107
131
 
108
132
  function getDoneOptionLabel(): string {
109
133
  return `${theme.status.success} Done selecting`;
@@ -481,11 +505,11 @@ export class AskTool implements AgentTool<typeof askSchema, AskToolDetails> {
481
505
  ): Promise<void> {
482
506
  const meta = q.deepInterview;
483
507
  if (!meta) return;
484
- try {
485
- const cwd = this.session.cwd;
486
- const sessionId = this.session.getSessionId?.() ?? undefined;
487
- const statePath = deepInterviewStatePath(cwd, sessionId);
488
- await appendOrMergeDeepInterviewRound(
508
+ const cwd = this.session.cwd;
509
+ const sessionId = this.session.getSessionId?.() ?? undefined;
510
+ const statePath = deepInterviewStatePath(cwd, sessionId);
511
+ await awaitDeepInterviewRecorderPersistence(
512
+ appendOrMergeDeepInterviewRound(
489
513
  cwd,
490
514
  statePath,
491
515
  {
@@ -500,12 +524,10 @@ export class AskTool implements AgentTool<typeof askSchema, AskToolDetails> {
500
524
  customInput,
501
525
  },
502
526
  { sessionId },
503
- );
504
- } catch (error) {
505
- logger.warn(
506
- `ask: deep-interview round recording failed: ${error instanceof Error ? error.message : String(error)}`,
507
- );
508
- }
527
+ ).then(async () => {
528
+ await syncDeepInterviewRecorderHud(cwd, statePath, sessionId);
529
+ }),
530
+ );
509
531
  }
510
532
 
511
533
  async execute(
@@ -6,6 +6,7 @@ import type { ImageContent } from "@gajae-code/ai";
6
6
  import { prompt } from "@gajae-code/utils";
7
7
  import * as z from "zod/v4";
8
8
  import computerDescription from "../prompts/tools/computer.md" with { type: "text" };
9
+ import { resizeImage } from "../utils/image-resize";
9
10
  import type { ToolSession } from "./index";
10
11
  import type { OutputMeta } from "./output-meta";
11
12
  import { ToolAbortError, ToolError, throwIfAborted } from "./tool-errors";
@@ -174,6 +175,11 @@ let platformOverrideForTests: NodeJS.Platform | undefined;
174
175
  let archOverrideForTests: NodeJS.Architecture | undefined;
175
176
  const screenshotFallbackDirs = new WeakMap<ToolSession, Promise<string>>();
176
177
 
178
+ const COMPUTER_INLINE_SCREENSHOT_MAX_WIDTH = 1568;
179
+ const COMPUTER_INLINE_SCREENSHOT_MAX_HEIGHT = 1568;
180
+ const COMPUTER_INLINE_SCREENSHOT_PROVIDER_MAX_BYTES = 5 * 1024 * 1024;
181
+ const COMPUTER_INLINE_SCREENSHOT_JPEG_QUALITY = 70;
182
+
177
183
  export function setComputerControllerFactoryForTests(factory: ComputerControllerFactory | undefined): void {
178
184
  controllerFactory = factory ?? createNativeComputerController;
179
185
  }
@@ -278,6 +284,9 @@ export class ComputerTool implements AgentTool<typeof computerSchema, ComputerTo
278
284
  if (batchResult.failedStep) {
279
285
  details.code = batchResult.failedStep.code;
280
286
  details.message = batchResult.failedStep.message;
287
+ if (batchResult.screenshotSource !== undefined) {
288
+ await persistScreenshotFallback(batchResult.screenshotSource, details.screenshot, this.session);
289
+ }
281
290
  await writeComputerAuditLog(this.session, details);
282
291
  return {
283
292
  ...toolResult(details).text(`${details.code}: ${details.message}`).done(),
@@ -285,11 +294,11 @@ export class ComputerTool implements AgentTool<typeof computerSchema, ComputerTo
285
294
  };
286
295
  }
287
296
  details.message = describeComputerSuccess(details);
288
- const image = imageContentFromNativeResult(batchResult.screenshotSource);
289
297
  if (batchResult.screenshotSource !== undefined) {
290
298
  await persistScreenshotFallback(batchResult.screenshotSource, details.screenshot, this.session);
291
299
  details.message = describeComputerSuccess(details);
292
300
  }
301
+ const image = await inlineImageContentFromNativeResult(batchResult.screenshotSource, details, this.session);
293
302
  await writeComputerAuditLog(this.session, details);
294
303
  return image
295
304
  ? toolResult(details)
@@ -302,11 +311,11 @@ export class ComputerTool implements AgentTool<typeof computerSchema, ComputerTo
302
311
  if (screenshot) details.screenshot = screenshot;
303
312
  details.status = "success";
304
313
  details.message = describeComputerSuccess(details);
305
- const image = imageContentFromNativeResult(result);
306
314
  if (screenshot) {
307
315
  await persistScreenshotFallback(result, details.screenshot, this.session);
308
316
  details.message = describeComputerSuccess(details);
309
317
  }
318
+ const image = await inlineImageContentFromNativeResult(result, details, this.session);
310
319
  await writeComputerAuditLog(this.session, details);
311
320
  return image
312
321
  ? toolResult(details)
@@ -472,7 +481,7 @@ function normalizeScreenshot(value: unknown): ComputerScreenshotDetails | undefi
472
481
  };
473
482
  }
474
483
 
475
- function imageContentFromNativeResult(value: unknown): ImageContent | undefined {
484
+ function fullResolutionImageContentFromNativeResult(value: unknown): ImageContent | undefined {
476
485
  const candidate =
477
486
  value && typeof value === "object" && "screenshot" in value
478
487
  ? (value as { screenshot?: unknown }).screenshot
@@ -483,13 +492,42 @@ function imageContentFromNativeResult(value: unknown): ImageContent | undefined
483
492
  return data ? { type: "image", data, mimeType: "image/png" } : undefined;
484
493
  }
485
494
 
495
+ async function inlineImageContentFromNativeResult(
496
+ value: unknown,
497
+ details: ComputerToolDetails,
498
+ session: ToolSession,
499
+ ): Promise<ImageContent | undefined> {
500
+ const image = fullResolutionImageContentFromNativeResult(value);
501
+ if (!image) return undefined;
502
+ const maxBytes = getInlineScreenshotMaxBytes(session);
503
+ const originalBytes = Buffer.byteLength(image.data, "base64");
504
+ if (originalBytes <= maxBytes) return image;
505
+
506
+ try {
507
+ const resized = await resizeImage(image, {
508
+ maxWidth: COMPUTER_INLINE_SCREENSHOT_MAX_WIDTH,
509
+ maxHeight: COMPUTER_INLINE_SCREENSHOT_MAX_HEIGHT,
510
+ maxBytes,
511
+ jpegQuality: COMPUTER_INLINE_SCREENSHOT_JPEG_QUALITY,
512
+ });
513
+ if (resized.buffer.length <= maxBytes) {
514
+ return { type: "image", data: resized.data, mimeType: resized.mimeType };
515
+ }
516
+ } catch {
517
+ // Keep the action successful and rely on the full-resolution artifact path below.
518
+ }
519
+
520
+ details.message = `${details.message} Inline screenshot omitted because it could not be bounded below ${formatByteCount(maxBytes)}; use the saved screenshot artifact instead.`;
521
+ return undefined;
522
+ }
523
+
486
524
  async function persistScreenshotFallback(
487
525
  value: unknown,
488
526
  screenshot: ComputerScreenshotDetails | undefined,
489
527
  session: ToolSession,
490
528
  ): Promise<void> {
491
529
  if (!screenshot || screenshot.path) return;
492
- const image = imageContentFromNativeResult(value);
530
+ const image = fullResolutionImageContentFromNativeResult(value);
493
531
  if (!image) return;
494
532
  const dir = await getScreenshotFallbackDir(session);
495
533
  const filePath = path.join(dir, `computer-${Date.now()}-${Math.random().toString(36).slice(2)}.png`);
@@ -526,6 +564,22 @@ function getPngByteLength(png: NativeScreenshot["png"]): number | undefined {
526
564
  return png.byteLength;
527
565
  }
528
566
 
567
+ function getInlineScreenshotMaxBytes(session: Pick<ToolSession, "settings">): number {
568
+ const configured = Number(session.settings.get("computer.screenshotMaxBytes"));
569
+ const finiteConfigured =
570
+ Number.isFinite(configured) && configured > 0
571
+ ? Math.floor(configured)
572
+ : COMPUTER_INLINE_SCREENSHOT_PROVIDER_MAX_BYTES;
573
+ return Math.min(finiteConfigured, COMPUTER_INLINE_SCREENSHOT_PROVIDER_MAX_BYTES);
574
+ }
575
+
576
+ function formatByteCount(bytes: number): string {
577
+ if (bytes < 1024) return `${bytes} bytes`;
578
+ const kib = bytes / 1024;
579
+ if (kib < 1024) return `${Math.round(kib)} KiB`;
580
+ return `${(kib / 1024).toFixed(1)} MiB`;
581
+ }
582
+
529
583
  function mapComputerError(error: unknown, hotkey?: string): { code: string; message: string } {
530
584
  if (error instanceof Error && (error.name === "AbortError" || error.name === "TimeoutError")) {
531
585
  return {
@@ -1,10 +0,0 @@
1
- import type { CustomCommand, CustomCommandAPI } from "../../../../extensibility/custom-commands/types";
2
- import type { HookCommandContext } from "../../../../extensibility/hooks/types";
3
- export declare class ReviewCommand implements CustomCommand {
4
- private api;
5
- name: string;
6
- description: string;
7
- constructor(api: CustomCommandAPI);
8
- execute(args: string[], ctx: HookCommandContext): Promise<string | undefined>;
9
- }
10
- export default ReviewCommand;