@tangle-network/agent-runtime 0.48.0 → 0.49.0

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 (40) hide show
  1. package/README.md +79 -15
  2. package/dist/agent.js +1 -1
  3. package/dist/chunk-GHX7XOJ2.js +433 -0
  4. package/dist/chunk-GHX7XOJ2.js.map +1 -0
  5. package/dist/{chunk-TJS7S3HJ.js → chunk-IQS4HI3F.js} +14 -5
  6. package/dist/chunk-IQS4HI3F.js.map +1 -0
  7. package/dist/{chunk-IW2LMLK6.js → chunk-PXUTIMGJ.js} +767 -129
  8. package/dist/chunk-PXUTIMGJ.js.map +1 -0
  9. package/dist/{chunk-656G2XCL.js → chunk-U2VEWKKK.js} +3 -3
  10. package/dist/{chunk-JNPK46YH.js → chunk-VIEDXELL.js} +408 -6
  11. package/dist/chunk-VIEDXELL.js.map +1 -0
  12. package/dist/{chunk-VR4JIC5H.js → chunk-XTEZ3YJ4.js} +2 -2
  13. package/dist/index.d.ts +29 -4
  14. package/dist/index.js +109 -21
  15. package/dist/index.js.map +1 -1
  16. package/dist/kb-gate-CsXpNRk7.d.ts +1145 -0
  17. package/dist/{loop-runner-bin-DEm4roYF.d.ts → loop-runner-bin-Cgn0A-NW.d.ts} +1 -1
  18. package/dist/loop-runner-bin.d.ts +2 -2
  19. package/dist/loop-runner-bin.js +3 -3
  20. package/dist/loops.d.ts +2 -2
  21. package/dist/loops.js +11 -1
  22. package/dist/mcp/bin.js +187 -24
  23. package/dist/mcp/bin.js.map +1 -1
  24. package/dist/mcp/index.d.ts +27 -124
  25. package/dist/mcp/index.js +28 -6
  26. package/dist/mcp/index.js.map +1 -1
  27. package/dist/platform.js +2 -2
  28. package/dist/platform.js.map +1 -1
  29. package/dist/runtime.d.ts +285 -8
  30. package/dist/runtime.js +11 -1
  31. package/dist/workflow.js +1 -1
  32. package/package.json +6 -5
  33. package/dist/chunk-IW2LMLK6.js.map +0 -1
  34. package/dist/chunk-JNPK46YH.js.map +0 -1
  35. package/dist/chunk-LX66I3SC.js +0 -218
  36. package/dist/chunk-LX66I3SC.js.map +0 -1
  37. package/dist/chunk-TJS7S3HJ.js.map +0 -1
  38. package/dist/kb-gate-51BlLlVM.d.ts +0 -529
  39. /package/dist/{chunk-656G2XCL.js.map → chunk-U2VEWKKK.js.map} +0 -0
  40. /package/dist/{chunk-VR4JIC5H.js.map → chunk-XTEZ3YJ4.js.map} +0 -0
@@ -1,6 +1,6 @@
1
1
  import { S as SandboxClient, f as LoopSandboxPlacement, e as LoopTraceEmitter } from '../types-nBMuollC.js';
2
- import { c as FleetHandle, d as DelegationExecutor, e as DelegateFeedbackArgs, f as DelegationFeedbackSnapshot, g as DelegationProfile, D as DelegateCodeArgs, h as DelegateResearchArgs, i as DelegateUiAuditArgs, j as DelegationStatus, k as DelegationProgress, l as DelegationResultPayload, m as DelegationError, n as DelegationStatusResult, o as DelegationHistoryArgs, p as DelegationHistoryEntry, q as CoderDelegate, R as ResearcherDelegate, U as UiAuditorDelegate, r as DelegateCodeResult, s as DelegateFeedbackResult, t as ResearchSource, u as DelegateResearchResult, v as DelegateUiAuditResult, w as DelegationHistoryResult, x as DelegationStatusArgs } from '../kb-gate-51BlLlVM.js';
3
- export { y as CoderReview, C as CoderReviewer, a as CoderWinnerSelection, z as CreateDefaultCoderDelegateOptions, b as CreateKbGateOptions, A as DelegateCodeConfig, B as DelegateResearchConfig, E as DelegateRunCtx, G as DelegateUiAuditConfig, H as DelegateUiAuditRoute, F as FactCandidate, I as FactJudge, J as FactJudgeVerdict, K as FeedbackRating, L as FeedbackRefersTo, M as FleetWorkspaceExecutorOptions, N as KbGateResult, O as ResearchOutputShape, S as SiblingSandboxExecutorOptions, P as UiAuditorDelegationOutput, Q as createDefaultCoderDelegate, T as createFleetWorkspaceExecutor, V as createKbGate, W as createSiblingSandboxExecutor } from '../kb-gate-51BlLlVM.js';
2
+ import { c as FleetHandle, d as DelegationExecutor, e as DelegateFeedbackArgs, f as DelegationFeedbackSnapshot, g as DelegationTaskQueue, h as CoderDelegate, R as ResearcherDelegate, U as UiAuditorDelegate, D as DelegateCodeArgs, i as DelegateCodeResult, j as DelegateFeedbackResult, k as ResearchSource, l as DelegateResearchArgs, m as DelegateResearchResult, n as DelegateUiAuditArgs, o as DelegateUiAuditResult, p as DelegationHistoryResult, q as DelegationHistoryArgs, r as DelegationStatusResult, s as DelegationStatusArgs } from '../kb-gate-CsXpNRk7.js';
3
+ export { t as CoderReview, C as CoderReviewer, a as CoderWinnerSelection, u as CreateDefaultCoderDelegateOptions, b as CreateKbGateOptions, v as DelegateCodeConfig, w as DelegateResearchConfig, x as DelegateRunCtx, y as DelegateUiAuditConfig, z as DelegateUiAuditRoute, A as DelegationError, B as DelegationHistoryEntry, E as DelegationPersistenceError, G as DelegationProfile, H as DelegationProgress, I as DelegationRecord, J as DelegationResultPayload, K as DelegationResumeContext, L as DelegationResumeDriver, M as DelegationResumeTick, N as DelegationRunContext, O as DelegationStateCorruptError, P as DelegationStatus, Q as DelegationStore, S as DelegationTaskQueueOptions, T as DetachedSessionRefParts, V as DetachedTurn, W as DriveTurnCapableBox, X as DriveTurnResumeDriverOptions, Y as DriveTurnTick, F as FactCandidate, Z as FactJudge, _ as FactJudgeVerdict, $ as FeedbackRating, a0 as FeedbackRefersTo, a1 as FileDelegationStore, a2 as FileDelegationStoreOptions, a3 as FleetWorkspaceExecutorOptions, a4 as InMemoryDelegationStore, a5 as KbGateResult, a6 as ResearchOutputShape, a7 as RunDetachedTurnOptions, a8 as SettleDetachedCoderTurnOptions, a9 as SiblingSandboxExecutorOptions, aa as SubmitInput, ab as SubmitOutput, ac as UiAuditorDelegationOutput, ad as coderTaskFromArgs, ae as createDefaultCoderDelegate, af as createDriveTurnResumeDriver, ag as createFleetWorkspaceExecutor, ah as createKbGate, ai as createSiblingSandboxExecutor, aj as detachedTurnEvents, ak as formatDetachedSessionRef, al as hashIdempotencyInput, am as parseDetachedSessionRef, an as runDetachedTurn, ao as settleDetachedCoderTurn } from '../kb-gate-CsXpNRk7.js';
4
4
  export { B as BuildDelegationMcpServerOptions, C as ComposeProductionAgentProfileOptions, D as DELEGATION_MCP_SERVER_KEY, b as buildDelegationMcpServer, c as composeProductionAgentProfile } from '../delegation-profile-1GbW5yA3.js';
5
5
  import { L as LocalHarness, r as runLocalHarness } from '../local-harness-KrdFTY5R.js';
6
6
  export { a as LocalHarnessResult, R as RunLocalHarnessOptions } from '../local-harness-KrdFTY5R.js';
@@ -290,127 +290,6 @@ interface InProcessExecutorDescribePlacement extends LoopSandboxPlacement {
290
290
  */
291
291
  declare function createInProcessExecutor(options: InProcessExecutorOptions): DelegationExecutor;
292
292
 
293
- /**
294
- * @experimental
295
- *
296
- * In-memory state for async MCP delegations. State machine:
297
- *
298
- * pending → running → completed | failed
299
- * ↘ cancelled (from any non-terminal state via cancel())
300
- *
301
- * Each `submit` returns a `taskId` immediately and kicks the work off in the
302
- * background. The work function receives an `AbortSignal` the queue fires
303
- * when `cancel(taskId)` is called. The queue does NOT supervise runtime
304
- * timeouts — the underlying `runLoop` driver / sandbox imposes those.
305
- *
306
- * Idempotency: callers may supply an `idempotencyKey` (hash of the input).
307
- * A duplicate `submit` with a known key returns the existing task instead of
308
- * starting a new one. Mutated input → different key → different task.
309
- *
310
- * Persistent state (sqlite) is a Phase 2 follow-up. The README documents the
311
- * in-memory limitation explicitly so consumers know a worker restart drops
312
- * pending delegations.
313
- */
314
-
315
- type AnyDelegateArgs = DelegateCodeArgs | DelegateResearchArgs | DelegateUiAuditArgs;
316
- /** @experimental */
317
- interface DelegationRecord {
318
- taskId: string;
319
- profile: DelegationProfile;
320
- namespace?: string;
321
- args: AnyDelegateArgs;
322
- status: DelegationStatus;
323
- progress?: DelegationProgress;
324
- result?: DelegationResultPayload;
325
- error?: DelegationError;
326
- costUsd?: number;
327
- startedAt: string;
328
- completedAt?: string;
329
- /** Sha-prefix hash of the canonical input — used for idempotency lookup. */
330
- idempotencyKey?: string;
331
- /** Feedback events keyed by this delegation's taskId. */
332
- feedback: DelegationFeedbackSnapshot[];
333
- }
334
- /** @experimental */
335
- interface SubmitInput<Args extends AnyDelegateArgs> {
336
- profile: DelegationProfile;
337
- args: Args;
338
- namespace?: string;
339
- idempotencyKey?: string;
340
- /**
341
- * Runs the underlying delegation. The queue passes a fresh `AbortSignal`
342
- * and a `report` channel for incremental progress updates. The function
343
- * MUST resolve with the typed `DelegationResultPayload['output']`; the
344
- * queue wraps it with the profile tag.
345
- */
346
- run: (ctx: {
347
- signal: AbortSignal;
348
- report(progress: DelegationProgress): void;
349
- }) => Promise<DelegationResultPayload['output']>;
350
- }
351
- /** @experimental */
352
- interface SubmitOutput {
353
- taskId: string;
354
- /** True when a prior matching `idempotencyKey` returned an existing record. */
355
- reused: boolean;
356
- }
357
- /** @experimental */
358
- interface DelegationTaskQueueOptions {
359
- /** ID generator override; default `randomTaskId`. */
360
- generateId?: () => string;
361
- /** Clock override; default `() => new Date().toISOString()`. */
362
- now?: () => string;
363
- }
364
- /** @experimental */
365
- declare class DelegationTaskQueue {
366
- private readonly records;
367
- private readonly controllers;
368
- private readonly byIdempotencyKey;
369
- private readonly generateId;
370
- private readonly now;
371
- constructor(options?: DelegationTaskQueueOptions);
372
- /**
373
- * Kick off a delegation in the background. Returns immediately. The
374
- * `taskId` is queryable via `status` once this method returns.
375
- */
376
- submit<Args extends AnyDelegateArgs>(input: SubmitInput<Args>): SubmitOutput;
377
- /**
378
- * Snapshot the current state of a delegation. Returns `undefined` for
379
- * unknown ids so callers can distinguish missing from terminal.
380
- */
381
- status(taskId: string): DelegationStatusResult | undefined;
382
- /**
383
- * Abort an in-flight delegation. Returns `false` if the task is unknown
384
- * or already terminal. The underlying `run` function MUST honor the
385
- * abort signal for the cancel to take effect; the queue marks the
386
- * record `cancelled` regardless so a misbehaving runner cannot pin the
387
- * UI on `running` forever.
388
- */
389
- cancel(taskId: string): boolean;
390
- /**
391
- * Append a feedback event to the matching delegation. Returns `false`
392
- * when `ref` does not name a known taskId — the caller should still
393
- * record the feedback through a different surface (artifact/outcome
394
- * kinds are not queue-bound).
395
- */
396
- attachFeedback(taskId: string, snapshot: DelegationFeedbackSnapshot): boolean;
397
- /**
398
- * Query the recorded delegations. Returns entries newest-first (by
399
- * `startedAt`), truncated to `limit`.
400
- */
401
- history(args?: DelegationHistoryArgs): DelegationHistoryEntry[];
402
- /** Test-only — number of in-flight (non-terminal) records. */
403
- inflightCount(): number;
404
- private execute;
405
- }
406
- /**
407
- * Best-effort stable hash for use as `idempotencyKey`. Not cryptographic;
408
- * collisions only affect dedupe, never correctness.
409
- *
410
- * @experimental
411
- */
412
- declare function hashIdempotencyInput(value: unknown): string;
413
-
414
293
  /**
415
294
  * @experimental
416
295
  *
@@ -451,6 +330,15 @@ interface McpServerOptions {
451
330
  feedbackStore?: FeedbackStore;
452
331
  /** Override the default in-memory task queue. */
453
332
  queue?: DelegationTaskQueue;
333
+ /**
334
+ * Record deterministic detached-session resume keys on single-variant
335
+ * coder/researcher submissions so a durable queue can resume them after a
336
+ * restart. Enable only when the wired delegates dispatch via sandbox
337
+ * sessions (`driveTurn`) AND `queue` persists records — the keys are inert
338
+ * otherwise. The bin turns this on alongside the durable store for
339
+ * session-backed (sibling/fleet) placements.
340
+ */
341
+ detachedDispatch?: boolean;
454
342
  /**
455
343
  * Extra tools to serve alongside the delegation tools, for example
456
344
  * `createCoordinationTools(...).tools`. Registered after the built-ins; a
@@ -733,6 +621,16 @@ interface DelegateCodeHandlerOptions {
733
621
  delegate: CoderDelegate;
734
622
  /** Override the duration hint. */
735
623
  estimateDurationMs?: (args: DelegateCodeArgs) => number;
624
+ /**
625
+ * Record a deterministic detached-session resume key on single-variant
626
+ * submissions (derived from the idempotency key, so retried identical
627
+ * inputs name the same logical turn). Enable only when the wired delegate
628
+ * dispatches via sandbox sessions — `createDefaultCoderDelegate` routes
629
+ * onto its `driveTurn` tick path when the ref is present. Fanout
630
+ * (`variants > 1`) never records a ref: one resume key cannot express N
631
+ * sessions + winner selection.
632
+ */
633
+ detachedDispatch?: boolean;
736
634
  }
