perchai-cli 2.4.35 → 2.4.37

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 (2) hide show
  1. package/dist/perch.mjs +61 -24
  2. package/package.json +1 -1
package/dist/perch.mjs CHANGED
@@ -75917,7 +75917,6 @@ function isTurnAbortedError(error) {
75917
75917
  var TURN_STOPPED_BY_USER_MESSAGE;
75918
75918
  var init_turnAbort = __esm({
75919
75919
  "features/perchTerminal/runtime/turnAbort.ts"() {
75920
- "use strict";
75921
75920
  TURN_STOPPED_BY_USER_MESSAGE = "Turn stopped by user.";
75922
75921
  }
75923
75922
  });
@@ -76218,7 +76217,6 @@ function getToolDisplayName(toolName) {
76218
76217
  var NON_MODULE_TOOL_OWNERS, TOOL_RISK, TOOL_DISPLAY_NAMES;
76219
76218
  var init_catalog = __esm({
76220
76219
  "features/perchTerminal/runtime/toolSystem/catalog.ts"() {
76221
- "use strict";
76222
76220
  init_toolNames();
76223
76221
  NON_MODULE_TOOL_OWNERS = {
76224
76222
  [TOOL_NAMES.listSources]: "lane",
@@ -83126,7 +83124,6 @@ function listFinancialRoleIds() {
83126
83124
  var FINANCIAL_ROLE_REGISTRY, evidenceScoutManifest;
83127
83125
  var init_financialRoles = __esm({
83128
83126
  "features/perchTerminal/agentPlatform/financialRoles.ts"() {
83129
- "use strict";
83130
83127
  FINANCIAL_ROLE_REGISTRY = /* @__PURE__ */ new Map();
83131
83128
  evidenceScoutManifest = {
83132
83129
  workerId: "evidence_scout",
@@ -138643,6 +138640,7 @@ function offSandboxEvent(runId, handler) {
138643
138640
  var LOCAL_WORKSPACE_ACCESS_UNAVAILABLE;
138644
138641
  var init_bridge = __esm({
138645
138642
  "features/perchTerminal/desktop/bridge.ts"() {
138643
+ "use strict";
138646
138644
  LOCAL_WORKSPACE_ACCESS_UNAVAILABLE = "Local workspace access is unavailable. Open Perch Desktop or update the app.";
138647
138645
  }
138648
138646
  });
@@ -197922,6 +197920,15 @@ async function dispatchAgentHandler(args, ctx) {
197922
197920
  const agentCtx = {
197923
197921
  workspaceRoot,
197924
197922
  desktopConnected: ctx.desktopConnected,
197923
+ // CLI surface: children inherit the local bridge and server auth, same as
197924
+ // flock's buildSpawnContext — otherwise filesystem workers fail with
197925
+ // worker_desktop_workspace_required on the CLI.
197926
+ cliLocalTools: ctx.cliLocalTools === true,
197927
+ scopedFolderPath: ctx.scopedFolderPath,
197928
+ cliServerAppUrl: ctx.cliServerAppUrl ?? null,
197929
+ cliServerAccessToken: ctx.cliServerAccessToken ?? null,
197930
+ marketDeskProxyAppUrl: ctx.marketDeskProxyAppUrl ?? null,
197931
+ marketDeskProxyAccessToken: ctx.marketDeskProxyAccessToken ?? null,
197925
197932
  activeRootPath: ctx.activeRootPath,
197926
197933
  permissionMode: ctx.permissionMode,
197927
197934
  workspaceId: ctx.workspaceId,
@@ -205368,7 +205375,7 @@ function clampInt(value, min2, max2, fallback) {
205368
205375
  const num = typeof value === "number" && Number.isFinite(value) ? Math.floor(value) : fallback;
205369
205376
  return Math.min(Math.max(num, min2), max2);
205370
205377
  }
205371
- var ADHOC_FORBIDDEN_TOOLS, ADHOC_WRITE_TOOLS, ADHOC_MAX_ITERATIONS, MAX_NAME_CHARS, MAX_CONTRACT_CHARS, DEFAULT_OUTPUT_CONTRACT;
205378
+ var ADHOC_FORBIDDEN_TOOLS, ADHOC_WRITE_TOOLS, ADHOC_MAX_ITERATIONS, ADHOC_MAX_TOOL_CALLS, MAX_NAME_CHARS, MAX_CONTRACT_CHARS, DEFAULT_OUTPUT_CONTRACT;
205372
205379
  var init_adhocManifest = __esm({
205373
205380
  "features/perchTerminal/runtime/workers/adhocManifest.ts"() {
205374
205381
  "use strict";
@@ -205397,6 +205404,7 @@ var init_adhocManifest = __esm({
205397
205404
  TOOL_NAMES.createDirectory
205398
205405
  ]);
205399
205406
  ADHOC_MAX_ITERATIONS = 10;
205407
+ ADHOC_MAX_TOOL_CALLS = 40;
205400
205408
  MAX_NAME_CHARS = 40;
205401
205409
  MAX_CONTRACT_CHARS = 240;
205402
205410
  DEFAULT_OUTPUT_CONTRACT = "Return a short structured summary of what was found or done.";
@@ -205485,6 +205493,14 @@ var init_spawnWorker = __esm({
205485
205493
  handler: async (args, ctx) => {
205486
205494
  let workerId = String(args.workerId ?? "");
205487
205495
  const objective = String(args.objective ?? "");
205496
+ if (!ctx.onEvent) {
205497
+ return {
205498
+ ok: false,
205499
+ workerId,
205500
+ summary: "spawn_worker requires an event sink from the parent tool loop.",
205501
+ errorCode: "worker_event_sink_missing"
205502
+ };
205503
+ }
205488
205504
  let adhocManifestId = null;
205489
205505
  let adhocNickname = null;
205490
205506
  const customSpec = parseAdhocSpec(args.custom);
@@ -205499,11 +205515,13 @@ var init_spawnWorker = __esm({
205499
205515
  if (workerId && customSpec && !resolveWorkerManifest(workerId)) {
205500
205516
  workerId = "";
205501
205517
  }
205518
+ let adhocDisplayTitle;
205502
205519
  if (!workerId && customSpec) {
205503
205520
  const { manifest, droppedTools } = buildAdhocWorkerManifest(customSpec);
205504
205521
  registerWorkerManifest(manifest);
205505
205522
  adhocManifestId = manifest.workerId;
205506
205523
  adhocNickname = flockNicknameFor(manifest.workerId, 0);
205524
+ adhocDisplayTitle = `${manifest.name} \xB7 ${adhocNickname}`;
205507
205525
  workerId = manifest.workerId;
205508
205526
  if (droppedTools.length > 0 && ctx.onEvent) {
205509
205527
  ctx.onEvent({
@@ -205524,15 +205542,7 @@ var init_spawnWorker = __esm({
205524
205542
  }
205525
205543
  const context = typeof args.context === "string" || typeof args.context === "object" && args.context !== null && !Array.isArray(args.context) ? args.context : void 0;
205526
205544
  const lane = typeof args.lane === "string" ? args.lane : void 0;
205527
- const maxIterations = typeof args.maxIterations === "number" ? args.maxIterations : void 0;
205528
- if (!ctx.onEvent) {
205529
- return {
205530
- ok: false,
205531
- workerId,
205532
- summary: "spawn_worker requires an event sink from the parent tool loop.",
205533
- errorCode: "worker_event_sink_missing"
205534
- };
205535
- }
205545
+ const maxIterations = typeof args.maxIterations === "number" ? adhocManifestId ? Math.min(args.maxIterations, ADHOC_MAX_ITERATIONS) : args.maxIterations : void 0;
205536
205546
  const enrichedContext = await threadPriorSpecialistContext({
205537
205547
  threadId: ctx.threadId,
205538
205548
  roleId: workerId,
@@ -205554,10 +205564,30 @@ Proceed with the available context. If a missing fact is essential, ask the user
205554
205564
  ].filter(Boolean).join("\n\n");
205555
205565
  try {
205556
205566
  const result2 = await spawnWorker(
205557
- { workerId, objective: workerObjective, context: enrichedContext, lane, maxIterations },
205558
205567
  {
205568
+ workerId,
205569
+ objective: workerObjective,
205570
+ context: enrichedContext,
205571
+ lane,
205572
+ maxIterations,
205573
+ // Ad-hoc workers get a hard real-tool-call ceiling (observed live:
205574
+ // an unbounded 66-call run). Registered workers keep their existing
205575
+ // behavior — suites and managed workflows own their own budgets.
205576
+ maxToolCalls: adhocManifestId ? ADHOC_MAX_TOOL_CALLS : void 0
205577
+ },
205578
+ {
205579
+ displayTitle: adhocDisplayTitle,
205559
205580
  workspaceRoot: effectiveWorkspaceRoot(ctx),
205560
205581
  desktopConnected: ctx.desktopConnected,
205582
+ // CLI surface: children inherit the local bridge and server auth,
205583
+ // same as flock's buildSpawnContext — without these, every worker
205584
+ // needing filesystem access dies with worker_desktop_workspace_required.
205585
+ cliLocalTools: ctx.cliLocalTools === true,
205586
+ scopedFolderPath: ctx.scopedFolderPath,
205587
+ cliServerAppUrl: ctx.cliServerAppUrl ?? null,
205588
+ cliServerAccessToken: ctx.cliServerAccessToken ?? null,
205589
+ marketDeskProxyAppUrl: ctx.marketDeskProxyAppUrl ?? null,
205590
+ marketDeskProxyAccessToken: ctx.marketDeskProxyAccessToken ?? null,
205561
205591
  activeRootPath: ctx.activeRootPath,
205562
205592
  permissionMode: ctx.permissionMode,
205563
205593
  workspaceId: ctx.workspaceId,
@@ -220218,12 +220248,13 @@ async function spawnWorker(args, ctx) {
220218
220248
  errorCode: "worker_not_found"
220219
220249
  };
220220
220250
  }
220251
+ const eventTitle = ctx.displayTitle?.trim() || manifest.name;
220221
220252
  const runDiscriminator = ctx.runId ?? Date.now().toString(36);
220222
220253
  const childThreadId = args.childThreadId ?? (ctx.threadId ? `${ctx.threadId}::worker::${args.workerId}::${runDiscriminator}` : null);
220223
220254
  const workerRun = ctx.threadId ? await registerWorkerRun({
220224
220255
  threadId: ctx.threadId,
220225
220256
  workerId: args.workerId,
220226
- title: manifest.name,
220257
+ title: eventTitle,
220227
220258
  objective: args.objective,
220228
220259
  context: args.context,
220229
220260
  parentToolCallId: ctx.parentToolCallId ?? null,
@@ -220246,14 +220277,14 @@ async function spawnWorker(args, ctx) {
220246
220277
  childThreadId,
220247
220278
  workerRunId: runtimeWorkerRunId,
220248
220279
  workerId: args.workerId,
220249
- title: manifest.name
220280
+ title: eventTitle
220250
220281
  });
220251
220282
  }
220252
220283
  ctx.onEvent({
220253
220284
  type: "worker_run_started",
220254
220285
  workerId: args.workerId,
220255
220286
  workerRunId: runtimeWorkerRunId,
220256
- title: manifest.name,
220287
+ title: eventTitle,
220257
220288
  objective: args.objective,
220258
220289
  contextSummary: summarizeWorkerContextForTranscript(args.context),
220259
220290
  childThreadId,
@@ -220460,18 +220491,24 @@ ${contextBlock}
220460
220491
  attachOperatorScreenshots: isBrowserDeliveryRole(args.workerId)
220461
220492
  };
220462
220493
  const result2 = await runModelToolLoop(loopInput);
220494
+ const approvalBlocked = result2.stopReason === "approval_required" ? result2.pendingApproval ?? null : null;
220463
220495
  const recoveredStructuredOutput = recoverWorkerStructuredOutput(args.workerId, args.objective, args.context, result2.toolCalls);
220464
220496
  const structuredOutput = parseStructuredRecordFromModelText(result2.text) ?? recoveredStructuredOutput;
220465
220497
  const missingRequiredOutput = result2.ok && Boolean(manifest.outputSchema) && !structuredOutput;
220466
220498
  const verifierPartialOrFail = (args.workerId === "source_verifier" || args.workerId === "legal_citation_verifier") && structuredOutput !== null && typeof structuredOutput === "object" && structuredOutput.verificationStatus !== "pass";
220467
220499
  const hasUsableOutput = Boolean(structuredOutput) || Boolean(recoveredStructuredOutput) || (result2.text?.trim().length ?? 0) > 50;
220468
- const workerOk = (result2.ok || Boolean(recoveredStructuredOutput)) && !missingRequiredOutput;
220469
- const usabilityStatus = resolveWorkerUsability({
220500
+ const workerOk = !approvalBlocked && (result2.ok || Boolean(recoveredStructuredOutput)) && !missingRequiredOutput;
220501
+ const usabilityStatus = approvalBlocked ? "needs_user_input" : resolveWorkerUsability({
220470
220502
  workerOk,
220471
220503
  hasUsableOutput,
220472
220504
  verifierPartialOrFail
220473
220505
  });
220474
220506
  const workerWarnings = [];
220507
+ if (approvalBlocked) {
220508
+ workerWarnings.push(
220509
+ "Worker stopped at an approval gate \u2014 the gated action did not run."
220510
+ );
220511
+ }
220475
220512
  if (verifierPartialOrFail && hasUsableOutput) {
220476
220513
  workerWarnings.push(`Verification returned "${structuredOutput?.verificationStatus ?? "unknown"}" \u2014 output usable with caveat.`);
220477
220514
  }
@@ -220483,7 +220520,7 @@ ${contextBlock}
220483
220520
  }
220484
220521
  const recoveredSummary = recoveredStructuredOutput ? summarizeRecoveredWorkerOutput(args.workerId, recoveredStructuredOutput) : null;
220485
220522
  const summary = truncateSummary(
220486
- workerOk ? !result2.ok && recoveredSummary ? recoveredSummary : result2.text || recoveredSummary || (recoveredStructuredOutput ? JSON.stringify(recoveredStructuredOutput) : "") : missingRequiredOutput ? result2.text || "Worker stopped without returning the required structured JSON output." : result2.text || result2.error || "Worker failed before producing output."
220523
+ approvalBlocked ? `Blocked at an approval gate: ${approvalBlocked.toolName ?? "a gated tool"} requires approval in the current permission mode${approvalBlocked.reason ? ` (${approvalBlocked.reason})` : ""}. The action did not run. Approve it interactively, or re-run under /permission take_the_wheel.` : workerOk ? !result2.ok && recoveredSummary ? recoveredSummary : result2.text || recoveredSummary || (recoveredStructuredOutput ? JSON.stringify(recoveredStructuredOutput) : "") : missingRequiredOutput ? result2.text || "Worker stopped without returning the required structured JSON output." : result2.text || result2.error || "Worker failed before producing output."
220487
220524
  );
220488
220525
  const durationMs = Date.now() - startMs;
220489
220526
  let contextPacket = null;
@@ -220520,7 +220557,7 @@ ${contextBlock}
220520
220557
  type: "worker_run_completed",
220521
220558
  workerId: args.workerId,
220522
220559
  workerRunId: runtimeWorkerRunId,
220523
- title: manifest.name,
220560
+ title: eventTitle,
220524
220561
  childThreadId,
220525
220562
  persistedThreadId,
220526
220563
  parentToolCallId: ctx.parentToolCallId ?? null,
@@ -220554,7 +220591,7 @@ ${contextBlock}
220554
220591
  missingRequiredOutput,
220555
220592
  verifierPartialOrFail,
220556
220593
  error: result2.error
220557
- }) : void 0,
220594
+ }) : approvalBlocked ? "worker_approval_required" : void 0,
220558
220595
  workerOffThreadTokens: workerTokenEstimate,
220559
220596
  contextPacket
220560
220597
  }, { supabase: ctx.supabase ?? null });
@@ -220578,7 +220615,7 @@ ${contextBlock}
220578
220615
  missingRequiredOutput,
220579
220616
  verifierPartialOrFail,
220580
220617
  error: result2.error
220581
- }) : void 0,
220618
+ }) : approvalBlocked ? "worker_approval_required" : void 0,
220582
220619
  warnings: workerWarnings.length > 0 ? workerWarnings : void 0
220583
220620
  };
220584
220621
  } catch (error) {
@@ -220589,7 +220626,7 @@ ${contextBlock}
220589
220626
  type: "worker_run_completed",
220590
220627
  workerId: args.workerId,
220591
220628
  workerRunId: runtimeWorkerRunId,
220592
- title: manifest.name,
220629
+ title: eventTitle,
220593
220630
  childThreadId,
220594
220631
  parentToolCallId: ctx.parentToolCallId ?? null,
220595
220632
  ok: false,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "perchai-cli",
3
- "version": "2.4.35",
3
+ "version": "2.4.37",
4
4
  "description": "Perch AI command-line interface",
5
5
  "bin": {
6
6
  "perch": "bin/perch"