737
635
  /** @experimental */
738
636
  declare function createDelegateCodeHandler(options: DelegateCodeHandlerOptions): (raw: unknown) => Promise<DelegateCodeResult>;
@@ -901,6 +799,11 @@ interface DelegateResearchHandlerOptions {
901
799
  queue: DelegationTaskQueue;
902
800
  delegate: ResearcherDelegate;
903
801
  estimateDurationMs?: (args: DelegateResearchArgs) => number;
802
+ /**
803
+ * Record a deterministic detached-session resume key on single-variant
804
+ * submissions. Same contract as `DelegateCodeHandlerOptions.detachedDispatch`.
805
+ */
806
+ detachedDispatch?: boolean;
904
807
  }
905
808
  /** @experimental */
906
809
  declare function createDelegateResearchHandler(options: DelegateResearchHandlerOptions): (raw: unknown) => Promise<DelegateResearchResult>;
@@ -1148,4 +1051,4 @@ declare function createPropagatingTraceEmitter(ctx: TraceContext): {
1148
1051
  */
1149
1052
  declare function traceContextToEnv(ctx: TraceContext): Record<string, string>;
1150
1053
 
1151
- export { type AnalystRegistry, type Check, type CheckRunnerOptions, CoderDelegate, type CoordinationEvent, type CoordinationTools, type CoordinationToolsOptions, type CreateWorktreeOptions, DELEGATE_CODE_DESCRIPTION, DELEGATE_CODE_INPUT_SCHEMA, DELEGATE_CODE_TOOL_NAME, DELEGATE_FEEDBACK_DESCRIPTION, DELEGATE_FEEDBACK_INPUT_SCHEMA, DELEGATE_FEEDBACK_TOOL_NAME, DELEGATE_RESEARCH_DESCRIPTION, DELEGATE_RESEARCH_INPUT_SCHEMA, DELEGATE_RESEARCH_TOOL_NAME, DELEGATE_UI_AUDIT_DESCRIPTION, DELEGATE_UI_AUDIT_INPUT_SCHEMA, DELEGATE_UI_AUDIT_TOOL_NAME, DELEGATION_HISTORY_DESCRIPTION, DELEGATION_HISTORY_INPUT_SCHEMA, DELEGATION_HISTORY_TOOL_NAME, DELEGATION_STATUS_DESCRIPTION, DELEGATION_STATUS_INPUT_SCHEMA, DELEGATION_STATUS_TOOL_NAME, DelegateCodeArgs, DelegateCodeResult, DelegateFeedbackArgs, DelegateFeedbackResult, DelegateResearchArgs, DelegateResearchResult, DelegateUiAuditArgs, DelegateUiAuditResult, DelegationError, DelegationExecutor, DelegationFeedbackSnapshot, DelegationHistoryArgs, DelegationHistoryEntry, DelegationHistoryResult, DelegationProfile, DelegationProgress, type DelegationRecord, DelegationResultPayload, DelegationStatus, DelegationStatusArgs, DelegationStatusResult, DelegationTaskQueue, type DelegationTaskQueueOptions, type DetectExecutorArgs, type DiffOptions, type DiffResult, type FeedbackEvent, type FeedbackStore, FleetHandle, type GitRunner, InMemoryFeedbackStore, type InProcessExecutorDescribePlacement, type InProcessExecutorOptions, type JsonRpcMessage, type JsonRpcResponse, LocalHarness, type MakeWorkerAgent, type McpServer, type McpServerOptions, type McpToolDescriptor, type McpTransport, type Question, type QuestionDecision, type QuestionPolicy, type QuestionRecord, type RemoveWorktreeOptions, ResearchSource, ResearcherDelegate, type SettledWorker, type SubmitInput, type SubmitOutput, type TraceContext, UiAuditorDelegate, type WorktreeHandle, captureWorktreeDiff, createCoordinationTools, createDelegateCodeHandler, createDelegateFeedbackHandler, createDelegateResearchHandler, createDelegateUiAuditHandler, createDelegationHistoryHandler, createDelegationStatusHandler, createInProcessExecutor, createInProcessTransport, createMcpServer, createPropagatingTraceEmitter, createWorktree, defaultChecks, detectExecutor, eventToSnapshot, hashIdempotencyInput, liftFindings, makeCheckRunner, readTraceContextFromEnv, removeWorktree, renderTrace, runCheck, runLocalHarness, traceContextToEnv, validateDelegateCodeArgs, validateDelegateFeedbackArgs, validateDelegateResearchArgs, validateDelegateUiAuditArgs, validateDelegationHistoryArgs, validateDelegationStatusArgs };
1054
+ export { type AnalystRegistry, type Check, type CheckRunnerOptions, CoderDelegate, type CoordinationEvent, type CoordinationTools, type CoordinationToolsOptions, type CreateWorktreeOptions, DELEGATE_CODE_DESCRIPTION, DELEGATE_CODE_INPUT_SCHEMA, DELEGATE_CODE_TOOL_NAME, DELEGATE_FEEDBACK_DESCRIPTION, DELEGATE_FEEDBACK_INPUT_SCHEMA, DELEGATE_FEEDBACK_TOOL_NAME, DELEGATE_RESEARCH_DESCRIPTION, DELEGATE_RESEARCH_INPUT_SCHEMA, DELEGATE_RESEARCH_TOOL_NAME, DELEGATE_UI_AUDIT_DESCRIPTION, DELEGATE_UI_AUDIT_INPUT_SCHEMA, DELEGATE_UI_AUDIT_TOOL_NAME, DELEGATION_HISTORY_DESCRIPTION, DELEGATION_HISTORY_INPUT_SCHEMA, DELEGATION_HISTORY_TOOL_NAME, DELEGATION_STATUS_DESCRIPTION, DELEGATION_STATUS_INPUT_SCHEMA, DELEGATION_STATUS_TOOL_NAME, DelegateCodeArgs, DelegateCodeResult, DelegateFeedbackArgs, DelegateFeedbackResult, DelegateResearchArgs, DelegateResearchResult, DelegateUiAuditArgs, DelegateUiAuditResult, DelegationExecutor, DelegationFeedbackSnapshot, DelegationHistoryArgs, DelegationHistoryResult, DelegationStatusArgs, DelegationStatusResult, DelegationTaskQueue, type DetectExecutorArgs, type DiffOptions, type DiffResult, type FeedbackEvent, type FeedbackStore, FleetHandle, type GitRunner, InMemoryFeedbackStore, type InProcessExecutorDescribePlacement, type InProcessExecutorOptions, type JsonRpcMessage, type JsonRpcResponse, LocalHarness, type MakeWorkerAgent, type McpServer, type McpServerOptions, type McpToolDescriptor, type McpTransport, type Question, type QuestionDecision, type QuestionPolicy, type QuestionRecord, type RemoveWorktreeOptions, ResearchSource, ResearcherDelegate, type SettledWorker, type TraceContext, UiAuditorDelegate, type WorktreeHandle, captureWorktreeDiff, createCoordinationTools, createDelegateCodeHandler, createDelegateFeedbackHandler, createDelegateResearchHandler, createDelegateUiAuditHandler, createDelegationHistoryHandler, createDelegationStatusHandler, createInProcessExecutor, createInProcessTransport, createMcpServer, createPropagatingTraceEmitter, createWorktree, defaultChecks, detectExecutor, eventToSnapshot, liftFindings, makeCheckRunner, readTraceContextFromEnv, removeWorktree, renderTrace, runCheck, runLocalHarness, traceContextToEnv, validateDelegateCodeArgs, validateDelegateFeedbackArgs, validateDelegateResearchArgs, validateDelegateUiAuditArgs, validateDelegationHistoryArgs, validateDelegationStatusArgs };
package/dist/mcp/index.js CHANGED
@@ -14,12 +14,12 @@ import {
14
14
  removeWorktree,
15
15
  traceContextToEnv,
16
16
  validateDelegateUiAuditArgs
17
- } from "../chunk-TJS7S3HJ.js";
17
+ } from "../chunk-IQS4HI3F.js";
18
18
  import "../chunk-WIR4HOOJ.js";
19
19
  import {
20
20
  mcpToolsForRuntimeMcp,
21
21
  mcpToolsForRuntimeMcpSubset
22
- } from "../chunk-VR4JIC5H.js";
22
+ } from "../chunk-XTEZ3YJ4.js";
23
23
  import {
24
24
  DELEGATE_CODE_DESCRIPTION,
25
25
  DELEGATE_CODE_INPUT_SCHEMA,
@@ -36,7 +36,11 @@ import {
36
36
  DELEGATION_STATUS_DESCRIPTION,
37
37
  DELEGATION_STATUS_INPUT_SCHEMA,
38
38
  DELEGATION_STATUS_TOOL_NAME,
39
+ DelegationPersistenceError,
40
+ DelegationStateCorruptError,
39
41
  DelegationTaskQueue,
42
+ FileDelegationStore,
43
+ InMemoryDelegationStore,
40
44
  InMemoryFeedbackStore,
41
45
  createDelegateCodeHandler,
42
46
  createDelegateFeedbackHandler,
@@ -50,15 +54,22 @@ import {
50
54
  validateDelegateResearchArgs,
51
55
  validateDelegationHistoryArgs,
52
56
  validateDelegationStatusArgs
53
- } from "../chunk-JNPK46YH.js";
57
+ } from "../chunk-VIEDXELL.js";
54
58
  import {
55
59
  createKbGate
56
60
  } from "../chunk-FNMGYYSS.js";
57
61
  import {
62
+ coderTaskFromArgs,
58
63
  createDefaultCoderDelegate,
64
+ createDriveTurnResumeDriver,
59
65
  createFleetWorkspaceExecutor,
60
- createSiblingSandboxExecutor
61
- } from "../chunk-LX66I3SC.js";
66
+ createSiblingSandboxExecutor,
67
+ detachedTurnEvents,
68
+ formatDetachedSessionRef,
69
+ parseDetachedSessionRef,
70
+ runDetachedTurn,
71
+ settleDetachedCoderTurn
72
+ } from "../chunk-GHX7XOJ2.js";
62
73
  import "../chunk-KADIJAD4.js";
63
74
  import {
64
75
  runLocalHarness
@@ -70,7 +81,7 @@ import {
70
81
  } from "../chunk-7JITYN6T.js";
71
82
  import {
72
83
  assertTraceDerivedFindings
73
- } from "../chunk-IW2LMLK6.js";
84
+ } from "../chunk-PXUTIMGJ.js";
74
85
  import "../chunk-GSUO5QS6.js";
75
86
  import "../chunk-DGUM43GV.js";
76
87
 
@@ -579,10 +590,15 @@ export {
579
590
  DELEGATION_STATUS_DESCRIPTION,
580
591
  DELEGATION_STATUS_INPUT_SCHEMA,
581
592
  DELEGATION_STATUS_TOOL_NAME,
593
+ DelegationPersistenceError,
594
+ DelegationStateCorruptError,
582
595
  DelegationTaskQueue,
596
+ FileDelegationStore,
597
+ InMemoryDelegationStore,
583
598
  InMemoryFeedbackStore,
584
599
  buildDelegationMcpServer,
585
600
  captureWorktreeDiff,
601
+ coderTaskFromArgs,
586
602
  composeProductionAgentProfile,
587
603
  createCoordinationTools,
588
604
  createDefaultCoderDelegate,
@@ -592,6 +608,7 @@ export {
592
608
  createDelegateUiAuditHandler,
593
609
  createDelegationHistoryHandler,
594
610
  createDelegationStatusHandler,
611
+ createDriveTurnResumeDriver,
595
612
  createFleetWorkspaceExecutor,
596
613
  createInProcessExecutor,
597
614
  createInProcessTransport,
@@ -601,18 +618,23 @@ export {
601
618
  createSiblingSandboxExecutor,
602
619
  createWorktree,
603
620
  defaultChecks,
621
+ detachedTurnEvents,
604
622
  detectExecutor,
605
623
  eventToSnapshot,
624
+ formatDetachedSessionRef,
606
625
  hashIdempotencyInput,
607
626
  liftFindings,
608
627
  makeCheckRunner,
609
628
  mcpToolsForRuntimeMcp,
610
629
  mcpToolsForRuntimeMcpSubset,
630
+ parseDetachedSessionRef,
611
631
  readTraceContextFromEnv,
612
632
  removeWorktree,
613
633
  renderTrace,
614
634
  runCheck,
635
+ runDetachedTurn,
615
636
  runLocalHarness,
637
+ settleDetachedCoderTurn,
616
638
  traceContextToEnv,
617
639
  validateDelegateCodeArgs,
618
640
  validateDelegateFeedbackArgs,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/mcp/tools/checks.ts","../../src/mcp/tools/coordination.ts"],"sourcesContent":["/**\n * @experimental\n *\n * The trace-analyst KIND directory — the operator's lenses, as composable DATA.\n *\n * An analyst is not one question. A kind is ONE lens (completeness, correctness, policy, efficiency,\n * tool-use, …); each emits `AnalystFinding`s tagged by its `area`. The driver `list_analysts` to see\n * the menu, `run_analyst(kind, worker)` to apply a lens, and `define_analyst` to author a new one —\n * so at test time you compose the exact lenses a domain needs (maximum specificity), not one generic\n * reviewer. The kinds are data, the runner is generic, and the finding shape + firewall are reused\n * from agent-eval / the keystone — never re-derived.\n *\n * A kind here is a lightweight lens (`Check`); it is a deliberate SUBSET of agent-eval's full\n * `TraceAnalystKindSpec`, so a kind that needs the heavy agentic actor (sub-agent recursion, tools,\n * goldens) upgrades to `createTraceAnalystKind` without changing this directory's surface.\n */\n\nimport {\n type AnalystFinding,\n type AnalystSeverity,\n type EvidenceRef,\n makeFinding,\n} from '@tangle-network/agent-eval'\nimport { assertTraceDerivedFindings } from '../../runtime'\n\n// agent-eval's root entry exports the lift (`makeFinding`) + the `AnalystFinding`/`EvidenceRef` shapes\n// but NOT the raw-row validator / schema prompt (kind-factory-internal). We inline a minimal,\n// equivalent pair so a lens emits the SAME finding shape without reaching into an unstable internal.\nconst ANALYST_SEVERITIES = ['critical', 'high', 'medium', 'low', 'info'] as const\n\nconst FINDING_SCHEMA_PROMPT = [\n 'Each finding is a JSON object with these fields:',\n '- severity: one of \"critical\" | \"high\" | \"medium\" | \"low\" | \"info\"',\n '- claim: one-sentence statement',\n '- evidence_uri: REQUIRED, never blank — exactly one of \"span://<trace>/<span>\", \"artifact://<path>\",',\n ' or \"metric://<name>\"; ALWAYS cite a real id from the trace. No citable id ⇒ omit the finding.',\n '- evidence_excerpt?: a short quote from the cited evidence',\n '- confidence: number 0..1',\n '- rationale?: one sentence of reasoning',\n '- recommended_action?: a concrete imperative (\"Add ...\", \"Replace ...\", \"Stop ...\")',\n 'Emit an empty array when there is nothing to report. Never fabricate evidence.',\n].join('\\n')\n\ninterface RawRow {\n severity: AnalystSeverity\n claim: string\n evidence_uri: string\n confidence: number\n evidence_excerpt?: string\n rationale?: string\n recommended_action?: string\n subject?: string\n}\n\n/** Validate one raw finding row (the lightweight equivalent of agent-eval's `parseRawFinding`):\n * require a claim + a real trace evidence_uri; drop anything else. Returns null to discard. */\nfunction validateRawFinding(row: unknown): RawRow | null {\n if (!row || typeof row !== 'object') return null\n const r = row as Record<string, unknown>\n if (typeof r.claim !== 'string' || r.claim.length === 0) return null\n if (typeof r.evidence_uri !== 'string' || !/^(span|artifact|metric):\\/\\//.test(r.evidence_uri))\n return null\n const sev = (ANALYST_SEVERITIES as readonly string[]).includes(r.severity as string)\n ? (r.severity as AnalystSeverity)\n : 'medium'\n return {\n severity: sev,\n claim: r.claim,\n evidence_uri: r.evidence_uri,\n confidence: typeof r.confidence === 'number' ? r.confidence : 0.5,\n ...(typeof r.evidence_excerpt === 'string' ? { evidence_excerpt: r.evidence_excerpt } : {}),\n ...(typeof r.rationale === 'string' ? { rationale: r.rationale } : {}),\n ...(typeof r.recommended_action === 'string'\n ? { recommended_action: r.recommended_action }\n : {}),\n ...(typeof r.subject === 'string' ? { subject: r.subject } : {}),\n }\n}\n\n/** One lens — a composable analyst kind. Identity fields mirror `TraceAnalystKindSpec` so a kind is\n * upgradeable to the full agentic factory; `lookFor` is the lens question the actor applies. */\nexport interface Check {\n readonly id: string\n readonly description: string\n /** Coarse classification stamped on every finding this kind emits (the renderer groups by it). */\n readonly area: string\n readonly version: string\n /** The lens — what this analyst looks for in the trace. */\n readonly lookFor: string\n}\n\n/** The built-in lens directory. Domain-blind (about any agent trace); compose at test time. */\nexport const defaultChecks: Record<string, Check> = {\n completeness: {\n id: 'completeness',\n description: 'Required work the trace does not yet show done or verified.',\n area: 'failure-mode',\n version: '1',\n lookFor:\n 'every change the task requires that the trace does NOT yet show completed AND verified by a ' +\n 'tool result. One finding per missing/unverified requirement.',\n },\n correctness: {\n id: 'correctness',\n description: 'Tool calls that produced wrong, erroring, or contradicted results.',\n area: 'correctness',\n version: '1',\n lookFor:\n 'tool calls whose RESULT shows an error, a wrong value, or contradicts what the task required ' +\n '(e.g. set the wrong field, value did not take, an error was ignored).',\n },\n policy: {\n id: 'policy',\n description: 'Actions that violate a stated policy, constraint, or allow-list.',\n area: 'safety',\n version: '1',\n lookFor:\n 'actions in the trace that violate a policy/constraint stated in the task or system prompt ' +\n '(forbidden tool, missing approval, out-of-scope mutation, skipped precondition).',\n },\n efficiency: {\n id: 'efficiency',\n description: 'Wasted, redundant, or looping work.',\n area: 'cost',\n version: '1',\n lookFor:\n 'redundant or wasted actions — repeated identical calls, a stalled line retried the same way, ' +\n 'work that produced no progress toward the goal.',\n },\n 'tool-use': {\n id: 'tool-use',\n description: 'Malformed or misused tool calls.',\n area: 'tool-use',\n version: '1',\n lookFor:\n 'tool calls with malformed/invalid arguments, the wrong tool for the intent, or a tool used ' +\n 'against its contract — judged from the call + its result.',\n },\n}\n\n/** Lift validated raw rows into `AnalystFinding`s (agent-eval `makeFinding` stamps `finding_id`/\n * `produced_at`), then enforce the trace-derived firewall (selector ≠ judge). Pure — no LLM. */\nexport function liftFindings(kind: Check, rows: unknown[], producedAt: string): AnalystFinding[] {\n const findings: AnalystFinding[] = []\n for (const row of rows) {\n const raw = validateRawFinding(row)\n if (!raw) continue\n findings.push(\n makeFinding({\n analyst_id: kind.id,\n area: kind.area,\n severity: raw.severity,\n claim: raw.claim,\n confidence: raw.confidence,\n produced_at: producedAt,\n evidence_refs: evidenceRefs(raw.evidence_uri, raw.evidence_excerpt),\n ...(raw.rationale ? { rationale: raw.rationale } : {}),\n ...(raw.recommended_action ? { recommended_action: raw.recommended_action } : {}),\n ...(raw.subject ? { subject: raw.subject } : {}),\n metadata: { kind_version: kind.version },\n }),\n )\n }\n assertTraceDerivedFindings(findings) // throws if a finding cites judge/verdict/score evidence\n return findings\n}\n\n/** Map a raw `evidence_uri` (span:// | artifact:// | metric://<name>) to a typed `EvidenceRef`. A\n * metric ref carries the bare NAME (the firewall checks the metric name for judge/verdict/score —\n * so a finding that cites a judge metric is rejected as not trace-derived). */\nfunction evidenceRefs(uri: string, excerpt?: string): EvidenceRef[] {\n const scheme = uri.split('://', 1)[0]\n if (scheme === 'metric')\n return [\n { kind: 'metric', uri: uri.replace(/^metric:\\/\\//, ''), ...(excerpt ? { excerpt } : {}) },\n ]\n const kind: EvidenceRef['kind'] = scheme === 'span' ? 'span' : 'artifact'\n return [{ kind, uri, ...(excerpt ? { excerpt } : {}) }]\n}\n\n/** Render a worker's trace (tool calls + results) into the text an analyst lens reads. Generic over\n * the trace shape: a `{ messages }` conversation, a bare message array, else stringified. */\nexport function renderTrace(trace: unknown): string {\n const messages = Array.isArray(trace)\n ? trace\n : trace &&\n typeof trace === 'object' &&\n Array.isArray((trace as { messages?: unknown[] }).messages)\n ? (trace as { messages: unknown[] }).messages\n : undefined\n if (!messages) return JSON.stringify(trace ?? {}).slice(0, 8000)\n return messages\n .map((m) => {\n const r = m as {\n role?: string\n content?: unknown\n tool_calls?: Array<{ function?: { name?: string; arguments?: string } }>\n }\n if (r.role === 'tool') return `RESULT ${String(r.content).slice(0, 300)}`\n const calls = r.tool_calls\n ?.map((c) => `${c.function?.name}(${c.function?.arguments})`)\n .join(', ')\n return calls ? `CALL ${calls}` : `SAY ${String(r.content ?? '').slice(0, 200)}`\n })\n .join('\\n')\n .slice(0, 8000)\n}\n\nexport interface CheckRunnerOptions {\n routerBaseUrl: string\n routerKey: string\n model: string\n /** Test/override seam — replace the LLM call. Default: a router chat completion. */\n chat?: (system: string, user: string) => Promise<string>\n}\n\n/** Run ONE lens over a trace → findings. Generic over any kind: prompt = the lens + the agent-eval\n * finding schema; the model's JSON array is parsed (`parseRawFinding`), lifted, and firewalled. */\nexport async function runCheck(\n kind: Check,\n trace: unknown,\n opts: CheckRunnerOptions,\n producedAt: string,\n): Promise<AnalystFinding[]> {\n const sys =\n `You are a trace analyst applying ONE lens: look for ${kind.lookFor}\\n\\n` +\n `${FINDING_SCHEMA_PROMPT}\\n\\nReturn ONLY a fenced \\`\\`\\`json array of finding objects (possibly empty).`\n const user = `WORKER TRACE:\\n${renderTrace(trace)}\\n\\nApply your lens and emit the findings array.`\n const chat = opts.chat ?? defaultChat(opts)\n const content = await chat(sys, user)\n const match = content.match(/```(?:json)?\\s*([\\s\\S]*?)```/)\n let rows: unknown[] = []\n try {\n const parsed = JSON.parse((match?.[1] ?? content).trim())\n rows = Array.isArray(parsed)\n ? parsed\n : Array.isArray((parsed as { findings?: unknown[] })?.findings)\n ? (parsed as { findings: unknown[] }).findings\n : []\n } catch {\n rows = []\n }\n return liftFindings(kind, rows, producedAt)\n}\n\nfunction defaultChat(opts: CheckRunnerOptions): (system: string, user: string) => Promise<string> {\n return async (system, user) => {\n const res = await fetch(`${opts.routerBaseUrl.replace(/\\/$/, '')}/chat/completions`, {\n method: 'POST',\n headers: { 'content-type': 'application/json', authorization: `Bearer ${opts.routerKey}` },\n body: JSON.stringify({\n model: opts.model,\n messages: [\n { role: 'system', content: system },\n { role: 'user', content: user },\n ],\n temperature: 0.3,\n }),\n })\n if (!res.ok) throw new Error(`analyst router ${res.status}`)\n const data = (await res.json()) as { choices?: Array<{ message?: { content?: string } }> }\n return data.choices?.[0]?.message?.content ?? ''\n }\n}\n\n/**\n * Build a `run_analyst` runner over a kind directory.\n * Returns findings, or a typed error for an unknown kind. `producedAt` is\n * passed in because replay-safe paths must not read `Date.now`.\n */\nexport function makeCheckRunner(\n kinds: Record<string, Check>,\n opts: CheckRunnerOptions,\n): (\n kindId: string,\n trace: unknown,\n producedAt: string,\n) => Promise<AnalystFinding[] | { error: string }> {\n return async (kindId, trace, producedAt) => {\n const kind = kinds[kindId]\n if (!kind)\n return {\n error: `unknown analyst kind ${JSON.stringify(kindId)} (have: ${Object.keys(kinds).join(', ')})`,\n }\n return runCheck(kind, trace, opts, producedAt)\n }\n}\n","/**\n * @experimental\n *\n * MCP binding for a live `Scope`. A sandbox driver gets the same small verbs\n * the in-process driver has: spawn, observe, await, steer, ask/answer, analyze,\n * and stop. Settled outputs remain Scope artifacts; product code can project\n * them into any UI/report envelope it needs.\n */\n\nimport type {\n Budget,\n ResultBlobStore,\n Scope,\n Settled,\n Agent as SuperviseAgent,\n} from '../../runtime'\nimport type { McpToolDescriptor } from '../server'\n\n/** A worker the driver has drained via `await_next`. */\nexport interface SettledWorker {\n readonly id: string\n readonly status: 'done' | 'down'\n readonly score?: number\n readonly valid?: boolean\n readonly outRef?: string\n readonly reason?: string\n}\n\nexport type QuestionLevel = 'worker' | 'driver' | 'loop'\nexport type QuestionUrgency = 'continue-without' | 'blocks-step' | 'blocks-run'\n\nexport interface QuestionOption {\n readonly label: string\n readonly tradeoff: string\n}\n\nexport interface Question {\n readonly id: string\n readonly from: string\n readonly level: QuestionLevel\n readonly question: string\n readonly reason: string\n readonly urgency: QuestionUrgency\n readonly options?: ReadonlyArray<QuestionOption>\n}\n\nexport type QuestionDecision =\n | { readonly kind: 'answer'; readonly answer: string; readonly by: string }\n | { readonly kind: 'defer'; readonly reason: string }\n | { readonly kind: 'escalate'; readonly to: 'parent' | 'user' | string; readonly reason: string }\n\nexport interface QuestionRecord extends Question {\n readonly status: 'open' | 'answered' | 'deferred' | 'escalated'\n readonly decision?: QuestionDecision\n readonly openedAt: number\n}\n\ntype QuestionInput = Omit<Question, 'id'> & { readonly id?: string }\nexport type QuestionPolicy = 'auto' | 'mustDecide' | 'bubble' | 'failClosed'\n\nexport interface AnalystRegistry {\n readonly kinds: ReadonlyArray<{ id: string; description: string; area: string }>\n readonly run: (kindId: string, trace: unknown) => Promise<unknown>\n}\n\nexport type CoordinationEvent = { readonly type: 'question'; readonly question: QuestionRecord }\n\nexport type MakeWorkerAgent = (profile: unknown) => SuperviseAgent<unknown, unknown>\n\nexport interface CoordinationToolsOptions {\n readonly scope: Scope<unknown>\n readonly blobs: ResultBlobStore\n readonly makeWorkerAgent: MakeWorkerAgent\n readonly perWorker: Budget\n readonly analysts?: AnalystRegistry\n readonly onEvent?: (event: CoordinationEvent) => void | Promise<void>\n readonly questionPolicy?: QuestionPolicy\n}\n\nexport interface CoordinationTools {\n readonly tools: McpToolDescriptor[]\n isStopped(): boolean\n stopReason(): string | undefined\n settled(): ReadonlyArray<SettledWorker>\n questions(): ReadonlyArray<QuestionRecord>\n}\n\nconst idArg = { type: 'string', description: 'The workerId returned by spawn_worker.' } as const\n\n/** Build the driver's MCP tools over a live scope. */\nexport function createCoordinationTools(opts: CoordinationToolsOptions): CoordinationTools {\n let stopped = false\n let reason: string | undefined\n let questionSeq = 0\n const ledger: SettledWorker[] = []\n const questions: QuestionRecord[] = []\n const questionPolicy = opts.questionPolicy ?? 'auto'\n\n const str = (v: unknown, field: string): string => {\n if (typeof v !== 'string' || v.length === 0)\n throw new Error(`coordination tools: \"${field}\" must be a non-empty string`)\n return v\n }\n const obj = (raw: unknown): Record<string, unknown> => {\n if (!raw || typeof raw !== 'object')\n throw new Error('coordination tools: arguments must be an object')\n return raw as Record<string, unknown>\n }\n const level = (v: unknown): Question['level'] => {\n if (v === 'worker' || v === 'driver' || v === 'loop') return v\n throw new Error('coordination tools: \"level\" must be worker, driver, or loop')\n }\n const urgency = (v: unknown): Question['urgency'] => {\n if (v === 'continue-without' || v === 'blocks-step' || v === 'blocks-run') return v\n throw new Error(\n 'coordination tools: \"urgency\" must be continue-without, blocks-step, or blocks-run',\n )\n }\n\n const recordSettled = (s: Settled<unknown>): SettledWorker => {\n const w: SettledWorker =\n s.kind === 'done'\n ? {\n id: s.handle.id,\n status: 'done',\n score: s.verdict?.score ?? 0,\n valid: s.verdict?.valid ?? false,\n outRef: s.outRef,\n }\n : { id: s.handle.id, status: 'down', reason: s.reason }\n ledger.push(w)\n return w\n }\n\n const nextQuestionId = (from: string): string => `${from}:q${questionSeq++}`\n const normalizeQuestion = (q: QuestionInput, fallbackFrom: string): Question => {\n const from = str(q.from ?? fallbackFrom, 'from')\n return {\n id: typeof q.id === 'string' && q.id.length > 0 ? q.id : nextQuestionId(from),\n from,\n level: level(q.level),\n question: str(q.question, 'question'),\n reason: str(q.reason, 'reason'),\n ...(q.options ? { options: q.options } : {}),\n urgency: urgency(q.urgency),\n }\n }\n const addQuestion = (\n raw: QuestionInput,\n fallbackFrom: string,\n decision?: QuestionDecision,\n ): { question: QuestionRecord; added: boolean } => {\n const q = normalizeQuestion(raw, fallbackFrom)\n const existing = questions.find((x) => x.id === q.id)\n if (existing) return { question: existing, added: false }\n const effectiveDecision =\n decision ??\n (questionPolicy === 'bubble'\n ? ({\n kind: 'escalate',\n to: 'parent',\n reason: 'question policy bubbled to parent',\n } as const)\n : undefined)\n const status: QuestionRecord['status'] =\n effectiveDecision?.kind === 'answer'\n ? 'answered'\n : effectiveDecision?.kind === 'defer'\n ? 'deferred'\n : effectiveDecision?.kind === 'escalate'\n ? 'escalated'\n : 'open'\n const record: QuestionRecord = {\n ...q,\n status,\n openedAt: Date.now(),\n ...(effectiveDecision ? { decision: effectiveDecision } : {}),\n }\n questions.push(record)\n return { question: record, added: true }\n }\n const emitNewQuestion = async (record: {\n question: QuestionRecord\n added: boolean\n }): Promise<QuestionRecord> => {\n if (record.added) await opts.onEvent?.({ type: 'question', question: record.question })\n return record.question\n }\n const decideQuestion = (questionId: string, decision: QuestionDecision): QuestionRecord => {\n const idx = questions.findIndex((q) => q.id === questionId)\n if (idx < 0) throw new Error(`unknown questionId ${JSON.stringify(questionId)}`)\n const prior = questions[idx] as QuestionRecord\n const status: QuestionRecord['status'] =\n decision.kind === 'answer' ? 'answered' : decision.kind === 'defer' ? 'deferred' : 'escalated'\n const next: QuestionRecord = { ...prior, status, decision }\n questions[idx] = next\n return next\n }\n const blockingQuestionsForStop = (): QuestionRecord[] => {\n if (questionPolicy === 'auto' || questionPolicy === 'bubble') return []\n return questions.filter((q) => {\n const blocking = q.urgency === 'blocks-step' || q.urgency === 'blocks-run'\n if (!blocking) return false\n if (questionPolicy === 'mustDecide') return q.status === 'open'\n return q.status !== 'answered' && q.status !== 'deferred'\n })\n }\n\n const tools: McpToolDescriptor[] = [\n {\n name: 'spawn_worker',\n description:\n 'Start a worker the driver will drive. `profile` is the worker or another driver; ' +\n '`task` is what it should do. Reserves budget from the conserved pool and fails closed.',\n inputSchema: {\n type: 'object',\n properties: {\n profile: { description: 'The worker/driver profile to run.' },\n task: { description: 'The task the worker should perform.' },\n label: { type: 'string', description: 'Optional trace label.' },\n },\n required: ['profile', 'task'],\n },\n handler: (raw) => {\n const a = obj(raw)\n const agent = opts.makeWorkerAgent(a.profile)\n const res = opts.scope.spawn(agent, a.task, {\n budget: opts.perWorker,\n label: typeof a.label === 'string' ? a.label : 'worker',\n })\n return Promise.resolve(res.ok ? { workerId: res.handle.id } : { error: res.reason })\n },\n },\n {\n name: 'observe_worker',\n description: 'Inspect a worker status, spend, and settled output artifact when available.',\n inputSchema: { type: 'object', properties: { workerId: idArg }, required: ['workerId'] },\n handler: async (raw) => {\n const id = str(obj(raw).workerId, 'workerId')\n const node = opts.scope.view.nodes.find((n) => n.id === id)\n if (!node) return { error: `unknown workerId ${JSON.stringify(id)}` }\n const output = node.outRef ? await opts.blobs.get(node.outRef) : undefined\n return {\n status: node.status,\n spent: node.spent,\n outRef: node.outRef ?? null,\n output: output ?? null,\n }\n },\n },\n {\n name: 'steer_worker',\n description: 'Deliver an out-of-band instruction to a running worker inbox.',\n inputSchema: {\n type: 'object',\n properties: {\n workerId: idArg,\n instruction: { type: 'string', description: 'What the worker should do next.' },\n },\n required: ['workerId', 'instruction'],\n },\n handler: (raw) => {\n const a = obj(raw)\n const delivered = opts.scope.send(str(a.workerId, 'workerId'), {\n steer: str(a.instruction, 'instruction'),\n })\n return Promise.resolve({ delivered })\n },\n },\n {\n name: 'await_next',\n description:\n 'Wait for the next spawned worker to settle. Returns { idle: true } when none are live.',\n inputSchema: { type: 'object', properties: {} },\n handler: async () => {\n const s = await opts.scope.next()\n if (!s) return { idle: true }\n const w = recordSettled(s)\n return w.status === 'done'\n ? {\n settled: w.id,\n status: 'done',\n score: w.score,\n valid: w.valid,\n outRef: w.outRef,\n }\n : { settled: w.id, status: 'down', reason: w.reason }\n },\n },\n {\n name: 'list_questions',\n description:\n 'List questions raised by workers, drivers, or analysts. Blocking stop behavior follows questionPolicy.',\n inputSchema: { type: 'object', properties: {} },\n handler: () => Promise.resolve({ questions }),\n },\n {\n name: 'answer_question',\n description: 'Record an answer, deferral, or escalation for a loop question.',\n inputSchema: {\n type: 'object',\n properties: {\n questionId: { type: 'string' },\n answer: { type: 'string' },\n by: { type: 'string', description: 'Node id or \"user\".' },\n deferReason: { type: 'string' },\n escalateTo: { type: 'string', enum: ['parent', 'user'] },\n escalateReason: { type: 'string' },\n },\n required: ['questionId'],\n },\n handler: (raw) => {\n const a = obj(raw)\n const questionId = str(a.questionId, 'questionId')\n if (typeof a.answer === 'string' && a.answer.length > 0) {\n return Promise.resolve({\n question: decideQuestion(questionId, {\n kind: 'answer',\n answer: a.answer,\n by: typeof a.by === 'string' && a.by.length > 0 ? a.by : 'user',\n }),\n })\n }\n if (typeof a.deferReason === 'string' && a.deferReason.length > 0) {\n return Promise.resolve({\n question: decideQuestion(questionId, {\n kind: 'defer',\n reason: a.deferReason,\n }),\n })\n }\n if (a.escalateTo === 'parent' || a.escalateTo === 'user') {\n const escalateReason =\n typeof a.escalateReason === 'string' && a.escalateReason.length > 0\n ? a.escalateReason\n : 'driver escalated'\n return Promise.resolve({\n question: decideQuestion(questionId, {\n kind: 'escalate',\n to: a.escalateTo,\n reason: escalateReason,\n }),\n })\n }\n throw new Error('answer_question: provide answer, deferReason, or escalateTo')\n },\n },\n {\n name: 'ask_parent',\n description: 'Raise a question to the parent driver/Pi/user when this driver cannot decide.',\n inputSchema: {\n type: 'object',\n properties: {\n from: { type: 'string' },\n level: { type: 'string', enum: ['worker', 'driver', 'loop'] },\n question: { type: 'string' },\n reason: { type: 'string' },\n urgency: { type: 'string', enum: ['continue-without', 'blocks-step', 'blocks-run'] },\n },\n required: ['from', 'level', 'question', 'reason', 'urgency'],\n },\n handler: async (raw) => {\n const a = obj(raw)\n const from = str(a.from, 'from')\n const q = await emitNewQuestion(\n addQuestion(\n {\n from,\n level: level(a.level),\n question: str(a.question, 'question'),\n reason: str(a.reason, 'reason'),\n urgency: urgency(a.urgency),\n },\n from,\n { kind: 'escalate', to: 'parent', reason: 'asked parent' },\n ),\n )\n return { question: q }\n },\n },\n {\n name: 'stop',\n description: 'Declare the run complete.',\n inputSchema: {\n type: 'object',\n properties: { reason: { type: 'string', description: 'Why you are stopping.' } },\n },\n handler: (raw) => {\n const blocking = blockingQuestionsForStop()\n if (blocking.length) {\n return Promise.resolve({\n stopped: false,\n error: 'unresolved-blocking-questions',\n questions: blocking,\n })\n }\n stopped = true\n const r = obj(raw).reason\n reason = typeof r === 'string' ? r : undefined\n return Promise.resolve({ stopped: true })\n },\n },\n ]\n\n if (opts.analysts) {\n tools.push({\n name: 'list_analysts',\n description: 'List trace-analyst lenses available to run over a settled worker.',\n inputSchema: { type: 'object', properties: {} },\n handler: () => Promise.resolve({ analysts: opts.analysts?.kinds }),\n })\n tools.push({\n name: 'run_analyst',\n description: 'Apply an analyst lens to a settled worker trace.',\n inputSchema: {\n type: 'object',\n properties: {\n kind: { type: 'string', description: 'The analyst kind id.' },\n workerId: idArg,\n },\n required: ['kind', 'workerId'],\n },\n handler: async (raw) => {\n const a = obj(raw)\n const id = str(a.workerId, 'workerId')\n const node = opts.scope.view.nodes.find((n) => n.id === id)\n if (!node) return { error: `unknown workerId ${JSON.stringify(id)}` }\n if (!node.outRef)\n return { error: `worker ${JSON.stringify(id)} has not settled — no trace to analyze yet` }\n const trace = await opts.blobs.get(node.outRef)\n return { findings: await opts.analysts?.run(str(a.kind, 'kind'), trace) }\n },\n })\n }\n\n return {\n tools,\n isStopped: () => stopped,\n stopReason: () => reason,\n settled: () => ledger,\n questions: () => questions,\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/mcp/tools/checks.ts","../../src/mcp/tools/coordination.ts"],"sourcesContent":["/**\n * @experimental\n *\n * The trace-analyst KIND directory — the operator's lenses, as composable DATA.\n *\n * An analyst is not one question. A kind is ONE lens (completeness, correctness, policy, efficiency,\n * tool-use, …); each emits `AnalystFinding`s tagged by its `area`. The driver `list_analysts` to see\n * the menu, `run_analyst(kind, worker)` to apply a lens, and `define_analyst` to author a new one —\n * so at test time you compose the exact lenses a domain needs (maximum specificity), not one generic\n * reviewer. The kinds are data, the runner is generic, and the finding shape + firewall are reused\n * from agent-eval / the keystone — never re-derived.\n *\n * A kind here is a lightweight lens (`Check`); it is a deliberate SUBSET of agent-eval's full\n * `TraceAnalystKindSpec`, so a kind that needs the heavy agentic actor (sub-agent recursion, tools,\n * goldens) upgrades to `createTraceAnalystKind` without changing this directory's surface.\n */\n\nimport {\n type AnalystFinding,\n type AnalystSeverity,\n type EvidenceRef,\n makeFinding,\n} from '@tangle-network/agent-eval'\nimport { assertTraceDerivedFindings } from '../../runtime'\n\n// agent-eval's root entry exports the lift (`makeFinding`) + the `AnalystFinding`/`EvidenceRef` shapes\n// but NOT the raw-row validator / schema prompt (kind-factory-internal). We inline a minimal,\n// equivalent pair so a lens emits the SAME finding shape without reaching into an unstable internal.\nconst ANALYST_SEVERITIES = ['critical', 'high', 'medium', 'low', 'info'] as const\n\nconst FINDING_SCHEMA_PROMPT = [\n 'Each finding is a JSON object with these fields:',\n '- severity: one of \"critical\" | \"high\" | \"medium\" | \"low\" | \"info\"',\n '- claim: one-sentence statement',\n '- evidence_uri: REQUIRED, never blank — exactly one of \"span://<trace>/<span>\", \"artifact://<path>\",',\n ' or \"metric://<name>\"; ALWAYS cite a real id from the trace. No citable id ⇒ omit the finding.',\n '- evidence_excerpt?: a short quote from the cited evidence',\n '- confidence: number 0..1',\n '- rationale?: one sentence of reasoning',\n '- recommended_action?: a concrete imperative (\"Add ...\", \"Replace ...\", \"Stop ...\")',\n 'Emit an empty array when there is nothing to report. Never fabricate evidence.',\n].join('\\n')\n\ninterface RawRow {\n severity: AnalystSeverity\n claim: string\n evidence_uri: string\n confidence: number\n evidence_excerpt?: string\n rationale?: string\n recommended_action?: string\n subject?: string\n}\n\n/** Validate one raw finding row (the lightweight equivalent of agent-eval's `parseRawFinding`):\n * require a claim + a real trace evidence_uri; drop anything else. Returns null to discard. */\nfunction validateRawFinding(row: unknown): RawRow | null {\n if (!row || typeof row !== 'object') return null\n const r = row as Record<string, unknown>\n if (typeof r.claim !== 'string' || r.claim.length === 0) return null\n if (typeof r.evidence_uri !== 'string' || !/^(span|artifact|metric):\\/\\//.test(r.evidence_uri))\n return null\n const sev = (ANALYST_SEVERITIES as readonly string[]).includes(r.severity as string)\n ? (r.severity as AnalystSeverity)\n : 'medium'\n return {\n severity: sev,\n claim: r.claim,\n evidence_uri: r.evidence_uri,\n confidence: typeof r.confidence === 'number' ? r.confidence : 0.5,\n ...(typeof r.evidence_excerpt === 'string' ? { evidence_excerpt: r.evidence_excerpt } : {}),\n ...(typeof r.rationale === 'string' ? { rationale: r.rationale } : {}),\n ...(typeof r.recommended_action === 'string'\n ? { recommended_action: r.recommended_action }\n : {}),\n ...(typeof r.subject === 'string' ? { subject: r.subject } : {}),\n }\n}\n\n/** One lens — a composable analyst kind. Identity fields mirror `TraceAnalystKindSpec` so a kind is\n * upgradeable to the full agentic factory; `lookFor` is the lens question the actor applies. */\nexport interface Check {\n readonly id: string\n readonly description: string\n /** Coarse classification stamped on every finding this kind emits (the renderer groups by it). */\n readonly area: string\n readonly version: string\n /** The lens — what this analyst looks for in the trace. */\n readonly lookFor: string\n}\n\n/** The built-in lens directory. Domain-blind (about any agent trace); compose at test time. */\nexport const defaultChecks: Record<string, Check> = {\n completeness: {\n id: 'completeness',\n description: 'Required work the trace does not yet show done or verified.',\n area: 'failure-mode',\n version: '1',\n lookFor:\n 'every change the task requires that the trace does NOT yet show completed AND verified by a ' +\n 'tool result. One finding per missing/unverified requirement.',\n },\n correctness: {\n id: 'correctness',\n description: 'Tool calls that produced wrong, erroring, or contradicted results.',\n area: 'correctness',\n version: '1',\n lookFor:\n 'tool calls whose RESULT shows an error, a wrong value, or contradicts what the task required ' +\n '(e.g. set the wrong field, value did not take, an error was ignored).',\n },\n policy: {\n id: 'policy',\n description: 'Actions that violate a stated policy, constraint, or allow-list.',\n area: 'safety',\n version: '1',\n lookFor:\n 'actions in the trace that violate a policy/constraint stated in the task or system prompt ' +\n '(forbidden tool, missing approval, out-of-scope mutation, skipped precondition).',\n },\n efficiency: {\n id: 'efficiency',\n description: 'Wasted, redundant, or looping work.',\n area: 'cost',\n version: '1',\n lookFor:\n 'redundant or wasted actions — repeated identical calls, a stalled line retried the same way, ' +\n 'work that produced no progress toward the goal.',\n },\n 'tool-use': {\n id: 'tool-use',\n description: 'Malformed or misused tool calls.',\n area: 'tool-use',\n version: '1',\n lookFor:\n 'tool calls with malformed/invalid arguments, the wrong tool for the intent, or a tool used ' +\n 'against its contract — judged from the call + its result.',\n },\n}\n\n/** Lift validated raw rows into `AnalystFinding`s (agent-eval `makeFinding` stamps `finding_id`/\n * `produced_at`), then enforce the trace-derived firewall (selector ≠ judge). Pure — no LLM. */\nexport function liftFindings(kind: Check, rows: unknown[], producedAt: string): AnalystFinding[] {\n const findings: AnalystFinding[] = []\n for (const row of rows) {\n const raw = validateRawFinding(row)\n if (!raw) continue\n findings.push(\n makeFinding({\n analyst_id: kind.id,\n area: kind.area,\n severity: raw.severity,\n claim: raw.claim,\n confidence: raw.confidence,\n produced_at: producedAt,\n evidence_refs: evidenceRefs(raw.evidence_uri, raw.evidence_excerpt),\n ...(raw.rationale ? { rationale: raw.rationale } : {}),\n ...(raw.recommended_action ? { recommended_action: raw.recommended_action } : {}),\n ...(raw.subject ? { subject: raw.subject } : {}),\n metadata: { kind_version: kind.version },\n }),\n )\n }\n assertTraceDerivedFindings(findings) // throws if a finding cites judge/verdict/score evidence\n return findings\n}\n\n/** Map a raw `evidence_uri` (span:// | artifact:// | metric://<name>) to a typed `EvidenceRef`. A\n * metric ref carries the bare NAME (the firewall checks the metric name for judge/verdict/score —\n * so a finding that cites a judge metric is rejected as not trace-derived). */\nfunction evidenceRefs(uri: string, excerpt?: string): EvidenceRef[] {\n const scheme = uri.split('://', 1)[0]\n if (scheme === 'metric')\n return [\n { kind: 'metric', uri: uri.replace(/^metric:\\/\\//, ''), ...(excerpt ? { excerpt } : {}) },\n ]\n const kind: EvidenceRef['kind'] = scheme === 'span' ? 'span' : 'artifact'\n return [{ kind, uri, ...(excerpt ? { excerpt } : {}) }]\n}\n\n/** Render a worker's trace (tool calls + results) into the text an analyst lens reads. Generic over\n * the trace shape: a `{ messages }` conversation, a bare message array, else stringified. */\nexport function renderTrace(trace: unknown): string {\n const messages = Array.isArray(trace)\n ? trace\n : trace &&\n typeof trace === 'object' &&\n Array.isArray((trace as { messages?: unknown[] }).messages)\n ? (trace as { messages: unknown[] }).messages\n : undefined\n if (!messages) return JSON.stringify(trace ?? {}).slice(0, 8000)\n return messages\n .map((m) => {\n const r = m as {\n role?: string\n content?: unknown\n tool_calls?: Array<{ function?: { name?: string; arguments?: string } }>\n }\n if (r.role === 'tool') return `RESULT ${String(r.content).slice(0, 300)}`\n const calls = r.tool_calls\n ?.map((c) => `${c.function?.name}(${c.function?.arguments})`)\n .join(', ')\n return calls ? `CALL ${calls}` : `SAY ${String(r.content ?? '').slice(0, 200)}`\n })\n .join('\\n')\n .slice(0, 8000)\n}\n\nexport interface CheckRunnerOptions {\n routerBaseUrl: string\n routerKey: string\n model: string\n /** Test/override seam — replace the LLM call. Default: a router chat completion. */\n chat?: (system: string, user: string) => Promise<string>\n}\n\n/** Run ONE lens over a trace → findings. Generic over any kind: prompt = the lens + the agent-eval\n * finding schema; the model's JSON array is parsed (`parseRawFinding`), lifted, and firewalled. */\nexport async function runCheck(\n kind: Check,\n trace: unknown,\n opts: CheckRunnerOptions,\n producedAt: string,\n): Promise<AnalystFinding[]> {\n const sys =\n `You are a trace analyst applying ONE lens: look for ${kind.lookFor}\\n\\n` +\n `${FINDING_SCHEMA_PROMPT}\\n\\nReturn ONLY a fenced \\`\\`\\`json array of finding objects (possibly empty).`\n const user = `WORKER TRACE:\\n${renderTrace(trace)}\\n\\nApply your lens and emit the findings array.`\n const chat = opts.chat ?? defaultChat(opts)\n const content = await chat(sys, user)\n const match = content.match(/```(?:json)?\\s*([\\s\\S]*?)```/)\n let rows: unknown[] = []\n try {\n const parsed = JSON.parse((match?.[1] ?? content).trim())\n rows = Array.isArray(parsed)\n ? parsed\n : Array.isArray((parsed as { findings?: unknown[] })?.findings)\n ? (parsed as { findings: unknown[] }).findings\n : []\n } catch {\n rows = []\n }\n return liftFindings(kind, rows, producedAt)\n}\n\nfunction defaultChat(opts: CheckRunnerOptions): (system: string, user: string) => Promise<string> {\n return async (system, user) => {\n const res = await fetch(`${opts.routerBaseUrl.replace(/\\/$/, '')}/chat/completions`, {\n method: 'POST',\n headers: { 'content-type': 'application/json', authorization: `Bearer ${opts.routerKey}` },\n body: JSON.stringify({\n model: opts.model,\n messages: [\n { role: 'system', content: system },\n { role: 'user', content: user },\n ],\n temperature: 0.3,\n }),\n })\n if (!res.ok) throw new Error(`analyst router ${res.status}`)\n const data = (await res.json()) as { choices?: Array<{ message?: { content?: string } }> }\n return data.choices?.[0]?.message?.content ?? ''\n }\n}\n\n/**\n * Build a `run_analyst` runner over a kind directory.\n * Returns findings, or a typed error for an unknown kind. `producedAt` is\n * passed in because replay-safe paths must not read `Date.now`.\n */\nexport function makeCheckRunner(\n kinds: Record<string, Check>,\n opts: CheckRunnerOptions,\n): (\n kindId: string,\n trace: unknown,\n producedAt: string,\n) => Promise<AnalystFinding[] | { error: string }> {\n return async (kindId, trace, producedAt) => {\n const kind = kinds[kindId]\n if (!kind)\n return {\n error: `unknown analyst kind ${JSON.stringify(kindId)} (have: ${Object.keys(kinds).join(', ')})`,\n }\n return runCheck(kind, trace, opts, producedAt)\n }\n}\n","/**\n * @experimental\n *\n * MCP binding for a live `Scope`. A sandbox driver gets the same small verbs\n * the in-process driver has: spawn, observe, await, steer, ask/answer, analyze,\n * and stop. Settled outputs remain Scope artifacts; product code can project\n * them into any UI/report envelope it needs.\n */\n\nimport type {\n Budget,\n ResultBlobStore,\n Scope,\n Settled,\n Agent as SuperviseAgent,\n} from '../../runtime'\nimport type { McpToolDescriptor } from '../server'\n\n/** A worker the driver has drained via `await_next`. */\nexport interface SettledWorker {\n readonly id: string\n readonly status: 'done' | 'down'\n readonly score?: number\n readonly valid?: boolean\n readonly outRef?: string\n readonly reason?: string\n}\n\nexport type QuestionLevel = 'worker' | 'driver' | 'loop'\nexport type QuestionUrgency = 'continue-without' | 'blocks-step' | 'blocks-run'\n\nexport interface QuestionOption {\n readonly label: string\n readonly tradeoff: string\n}\n\nexport interface Question {\n readonly id: string\n readonly from: string\n readonly level: QuestionLevel\n readonly question: string\n readonly reason: string\n readonly urgency: QuestionUrgency\n readonly options?: ReadonlyArray<QuestionOption>\n}\n\nexport type QuestionDecision =\n | { readonly kind: 'answer'; readonly answer: string; readonly by: string }\n | { readonly kind: 'defer'; readonly reason: string }\n | { readonly kind: 'escalate'; readonly to: 'parent' | 'user' | string; readonly reason: string }\n\nexport interface QuestionRecord extends Question {\n readonly status: 'open' | 'answered' | 'deferred' | 'escalated'\n readonly decision?: QuestionDecision\n readonly openedAt: number\n}\n\ntype QuestionInput = Omit<Question, 'id'> & { readonly id?: string }\nexport type QuestionPolicy = 'auto' | 'mustDecide' | 'bubble' | 'failClosed'\n\nexport interface AnalystRegistry {\n readonly kinds: ReadonlyArray<{ id: string; description: string; area: string }>\n readonly run: (kindId: string, trace: unknown) => Promise<unknown>\n}\n\nexport type CoordinationEvent = { readonly type: 'question'; readonly question: QuestionRecord }\n\nexport type MakeWorkerAgent = (profile: unknown) => SuperviseAgent<unknown, unknown>\n\nexport interface CoordinationToolsOptions {\n readonly scope: Scope<unknown>\n readonly blobs: ResultBlobStore\n readonly makeWorkerAgent: MakeWorkerAgent\n readonly perWorker: Budget\n readonly analysts?: AnalystRegistry\n readonly onEvent?: (event: CoordinationEvent) => void | Promise<void>\n readonly questionPolicy?: QuestionPolicy\n}\n\nexport interface CoordinationTools {\n readonly tools: McpToolDescriptor[]\n isStopped(): boolean\n stopReason(): string | undefined\n settled(): ReadonlyArray<SettledWorker>\n questions(): ReadonlyArray<QuestionRecord>\n}\n\nconst idArg = { type: 'string', description: 'The workerId returned by spawn_worker.' } as const\n\n/** Build the driver's MCP tools over a live scope. */\nexport function createCoordinationTools(opts: CoordinationToolsOptions): CoordinationTools {\n let stopped = false\n let reason: string | undefined\n let questionSeq = 0\n const ledger: SettledWorker[] = []\n const questions: QuestionRecord[] = []\n const questionPolicy = opts.questionPolicy ?? 'auto'\n\n const str = (v: unknown, field: string): string => {\n if (typeof v !== 'string' || v.length === 0)\n throw new Error(`coordination tools: \"${field}\" must be a non-empty string`)\n return v\n }\n const obj = (raw: unknown): Record<string, unknown> => {\n if (!raw || typeof raw !== 'object')\n throw new Error('coordination tools: arguments must be an object')\n return raw as Record<string, unknown>\n }\n const level = (v: unknown): Question['level'] => {\n if (v === 'worker' || v === 'driver' || v === 'loop') return v\n throw new Error('coordination tools: \"level\" must be worker, driver, or loop')\n }\n const urgency = (v: unknown): Question['urgency'] => {\n if (v === 'continue-without' || v === 'blocks-step' || v === 'blocks-run') return v\n throw new Error(\n 'coordination tools: \"urgency\" must be continue-without, blocks-step, or blocks-run',\n )\n }\n\n const recordSettled = (s: Settled<unknown>): SettledWorker => {\n const w: SettledWorker =\n s.kind === 'done'\n ? {\n id: s.handle.id,\n status: 'done',\n score: s.verdict?.score ?? 0,\n valid: s.verdict?.valid ?? false,\n outRef: s.outRef,\n }\n : { id: s.handle.id, status: 'down', reason: s.reason }\n ledger.push(w)\n return w\n }\n\n const nextQuestionId = (from: string): string => `${from}:q${questionSeq++}`\n const normalizeQuestion = (q: QuestionInput, fallbackFrom: string): Question => {\n const from = str(q.from ?? fallbackFrom, 'from')\n return {\n id: typeof q.id === 'string' && q.id.length > 0 ? q.id : nextQuestionId(from),\n from,\n level: level(q.level),\n question: str(q.question, 'question'),\n reason: str(q.reason, 'reason'),\n ...(q.options ? { options: q.options } : {}),\n urgency: urgency(q.urgency),\n }\n }\n const addQuestion = (\n raw: QuestionInput,\n fallbackFrom: string,\n decision?: QuestionDecision,\n ): { question: QuestionRecord; added: boolean } => {\n const q = normalizeQuestion(raw, fallbackFrom)\n const existing = questions.find((x) => x.id === q.id)\n if (existing) return { question: existing, added: false }\n const effectiveDecision =\n decision ??\n (questionPolicy === 'bubble'\n ? ({\n kind: 'escalate',\n to: 'parent',\n reason: 'question policy bubbled to parent',\n } as const)\n : undefined)\n const status: QuestionRecord['status'] =\n effectiveDecision?.kind === 'answer'\n ? 'answered'\n : effectiveDecision?.kind === 'defer'\n ? 'deferred'\n : effectiveDecision?.kind === 'escalate'\n ? 'escalated'\n : 'open'\n const record: QuestionRecord = {\n ...q,\n status,\n openedAt: Date.now(),\n ...(effectiveDecision ? { decision: effectiveDecision } : {}),\n }\n questions.push(record)\n return { question: record, added: true }\n }\n const emitNewQuestion = async (record: {\n question: QuestionRecord\n added: boolean\n }): Promise<QuestionRecord> => {\n if (record.added) await opts.onEvent?.({ type: 'question', question: record.question })\n return record.question\n }\n const decideQuestion = (questionId: string, decision: QuestionDecision): QuestionRecord => {\n const idx = questions.findIndex((q) => q.id === questionId)\n if (idx < 0) throw new Error(`unknown questionId ${JSON.stringify(questionId)}`)\n const prior = questions[idx] as QuestionRecord\n const status: QuestionRecord['status'] =\n decision.kind === 'answer' ? 'answered' : decision.kind === 'defer' ? 'deferred' : 'escalated'\n const next: QuestionRecord = { ...prior, status, decision }\n questions[idx] = next\n return next\n }\n const blockingQuestionsForStop = (): QuestionRecord[] => {\n if (questionPolicy === 'auto' || questionPolicy === 'bubble') return []\n return questions.filter((q) => {\n const blocking = q.urgency === 'blocks-step' || q.urgency === 'blocks-run'\n if (!blocking) return false\n if (questionPolicy === 'mustDecide') return q.status === 'open'\n return q.status !== 'answered' && q.status !== 'deferred'\n })\n }\n\n const tools: McpToolDescriptor[] = [\n {\n name: 'spawn_worker',\n description:\n 'Start a worker the driver will drive. `profile` is the worker or another driver; ' +\n '`task` is what it should do. Reserves budget from the conserved pool and fails closed.',\n inputSchema: {\n type: 'object',\n properties: {\n profile: { description: 'The worker/driver profile to run.' },\n task: { description: 'The task the worker should perform.' },\n label: { type: 'string', description: 'Optional trace label.' },\n },\n required: ['profile', 'task'],\n },\n handler: (raw) => {\n const a = obj(raw)\n const agent = opts.makeWorkerAgent(a.profile)\n const res = opts.scope.spawn(agent, a.task, {\n budget: opts.perWorker,\n label: typeof a.label === 'string' ? a.label : 'worker',\n })\n return Promise.resolve(res.ok ? { workerId: res.handle.id } : { error: res.reason })\n },\n },\n {\n name: 'observe_worker',\n description: 'Inspect a worker status, spend, and settled output artifact when available.',\n inputSchema: { type: 'object', properties: { workerId: idArg }, required: ['workerId'] },\n handler: async (raw) => {\n const id = str(obj(raw).workerId, 'workerId')\n const node = opts.scope.view.nodes.find((n) => n.id === id)\n if (!node) return { error: `unknown workerId ${JSON.stringify(id)}` }\n const output = node.outRef ? await opts.blobs.get(node.outRef) : undefined\n return {\n status: node.status,\n spent: node.spent,\n outRef: node.outRef ?? null,\n output: output ?? null,\n }\n },\n },\n {\n name: 'steer_worker',\n description: 'Deliver an out-of-band instruction to a running worker inbox.',\n inputSchema: {\n type: 'object',\n properties: {\n workerId: idArg,\n instruction: { type: 'string', description: 'What the worker should do next.' },\n },\n required: ['workerId', 'instruction'],\n },\n handler: (raw) => {\n const a = obj(raw)\n const delivered = opts.scope.send(str(a.workerId, 'workerId'), {\n steer: str(a.instruction, 'instruction'),\n })\n return Promise.resolve({ delivered })\n },\n },\n {\n name: 'await_next',\n description:\n 'Wait for the next spawned worker to settle. Returns { idle: true } when none are live.',\n inputSchema: { type: 'object', properties: {} },\n handler: async () => {\n const s = await opts.scope.next()\n if (!s) return { idle: true }\n const w = recordSettled(s)\n return w.status === 'done'\n ? {\n settled: w.id,\n status: 'done',\n score: w.score,\n valid: w.valid,\n outRef: w.outRef,\n }\n : { settled: w.id, status: 'down', reason: w.reason }\n },\n },\n {\n name: 'list_questions',\n description:\n 'List questions raised by workers, drivers, or analysts. Blocking stop behavior follows questionPolicy.',\n inputSchema: { type: 'object', properties: {} },\n handler: () => Promise.resolve({ questions }),\n },\n {\n name: 'answer_question',\n description: 'Record an answer, deferral, or escalation for a loop question.',\n inputSchema: {\n type: 'object',\n properties: {\n questionId: { type: 'string' },\n answer: { type: 'string' },\n by: { type: 'string', description: 'Node id or \"user\".' },\n deferReason: { type: 'string' },\n escalateTo: { type: 'string', enum: ['parent', 'user'] },\n escalateReason: { type: 'string' },\n },\n required: ['questionId'],\n },\n handler: (raw) => {\n const a = obj(raw)\n const questionId = str(a.questionId, 'questionId')\n if (typeof a.answer === 'string' && a.answer.length > 0) {\n return Promise.resolve({\n question: decideQuestion(questionId, {\n kind: 'answer',\n answer: a.answer,\n by: typeof a.by === 'string' && a.by.length > 0 ? a.by : 'user',\n }),\n })\n }\n if (typeof a.deferReason === 'string' && a.deferReason.length > 0) {\n return Promise.resolve({\n question: decideQuestion(questionId, {\n kind: 'defer',\n reason: a.deferReason,\n }),\n })\n }\n if (a.escalateTo === 'parent' || a.escalateTo === 'user') {\n const escalateReason =\n typeof a.escalateReason === 'string' && a.escalateReason.length > 0\n ? a.escalateReason\n : 'driver escalated'\n return Promise.resolve({\n question: decideQuestion(questionId, {\n kind: 'escalate',\n to: a.escalateTo,\n reason: escalateReason,\n }),\n })\n }\n throw new Error('answer_question: provide answer, deferReason, or escalateTo')\n },\n },\n {\n name: 'ask_parent',\n description: 'Raise a question to the parent driver/Pi/user when this driver cannot decide.',\n inputSchema: {\n type: 'object',\n properties: {\n from: { type: 'string' },\n level: { type: 'string', enum: ['worker', 'driver', 'loop'] },\n question: { type: 'string' },\n reason: { type: 'string' },\n urgency: { type: 'string', enum: ['continue-without', 'blocks-step', 'blocks-run'] },\n },\n required: ['from', 'level', 'question', 'reason', 'urgency'],\n },\n handler: async (raw) => {\n const a = obj(raw)\n const from = str(a.from, 'from')\n const q = await emitNewQuestion(\n addQuestion(\n {\n from,\n level: level(a.level),\n question: str(a.question, 'question'),\n reason: str(a.reason, 'reason'),\n urgency: urgency(a.urgency),\n },\n from,\n { kind: 'escalate', to: 'parent', reason: 'asked parent' },\n ),\n )\n return { question: q }\n },\n },\n {\n name: 'stop',\n description: 'Declare the run complete.',\n inputSchema: {\n type: 'object',\n properties: { reason: { type: 'string', description: 'Why you are stopping.' } },\n },\n handler: (raw) => {\n const blocking = blockingQuestionsForStop()\n if (blocking.length) {\n return Promise.resolve({\n stopped: false,\n error: 'unresolved-blocking-questions',\n questions: blocking,\n })\n }\n stopped = true\n const r = obj(raw).reason\n reason = typeof r === 'string' ? r : undefined\n return Promise.resolve({ stopped: true })\n },\n },\n ]\n\n if (opts.analysts) {\n tools.push({\n name: 'list_analysts',\n description: 'List trace-analyst lenses available to run over a settled worker.',\n inputSchema: { type: 'object', properties: {} },\n handler: () => Promise.resolve({ analysts: opts.analysts?.kinds }),\n })\n tools.push({\n name: 'run_analyst',\n description: 'Apply an analyst lens to a settled worker trace.',\n inputSchema: {\n type: 'object',\n properties: {\n kind: { type: 'string', description: 'The analyst kind id.' },\n workerId: idArg,\n },\n required: ['kind', 'workerId'],\n },\n handler: async (raw) => {\n const a = obj(raw)\n const id = str(a.workerId, 'workerId')\n const node = opts.scope.view.nodes.find((n) => n.id === id)\n if (!node) return { error: `unknown workerId ${JSON.stringify(id)}` }\n if (!node.outRef)\n return { error: `worker ${JSON.stringify(id)} has not settled — no trace to analyze yet` }\n const trace = await opts.blobs.get(node.outRef)\n return { findings: await opts.analysts?.run(str(a.kind, 'kind'), trace) }\n },\n })\n }\n\n return {\n tools,\n isStopped: () => stopped,\n stopReason: () => reason,\n settled: () => ledger,\n questions: () => questions,\n }\n}\n"],"mappings":"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","names":[]}
package/dist/platform.js CHANGED
@@ -20,7 +20,7 @@ var PlatformAuthClient = class {
20
20
  if (!options.appId) throw new Error("PlatformAuthClient: appId is required");
21
21
  this.baseUrl = options.baseUrl.replace(/\/+$/, "");
22
22
  this.appId = options.appId;
23
- this.fetchImpl = options.fetchImpl ?? fetch;
23
+ this.fetchImpl = options.fetchImpl ?? ((url, init) => fetch(url, init));
24
24
  }
25
25
  /**
26
26
  * Build the URL the user is redirected to in order to start SSO.
@@ -90,7 +90,7 @@ var PlatformHubClient = class {
90
90
  if (!options.bearer) throw new Error("PlatformHubClient: bearer is required");
91
91
  this.baseUrl = options.baseUrl.replace(/\/+$/, "");
92
92
  this.bearer = options.bearer;
93
- this.fetchImpl = options.fetchImpl ?? fetch;
93
+ this.fetchImpl = options.fetchImpl ?? ((url, init) => fetch(url, init));
94
94
  }
95
95
  /** List the integration catalog (providers + connectors). */
96
96
  catalog() {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/platform/auth.ts","../src/platform/integrations.ts"],"sourcesContent":["/**\n * Server-side client for the Tangle platform's cross-site SSO bridge.\n *\n * Consumer apps (gtm-agent, tax-agent, legal-agent, creative-agent, …)\n * use this to:\n * 1. Build an /authorize URL that lands the user on id.tangle.tools\n * and brings them back with a single-use code.\n * 2. Exchange that code for an API key + the user's identity.\n *\n * The platform endpoint contract is documented in\n * `products/platform/api/src/routes/cross-site.ts`. This client only\n * speaks HTTP — no SDK weight, no transitive deps.\n */\n\nexport interface PlatformAuthClientOptions {\n /** Platform base URL, e.g. `https://id.tangle.tools`. */\n baseUrl: string\n /** App id as registered in the platform's TRUSTED_APPS registry. */\n appId: string\n /** Override the global fetch (useful for tests + edge runtimes). */\n fetchImpl?: typeof fetch\n}\n\nexport interface AuthorizeUrlOptions {\n /** Required CSRF token; the consumer verifies it on the callback. */\n state: string\n /**\n * Final redirect URI. Must be one of the URIs registered for `appId`\n * on the platform. Omit to use the first registered URI.\n */\n redirectUri?: string\n /** Force the login screen even if a session is already active. */\n prompt?: 'login'\n /** Pre-fill the email field on the login screen. */\n email?: string\n}\n\nexport interface ExchangeCodeResult {\n apiKey: string\n user: {\n id: string\n email: string\n name?: string\n }\n plan: {\n tier: string\n }\n}\n\nexport class PlatformAuthError extends Error {\n constructor(\n message: string,\n public readonly status: number,\n public readonly body: unknown,\n ) {\n super(message)\n this.name = 'PlatformAuthError'\n }\n}\n\nexport class PlatformAuthClient {\n private readonly baseUrl: string\n private readonly appId: string\n private readonly fetchImpl: typeof fetch\n\n constructor(options: PlatformAuthClientOptions) {\n if (!options.baseUrl) throw new Error('PlatformAuthClient: baseUrl is required')\n if (!options.appId) throw new Error('PlatformAuthClient: appId is required')\n this.baseUrl = options.baseUrl.replace(/\\/+$/, '')\n this.appId = options.appId\n this.fetchImpl = options.fetchImpl ?? fetch\n }\n\n /**\n * Build the URL the user is redirected to in order to start SSO.\n * The platform redirects back to one of `appId`'s registered\n * `redirectUris` with `?code=...&app=...&state=...`.\n */\n authorizeUrl(options: AuthorizeUrlOptions): string {\n if (!options.state) {\n throw new Error('PlatformAuthClient.authorizeUrl: state is required for CSRF')\n }\n const url = new URL('/cross-site/authorize', this.baseUrl)\n url.searchParams.set('app', this.appId)\n url.searchParams.set('state', options.state)\n if (options.redirectUri) url.searchParams.set('redirect', options.redirectUri)\n if (options.prompt) url.searchParams.set('prompt', options.prompt)\n if (options.email) url.searchParams.set('email', options.email)\n return url.toString()\n }\n\n /**\n * Exchange a single-use auth code (delivered to the consumer's\n * callback by the platform) for an API key + the user's identity.\n * Codes are single-use and expire ~5 minutes after issue.\n */\n async exchange(code: string): Promise<ExchangeCodeResult> {\n if (!code) throw new Error('PlatformAuthClient.exchange: code is required')\n const res = await this.fetchImpl(`${this.baseUrl}/cross-site/exchange`, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ code, app: this.appId }),\n })\n const body = await res.json().catch(() => null)\n if (!res.ok) {\n const message =\n body && typeof body === 'object' && 'error' in body && typeof body.error === 'string'\n ? body.error\n : `Platform exchange failed (${res.status})`\n throw new PlatformAuthError(message, res.status, body)\n }\n const result = body as Partial<ExchangeCodeResult>\n if (!result.apiKey || !result.user?.id) {\n throw new PlatformAuthError(\n 'Platform exchange response is missing apiKey or user',\n res.status,\n body,\n )\n }\n return result as ExchangeCodeResult\n }\n}\n","/**\n * Server-side client for the Tangle platform's integrations hub\n * (`/v1/integrations/*`). Consumer apps use this instead of rolling\n * their own OAuth + connection tables.\n *\n * Auth: the caller supplies a bearer (either the user's API key from\n * cross-site exchange, or a platform service token) on construction.\n * Per-request override via `headers` is supported.\n *\n * Endpoint contract: `products/platform/api/src/routes/integrations.ts`.\n */\n\nexport interface PlatformHubClientOptions {\n /** Platform base URL, e.g. `https://id.tangle.tools`. */\n baseUrl: string\n /** Bearer credential — user API key or service token. */\n bearer: string\n /** Override fetch (tests + edge runtimes). */\n fetchImpl?: typeof fetch\n}\n\nexport interface PlatformConnection {\n id: string\n providerId: string\n connectorId: string\n status: 'connected' | 'pending' | 'revoked' | 'expired' | string\n grantedScopes?: string[]\n account?: { identity?: string; displayName?: string } & Record<string, unknown>\n metadata?: Record<string, unknown>\n expiresAt?: string | null\n createdAt?: string\n updatedAt?: string\n}\n\nexport interface PlatformCatalogProvider {\n providerId: string\n displayName?: string\n description?: string\n authMode?: string\n connectors?: PlatformCatalogConnector[]\n [k: string]: unknown\n}\n\nexport interface PlatformCatalogConnector {\n connectorId: string\n displayName?: string\n description?: string\n scopes?: string[]\n [k: string]: unknown\n}\n\nexport interface StartAuthInput {\n providerId: string\n connectorId: string\n /** Where the platform redirects the user back to after OAuth. */\n returnUrl: string\n requestedScopes?: string[]\n state?: string\n metadata?: Record<string, unknown>\n /** Required when the bearer is a service token impersonating a user. */\n ownerUserId?: string\n}\n\nexport interface StartAuthResult {\n authorizationUrl: string\n state: string\n}\n\nexport interface BundleCapabilityInput {\n manifestId?: string\n grantIds?: string[]\n subject: { type: 'user' | 'team' | 'app'; id: string }\n ttlMs: number\n}\n\nexport interface BundleCapabilityResult {\n bundle: Record<string, unknown>\n env: Record<string, string>\n}\n\nexport interface HealthCheck {\n connectionId: string\n providerId: string\n connectorId: string\n status: 'ok' | 'degraded' | 'failing' | 'unknown' | string\n checks?: Record<string, unknown>\n checkedAt?: string\n}\n\nexport class PlatformHubError extends Error {\n constructor(\n message: string,\n public readonly status: number,\n public readonly code: string | undefined,\n public readonly body: unknown,\n ) {\n super(message)\n this.name = 'PlatformHubError'\n }\n}\n\ninterface PlatformEnvelope<T> {\n success: boolean\n data?: T\n error?: { code?: string; message?: string } | string\n}\n\nexport class PlatformHubClient {\n private readonly baseUrl: string\n private readonly bearer: string\n private readonly fetchImpl: typeof fetch\n\n constructor(options: PlatformHubClientOptions) {\n if (!options.baseUrl) throw new Error('PlatformHubClient: baseUrl is required')\n if (!options.bearer) throw new Error('PlatformHubClient: bearer is required')\n this.baseUrl = options.baseUrl.replace(/\\/+$/, '')\n this.bearer = options.bearer\n this.fetchImpl = options.fetchImpl ?? fetch\n }\n\n /** List the integration catalog (providers + connectors). */\n catalog(): Promise<{ providers: PlatformCatalogProvider[] } & Record<string, unknown>> {\n return this.request('GET', '/v1/integrations/catalog')\n }\n\n /** List the calling user's integration connections. */\n async listConnections(): Promise<PlatformConnection[]> {\n const data = await this.request<{ connections: PlatformConnection[] }>(\n 'GET',\n '/v1/integrations/connections',\n )\n return data.connections\n }\n\n /** Revoke (and disable) a connection by id. */\n revokeConnection(connectionId: string): Promise<{\n connection: PlatformConnection\n revokedGrants: unknown[]\n providerRevocation: { ok: boolean }\n }> {\n return this.request(\n 'DELETE',\n `/v1/integrations/connections/${encodeURIComponent(connectionId)}`,\n )\n }\n\n /** Begin OAuth — returns the URL to send the user to. */\n startAuth(input: StartAuthInput): Promise<StartAuthResult> {\n return this.request('POST', '/v1/integrations/auth/start', input)\n }\n\n /** List connection healthchecks (last known state). */\n async listHealthchecks(): Promise<HealthCheck[]> {\n const data = await this.request<{ healthchecks: HealthCheck[] }>(\n 'GET',\n '/v1/integrations/healthchecks',\n )\n return data.healthchecks\n }\n\n /** Trigger a fresh healthcheck pass. */\n runHealthchecks(): Promise<{ scheduled: number }> {\n return this.request('POST', '/v1/integrations/healthchecks/run', {})\n }\n\n /**\n * Mint a sandbox-injectable capability bundle (env vars + scoped\n * capability tokens) so a sandbox can invoke integrations on the\n * user's behalf without seeing the underlying provider tokens.\n */\n bundleCapabilities(input: BundleCapabilityInput): Promise<BundleCapabilityResult> {\n return this.request('POST', '/v1/integrations/capabilities/bundle', input)\n }\n\n private async request<T>(\n method: 'GET' | 'POST' | 'DELETE' | 'PUT',\n path: string,\n body?: unknown,\n ): Promise<T> {\n const headers: Record<string, string> = {\n authorization: `Bearer ${this.bearer}`,\n accept: 'application/json',\n }\n if (body !== undefined) headers['content-type'] = 'application/json'\n\n const res = await this.fetchImpl(`${this.baseUrl}${path}`, {\n method,\n headers,\n body: body !== undefined ? JSON.stringify(body) : undefined,\n })\n const text = await res.text()\n let parsed: PlatformEnvelope<T> | null = null\n if (text) {\n try {\n parsed = JSON.parse(text)\n } catch {\n // fall through to error handling below\n }\n }\n if (!res.ok || (parsed && parsed.success === false)) {\n const code = parsed?.error && typeof parsed.error === 'object' ? parsed.error.code : undefined\n const message =\n (parsed?.error && typeof parsed.error === 'object' && parsed.error.message) ||\n (typeof parsed?.error === 'string' ? parsed.error : `Platform hub error (${res.status})`)\n throw new PlatformHubError(message, res.status, code, parsed ?? text)\n }\n if (!parsed) {\n throw new PlatformHubError(\n `Platform hub returned non-JSON success (${res.status})`,\n res.status,\n undefined,\n text,\n )\n }\n if (parsed.data === undefined) {\n throw new PlatformHubError(\n 'Platform hub envelope missing `data`',\n res.status,\n undefined,\n parsed,\n )\n }\n return parsed.data\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/platform/auth.ts","../src/platform/integrations.ts"],"sourcesContent":["/**\n * Server-side client for the Tangle platform's cross-site SSO bridge.\n *\n * Consumer apps (gtm-agent, tax-agent, legal-agent, creative-agent, …)\n * use this to:\n * 1. Build an /authorize URL that lands the user on id.tangle.tools\n * and brings them back with a single-use code.\n * 2. Exchange that code for an API key + the user's identity.\n *\n * The platform endpoint contract is documented in\n * `products/platform/api/src/routes/cross-site.ts`. This client only\n * speaks HTTP — no SDK weight, no transitive deps.\n */\n\nexport interface PlatformAuthClientOptions {\n /** Platform base URL, e.g. `https://id.tangle.tools`. */\n baseUrl: string\n /** App id as registered in the platform's TRUSTED_APPS registry. */\n appId: string\n /** Override the global fetch (useful for tests + edge runtimes). */\n fetchImpl?: typeof fetch\n}\n\nexport interface AuthorizeUrlOptions {\n /** Required CSRF token; the consumer verifies it on the callback. */\n state: string\n /**\n * Final redirect URI. Must be one of the URIs registered for `appId`\n * on the platform. Omit to use the first registered URI.\n */\n redirectUri?: string\n /** Force the login screen even if a session is already active. */\n prompt?: 'login'\n /** Pre-fill the email field on the login screen. */\n email?: string\n}\n\nexport interface ExchangeCodeResult {\n apiKey: string\n user: {\n id: string\n email: string\n name?: string\n }\n plan: {\n tier: string\n }\n}\n\nexport class PlatformAuthError extends Error {\n constructor(\n message: string,\n public readonly status: number,\n public readonly body: unknown,\n ) {\n super(message)\n this.name = 'PlatformAuthError'\n }\n}\n\nexport class PlatformAuthClient {\n private readonly baseUrl: string\n private readonly appId: string\n private readonly fetchImpl: typeof fetch\n\n constructor(options: PlatformAuthClientOptions) {\n if (!options.baseUrl) throw new Error('PlatformAuthClient: baseUrl is required')\n if (!options.appId) throw new Error('PlatformAuthClient: appId is required')\n this.baseUrl = options.baseUrl.replace(/\\/+$/, '')\n this.appId = options.appId\n this.fetchImpl =\n options.fetchImpl ??\n ((url: Parameters<typeof fetch>[0], init?: Parameters<typeof fetch>[1]) => fetch(url, init))\n }\n\n /**\n * Build the URL the user is redirected to in order to start SSO.\n * The platform redirects back to one of `appId`'s registered\n * `redirectUris` with `?code=...&app=...&state=...`.\n */\n authorizeUrl(options: AuthorizeUrlOptions): string {\n if (!options.state) {\n throw new Error('PlatformAuthClient.authorizeUrl: state is required for CSRF')\n }\n const url = new URL('/cross-site/authorize', this.baseUrl)\n url.searchParams.set('app', this.appId)\n url.searchParams.set('state', options.state)\n if (options.redirectUri) url.searchParams.set('redirect', options.redirectUri)\n if (options.prompt) url.searchParams.set('prompt', options.prompt)\n if (options.email) url.searchParams.set('email', options.email)\n return url.toString()\n }\n\n /**\n * Exchange a single-use auth code (delivered to the consumer's\n * callback by the platform) for an API key + the user's identity.\n * Codes are single-use and expire ~5 minutes after issue.\n */\n async exchange(code: string): Promise<ExchangeCodeResult> {\n if (!code) throw new Error('PlatformAuthClient.exchange: code is required')\n const res = await this.fetchImpl(`${this.baseUrl}/cross-site/exchange`, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ code, app: this.appId }),\n })\n const body = await res.json().catch(() => null)\n if (!res.ok) {\n const message =\n body && typeof body === 'object' && 'error' in body && typeof body.error === 'string'\n ? body.error\n : `Platform exchange failed (${res.status})`\n throw new PlatformAuthError(message, res.status, body)\n }\n const result = body as Partial<ExchangeCodeResult>\n if (!result.apiKey || !result.user?.id) {\n throw new PlatformAuthError(\n 'Platform exchange response is missing apiKey or user',\n res.status,\n body,\n )\n }\n return result as ExchangeCodeResult\n }\n}\n","/**\n * Server-side client for the Tangle platform's integrations hub\n * (`/v1/integrations/*`). Consumer apps use this instead of rolling\n * their own OAuth + connection tables.\n *\n * Auth: the caller supplies a bearer (either the user's API key from\n * cross-site exchange, or a platform service token) on construction.\n * Per-request override via `headers` is supported.\n *\n * Endpoint contract: `products/platform/api/src/routes/integrations.ts`.\n */\n\nexport interface PlatformHubClientOptions {\n /** Platform base URL, e.g. `https://id.tangle.tools`. */\n baseUrl: string\n /** Bearer credential — user API key or service token. */\n bearer: string\n /** Override fetch (tests + edge runtimes). */\n fetchImpl?: typeof fetch\n}\n\nexport interface PlatformConnection {\n id: string\n providerId: string\n connectorId: string\n status: 'connected' | 'pending' | 'revoked' | 'expired' | string\n grantedScopes?: string[]\n account?: { identity?: string; displayName?: string } & Record<string, unknown>\n metadata?: Record<string, unknown>\n expiresAt?: string | null\n createdAt?: string\n updatedAt?: string\n}\n\nexport interface PlatformCatalogProvider {\n providerId: string\n displayName?: string\n description?: string\n authMode?: string\n connectors?: PlatformCatalogConnector[]\n [k: string]: unknown\n}\n\nexport interface PlatformCatalogConnector {\n connectorId: string\n displayName?: string\n description?: string\n scopes?: string[]\n [k: string]: unknown\n}\n\nexport interface StartAuthInput {\n providerId: string\n connectorId: string\n /** Where the platform redirects the user back to after OAuth. */\n returnUrl: string\n requestedScopes?: string[]\n state?: string\n metadata?: Record<string, unknown>\n /** Required when the bearer is a service token impersonating a user. */\n ownerUserId?: string\n}\n\nexport interface StartAuthResult {\n authorizationUrl: string\n state: string\n}\n\nexport interface BundleCapabilityInput {\n manifestId?: string\n grantIds?: string[]\n subject: { type: 'user' | 'team' | 'app'; id: string }\n ttlMs: number\n}\n\nexport interface BundleCapabilityResult {\n bundle: Record<string, unknown>\n env: Record<string, string>\n}\n\nexport interface HealthCheck {\n connectionId: string\n providerId: string\n connectorId: string\n status: 'ok' | 'degraded' | 'failing' | 'unknown' | string\n checks?: Record<string, unknown>\n checkedAt?: string\n}\n\nexport class PlatformHubError extends Error {\n constructor(\n message: string,\n public readonly status: number,\n public readonly code: string | undefined,\n public readonly body: unknown,\n ) {\n super(message)\n this.name = 'PlatformHubError'\n }\n}\n\ninterface PlatformEnvelope<T> {\n success: boolean\n data?: T\n error?: { code?: string; message?: string } | string\n}\n\nexport class PlatformHubClient {\n private readonly baseUrl: string\n private readonly bearer: string\n private readonly fetchImpl: typeof fetch\n\n constructor(options: PlatformHubClientOptions) {\n if (!options.baseUrl) throw new Error('PlatformHubClient: baseUrl is required')\n if (!options.bearer) throw new Error('PlatformHubClient: bearer is required')\n this.baseUrl = options.baseUrl.replace(/\\/+$/, '')\n this.bearer = options.bearer\n this.fetchImpl =\n options.fetchImpl ??\n ((url: Parameters<typeof fetch>[0], init?: Parameters<typeof fetch>[1]) => fetch(url, init))\n }\n\n /** List the integration catalog (providers + connectors). */\n catalog(): Promise<{ providers: PlatformCatalogProvider[] } & Record<string, unknown>> {\n return this.request('GET', '/v1/integrations/catalog')\n }\n\n /** List the calling user's integration connections. */\n async listConnections(): Promise<PlatformConnection[]> {\n const data = await this.request<{ connections: PlatformConnection[] }>(\n 'GET',\n '/v1/integrations/connections',\n )\n return data.connections\n }\n\n /** Revoke (and disable) a connection by id. */\n revokeConnection(connectionId: string): Promise<{\n connection: PlatformConnection\n revokedGrants: unknown[]\n providerRevocation: { ok: boolean }\n }> {\n return this.request(\n 'DELETE',\n `/v1/integrations/connections/${encodeURIComponent(connectionId)}`,\n )\n }\n\n /** Begin OAuth — returns the URL to send the user to. */\n startAuth(input: StartAuthInput): Promise<StartAuthResult> {\n return this.request('POST', '/v1/integrations/auth/start', input)\n }\n\n /** List connection healthchecks (last known state). */\n async listHealthchecks(): Promise<HealthCheck[]> {\n const data = await this.request<{ healthchecks: HealthCheck[] }>(\n 'GET',\n '/v1/integrations/healthchecks',\n )\n return data.healthchecks\n }\n\n /** Trigger a fresh healthcheck pass. */\n runHealthchecks(): Promise<{ scheduled: number }> {\n return this.request('POST', '/v1/integrations/healthchecks/run', {})\n }\n\n /**\n * Mint a sandbox-injectable capability bundle (env vars + scoped\n * capability tokens) so a sandbox can invoke integrations on the\n * user's behalf without seeing the underlying provider tokens.\n */\n bundleCapabilities(input: BundleCapabilityInput): Promise<BundleCapabilityResult> {\n return this.request('POST', '/v1/integrations/capabilities/bundle', input)\n }\n\n private async request<T>(\n method: 'GET' | 'POST' | 'DELETE' | 'PUT',\n path: string,\n body?: unknown,\n ): Promise<T> {\n const headers: Record<string, string> = {\n authorization: `Bearer ${this.bearer}`,\n accept: 'application/json',\n }\n if (body !== undefined) headers['content-type'] = 'application/json'\n\n const res = await this.fetchImpl(`${this.baseUrl}${path}`, {\n method,\n headers,\n body: body !== undefined ? JSON.stringify(body) : undefined,\n })\n const text = await res.text()\n let parsed: PlatformEnvelope<T> | null = null\n if (text) {\n try {\n parsed = JSON.parse(text)\n } catch {\n // fall through to error handling below\n }\n }\n if (!res.ok || (parsed && parsed.success === false)) {\n const code = parsed?.error && typeof parsed.error === 'object' ? parsed.error.code : undefined\n const message =\n (parsed?.error && typeof parsed.error === 'object' && parsed.error.message) ||\n (typeof parsed?.error === 'string' ? parsed.error : `Platform hub error (${res.status})`)\n throw new PlatformHubError(message, res.status, code, parsed ?? text)\n }\n if (!parsed) {\n throw new PlatformHubError(\n `Platform hub returned non-JSON success (${res.status})`,\n res.status,\n undefined,\n text,\n )\n }\n if (parsed.data === undefined) {\n throw new PlatformHubError(\n 'Platform hub envelope missing `data`',\n res.status,\n undefined,\n parsed,\n )\n }\n return parsed.data\n }\n}\n"],"mappings":"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","names":[]}