@ordewell/core 0.10.12 → 0.11.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.
- package/AUTHORS.md +37 -0
- package/NOTICE +71 -0
- package/README.md +1 -1
- package/dist/{IFileSystem-1PqRCjhu.d.mts → IRunner-B5l9PCTv.d.ts} +926 -102
- package/dist/{IFileSystem-lTRL_G9Z.d.ts → IRunner-DBgDx_Mr.d.mts} +926 -102
- package/dist/{ModeResolver-CoJAJD-f.d.ts → ModeResolver-BDAgouuE.d.mts} +9 -2
- package/dist/{ModeResolver-6TQXVsde.d.mts → ModeResolver-DyXeZ9ib.d.ts} +9 -2
- package/dist/{Task-CfBM0wkV.d.mts → Task-BL4Idm9r.d.mts} +656 -26
- package/dist/{Task-CfBM0wkV.d.ts → Task-BL4Idm9r.d.ts} +656 -26
- package/dist/{chunk-ESKK5I4F.mjs → chunk-4QXOWEGC.mjs} +1888 -334
- package/dist/chunk-4QXOWEGC.mjs.map +1 -0
- package/dist/{chunk-KWS3VEER.mjs → chunk-MYXMIVWA.mjs} +6 -6
- package/dist/chunk-MYXMIVWA.mjs.map +1 -0
- package/dist/{chunk-PFH7WFIB.mjs → chunk-QTZ5XTBY.mjs} +228 -15
- package/dist/chunk-QTZ5XTBY.mjs.map +1 -0
- package/dist/{chunk-24EL4Z2W.mjs → chunk-YAFNYNFX.mjs} +342 -36
- package/dist/chunk-YAFNYNFX.mjs.map +1 -0
- package/dist/index.d.mts +1488 -769
- package/dist/index.d.ts +1488 -769
- package/dist/index.js +32003 -20350
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +29380 -19553
- package/dist/index.mjs.map +1 -1
- package/dist/parsing.d.mts +2 -2
- package/dist/parsing.d.ts +2 -2
- package/dist/parsing.js +232 -25
- package/dist/parsing.js.map +1 -1
- package/dist/parsing.mjs +3 -3
- package/dist/plan-utils.d.mts +4 -4
- package/dist/plan-utils.d.ts +4 -4
- package/dist/plan-utils.js +1156 -96
- package/dist/plan-utils.js.map +1 -1
- package/dist/plan-utils.mjs +144 -8
- package/dist/{runSettingsText-Jb_efnI4.d.mts → runSettingsText-BKwWs052.d.mts} +2882 -621
- package/dist/{runSettingsText-C5uv2axI.d.ts → runSettingsText-CAXiTpsj.d.ts} +2882 -621
- package/dist/testing.d.mts +10 -4
- package/dist/testing.d.ts +10 -4
- package/dist/testing.js +30 -7
- package/dist/testing.js.map +1 -1
- package/dist/testing.mjs +26 -7
- package/dist/testing.mjs.map +1 -1
- package/package.json +7 -3
- package/skills/diagnose/SKILL.md +52 -0
- package/skills/explore/SKILL.md +65 -0
- package/dist/chunk-24EL4Z2W.mjs.map +0 -1
- package/dist/chunk-ESKK5I4F.mjs.map +0 -1
- package/dist/chunk-KWS3VEER.mjs.map +0 -1
- package/dist/chunk-NJGID6BG.mjs +0 -115
- package/dist/chunk-NJGID6BG.mjs.map +0 -1
- package/dist/chunk-PFH7WFIB.mjs.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export { A as ApprovalRecord, a as AttemptUsage, b as AwaitingReason, B as BUILTIN_SKILL_NAMES, C as
|
|
3
|
-
import {
|
|
4
|
-
export { A as ACT_RISK, a as AUTORUN_RISK,
|
|
5
|
-
import {
|
|
6
|
-
export { A as AUTO_COMMANDS, b as AgentAdapterFactory, g as AllProviderModels, h as AnswerApprovalArgs,
|
|
7
|
-
import { R as RunnerModeInfo } from './ModeResolver-
|
|
8
|
-
export { a as autonomyLevelLabel, p as parseAutonomyLevel, r as runnerModesFrom } from './ModeResolver-
|
|
1
|
+
import { az as RunnerId, au as ResearchProgress, b6 as UsageRecord, at as ResearchLogEntry, aS as Task, i as DiscoveredModel, I as IIsolationPreview, x as IWorktreeIsolation, $ as IsolationTaskStatus, a0 as IsolationView, a8 as PlanIsolation, a1 as LegacyPlanState, aA as RunnerSessionCost, as as ReportedWindow, ag as PlannerUsage, a$ as TaskSkillSnapshot, aO as SkillsService, E as ExecutionActor, b0 as TaskSnapshot, a9 as PlanState, b8 as Verdict, aP as StoredHandoff, p as HandoffCheck } from './Task-BL4Idm9r.js';
|
|
2
|
+
export { A as ApprovalRecord, a as AttemptUsage, b as AwaitingReason, B as BUILTIN_SKILL_NAMES, C as ContextCheckpoint, c as ContextFill, d as ConversationMessage, e as CostProvenance, D as DEFAULT_LOOP_ROUNDS, f as DEFAULT_RUNNERS, g as DEFAULT_SUPERVISOR_RETRY_LIMIT, h as DIGEST_FINDINGS, j as ExecutionCommandName, k as ExecutionRecord, F as FindingSeverity, G as GuardTarget, l as GuardTrip, H as HANDOFF_LIMITS, m as HANDOFF_PUSH_CHARS, n as Handoff, o as HandoffArtifact, q as HandoffCommit, r as HandoffDigest, s as HandoffEvidence, t as HandoffFinding, u as HandoffPatch, v as HandoffPreviewOptions, w as HandoffTaskName, y as IntegrationDisposal, z as InvalidSkill, J as IsolationAvailability, K as IsolationHandoff, L as IsolationHandoffRepo, M as IsolationInactiveReason, N as IsolationLandedTask, O as IsolationLanding, P as IsolationMergeBlock, Q as IsolationMergeBlockReason, R as IsolationMergeResult, S as IsolationOutcome, T as IsolationPreview, U as IsolationPruneResult, V as IsolationRemoval, W as IsolationRepo, X as IsolationRun, Y as IsolationTaskRecord, Z as IsolationTaskRef, _ as IsolationTaskRepo, a2 as LoopSubject, a3 as MAX_LOOP_ROUNDS, a4 as ModelUsage, a5 as PatchFlag, a6 as PatchView, aa as PlanStatus, ab as PlanUsage, ac as PlannerCompaction, ad as PlannerCompactionOutcome, ae as PlannerContextPause, af as PlannerResendState, ah as PrepareIntent, ai as PreparedTask, aj as PreservedWork, ak as PreviewRepo, al as PreviousWork, am as REPORT_MAX_CHARS, an as RefusedRemoval, ao as RepairEvidence, ap as ReplyRun, aq as RepoGroupLayout, ar as RepoHead, av as ResearchStep, aw as ResearchStepOutcome, ay as RunSettings, aB as SEVERITY_LABEL, aC as ScriptConsent, aD as ScriptResult, aE as SessionBilling, aF as SetupFailure, aG as ShadowedSkill, aH as SkillAppliesTo, aI as SkillCatalog, aJ as SkillInfo, aK as SkillLoad, aL as SkillLoadNotice, aM as SkillMetadata, aN as SkillSource, aR as SupervisorLevel, aV as TaskIsolation, aW as TaskIsolationState, aX as TaskLoop, aY as TaskModelAssignment, b1 as TaskStatus, b2 as TaskType, b3 as TaskUsageSummary, b4 as TreeSnapshot, b5 as UsageLine, b7 as UsageTotals, b9 as VerificationCheck, ba as addAttemptUsage, bb as addModelUsage, bc as addPlannerUsage, bd as addUsage, be as addUsageTotals, bf as artifactLines, bg as betweenRounds, bh as boundedHandoffLines, bi as byteSize, bj as checkHandoff, bk as checkOf, bl as contextMeterText, bm as contextMeterTitle, bn as costText, bo as countedSessionCost, bp as createEmptyPlan, bq as createSkillsService, br as createTask, bs as endAttemptUsage, bt as findingLines, bu as flattenTasks, bv as flattenTasksWithParents, bw as formatCost, bx as formatTokenCount, by as handoffDigest, bz as handoffLines, bA as handoffPreviewLines, bB as handoffReferenceText, bC as handoffWakeLines, bD as inLoop, bE as isAwaitingReason, bF as isMeasured, bG as isSupervisorLevel, bH as isUserMessage, bI as loopRemovalRefusal, bJ as loopRoundOf, bK as migratePlanState, bL as modelCostTitle, bM as namedHandoff, bN as openingLines, bO as outOfRounds, bP as partedPromptUsage, bQ as patchChangesText, bR as patchFlagText, bS as patchLines, bT as patchLinesText, bU as patchText, bV as patchView, bW as pausedOnLimit, bX as planUsage, bY as plannerContextFill, bZ as readableTaskIds, b_ as rejoinPlanTree, b$ as resumedSessionWindow, c0 as savedPatchOf, c1 as savedPatchView, c2 as savedPatchViews, c3 as severityLabel, c4 as startAttemptUsage, c5 as storedHandoff, c6 as subagentCostTitle, c7 as taskUsageSummary, c8 as tasksTotalText, c9 as usageLine, ca as usageText, cb as waitsForApproval, cc as withPatch, cd as worstSeverity } from './Task-BL4Idm9r.js';
|
|
3
|
+
import { da as TurnBudgets, b4 as PlanIntake, ao as IWebFetcher, V as ConversationTurn, bj as PlannerModes, by as ResolveAll, dj as WebReadPolicy, dg as WebRead, dh as WebReadDecision, di as WebReadOptions, b0 as PendingApprovals, al as IAiService, ba as PlannerContextDeps, bb as PlannerContextStatus, M as ContextCondenseRequest, T as ConversationRequest, bL as RunnerAuthExec, bK as RunnerAuth, b as AccountLimitBucket, c as AccountLimitSnapshot, t as AssignmentWriter, s as AssignmentScope, cS as TaskQueryCatalog, q as AssignmentCatalog, bO as RunnerCatalog, c6 as SessionMessage, b_ as SessionBroadcaster, c8 as SessionNotice, b8 as PlanStore, cM as TaskOrchestrator, at as IsolationRunController, aX as OrchestratorObserver, cB as TaskLogEvent, bx as ResearchTasks, an as INotification, ag as GlobalRunSettings, c1 as SessionHeld, c3 as SessionLease, bd as PlannerConversationHost, bc as PlannerConversation, aa as ExecutionCommand, F as CommandOutcome, a$ as PendingApproval, P as ConversationCompaction, bA as RewindTarget, bJ as RunView, bE as RunMergeView, bC as RunActivity, cP as TaskOutputSource, aw as LeaseHost, dd as UserSettings, aB as LiveTailOptions, aA as LiveTail, c7 as SessionMeta, bi as PlannerModelStore, bh as PlannerModelRecall, be as PlannerModelCandidate } from './runSettingsText-CAXiTpsj.js';
|
|
4
|
+
export { A as ACT_RISK, a as AUTORUN_RISK, d as AccountLimitStatus, e as AccountLimitWindow, f as AccountLimitsFrame, g as AccountLimitsMessage, h as AdoptSessionResponse, i as ApplyTaskOpsResult, j as ApprovalAnswerResponse, k as ApprovalBlock, l as ApprovalRequestMessage, m as ApprovalStatus, n as ApprovalsResponse, o as ApproveReviewResponse, p as AskOptions, r as AssignmentIssue, u as AutoMergeTrigger, B as BlockingSubject, C as CHAT_COMMANDS, v as CHECKPOINT_TRUNCATE_LENGTH, w as CancelPlanningResponse, x as CancelResumeResponse, y as CliAgentAiService, z as CliAgentAiServiceDeps, D as CommandBlock, E as CommandDescriptor, G as CommandPayload, H as CommandStatus, I as CommandsResponse, J as CompactionBlock, K as CompactionStatus, L as Consent, N as ConversationBusyError, O as ConversationCompactResponse, Q as ConversationEditError, R as ConversationForkResponse, S as ConversationInput, U as ConversationRewindResponse, W as ConversationView, X as DEFAULT_WEB_READ_BUDGET, Y as DaemonErrorCode, Z as DecideOptions, _ as DiffRow, $ as DiffRowKind, a0 as DiffStat, a1 as DisplayBlock, a2 as EMPTY_CONVERSATION, a3 as EMPTY_HOLD, a4 as EMPTY_RUN, a5 as EMPTY_TASK_LOG, a6 as EMPTY_TASK_LOG_FOLLOW, a7 as ErrorBody, a8 as ExecuteCommandResponse, a9 as ExecuteResponse, ab as ExecutionCommands, ac as ExecutionHost, ad as ExecutionSummary, ae as GatedConversation, af as GeneratePlanResponse, ah as HEADLESS_CLI_COMMANDS, ai as HandoffBlock, aj as HandoffForkRepo, ak as HandoffPeekSubject, am as IDLE_ACTIVITY, ap as IsolationDiffResponse, aq as IsolationMergeResponse, ar as IsolationPreviewNotice, as as IsolationPreviewResponse, au as LEASE_HEARTBEAT_MS, av as LEASE_STALE_MS, ax as LeaseHostKind, ay as LeaseHostOptions, az as LiveOutputLookup, aC as LocalEntry, aD as LoopCheckFacts, aE as LoopCheckState, aF as LoopGuard, aG as MappedTool, aH as MarkdownToken, aI as MergeGateEntry, aJ as MergeGateResponse, aK as MergeWordingHandoff, aL as MessageBlock, aM as MessageRole, aN as ModelsResponse, aO as NOT_STARTED, aP as NO_TURN, aQ as NewTaskFields, aR as NotificationAction, aS as OUTPUT_LINES_DEFAULT, aT as OUTPUT_LINES_MAX, aU as OkResponse, aV as OpRef, aW as OpRefusal, aY as OutputPreview, aZ as OverrideDirection, a_ as PLANNED_WITH_LABEL, b1 as PendingApprovalsOptions, b2 as PlanBlock, b3 as PlanBlocks, b5 as PlanMarkerStatus, b6 as PlanResponse, b7 as PlanSnapshot, b9 as PlannerCommandSyntax, bf as PlannerModelChoice, bg as PlannerModelMemory, bk as PlannerNotReady, bl as PlannerNotReadyError, bm as PlannerReadinessConfig, bn as PlannerSubmission, bo as PlannerTurnDiscardedError, bp as PlannerTurnStoppedError, bq as PlannerUsageLimitError, br as PrdResponse, bs as PromptHold, bt as REPORT_PREVIEW_LINES, bu as RUN_SETTINGS_DEFAULTS, bv as ReadRunnerAuthOptions, bz as ResolveConflictResponse, bB as RewindTargetsResponse, bD as RunInput, bF as RunSettingsError, bG as RunSnapshotFrame, bH as RunTask, bI as RunTaskStatus, bM as RunnerAuthExecOptions, bN as RunnerAuthExecResult, bP as RunnerLoadedBlock, bQ as RunnersResponse, bR as STOPPED_BEFORE_START, bS as SUPERVISOR_LEVELS, bT as SUPERVISOR_LEVEL_LABEL, bU as SerializedConversationMessage, bV as SerializedPendingTurn, bW as SerializedPlan, bX as SerializedTask, bY as SerializedTaskStatus, bZ as ServerInfoResponse, b$ as SessionData, c0 as SessionFrame, c2 as SessionHeldError, c4 as SessionLeaseRecord, c5 as SessionListResponse, c9 as SessionResponse, ca as SettingsResponse, cb as SettingsService, cc as SettingsUpdateResponse, cd as SkillInvocation, ce as SkillLoadBlock, cf as SkillToken, cg as StartAdmission, ch as StopResponse, ci as StreamStamp, cj as SubagentBlock, ck as SubagentChild, cl as SubagentStatus, cm as SupervisorPolicy, cn as SurfacePlan, co as SurfacePlanState, cp as SurfaceTask, cq as TASK_QUERY_ANSWER_MAX_CHARS, cr as TASK_QUERY_ANSWER_OR_OPS, cs as TASK_QUERY_FIELDS, ct as TASK_QUERY_PROTOCOL, cu as TASK_QUERY_REMINDER, cv as TERMINAL_UI_COMMANDS, cw as TakenPrompt, cx as TaskAction, cy as TaskAttemptSnapshot, cz as TaskLogAttemptsResponse, cA as TaskLogBatch, cC as TaskLogFollow, cD as TaskLogFollowInput, cE as TaskLogHeaderKind, cF as TaskLogHeaderTask, cG as TaskLogHeaderUsage, cH as TaskLogHeaderView, cI as TaskLogResponse, cJ as TaskLogView, cK as TaskMessageResponse, cL as TaskOp, cN as TaskOrchestratorDeps, cO as TaskOrchestratorOptions, cQ as TaskPlacement, cR as TaskQuery, cT as TaskQueryField, cU as TaskRef, cV as TaskRowAction, cW as TaskRowContext, cX as TaskRowHandoff, cY as TaskRowIsolation, cZ as TaskRowKind, c_ as TaskRowLoop, c$ as TaskRowPlacement, d0 as TaskRowSubject, d1 as TaskRowUsage, d2 as TaskRowView, d3 as TaskRunFacts, d4 as TaskStatusKind, d5 as ThinkingDisplayBlock, d6 as ToolBlock, d7 as ToolHeadline, d8 as ToolStatus, d9 as TreeTask, db as TurnGate, dc as UsageBlock, de as WAITS_FOR_APPROVAL_LABEL, df as WakeUpItem, dk as Worded, dl as WorkspacesResponse, dm as abbreviateHome, dn as accountLimitPercentText, dp as accountLimitWindowLabel, dq as accountLimitsOf, dr as accountLimitsText, ds as accountLimitsTitle, dt as aheadOfDraft, du as applyTaskOps, dv as approvalKindText, dw as approvalLabel, dx as approvalStatusText, dy as assignedRunnerOf, dz as assignmentIssue, dA as assignmentIssueText, dB as automergeSummary, dC as autorunSummary, dD as awaitingLabel, dE as blockNotice, dF as blockNotices, dG as blockedByLabel, dH as blockingFailures, dI as canMergeTasks, dJ as canSetDependencies, dK as canSplitTask, dL as capConflictFiles, dM as cardEditNeedsUnstarted, dN as cardEditable, dO as checkoutRule, dP as classifyOutcome, dQ as coalesceTaskLog, dR as compactionText, dS as confirmedOverride, dT as createAiService, dU as dependencyCandidates, dV as dependentsNotice, dW as dependentsOf, dX as describeHeld, dY as describeHolder, dZ as describeIsolationPreview, d_ as describeMergeResult, d$ as describePlannerNotReady, e0 as diffRows, e1 as diffStat, e2 as diffSummary, e3 as digestTaskLog, e4 as drainNext, e5 as editableWhileRunning, e6 as executionSummary, e7 as followTaskLog, e8 as followTurn, e9 as fromTranscript, ea as getSettingsPath, eb as handoffBaseLine, ec as handoffBranchName, ed as handoffFindingsText, ee as handoffPeekParts, ef as hasAccountLimits, eg as hasHiddenDetail, eh as hasLongReport, ei as holdLabel, ej as holdPrompt, el as isRepoGroup, em as isTaskRunning, en as lastServedModel, eo as loadedSkillTokens, ep as logContinues, eq as logResumes, er as loopBodyLabel, es as loopBodyRound, et as loopCheckLabel, eu as loopCheckState, ev as loopLeaveNotice, ew as loopRowParts, ex as manualOverrideConfirmation, ey as manualOverrideStopFirst, ez as mapAgentTool, eA as markAction, eB as markdownHtml, eC as markdownTokens, eD as mergeOutcome, eE as mergeTarget, eF as namedRepos, eG as newTaskFields, eH as noExecutorRefusal, eI as normalizeAgentArgs, eJ as opRefusalText, eK as opsEditable, eL as outputLines, eM as outputPreview, eN as overrideNeedsConfirmation, eO as parseCount, eP as parseSwitch, eQ as parseTaskOpsJson, eR as parseTaskQueryJson, eS as pastGateConfirmation, eT as planBlocks, eU as planMarkerParts, eV as plannerMessage, eW as plannerNotReady, eX as plannerNotReadyFor, eY as plannerTranscript, eZ as processLeaseHost, e_ as ranSealed, e$ as readRunnerAuth, f0 as receiptLabel, f1 as reconcileApprovals, f2 as recordRunnerAuth, f3 as recordedRunnerAuth, f4 as reduceConversation, f5 as reduceRun, f6 as reduceTaskLog, f7 as renderTaskQueryAnswer, f8 as repairedLanded, f9 as repairedNotice, fa as repeatingChecks, fb as replayTaskLog, fc as repoBaseLine, fd as repoResultLines, fe as reposWithWork, ff as resetRunnerAuth, fg as resolveSkillInvocation, fh as resolveTaskRef, fi as resolveUserTaskRef, fj as resumeLabel, fk as resumeTime, fl as runHoldsEditors, fm as runSettingsOf, fn as runnerToolSubject, fo as scriptExitText, fp as scriptRunText, fq as secondsText, fr as serializePlan, fs as serializeTask, ft as serializeTaskStatus, fu as skillTokens, fv as skippedLabel, fw as stopTurn, fx as subtreeIds, fy as summarizeToolCall, fz as supervisorSummary, fA as surfacePlan, fB as surfacePlanState, fC as takeAt, fD as taskActionCommand, fE as taskChatAvailable, fF as taskLogCommands, fG as taskLogForSurface, fH as taskLogHeaderView, fI as taskOrderLabel, fJ as taskPlacement, fK as taskQuerySignature, fL as taskRef, fM as taskRefOf, fN as taskRowActions, fO as taskRowView, fP as taskStartedNotice, fQ as taskStatusKind, fR as textHasTaskOps, fS as textHasTaskQuery, fT as titledRefs, fU as titledTaskRef, fV as titledTaskRefOf, fW as toTaskLogEvent, fX as toolHeadline, fY as trailerSummary, fZ as trimToolOutput, f_ as truncateCheckpointSummary, f$ as unsendAll, g0 as unsendLatest, g1 as wakeUpItems, g2 as walkPlan, g3 as withoutSealedMark, g4 as workspaceEnvOf } from './runSettingsText-CAXiTpsj.js';
|
|
5
|
+
import { O as IConfig, P as IFileSystem, am as PlannerToolHandler, aj as PlannerShellSandbox, aw as ResearchShell, N as IApproval, au as ReadFileOpts, bq as ToolOutcome, L as GrepOptions, b1 as ShellLaunch, K as GlobOptions, H as FindSymbolOptions, B as BashOptions, bl as TaskShellSite, bk as TaskShell, az as RuleWord, af as PlannerAllowlist, aV as ScriptBody, Q as IRunner, ag as PlannerBackendId, ap as ProviderModelLists, f as AiProvider, n as ApprovalModeSetting, aN as RunnerRegistry, a8 as OrchestratorOption, d as AgentProcessDeps, be as TaskModeAgentAdapter, e as AgentStartOptions, a as AgentAdapter, c as AgentEvent, aE as RunnerCommand$1, s as AttachState, k as ApprovalDecision, an as ProjectMcpServer, R as IRunnerSession, o as ApprovalPolicy, j as ApprovalAnswer, a9 as OrdewellMcpServer, bb as TaskCompleteArgs, aW as ScriptExit, t as CheckpointAnswer, b5 as StructuredTurnEnd, b4 as StructuredEvent, bd as TaskMessageFrom, ar as QueuedTaskMessage, bm as TaskStartOptions, bn as TaskTokenScope, a0 as McpToolReply, bp as TaskWebReads, av as ReadTaskArgs, i as ApplyPatchArgs, aI as RunnerManifest, bj as TaskRunnerFlags } from './IRunner-B5l9PCTv.js';
|
|
6
|
+
export { A as AUTO_COMMANDS, b as AgentAdapterFactory, g as AllProviderModels, h as AnswerApprovalArgs, l as ApprovalKind, m as ApprovalMode, p as ApprovalPolicyOptions, q as ApprovalRequest, r as ApprovalSource, C as CatalogModel, u as CheckpointArgs, v as CommandClassification, w as CommandTier, x as CommandWords, D as DEFAULT_PLANNER_ALLOWLIST, y as DEFAULT_SCRIPT_TIMEOUT_MS, z as DENY_ALL, E as DiscoveryCommand, F as EditPlanArgs, G as FetchAllProviderModelsOptions, I as GIT_READONLY_SUBCOMMANDS, J as GREP_DEFAULT_HEAD_LIMIT, M as GrepOutputMode, S as InvokedCommand, T as LineBuffer, U as ListModelsArgs, V as ListRunnersArgs, W as LoadSkillArgs, X as McpClientConfig, Y as McpCredential, Z as McpRefusal, _ as McpTool, $ as McpToolContext, a1 as MessageTaskArgs, a2 as ModelCatalog, a3 as ModelShortcut, a4 as ORCHESTRATOR_SHORTCUTS, a5 as ORDEWELL_MCP_PATH, a6 as ORDEWELL_MCP_SERVER_NAME, a7 as OneTaskArgs, aa as OwnSealedRuns, ab as OwnerOnlyFile, ac as PLANNER_EXECUTION_TOOLS, ad as PLANNER_SANDBOX_DOCS, ae as PLANNER_TOOLS, ah as PlannerSandboxAvailability, ai as PlannerSandboxDeps, ak as PlannerStartOptions, al as PlannerTokenScope, ao as ProviderCredentialSource, aq as ProviderModelsResult, as as READ_ONLY_TASK_TOOLS, at as REFUSED_COMMANDS, ax as ResearchShellDeps, ay as RetryTaskArgs, aA as RunCommandArgs, aB as RunPlanArgs, aC as RunnerAuthSpec, aD as RunnerAuthStatus, aF as RunnerCommandKind, aG as RunnerEntry, aH as RunnerFeatures, aJ as RunnerMcpServer, aK as RunnerMode, aL as RunnerModelDiscovery, aM as RunnerModelRef, aO as SEALED_LIMITS, aP as SEARCH_EXCLUSIONS, aQ as SandboxBackend, aR as SandboxInvocation, aS as SandboxLaunch, aT as SandboxLimits, aU as SandboxProfile, aX as ScriptFullOutput, aY as ScriptRun, aZ as ScriptStatus, a_ as SealedAvailability, a$ as SealedRunOptions, b0 as ShellDialect, b2 as SpawnFn, b3 as StandingDecision, b6 as SubmitPlanArgs, b7 as TASK_COMPLETE_TOOL, b8 as TASK_COMPLETION_CONTRACT, b9 as TASK_SEALED_LIMITS, ba as TASK_TOOLS, bc as TaskDiffArgs, bf as TaskModeUnsupportedError, bg as TaskOutputArgs, bh as TaskQueryArgs, bi as TaskRunCommandArgs, bo as TaskToolHandler, bs as approvalScopes, bt as classifyCommand, bu as clearPlannerSandboxCache, bv as clearResearchShellCache, bw as collectProviderCredentials, bx as commandAllowedBy, by as commandLine, bz as effectiveApprovalMode, bA as enabledRunners, bB as fetchAllProviderModels, bC as findRunnerCommand, bD as isGranted, bE as isRunnerApproval, bF as knownModelId, bG as mcpClientConfig, bH as ownerOnlyConfigFile, bI as parseAllowlist, bJ as parseApprovalModeSetting, bK as researchShellWarning, bL as researchToolsPath, bM as resolveModelShortcut, bN as resolvePlannerSandbox, bO as resolveProvider, bP as resolveResearchShell, bQ as scopeAllowed, bR as scriptBodyOf, bS as scriptBodyText, bT as scriptTaskText, bU as sharedMcpServer, bV as taskCompletionContract, bW as timeLimitText, bX as toApprovalDecision, bY as toOrchestratorOptions, bZ as toolAllowed } from './IRunner-B5l9PCTv.js';
|
|
7
|
+
import { R as RunnerModeInfo } from './ModeResolver-DyXeZ9ib.js';
|
|
8
|
+
export { a as autonomyLevelLabel, p as parseAutonomyFlag, b as parseAutonomyLevel, r as runnerModesFrom } from './ModeResolver-DyXeZ9ib.js';
|
|
9
|
+
import { WorkerOptions, Worker } from 'worker_threads';
|
|
9
10
|
import { ChildProcess } from 'child_process';
|
|
10
11
|
import { EventEmitter } from 'events';
|
|
11
12
|
import 'zod/v4';
|
|
@@ -18,427 +19,195 @@ type GitExecFn = (file: string, args: string[], opts: {
|
|
|
18
19
|
stderr: string;
|
|
19
20
|
}>;
|
|
20
21
|
|
|
21
|
-
/** One call at the command seam, as every route words it (ADR-0029). Task references are resolved here. */
|
|
22
|
-
type ExecutionCommand = {
|
|
23
|
-
command: 'run_plan';
|
|
24
|
-
} | {
|
|
25
|
-
command: 'run_task';
|
|
26
|
-
task: string;
|
|
27
|
-
} | {
|
|
28
|
-
command: 'stop_task';
|
|
29
|
-
task: string;
|
|
30
|
-
} | {
|
|
31
|
-
command: 'stop_run';
|
|
32
|
-
}
|
|
33
22
|
/**
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
23
|
+
* A message or interrupt a task cannot take: it is not running, or it is
|
|
24
|
+
* waiting on something a message does not answer.
|
|
25
|
+
* The request is wrong, not the orchestrator, so a surface says why.
|
|
37
26
|
*/
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
task: string;
|
|
41
|
-
from: 'fresh' | 'session';
|
|
42
|
-
message?: string;
|
|
43
|
-
}
|
|
44
|
-
/** `force`: the user's force send (ADR-0023, F1), which interrupts the running turn and is read next. */
|
|
45
|
-
| {
|
|
46
|
-
command: 'message_task';
|
|
47
|
-
task: string;
|
|
48
|
-
text: string;
|
|
49
|
-
force?: boolean;
|
|
50
|
-
}
|
|
51
|
-
/** `answer` is checked here rather than typed: an `allow` must reach the seam to be refused with its reason. */
|
|
52
|
-
| {
|
|
53
|
-
command: 'answer_approval';
|
|
54
|
-
task: string;
|
|
55
|
-
approval?: string;
|
|
56
|
-
answer: string;
|
|
57
|
-
note?: string;
|
|
58
|
-
}
|
|
59
|
-
/** Merge all: the run's landed work into the user's branch (ADR-0013). */
|
|
60
|
-
| {
|
|
61
|
-
command: 'merge_all';
|
|
62
|
-
}
|
|
63
|
-
/** End a task as skipped: nothing it did lands, and its dependents go ahead without it once the work it waited on is done. `reason` is required of anyone but the user. */
|
|
64
|
-
| {
|
|
65
|
-
command: 'skip_task';
|
|
66
|
-
task: string;
|
|
67
|
-
reason?: string;
|
|
68
|
-
}
|
|
69
|
-
/** The user's force start: past a failed dependency or a merge gate, queued behind dependencies still under way (ADR-0035). */
|
|
70
|
-
| {
|
|
71
|
-
command: 'force_start';
|
|
72
|
-
task: string;
|
|
73
|
-
}
|
|
74
|
-
/** The user vouches for the task's work, which lands as a passed verdict's would; never anyone else (ADR-0029). */
|
|
75
|
-
| {
|
|
76
|
-
command: 'mark_complete';
|
|
77
|
-
task: string;
|
|
78
|
-
}
|
|
79
|
-
/** The user takes a completion back: the task is not started again, and held until it is retried or started. */
|
|
80
|
-
| {
|
|
81
|
-
command: 'mark_not_done';
|
|
82
|
-
task: string;
|
|
83
|
-
}
|
|
84
|
-
/** Stop a structured task's running turn, keeping its session: it then waits for the user's message. */
|
|
85
|
-
| {
|
|
86
|
-
command: 'interrupt_task';
|
|
87
|
-
task: string;
|
|
88
|
-
}
|
|
89
|
-
/** Force send a message queued behind the running turn (ADR-0023, F1); `id` is the one `message_task` answered with. */
|
|
90
|
-
| {
|
|
91
|
-
command: 'force_send_queued';
|
|
92
|
-
task: string;
|
|
93
|
-
id: string;
|
|
94
|
-
}
|
|
95
|
-
/** Take back a message still queued behind the running turn. */
|
|
96
|
-
| {
|
|
97
|
-
command: 'remove_queued';
|
|
98
|
-
task: string;
|
|
99
|
-
id: string;
|
|
27
|
+
declare class TaskControlError extends Error {
|
|
28
|
+
constructor(message: string);
|
|
100
29
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
30
|
+
|
|
31
|
+
/** Structural subset of an OpenAI-style chat message that compaction reads and rewrites. */
|
|
32
|
+
interface CompactableMessage {
|
|
33
|
+
role: string;
|
|
34
|
+
content?: unknown;
|
|
35
|
+
tool_call_id?: string;
|
|
36
|
+
tool_calls?: Array<{
|
|
37
|
+
id?: string;
|
|
38
|
+
function?: {
|
|
39
|
+
name?: string;
|
|
40
|
+
arguments?: string;
|
|
41
|
+
};
|
|
42
|
+
}>;
|
|
105
43
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
reason?: string;
|
|
44
|
+
|
|
45
|
+
interface ToolCall {
|
|
46
|
+
name: string;
|
|
47
|
+
args: Record<string, unknown>;
|
|
48
|
+
id?: string;
|
|
112
49
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
/** `message_task`: the queued message's id, which the surface's button answers with. */
|
|
120
|
-
{
|
|
121
|
-
kind: 'message';
|
|
122
|
-
id: string;
|
|
50
|
+
interface ToolResult {
|
|
51
|
+
name: string;
|
|
52
|
+
output: string;
|
|
53
|
+
truncated: boolean;
|
|
54
|
+
totalChars: number;
|
|
55
|
+
id?: string;
|
|
123
56
|
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
57
|
+
interface ResearchTurn {
|
|
58
|
+
text: string;
|
|
59
|
+
toolCalls: ToolCall[];
|
|
60
|
+
hasToolCalls: boolean;
|
|
61
|
+
/** Reasoning/chain-of-thought captured separately from `text` so it never pollutes plan JSON. */
|
|
62
|
+
reasoning?: string;
|
|
63
|
+
/** Provider finish reason, normalized: 'length' means the output-token limit cut the reply mid-stream. */
|
|
64
|
+
finishReason?: string;
|
|
65
|
+
/** Exact prompt tokens this turn consumed, when the provider reports usage. */
|
|
66
|
+
promptTokens?: number;
|
|
67
|
+
/** The segment `text` streamed under, where the provider streams it. */
|
|
68
|
+
segmentId?: string;
|
|
128
69
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
* nothing above it moves.
|
|
164
|
-
*/
|
|
165
|
-
type SupervisorPolicy = (level: SupervisorLevel, command: ExecutionCommandName) => Consent;
|
|
166
|
-
/**
|
|
167
|
-
* The supervisor levels (ADR-0029). Off: it does not act. Watch: it reads and
|
|
168
|
-
* suggests, and every execution command it calls is refused. Act: every
|
|
169
|
-
* command runs without asking — choosing Act is the consent — inside the loop
|
|
170
|
-
* guards; what a command may never do, like allowing an approval, is still
|
|
171
|
-
* refused by the command itself.
|
|
172
|
-
*/
|
|
173
|
-
declare const SUPERVISOR_LEVELS: SupervisorPolicy;
|
|
174
|
-
/**
|
|
175
|
-
* A check that stops an actor spinning (ADR-0029's loop guards): the trip —
|
|
176
|
-
* the note naming the guard and what would be accepted, and what the user is
|
|
177
|
-
* told — or null to let the call through. Run once the call is valid and
|
|
178
|
-
* consented to, before anyone is asked.
|
|
179
|
-
*/
|
|
180
|
-
type LoopGuard = (actor: ExecutionActor, command: ExecutionCommand, target: GuardTarget | undefined) => GuardTrip | null;
|
|
181
|
-
/** A runner request waiting on a task, as the caller is shown it. */
|
|
182
|
-
interface WaitingRequest {
|
|
183
|
-
id: string;
|
|
184
|
-
subject: string;
|
|
70
|
+
interface ResearchChat {
|
|
71
|
+
sendMessage(text: string, signal?: AbortSignal): Promise<ResearchTurn>;
|
|
72
|
+
sendToolResults(results: ToolResult[], signal?: AbortSignal): Promise<ResearchTurn>;
|
|
73
|
+
/**
|
|
74
|
+
* Optional: prune older workspace reads from the history (everything else,
|
|
75
|
+
* and the newest rounds, are kept) so a follow-up emission has context to
|
|
76
|
+
* spend on output. Returns the number of characters removed.
|
|
77
|
+
*/
|
|
78
|
+
compactHistory?(): number;
|
|
79
|
+
/**
|
|
80
|
+
* Whether a call's input is held: the call could not fit the model's window
|
|
81
|
+
* (`PlannerContextExhaustedError`), so its user message or tool results were
|
|
82
|
+
* kept out of the history. The next message drops a held message and files
|
|
83
|
+
* held results as a turn before it.
|
|
84
|
+
*/
|
|
85
|
+
holdsInput?(): boolean;
|
|
86
|
+
/** Send the held input again, once room is made: no tool runs a second time. */
|
|
87
|
+
resend?(signal?: AbortSignal): Promise<ResearchTurn>;
|
|
88
|
+
/** Whether {@link retry} can send the held input: a window is known to compact against. */
|
|
89
|
+
retryable?(): boolean;
|
|
90
|
+
/** The user's Retry compaction: condense with their consent, then send the held input once. */
|
|
91
|
+
retry?(signal?: AbortSignal): Promise<ResearchTurn>;
|
|
92
|
+
/**
|
|
93
|
+
* Take `history` in place of the whole message list in one step — a summary
|
|
94
|
+
* swapped in for what it condensed. Refused, changing nothing, unless each
|
|
95
|
+
* tool result answers a call of the assistant message just before it, once.
|
|
96
|
+
*/
|
|
97
|
+
reseed?(history: readonly CompactableMessage[]): void;
|
|
98
|
+
/**
|
|
99
|
+
* Optional: the answer to a call the open turn already made in rounds
|
|
100
|
+
* condensed out of the model's sight, in place of running it again
|
|
101
|
+
* (ADR-0002). Undefined for a call that runs.
|
|
102
|
+
*/
|
|
103
|
+
answered?(call: ToolCall): string | undefined;
|
|
185
104
|
}
|
|
186
|
-
/**
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
/**
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
/** The
|
|
197
|
-
|
|
198
|
-
/** A task the scheduler leaves for the user to approve: added to the plan since they approved it (ADR-0035). */
|
|
199
|
-
waitsForApproval(taskId: string): boolean;
|
|
200
|
-
/** A start the user consented to approves these tasks, before it acts. */
|
|
201
|
-
approve(taskIds: readonly string[]): void;
|
|
202
|
-
/** Full autonomy: starts follow plan approval without a question. */
|
|
203
|
-
autonomous(): boolean;
|
|
204
|
-
/** The user's autorun setting, as it is now (ADR-0030). */
|
|
205
|
-
autorun(): boolean;
|
|
206
|
-
/** The scheduler is driving the plan: ready tasks start as slots free. */
|
|
207
|
-
scheduling(): boolean;
|
|
208
|
-
/** An open planner turn holds the scheduler's new starts until its reply ends. */
|
|
209
|
-
startsHeld(): boolean;
|
|
210
|
-
/** Work is running right now. */
|
|
211
|
-
hasLiveWork(): boolean;
|
|
212
|
-
/** Something will start without being asked again: a start admitted and not yet claimed, or a scheduled resume. */
|
|
213
|
-
startsPending(): boolean;
|
|
214
|
-
/** Admit a start that waits before it claims; see {@link StartAdmission}. */
|
|
215
|
-
admitStart(): StartAdmission;
|
|
216
|
-
/** The task's attempt is live: starting, running or landing. */
|
|
217
|
-
running(taskId: string): boolean;
|
|
218
|
-
maxParallel(): number;
|
|
219
|
-
/** The run waits on the user to stash or skip isolation before anything starts. */
|
|
220
|
-
runBlocked(): boolean;
|
|
221
|
-
/**
|
|
222
|
-
* Every reason the task cannot start now, from the scheduler's one start
|
|
223
|
-
* rule (ADR-0034). Takes the task, not its id: one a held edit changes or
|
|
224
|
-
* adds is judged as the edit leaves it.
|
|
225
|
-
*/
|
|
226
|
-
startWaits(task: Readonly<Task>): readonly StartWait[];
|
|
227
|
-
/** The runner requests waiting on a task for an answer. */
|
|
228
|
-
waitingRequests(taskId: string): readonly WaitingRequest[];
|
|
229
|
-
/** A start is told who asked: whether a run it opens continues the last one depends on it (ADR-0029). */
|
|
230
|
-
runPlan(actor: ExecutionActor): Promise<void>;
|
|
231
|
-
/**
|
|
232
|
-
* The user's Execute while a run is under way, once it approved every task:
|
|
233
|
-
* the run takes them in, each starting once its dependencies finish. Answers
|
|
234
|
-
* the line that says so, naming how many had waited for approval.
|
|
235
|
-
*/
|
|
236
|
-
joinRun(approved: number): Promise<string>;
|
|
237
|
-
startTask(taskId: string, actor: ExecutionActor): Promise<void>;
|
|
238
|
-
/** Force start the task; answers the line saying it waits for its dependencies, when it was queued behind them rather than started. */
|
|
239
|
-
forceStart(taskId: string): Promise<string | undefined>;
|
|
240
|
-
markComplete(taskId: string): Promise<void>;
|
|
241
|
-
markNotDone(taskId: string): Promise<void>;
|
|
242
|
-
interrupt(taskId: string): Promise<void>;
|
|
243
|
-
stopTask(taskId: string): Promise<void>;
|
|
244
|
-
stopRun(): void;
|
|
245
|
-
retryTask(taskId: string, actor: ExecutionActor): Promise<void>;
|
|
246
|
-
/** End the task as skipped, landing nothing of it; see {@link TaskOrchestrator.skipTask}. */
|
|
247
|
-
skipTask(taskId: string, reason: string | undefined, actor: ExecutionActor): Promise<void>;
|
|
248
|
-
continueTask(taskId: string, message: string, actor: ExecutionActor): Promise<void>;
|
|
249
|
-
/** Resume a task paused on a usage limit now; see {@link TaskOrchestrator.resumeNow}. */
|
|
250
|
-
resumeNow(taskId: string, message: string | undefined, actor: ExecutionActor): Promise<void>;
|
|
251
|
-
messageTask(taskId: string, text: string): string;
|
|
252
|
-
/** Force send (ADR-0023, F1): interrupt the running turn and deliver this next. */
|
|
253
|
-
forceMessage(taskId: string, text: string): string;
|
|
254
|
-
/** False once the message was delivered. */
|
|
255
|
-
forceSendQueued(taskId: string, id: string): boolean;
|
|
256
|
-
/** False once the message was delivered or taken back. */
|
|
257
|
-
removeQueued(taskId: string, id: string): boolean;
|
|
258
|
-
/** False when no resume was scheduled. */
|
|
259
|
-
cancelResume(taskId: string): Promise<boolean>;
|
|
260
|
-
/** The task waits at a checkpoint, and a runner is left to hear the answer. */
|
|
261
|
-
awaitsCheckpoint(taskId: string): boolean;
|
|
262
|
-
answerCheckpoint(taskId: string, approve: boolean, reason?: string): void;
|
|
263
|
-
/** Sign off the review: the plan is the user's, and runs. */
|
|
264
|
-
approveReview(): Promise<void>;
|
|
265
|
-
/** Answer a runner's request, as its card does; false once it was answered or withdrawn. */
|
|
266
|
-
answerRequest(requestId: string, decision: ApprovalDecision): boolean;
|
|
267
|
-
/** Merge all, through the queue it shares with landings. */
|
|
268
|
-
mergeAll(): Promise<IsolationMergeResult>;
|
|
269
|
-
/** Keep the call in the timeline, worded as `text`. */
|
|
270
|
-
record(record: ExecutionRecord, text: string): void;
|
|
271
|
-
/** A loop guard stopped a call: the user is told, as the supervisor's message. */
|
|
272
|
-
guardTripped(trip: GuardTrip): void;
|
|
273
|
-
/**
|
|
274
|
-
* The open planner turn holds an edit — to this task, or to any when none is
|
|
275
|
-
* named — that lands only when its reply ends.
|
|
276
|
-
*/
|
|
277
|
-
heldEdit(taskId?: string): boolean;
|
|
278
|
-
/** The plan's task tree as the open turn's held edit leaves it: as it is, when it holds none or one that would not apply. */
|
|
279
|
-
editedTasks(): readonly Task[];
|
|
280
|
-
/** The id of the task the open turn's held edit makes under this batch handle; undefined when it names none. */
|
|
281
|
-
heldHandle(name: string): string | undefined;
|
|
282
|
-
/**
|
|
283
|
-
* Run the command again, as the same actor, once the open turn's reply has
|
|
284
|
-
* landed its edit; `intent` names it if it never does. `admission` is
|
|
285
|
-
* released once it has run or been dropped.
|
|
286
|
-
*/
|
|
287
|
-
deferUntilLanded(command: ExecutionCommand, actor: ExecutionActor, intent: string, admission: StartAdmission): void;
|
|
288
|
-
/** A command deferred behind an edit did not run once the edit landed: the user is told, and so is the planner's next turn. */
|
|
289
|
-
queuedNotRun(text: string): void;
|
|
290
|
-
}
|
|
291
|
-
interface ExecutionCommandsDeps {
|
|
292
|
-
host: ExecutionHost;
|
|
293
|
-
/** The approval card channel a Guarded start asks through. */
|
|
294
|
-
consent: Pick<IApproval, 'request'>;
|
|
295
|
-
supervisor?: SupervisorPolicy;
|
|
296
|
-
guards?: readonly LoopGuard[];
|
|
297
|
-
now?: () => string;
|
|
105
|
+
/** Everything one conversation turn needs beyond the user message itself. */
|
|
106
|
+
interface ConversationTurnContext {
|
|
107
|
+
chat: ResearchChat;
|
|
108
|
+
fs: IFileSystem;
|
|
109
|
+
runners: RunnerId[];
|
|
110
|
+
runnerModes?: Record<RunnerId, RunnerModeInfo[]>;
|
|
111
|
+
/** See {@link ConversationRequest.liveScope}. */
|
|
112
|
+
liveScope?: () => PlanIntake;
|
|
113
|
+
autonomousDefault?: boolean;
|
|
114
|
+
fetcher?: IWebFetcher;
|
|
115
|
+
/** The session's planner tools; the conversation offers their task reads and execution tools (ADR-0029) when set. */
|
|
116
|
+
plannerTools?: PlannerToolHandler;
|
|
298
117
|
}
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
*/
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
118
|
+
declare abstract class BaseAiService {
|
|
119
|
+
protected config: IConfig;
|
|
120
|
+
protected turnBudgets?: TurnBudgets | undefined;
|
|
121
|
+
protected conversation: {
|
|
122
|
+
ctx: ConversationTurnContext;
|
|
123
|
+
setProgress: (fn: (p: ResearchProgress) => void) => void;
|
|
124
|
+
} | null;
|
|
125
|
+
protected activeAbort: AbortController | null;
|
|
126
|
+
/** See {@link compactions}. */
|
|
127
|
+
private compacted;
|
|
128
|
+
constructor(config: IConfig, turnBudgets?: TurnBudgets | undefined);
|
|
129
|
+
abstract reset(): void;
|
|
130
|
+
abstract ensureInit(): void;
|
|
131
|
+
hasActiveConversation(): boolean;
|
|
132
|
+
pruneContext(): number;
|
|
133
|
+
/**
|
|
134
|
+
* The compactions of a conversation's history that changed something, which
|
|
135
|
+
* the chat reports through {@link countCompaction}. A pruning stubs tool
|
|
136
|
+
* output alone, never the user messages a plan block rides in, but it counts
|
|
137
|
+
* all the same: the conversation would rather send the plan whole again than
|
|
138
|
+
* trust a context changed under it (ADR-0012 T10).
|
|
139
|
+
*/
|
|
140
|
+
compactions(): number;
|
|
141
|
+
protected countCompaction(): void;
|
|
142
|
+
protected startAbortScope(callerSignal?: AbortSignal): AbortSignal;
|
|
143
|
+
protected stopAbortScope(): void;
|
|
144
|
+
continueConversation(userMessage: string, onProgress: (progress: ResearchProgress) => void, signal?: AbortSignal): Promise<ConversationTurn>;
|
|
145
|
+
heldInputRetryable(): boolean;
|
|
146
|
+
/** The turn a held input was for, carried on from it: its first call is the retry, every later one as in any turn. */
|
|
147
|
+
retryHeldInput(onProgress: (progress: ResearchProgress) => void, signal?: AbortSignal): Promise<ConversationTurn>;
|
|
148
|
+
protected abstract streamPlanText(prompt: string, repairHint: string | undefined, onToken: (token: string) => void, onReasoning?: (token: string) => void, signal?: AbortSignal): Promise<string>;
|
|
149
|
+
/**
|
|
150
|
+
* Build a fresh chat for one research subagent (own history, subagent system
|
|
151
|
+
* prompt, cheap model). Null means the provider does not support subagents —
|
|
152
|
+
* the spawn tool then degrades to a steering message. `onReasoning` streams
|
|
153
|
+
* live reasoning deltas on models that expose them, same as the top-level loop;
|
|
154
|
+
* `onUsage` takes each call's usage, as the planner's own chat reports it.
|
|
155
|
+
*/
|
|
156
|
+
protected createSubagentChat(_onReasoning?: (delta: string) => void, _onUsage?: (record: UsageRecord) => void): ResearchChat | null;
|
|
157
|
+
/**
|
|
158
|
+
* One spawn_research_agent tool call, executed at the service layer (not in
|
|
159
|
+
* executeTool — that would cycle the imports). Every failure path returns a
|
|
160
|
+
* steering/failed result and the loop continues sequentially: a subagent can
|
|
161
|
+
* never fail a plan or a turn.
|
|
162
|
+
*/
|
|
163
|
+
private executeSpawnAgent;
|
|
164
|
+
/** Collect project context for the planning phase. Shared with the harness backend. */
|
|
165
|
+
protected static collectResearchContext(fs: IFileSystem, runners: RunnerId[]): Promise<string>;
|
|
166
|
+
/**
|
|
167
|
+
* Execute one round of tool calls and report each through onProgress.
|
|
168
|
+
* Returns the results to feed back plus the log entries produced.
|
|
169
|
+
*/
|
|
170
|
+
private executeToolCalls;
|
|
315
171
|
/**
|
|
316
|
-
*
|
|
317
|
-
* its
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
172
|
+
* Countdown appended to the last tool result of the final few rounds, so the
|
|
173
|
+
* model lands the turn on its own terms instead of being cut off exactly at
|
|
174
|
+
* the budget boundary mid-exploration.
|
|
175
|
+
*/
|
|
176
|
+
private static appendBudgetCountdown;
|
|
177
|
+
/**
|
|
178
|
+
* Run one planner conversation turn (ADR-0002): send the message, satisfy
|
|
179
|
+
* tool calls until the model answers in prose or JSON, and settle the reply
|
|
180
|
+
* through {@link settleReply}, which owns classification and every
|
|
181
|
+
* corrective retry. The model decides transitions — there are no sentinels
|
|
182
|
+
* and no question tags. A turn whose final text parses as a `{tasks:[...]}`
|
|
183
|
+
* object commits the plan; anything else is a message to the user.
|
|
184
|
+
*/
|
|
185
|
+
protected runConversationTurn(ctx: ConversationTurnContext, message: string, onProgress: (progress: ResearchProgress) => void, signal?: AbortSignal,
|
|
186
|
+
/** What the turn's first call is, in place of sending `message`: a held input sent again. */
|
|
187
|
+
firstCall?: () => Promise<ResearchTurn>): Promise<ConversationTurn>;
|
|
188
|
+
/** One model call of a conversation turn: the message, then tool rounds until the model replies without tools. */
|
|
189
|
+
private runToolRounds;
|
|
322
190
|
/**
|
|
323
|
-
*
|
|
324
|
-
*
|
|
325
|
-
*
|
|
191
|
+
* One round's calls run, except those the chat answers as already made in
|
|
192
|
+
* the turn's condensed rounds (ADR-0002): each of those is answered with
|
|
193
|
+
* what it returned and shown as not executed, before anything runs.
|
|
194
|
+
* Results and steps stay in call order.
|
|
326
195
|
*/
|
|
327
|
-
|
|
196
|
+
private runRound;
|
|
328
197
|
/**
|
|
329
|
-
*
|
|
330
|
-
*
|
|
331
|
-
*
|
|
332
|
-
* and one the user will be asked about says so. `located` is the task as the
|
|
333
|
-
* plan has it now, absent for a task the edit adds.
|
|
198
|
+
* Run the LLM tool-calling research loop for one-shot planning. Returns
|
|
199
|
+
* parsed tasks if a plan was emitted mid-loop, or null if the loop
|
|
200
|
+
* exhausted without a valid plan.
|
|
334
201
|
*/
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
* approves the tasks the card named, and no others.
|
|
345
|
-
*/
|
|
346
|
-
private consented;
|
|
347
|
-
/**
|
|
348
|
-
* With autorun on and Full, a planner turn may start a task added after the
|
|
349
|
-
* user approved the plan (ADR-0030). Read at each start, so switching either
|
|
350
|
-
* off stops it at once; never on a plan the user has not approved.
|
|
351
|
-
*/
|
|
352
|
-
private addedMayStart;
|
|
353
|
-
/**
|
|
354
|
-
* Guarded means "ask the user first": a planner start in the user's own
|
|
355
|
-
* turn asks, so tasks they have not approved go into the question rather
|
|
356
|
-
* than refusing it. The supervisor's starts stay within what the user
|
|
357
|
-
* approved (ADR-0029).
|
|
358
|
-
*/
|
|
359
|
-
private asksToApprove;
|
|
360
|
-
/**
|
|
361
|
-
* Who may do what without the mandate (#23): the user's own call needs no
|
|
362
|
-
* consent, and their own controls are theirs alone; a planner turn may
|
|
363
|
-
* always end or steer work, and starts it only as the autonomy level says;
|
|
364
|
-
* the supervisor's level decides for it.
|
|
365
|
-
*/
|
|
366
|
-
private consent;
|
|
367
|
-
/**
|
|
368
|
-
* Whether the command can run now, and how, judged against `tasks`: the
|
|
369
|
-
* plan, or the plan as the turn's held edit leaves it. Read afresh after a
|
|
370
|
-
* question, since answering takes time.
|
|
371
|
-
*/
|
|
372
|
-
private prepare;
|
|
373
|
-
private prepareRunPlan;
|
|
374
|
-
/** A start of one task: `run_task`, or a fresh `retry_task`, which also takes a task that failed or waits on the user. */
|
|
375
|
-
private prepareStart;
|
|
376
|
-
/**
|
|
377
|
-
* The user's force start goes past what the scheduler waits for, so only
|
|
378
|
-
* what no start could get past is refused here; the start rule decides the
|
|
379
|
-
* rest at the claim, and a dependency still under way queues it.
|
|
380
|
-
*/
|
|
381
|
-
private prepareForceStart;
|
|
382
|
-
/** Signing off the review approves every task in the plan, as executing it does: the seam records that before it acts. */
|
|
383
|
-
private prepareApproveReview;
|
|
384
|
-
private prepareMarkComplete;
|
|
385
|
-
private prepareMarkNotDone;
|
|
386
|
-
private prepareInterrupt;
|
|
387
|
-
private prepareCancelResume;
|
|
388
|
-
private prepareCheckpoint;
|
|
389
|
-
private prepareContinue;
|
|
390
|
-
/**
|
|
391
|
-
* A pause is not a failure: the attempt stopped on its account's limit, so
|
|
392
|
-
* its saved session goes on where it was, told the limit has reset. The
|
|
393
|
-
* message is what to add to that; none is needed.
|
|
394
|
-
*/
|
|
395
|
-
private prepareResume;
|
|
396
|
-
private prepareStop;
|
|
397
|
-
private prepareStopRun;
|
|
398
|
-
private prepareMessage;
|
|
399
|
-
/** A message queued behind the running turn, sent now or taken back; one delivered meanwhile is past either. */
|
|
400
|
-
private prepareQueued;
|
|
401
|
-
/**
|
|
402
|
-
* The user answers a runner's request as its card does. Anyone else only
|
|
403
|
-
* narrows or hands it on: allowing would widen the mode the plan gave the
|
|
404
|
-
* task (ADR-0029).
|
|
405
|
-
*/
|
|
406
|
-
private prepareAnswer;
|
|
407
|
-
private prepareMergeAll;
|
|
408
|
-
/**
|
|
409
|
-
* A skip is a decision not to wait for the task. Running it again undoes
|
|
410
|
-
* that decision, so the supervisor leaves it to the user rather than going
|
|
411
|
-
* round between the two.
|
|
412
|
-
*/
|
|
413
|
-
private skippedRefusal;
|
|
414
|
-
/**
|
|
415
|
-
* A skip ends a task without a verdict and lands nothing, so it never
|
|
416
|
-
* vouches for work. Anyone but the user names why, and the supervisor only
|
|
417
|
-
* gives up on a task that already needs someone: failed, blocked, or
|
|
418
|
-
* waiting for input.
|
|
419
|
-
*/
|
|
420
|
-
private prepareSkip;
|
|
421
|
-
/**
|
|
422
|
-
* Why a start is not the user's to have made, or the task it asks them to
|
|
423
|
-
* approve, or null: the user's own call is its own approval.
|
|
424
|
-
*/
|
|
425
|
-
private unapproved;
|
|
426
|
-
/**
|
|
427
|
-
* The Guarded question, on the card the user answers other planner requests
|
|
428
|
-
* on. It names every task a yes approves, since a yes is the user's
|
|
429
|
-
* approval of them as Execute plan would be.
|
|
430
|
-
*/
|
|
431
|
-
private question;
|
|
432
|
-
/** What was asked, as "start task #4 "Title"". */
|
|
433
|
-
private intent;
|
|
434
|
-
private refuse;
|
|
435
|
-
private keep;
|
|
436
|
-
private all;
|
|
437
|
-
private located;
|
|
438
|
-
/** A reference read against the plan as the held edit leaves it, where the handles its batch gives come first. */
|
|
439
|
-
private locateAsEdited;
|
|
440
|
-
/** A reference as a caller writes one — see {@link resolveTaskRef}; the user's as they type one ({@link resolveUserTaskRef}). */
|
|
441
|
-
private locate;
|
|
202
|
+
protected runResearchLoop(chat: ResearchChat, firstMessage: string, fs: IFileSystem, onProgress: (progress: ResearchProgress) => void, runners: RunnerId[], initialLog?: ResearchLogEntry[], fetcher?: IWebFetcher, userGoal?: string, runnerModes?: Record<RunnerId, RunnerModeInfo[]>, autonomousDefault?: boolean, signal?: AbortSignal): Promise<{
|
|
203
|
+
tasks: Task[] | null;
|
|
204
|
+
researchLog: ResearchLogEntry[];
|
|
205
|
+
researchResults: string;
|
|
206
|
+
}>;
|
|
207
|
+
protected generatePlanFallback(userDescription: string, contextStr: string, researchResults: string, modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>, runners: RunnerId[], onProgress: (progress: ResearchProgress) => void, researchLog?: ResearchLogEntry[], runnerModes?: Record<RunnerId, RunnerModeInfo[]>, autonomousDefault?: boolean, signal?: AbortSignal, modes?: PlannerModes): Promise<{
|
|
208
|
+
tasks: Task[];
|
|
209
|
+
researchLog: ResearchLogEntry[];
|
|
210
|
+
}>;
|
|
442
211
|
}
|
|
443
212
|
|
|
444
213
|
/**
|
|
@@ -455,9 +224,10 @@ declare class ExecutionCommands {
|
|
|
455
224
|
*/
|
|
456
225
|
declare abstract class BaseFileSystem implements IFileSystem {
|
|
457
226
|
private readonly resolveWebHost;
|
|
227
|
+
private readonly sandbox;
|
|
458
228
|
private approval;
|
|
459
229
|
private outboundSecrets;
|
|
460
|
-
constructor(resolveWebHost?: ResolveAll);
|
|
230
|
+
constructor(resolveWebHost?: ResolveAll, sandbox?: PlannerShellSandbox);
|
|
461
231
|
/**
|
|
462
232
|
* The interpreter `execBashImpl` will hand the command to. Owned here rather
|
|
463
233
|
* than per-adapter because {@link classifyCommand} has to be told the same
|
|
@@ -468,12 +238,20 @@ declare abstract class BaseFileSystem implements IFileSystem {
|
|
|
468
238
|
/** Surfaces inject the human channel here; without it, external access is denied. */
|
|
469
239
|
setApproval(approval: IApproval): void;
|
|
470
240
|
setOutboundSecrets(secrets: () => Iterable<string>): void;
|
|
241
|
+
setNotice(notice: (message: string) => void): void;
|
|
242
|
+
endSession(): void;
|
|
243
|
+
canSeal(): Promise<boolean>;
|
|
471
244
|
abstract getWorkspaceRoot(): string;
|
|
472
245
|
protected abstract readFileImpl(absPath: string, opts?: ReadFileOpts): Promise<ToolOutcome>;
|
|
473
246
|
protected abstract globImpl(pattern: string, absRoot: string, headLimit: number): Promise<ToolOutcome>;
|
|
474
247
|
protected abstract grepImpl(pattern: string, absRoot: string, opts: GrepOptions): Promise<ToolOutcome>;
|
|
475
248
|
protected abstract listDirImpl(absPath: string, depth: number): Promise<ToolOutcome>;
|
|
476
|
-
|
|
249
|
+
/**
|
|
250
|
+
* Run `command` through `shell` from `cwd`, appending it after
|
|
251
|
+
* `shell.args`; `shell.file: null` is `shell: true`. `cwd` is the workspace
|
|
252
|
+
* root, or a read-only task's working directory (ADR-0046).
|
|
253
|
+
*/
|
|
254
|
+
protected abstract execBashImpl(command: string, shell: ShellLaunch, signal: AbortSignal | undefined, cwd: string): Promise<ToolOutcome>;
|
|
477
255
|
/**
|
|
478
256
|
* Resolve `p` and confirm the planner may touch it. In-workspace paths pass
|
|
479
257
|
* silently; anything else needs one approval, remembered per containing
|
|
@@ -506,17 +284,66 @@ declare abstract class BaseFileSystem implements IFileSystem {
|
|
|
506
284
|
*/
|
|
507
285
|
private outsidePaths;
|
|
508
286
|
private policyOptions;
|
|
287
|
+
private plannerSite;
|
|
509
288
|
/**
|
|
510
289
|
* Three tiers (see `commandPolicy.ts`): read-only inspection runs silently,
|
|
511
290
|
* anything else asks once and is remembered, and writes are refused outright
|
|
512
291
|
* because a planner that mutates the workspace has stopped being a planner.
|
|
292
|
+
* Where the sandbox can seal a command, what the envelope would refuse
|
|
293
|
+
* without asking anyone runs sealed instead (ADR-0036 S2): the classifier's
|
|
294
|
+
* refusal, and the approval mode's. A person's denial still refuses.
|
|
513
295
|
*
|
|
514
296
|
* Everything a command needs — its own approval and every outside directory
|
|
515
297
|
* it touches — is one request, so one command is one prompt. Each scope is
|
|
516
298
|
* still granted separately: approving the pair does not approve another
|
|
517
299
|
* directory the next command names.
|
|
518
300
|
*/
|
|
519
|
-
bash(command: string, signal?: AbortSignal): Promise<ToolOutcome>;
|
|
301
|
+
bash(command: string, signal?: AbortSignal, opts?: BashOptions): Promise<ToolOutcome>;
|
|
302
|
+
/**
|
|
303
|
+
* A read-only task's `run_command` (ADR-0046): the planner's classifier,
|
|
304
|
+
* path confinement, allowlist and exclusions, at the task's working
|
|
305
|
+
* directory, asking nobody. What would ask or be refused runs sealed, the
|
|
306
|
+
* workspace readable and the task's worktree writable, or is refused where
|
|
307
|
+
* no sandbox can seal it. What the allowlist or the read-only tier runs
|
|
308
|
+
* runs as the planner's command would, until the shell's first sealed run;
|
|
309
|
+
* from then on every command runs sealed. Its scratch directory is its own.
|
|
310
|
+
*/
|
|
311
|
+
taskShell({ cwd, writable, worktrees }: TaskShellSite): TaskShell;
|
|
312
|
+
/**
|
|
313
|
+
* Ordewell's own script in a read-only task's shell (ADR-0050), sealed from
|
|
314
|
+
* one of its worktree roots. No command rule judges it, since the task did
|
|
315
|
+
* not write it; it runs under the task's sealed profile and is checked
|
|
316
|
+
* after as the task's own sealed runs are, so git that reads a worktree a
|
|
317
|
+
* sealed run wrote runs only inside the seal (ADR-0046).
|
|
318
|
+
*/
|
|
319
|
+
private runOwn;
|
|
320
|
+
private runIn;
|
|
321
|
+
/**
|
|
322
|
+
* A scope inside `command` the user denied on the card this session, or
|
|
323
|
+
* undefined (ADR-0036 S3). The whole command's request is peeked by the
|
|
324
|
+
* caller; this reaches the commands a refused wrapper hides, each remembered
|
|
325
|
+
* under its own scope, so wrapping a denied command never routes around the
|
|
326
|
+
* denial.
|
|
327
|
+
*/
|
|
328
|
+
private deniedInnerScope;
|
|
329
|
+
/** A refusal the envelope reached without asking anyone, run sealed where this host can (ADR-0036 S2), or `refused` as it was (S6). */
|
|
330
|
+
private sealedInstead;
|
|
331
|
+
/**
|
|
332
|
+
* One sealed run (S1): no network, no home, nothing it writes reaching the
|
|
333
|
+
* workspace, and nobody asked. What the user said no to stays refused (S3):
|
|
334
|
+
* a `!` exclusion naming the command or a path it touches, and a denial
|
|
335
|
+
* given on the card this session.
|
|
336
|
+
*/
|
|
337
|
+
private runSealed;
|
|
338
|
+
/**
|
|
339
|
+
* One sealed run from `cwd`, and what follows every one in a read-only
|
|
340
|
+
* task's shell (ADR-0046): the `.git` record checked, a planted `.git` and
|
|
341
|
+
* every link out of the worktree removed, and the shell stopped where that
|
|
342
|
+
* could not hold. `swept` says what was removed, for the result.
|
|
343
|
+
*/
|
|
344
|
+
private sealedRun;
|
|
345
|
+
/** Every command the planner's shell starts goes through here, inside the sandbox where this host has one (ADR-0011 B1, B6). */
|
|
346
|
+
private runShell;
|
|
520
347
|
}
|
|
521
348
|
|
|
522
349
|
/** One directory entry, as the host's file API reports it. */
|
|
@@ -719,10 +546,10 @@ interface HttpWebFetcherOptions {
|
|
|
719
546
|
cache?: WebResponseCache;
|
|
720
547
|
/** Shared across sessions so the search cooldown is process-wide. */
|
|
721
548
|
searchProvider?: ISearchProvider;
|
|
722
|
-
/** False for a research subagent, which must never prompt (see {@link forSubagent}). */
|
|
549
|
+
/** False for a research subagent or a read-only task, which must never prompt (see {@link forSubagent}, {@link forTask}). */
|
|
723
550
|
prompting?: boolean;
|
|
724
551
|
}
|
|
725
|
-
type WebReadDecider = Pick<WebReadPolicy, 'decide'> & Partial<Pick<WebReadPolicy, 'searchesUnasked'>>;
|
|
552
|
+
type WebReadDecider = Pick<WebReadPolicy, 'decide'> & Partial<Pick<WebReadPolicy, 'searchesUnasked' | 'remaining' | 'forTask'>>;
|
|
726
553
|
declare class HttpWebFetcher implements IWebFetcher {
|
|
727
554
|
private readonly policy;
|
|
728
555
|
private readonly fetchImpl;
|
|
@@ -735,10 +562,20 @@ declare class HttpWebFetcher implements IWebFetcher {
|
|
|
735
562
|
constructor(opts: HttpWebFetcherOptions);
|
|
736
563
|
decide(read: WebRead): Promise<WebReadDecision>;
|
|
737
564
|
private get decideOptions();
|
|
565
|
+
private optionsOf;
|
|
738
566
|
forSubagent(): IWebFetcher;
|
|
567
|
+
/**
|
|
568
|
+
* The fetcher for one read-only task attempt (ADR-0046): a subagent's, never
|
|
569
|
+
* prompting, over the policy's {@link WebReadPolicy.forTask}, so the attempt
|
|
570
|
+
* has a budget of its own while the cache, transport and search provider,
|
|
571
|
+
* and with them the search cooldown, stay the session's.
|
|
572
|
+
*/
|
|
573
|
+
forTask(task: string): IWebFetcher | undefined;
|
|
574
|
+
private nonPrompting;
|
|
739
575
|
searchesUnasked(provider: string): boolean;
|
|
740
|
-
|
|
741
|
-
|
|
576
|
+
remaining(): number | undefined;
|
|
577
|
+
fetch(url: string, opts?: WebReadOptions): Promise<ToolOutcome>;
|
|
578
|
+
search(query: string, opts?: WebReadOptions): Promise<ToolOutcome>;
|
|
742
579
|
private get;
|
|
743
580
|
private render;
|
|
744
581
|
private getSearchPage;
|
|
@@ -753,6 +590,106 @@ declare class HttpWebFetcher implements IWebFetcher {
|
|
|
753
590
|
private hop;
|
|
754
591
|
}
|
|
755
592
|
|
|
593
|
+
/**
|
|
594
|
+
* The daily version check (ADR-0048): one ping a day that counts installs
|
|
595
|
+
* under an install ID replaced every 30 days, and may answer with a newer
|
|
596
|
+
* version.
|
|
597
|
+
*/
|
|
598
|
+
declare const VERSION_CHECK_URL = "https://ordewell.ai/api/v1/ping";
|
|
599
|
+
declare const VERSION_CHECK_NOTICE: string;
|
|
600
|
+
/** The slice of `fetch` the check uses; the platform `fetch` satisfies it. */
|
|
601
|
+
type PingFetch = (url: string, init: {
|
|
602
|
+
method: 'GET';
|
|
603
|
+
signal: AbortSignal;
|
|
604
|
+
redirect: 'manual';
|
|
605
|
+
}) => Promise<{
|
|
606
|
+
status: number;
|
|
607
|
+
text(): Promise<string>;
|
|
608
|
+
}>;
|
|
609
|
+
interface VersionCheckOptions {
|
|
610
|
+
/** The running version, sent as `v` and compared against the answer. */
|
|
611
|
+
version: string;
|
|
612
|
+
/** The one-time notice, on the first start on a machine. */
|
|
613
|
+
onNotice(text: string): void;
|
|
614
|
+
/** A newer version is out; `text` is the line to show. */
|
|
615
|
+
onUpdate(text: string, latest: string): void;
|
|
616
|
+
/** False turns the whole check off, as the off-switch variables do. */
|
|
617
|
+
telemetryEnabled?: boolean;
|
|
618
|
+
env?: Record<string, string | undefined>;
|
|
619
|
+
/** Where the state file lives; `globalDataDir()` by default. */
|
|
620
|
+
stateDir?: string;
|
|
621
|
+
fetch?: PingFetch;
|
|
622
|
+
now?: () => number;
|
|
623
|
+
}
|
|
624
|
+
interface VersionCheck {
|
|
625
|
+
/** Settles once no ping is in flight. Never rejects. */
|
|
626
|
+
settled(): Promise<void>;
|
|
627
|
+
/** Stops the daily re-check. */
|
|
628
|
+
stop(): void;
|
|
629
|
+
}
|
|
630
|
+
/**
|
|
631
|
+
* Starts the check for this process: the one-time notice on the first start
|
|
632
|
+
* on a machine, otherwise a ping if a day has passed since the last one, and
|
|
633
|
+
* the same test again on an unref'd timer for as long as the process lives.
|
|
634
|
+
* Never throws and never waits on the network.
|
|
635
|
+
*/
|
|
636
|
+
declare function startVersionCheck(options: VersionCheckOptions): VersionCheck;
|
|
637
|
+
|
|
638
|
+
/**
|
|
639
|
+
* The effect allowlist (ADR-0035): the user's standing approval for named
|
|
640
|
+
* effects, beside the planner allowlist, which names reads. It pre-approves a
|
|
641
|
+
* script task whose `commands` are all covered; it never covers a `script`
|
|
642
|
+
* body, whose shell text no rule can be matched against.
|
|
643
|
+
*
|
|
644
|
+
* A rule is matched against the whole command, every word in order and flags
|
|
645
|
+
* included, because an effect's flags change what it does: `git push origin
|
|
646
|
+
* feature/*` covers `git push origin feature/login`, never the same push with
|
|
647
|
+
* `--force`. `*` stands for one word, or inside a word for any run of
|
|
648
|
+
* characters, as in the planner allowlist, except that it never stands for
|
|
649
|
+
* what changes the effect: a flag (`--force`, and `/force` on Windows), a
|
|
650
|
+
* refspec's force or delete (`+main`, `:main`), or a `:` outside a URL
|
|
651
|
+
* (`feature/x:main`, which pushes to `main`). The rule writes any of those
|
|
652
|
+
* itself. A rule spells out its operation before any `*`, so
|
|
653
|
+
* `az webapp config * set` is no rule at all.
|
|
654
|
+
*
|
|
655
|
+
* Exclusions are the planner allowlist's `!` entries, with any `!` entry
|
|
656
|
+
* written here; an exclusion wins. A command exclusion is matched as the
|
|
657
|
+
* planner allowlist matches it; a path or URL exclusion holds for an argument
|
|
658
|
+
* that names an absolute path or URL it covers, whole or after a `=`, `@`,
|
|
659
|
+
* `:` or `,` or a short flag (`--url=…`, `-d @…`). A relative path is not
|
|
660
|
+
* resolved, since the body does not say where it runs. A program named by its
|
|
661
|
+
* path is a file the repository ships (ADR-0026), so it is never covered.
|
|
662
|
+
* There are no built-in rules: a default would pre-approve an effect the user
|
|
663
|
+
* never chose.
|
|
664
|
+
*/
|
|
665
|
+
interface EffectRule {
|
|
666
|
+
text: string;
|
|
667
|
+
binary: string;
|
|
668
|
+
words: RuleWord[];
|
|
669
|
+
}
|
|
670
|
+
interface EffectRules {
|
|
671
|
+
rules: EffectRule[];
|
|
672
|
+
exclusions: PlannerAllowlist;
|
|
673
|
+
platform: NodeJS.Platform;
|
|
674
|
+
/** The entries that are no rule, each with the warning that says why it is ignored. */
|
|
675
|
+
ignored: {
|
|
676
|
+
rule: string;
|
|
677
|
+
warning: string;
|
|
678
|
+
}[];
|
|
679
|
+
}
|
|
680
|
+
/**
|
|
681
|
+
* `entries` are the effect allowlist's; `plannerEntries` the planner allowlist
|
|
682
|
+
* in force, whose `!` entries hold here too; `platform` the one the commands
|
|
683
|
+
* run on, which decides how a flag is spelled and how a path resolves.
|
|
684
|
+
*/
|
|
685
|
+
declare function parseEffectAllowlist(entries: readonly string[], plannerEntries?: readonly string[], platform?: NodeJS.Platform): EffectRules;
|
|
686
|
+
/**
|
|
687
|
+
* The rules, by name, that cover every command of a `commands` body, or null
|
|
688
|
+
* when one command is not covered, an exclusion holds for one, or the body is
|
|
689
|
+
* a `script`.
|
|
690
|
+
*/
|
|
691
|
+
declare function effectRuleFor(list: EffectRules, body: ScriptBody): string | null;
|
|
692
|
+
|
|
756
693
|
/**
|
|
757
694
|
* Carries a structured task's tool requests to the session's one approval
|
|
758
695
|
* seam (ADR-0018, A1), so a runner's request is answered through
|
|
@@ -1004,8 +941,11 @@ declare abstract class BaseConfig implements IConfig {
|
|
|
1004
941
|
get conflictRepairAttempts(): number;
|
|
1005
942
|
get approvalMode(): ApprovalModeSetting;
|
|
1006
943
|
get webReadBudget(): number;
|
|
944
|
+
/** The native-shell opt-in (ADR-0036 N1): off unless the launching environment says on. Never a workspace variable. */
|
|
945
|
+
get plannerNativeShell(): boolean;
|
|
1007
946
|
get approvalDefaults(): boolean;
|
|
1008
947
|
get approvalPreApproved(): string[];
|
|
948
|
+
get effectAllowlist(): string[];
|
|
1009
949
|
/**
|
|
1010
950
|
* Who plans when no surface setting names a planner: an explicit
|
|
1011
951
|
* AI_PROVIDER, then a vendor whose key is in the environment,
|
|
@@ -1084,18 +1024,6 @@ declare class EnvConfig extends BaseConfig {
|
|
|
1084
1024
|
setProviderModelLists(): void;
|
|
1085
1025
|
}
|
|
1086
1026
|
|
|
1087
|
-
/**
|
|
1088
|
-
* How "Merge all" went, in words every surface shares. `group` is whether the
|
|
1089
|
-
* run spans more than a lone repo at `.`; only a merge into every repository
|
|
1090
|
-
* has something to say about that. `repaired` names the landed tasks that only
|
|
1091
|
-
* landed after a conflict repair (ADR-0015), so a clean-looking merge still
|
|
1092
|
-
* points review at what changed to get there.
|
|
1093
|
-
*/
|
|
1094
|
-
declare function describeMergeResult(result: IsolationMergeResult, branch: string, group: boolean, repaired?: IsolationLandedTask[]): {
|
|
1095
|
-
level: 'info' | 'warn' | 'error';
|
|
1096
|
-
message: string;
|
|
1097
|
-
};
|
|
1098
|
-
|
|
1099
1027
|
interface WorktreeIsolationDeps {
|
|
1100
1028
|
config: Pick<IConfig, 'worktreeIsolation' | 'worktreeSetupCommand' | 'workspaceRepos' | 'worktreeLinks'>;
|
|
1101
1029
|
/** Test seam: every git invocation goes through this. */
|
|
@@ -1103,7 +1031,11 @@ interface WorktreeIsolationDeps {
|
|
|
1103
1031
|
resolvePath?: () => Promise<string>;
|
|
1104
1032
|
platform?: NodeJS.Platform;
|
|
1105
1033
|
mintRunId?: () => string;
|
|
1034
|
+
/** Whether the commits Ordewell writes end with the Planned-with trailer; read as each is written, so a change reaches the next landing. */
|
|
1035
|
+
plannedWith?: () => boolean;
|
|
1106
1036
|
}
|
|
1037
|
+
/** The preview alone, for a surface that shows isolation without ever running it. */
|
|
1038
|
+
declare function createIsolationPreview(deps: Pick<WorktreeIsolationDeps, 'config' | 'execFileImpl' | 'resolvePath'>): IIsolationPreview;
|
|
1107
1039
|
declare function createWorktreeIsolation(deps: WorktreeIsolationDeps): IWorktreeIsolation;
|
|
1108
1040
|
|
|
1109
1041
|
/** A task record as ADR-0013 persisted it, for one repository. */
|
|
@@ -1136,35 +1068,17 @@ interface Adr0013PlanIsolation {
|
|
|
1136
1068
|
* off exactly as it would have.
|
|
1137
1069
|
*/
|
|
1138
1070
|
declare function migratePlanIsolation(state: PlanIsolation | Adr0013PlanIsolation): PlanIsolation;
|
|
1139
|
-
|
|
1140
|
-
/** The part of a run's handoff a Merge confirmation is worded from; structural, so each surface passes the handoff it holds. */
|
|
1141
|
-
interface MergeWordingHandoff {
|
|
1142
|
-
repos: readonly {
|
|
1143
|
-
path: string;
|
|
1144
|
-
baseBranch?: string;
|
|
1145
|
-
landed: readonly unknown[];
|
|
1146
|
-
}[];
|
|
1147
|
-
}
|
|
1148
|
-
/**
|
|
1149
|
-
* Whether the run spans more than a lone repo at the workspace root. A group of
|
|
1150
|
-
* one at `.` is worded and drawn exactly as it was before repo groups; anything
|
|
1151
|
-
* else names its repos.
|
|
1152
|
-
*/
|
|
1153
|
-
declare function isRepoGroup(handoff: {
|
|
1154
|
-
repos: readonly {
|
|
1155
|
-
path: string;
|
|
1156
|
-
}[];
|
|
1157
|
-
}): boolean;
|
|
1158
|
-
/** The repos Merge all will merge: those with work on their integration branch, else all of them. */
|
|
1159
|
-
declare function reposWithWork(handoff: MergeWordingHandoff): string[];
|
|
1160
1071
|
/**
|
|
1161
|
-
* What a
|
|
1162
|
-
*
|
|
1163
|
-
*
|
|
1072
|
+
* What a persisted plan says about its isolated run, as a surface shows it: the
|
|
1073
|
+
* handoff and each task's mark. `null` when the payload carries no record — a
|
|
1074
|
+
* planner reply, or a plan that never isolated — which says nothing either way.
|
|
1075
|
+
*
|
|
1076
|
+
* This is the one reading of a saved record outside the daemon: the migration
|
|
1077
|
+
* from the ADR-0013 shape happens here, so no surface grows its own parser.
|
|
1078
|
+
* `repairLimit` is server config a saved plan never carries; without it the
|
|
1079
|
+
* repair attempt is left for a live status update to fill in.
|
|
1164
1080
|
*/
|
|
1165
|
-
declare function
|
|
1166
|
-
/** The refusal Merge all makes when a repo is on another branch, for a confirmation to warn of; empty when no repo named a branch. */
|
|
1167
|
-
declare function checkoutRule(handoff: MergeWordingHandoff): string;
|
|
1081
|
+
declare function isolationViewOfPlan(plan: unknown, repairLimit?: number): IsolationView | null;
|
|
1168
1082
|
|
|
1169
1083
|
interface ILogger {
|
|
1170
1084
|
warn(scope: string, message: string, err?: unknown): void;
|
|
@@ -1174,139 +1088,49 @@ declare class ConsoleLogger implements ILogger {
|
|
|
1174
1088
|
}
|
|
1175
1089
|
declare const defaultLogger: ILogger;
|
|
1176
1090
|
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
id?: string;
|
|
1181
|
-
}
|
|
1182
|
-
interface ToolResult {
|
|
1183
|
-
name: string;
|
|
1184
|
-
output: string;
|
|
1185
|
-
truncated: boolean;
|
|
1186
|
-
totalChars: number;
|
|
1187
|
-
id?: string;
|
|
1091
|
+
/** What a Gemini planner is built with beyond its config. */
|
|
1092
|
+
interface GeminiServiceDeps extends PlannerContextDeps {
|
|
1093
|
+
turnBudgets?: TurnBudgets;
|
|
1188
1094
|
}
|
|
1189
|
-
interface ResearchTurn {
|
|
1190
|
-
text: string;
|
|
1191
|
-
toolCalls: ToolCall[];
|
|
1192
|
-
hasToolCalls: boolean;
|
|
1193
|
-
/** Reasoning/chain-of-thought captured separately from `text` so it never pollutes plan JSON. */
|
|
1194
|
-
reasoning?: string;
|
|
1195
|
-
/** Provider finish reason, normalized: 'length' means the output-token limit cut the reply mid-stream. */
|
|
1196
|
-
finishReason?: string;
|
|
1197
|
-
/** Exact prompt tokens this turn consumed, when the provider reports usage — drives proactive compaction. */
|
|
1198
|
-
promptTokens?: number;
|
|
1199
|
-
/** The segment `text` streamed under, where the provider streams it. */
|
|
1200
|
-
segmentId?: string;
|
|
1201
|
-
}
|
|
1202
|
-
interface ResearchChat {
|
|
1203
|
-
sendMessage(text: string, signal?: AbortSignal): Promise<ResearchTurn>;
|
|
1204
|
-
sendToolResults(results: ToolResult[], signal?: AbortSignal): Promise<ResearchTurn>;
|
|
1205
|
-
/**
|
|
1206
|
-
* Optional: prune bulky raw tool outputs from the history in place (subagent
|
|
1207
|
-
* digests are kept) so a follow-up emission has context to spend on output.
|
|
1208
|
-
* Returns the number of characters removed. Providers whose SDK owns the
|
|
1209
|
-
* history (Gemini) may not support it.
|
|
1210
|
-
*/
|
|
1211
|
-
compactHistory?(): number;
|
|
1212
|
-
}
|
|
1213
|
-
/** Everything one conversation turn needs beyond the user message itself. */
|
|
1214
|
-
interface ConversationTurnContext {
|
|
1215
|
-
chat: ResearchChat;
|
|
1216
|
-
fs: IFileSystem;
|
|
1217
|
-
runners: RunnerId[];
|
|
1218
|
-
runnerModes?: Record<RunnerId, RunnerModeInfo[]>;
|
|
1219
|
-
autonomousDefault?: boolean;
|
|
1220
|
-
fetcher?: IWebFetcher;
|
|
1221
|
-
/** The session's planner tools; the conversation offers their task reads and execution tools (ADR-0029) when set. */
|
|
1222
|
-
plannerTools?: PlannerToolHandler;
|
|
1223
|
-
}
|
|
1224
|
-
declare abstract class BaseAiService {
|
|
1225
|
-
protected config: IConfig;
|
|
1226
|
-
protected conversation: {
|
|
1227
|
-
ctx: ConversationTurnContext;
|
|
1228
|
-
setProgress: (fn: (p: ResearchProgress) => void) => void;
|
|
1229
|
-
} | null;
|
|
1230
|
-
protected activeAbort: AbortController | null;
|
|
1231
|
-
constructor(config: IConfig);
|
|
1232
|
-
abstract reset(): void;
|
|
1233
|
-
abstract ensureInit(): void;
|
|
1234
|
-
hasActiveConversation(): boolean;
|
|
1235
|
-
pruneContext(): number;
|
|
1236
|
-
protected startAbortScope(callerSignal?: AbortSignal): AbortSignal;
|
|
1237
|
-
protected stopAbortScope(): void;
|
|
1238
|
-
continueConversation(userMessage: string, onProgress: (progress: ResearchProgress) => void, signal?: AbortSignal): Promise<ConversationTurn>;
|
|
1239
|
-
protected abstract streamPlanText(prompt: string, repairHint: string | undefined, onToken: (token: string) => void, onReasoning?: (token: string) => void, signal?: AbortSignal): Promise<string>;
|
|
1240
|
-
/**
|
|
1241
|
-
* Build a fresh chat for one research subagent (own history, subagent system
|
|
1242
|
-
* prompt, cheap model). Null means the provider does not support subagents —
|
|
1243
|
-
* the spawn tool then degrades to a steering message. `onReasoning` streams
|
|
1244
|
-
* live reasoning deltas on models that expose them, same as the top-level loop;
|
|
1245
|
-
* `onUsage` takes each call's usage, as the planner's own chat reports it.
|
|
1246
|
-
*/
|
|
1247
|
-
protected createSubagentChat(_onReasoning?: (delta: string) => void, _onUsage?: (record: UsageRecord) => void): ResearchChat | null;
|
|
1248
|
-
/**
|
|
1249
|
-
* One spawn_research_agent tool call, executed at the service layer (not in
|
|
1250
|
-
* executeTool — that would cycle the imports). Every failure path returns a
|
|
1251
|
-
* steering/failed result and the loop continues sequentially: a subagent can
|
|
1252
|
-
* never fail a plan or a turn.
|
|
1253
|
-
*/
|
|
1254
|
-
private executeSpawnAgent;
|
|
1255
|
-
/** Collect project context for the planning phase. Shared with the harness backend. */
|
|
1256
|
-
protected static collectResearchContext(fs: IFileSystem, runners: RunnerId[]): Promise<string>;
|
|
1257
|
-
/**
|
|
1258
|
-
* Execute one round of tool calls and report each through onProgress.
|
|
1259
|
-
* Returns the results to feed back plus the log entries produced.
|
|
1260
|
-
*/
|
|
1261
|
-
private executeToolCalls;
|
|
1262
|
-
/**
|
|
1263
|
-
* Countdown appended to the last tool result of the final few rounds, so the
|
|
1264
|
-
* model lands the turn on its own terms instead of being cut off exactly at
|
|
1265
|
-
* the budget boundary mid-exploration.
|
|
1266
|
-
*/
|
|
1267
|
-
private static appendBudgetCountdown;
|
|
1268
|
-
/**
|
|
1269
|
-
* Run one planner conversation turn (ADR-0002): send the message, satisfy
|
|
1270
|
-
* tool calls until the model answers in prose or JSON, and settle the reply
|
|
1271
|
-
* through {@link settleReply}, which owns classification and every
|
|
1272
|
-
* corrective retry. The model decides transitions — there are no sentinels
|
|
1273
|
-
* and no question tags. A turn whose final text parses as a `{tasks:[...]}`
|
|
1274
|
-
* object commits the plan; anything else is a message to the user.
|
|
1275
|
-
*/
|
|
1276
|
-
protected runConversationTurn(ctx: ConversationTurnContext, message: string, onProgress: (progress: ResearchProgress) => void, signal?: AbortSignal): Promise<ConversationTurn>;
|
|
1277
|
-
/** One model call of a conversation turn: the message, then tool rounds until the model replies without tools. */
|
|
1278
|
-
private runToolRounds;
|
|
1279
|
-
/**
|
|
1280
|
-
* Run the LLM tool-calling research loop for one-shot planning. Returns
|
|
1281
|
-
* parsed tasks if a plan was emitted mid-loop, or null if the loop
|
|
1282
|
-
* exhausted without a valid plan.
|
|
1283
|
-
*/
|
|
1284
|
-
protected runResearchLoop(chat: ResearchChat, firstMessage: string, fs: IFileSystem, onProgress: (progress: ResearchProgress) => void, runners: RunnerId[], initialLog?: ResearchLogEntry[], fetcher?: IWebFetcher, userGoal?: string, runnerModes?: Record<RunnerId, RunnerModeInfo[]>, autonomousDefault?: boolean, signal?: AbortSignal): Promise<{
|
|
1285
|
-
tasks: Task[] | null;
|
|
1286
|
-
researchLog: ResearchLogEntry[];
|
|
1287
|
-
researchResults: string;
|
|
1288
|
-
}>;
|
|
1289
|
-
protected generatePlanFallback(userDescription: string, contextStr: string, researchResults: string, modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>, runners: RunnerId[], onProgress: (progress: ResearchProgress) => void, researchLog?: ResearchLogEntry[], runnerModes?: Record<RunnerId, RunnerModeInfo[]>, autonomousDefault?: boolean, signal?: AbortSignal, modes?: PlannerModes): Promise<{
|
|
1290
|
-
tasks: Task[];
|
|
1291
|
-
researchLog: ResearchLogEntry[];
|
|
1292
|
-
}>;
|
|
1293
|
-
}
|
|
1294
|
-
|
|
1295
1095
|
declare class GeminiService extends BaseAiService implements IAiService {
|
|
1096
|
+
private readonly deps;
|
|
1296
1097
|
private genAI;
|
|
1297
1098
|
private genAIKey;
|
|
1298
1099
|
private model;
|
|
1299
1100
|
/** The id `model` was made for; the SDK's own `model.model` is its `models/…` resource path. */
|
|
1300
1101
|
private modelId;
|
|
1301
|
-
|
|
1102
|
+
/** Outlives a conversation: what a model's provider measured still holds for the next one on it. */
|
|
1103
|
+
private readonly gauge;
|
|
1104
|
+
constructor(config: IConfig, deps?: GeminiServiceDeps);
|
|
1302
1105
|
private init;
|
|
1303
1106
|
/** The planner model picked for this session, as the API names it. */
|
|
1304
1107
|
private plannerModel;
|
|
1305
1108
|
private getPlanningModel;
|
|
1109
|
+
/**
|
|
1110
|
+
* Gemini's catalog states a model's prompt limit (`inputTokenLimit`, which
|
|
1111
|
+
* the catalog carries as the model's window) apart from its reply limit
|
|
1112
|
+
* (`outputTokenLimit`): the reply is never taken out of the prompt's room.
|
|
1113
|
+
*/
|
|
1114
|
+
private limitsOf;
|
|
1115
|
+
private autoCompaction;
|
|
1116
|
+
/** Read at each call, so a model or setting changed mid-turn applies from its next call. */
|
|
1117
|
+
private plannerBudget;
|
|
1118
|
+
/** What automatic compaction does for the planner model configured now. */
|
|
1119
|
+
plannerContextStatus(): PlannerContextStatus;
|
|
1120
|
+
/** A chat on the planner model, whichever it is at each call. */
|
|
1121
|
+
private chat;
|
|
1122
|
+
/**
|
|
1123
|
+
* One call on the planner's own model and key that declares no functions:
|
|
1124
|
+
* what a summary of its context is written by. Its usage is reported like
|
|
1125
|
+
* any call's, for the caller to mark as measuring no context.
|
|
1126
|
+
*/
|
|
1127
|
+
private readonly summaryCall;
|
|
1128
|
+
private summarizer;
|
|
1129
|
+
condenseContext(request: ContextCondenseRequest): Promise<string>;
|
|
1306
1130
|
ensureInit(): void;
|
|
1307
1131
|
reset(): void;
|
|
1308
1132
|
startConversation(req: ConversationRequest): Promise<ConversationTurn>;
|
|
1309
|
-
protected streamPlanText(prompt: string, repairHint: string | undefined, onToken: (token: string) => void, onReasoning?: (token: string) => void,
|
|
1133
|
+
protected streamPlanText(prompt: string, repairHint: string | undefined, onToken: (token: string) => void, onReasoning?: (token: string) => void, signal?: AbortSignal): Promise<string>;
|
|
1310
1134
|
/**
|
|
1311
1135
|
* Drain a Gemini content stream, routing "thought" parts to the reasoning channel
|
|
1312
1136
|
* and answer text to the parser. `chunk.text()` throws when a chunk is reasoning-only,
|
|
@@ -1315,18 +1139,41 @@ declare class GeminiService extends BaseAiService implements IAiService {
|
|
|
1315
1139
|
private consumePlanStream;
|
|
1316
1140
|
/** Gemini-specific stream over raw Parts for generatePlanDirect. */
|
|
1317
1141
|
private streamPlanTextWithParts;
|
|
1142
|
+
/** One plan emission, asking for no longer a reply than the model states it serves. */
|
|
1143
|
+
private emitPlan;
|
|
1318
1144
|
researchAndPlan(userDescription: string, runners: RunnerId[], modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>, fs: IFileSystem, onProgress: (progress: ResearchProgress) => void, fetcher?: IWebFetcher, runnerModes?: Record<RunnerId, RunnerModeInfo[]>, modes?: PlannerModes, signal?: AbortSignal): Promise<{
|
|
1319
1145
|
tasks: Task[];
|
|
1320
1146
|
researchLog: ResearchLogEntry[];
|
|
1321
1147
|
researchResults: string;
|
|
1322
1148
|
}>;
|
|
1323
|
-
generatePlanDirect(userDescription: string, runners?: RunnerId[], modelsByRunner?: Partial<Record<RunnerId, DiscoveredModel[]>>, onToken?: (token: string) => void, fs?: IFileSystem, _fetcher?: IWebFetcher, runnerModes?: Record<RunnerId, RunnerModeInfo[]>, modes?: PlannerModes,
|
|
1149
|
+
generatePlanDirect(userDescription: string, runners?: RunnerId[], modelsByRunner?: Partial<Record<RunnerId, DiscoveredModel[]>>, onToken?: (token: string) => void, fs?: IFileSystem, _fetcher?: IWebFetcher, runnerModes?: Record<RunnerId, RunnerModeInfo[]>, modes?: PlannerModes, signal?: AbortSignal): Promise<Task[]>;
|
|
1324
1150
|
}
|
|
1325
1151
|
|
|
1152
|
+
/** What an API planner is built with beyond its config. */
|
|
1153
|
+
interface OpenAiServiceDeps extends PlannerContextDeps {
|
|
1154
|
+
turnBudgets?: TurnBudgets;
|
|
1155
|
+
}
|
|
1326
1156
|
declare class OpenAiService extends BaseAiService implements IAiService {
|
|
1157
|
+
private readonly deps;
|
|
1327
1158
|
private client;
|
|
1328
1159
|
private clientCredentials;
|
|
1329
|
-
|
|
1160
|
+
/** Outlives a conversation: what a model's provider measured still holds for the next one on it. */
|
|
1161
|
+
private readonly gauge;
|
|
1162
|
+
constructor(config: IConfig, deps?: OpenAiServiceDeps);
|
|
1163
|
+
private limitsOf;
|
|
1164
|
+
private autoCompaction;
|
|
1165
|
+
/** Read at each call, so a model or setting changed mid-turn applies from its next call. */
|
|
1166
|
+
private plannerBudget;
|
|
1167
|
+
/**
|
|
1168
|
+
* One call on the planner's own model and credentials that offers no tools:
|
|
1169
|
+
* what a summary of its context is written by. Its usage is reported like
|
|
1170
|
+
* any call's, for the caller to mark as measuring no context.
|
|
1171
|
+
*/
|
|
1172
|
+
private readonly summaryCall;
|
|
1173
|
+
private summarizer;
|
|
1174
|
+
condenseContext(request: ContextCondenseRequest): Promise<string>;
|
|
1175
|
+
/** What automatic compaction does for the planner model configured now. */
|
|
1176
|
+
plannerContextStatus(): PlannerContextStatus;
|
|
1330
1177
|
/**
|
|
1331
1178
|
* Rebuilt whenever the key or endpoint differs from the one the client was
|
|
1332
1179
|
* made with. A Session outlives `/key` and endpoint edits, so a client cached
|
|
@@ -1434,11 +1281,20 @@ declare class ModelResolver {
|
|
|
1434
1281
|
private discovery;
|
|
1435
1282
|
private fetchImpl?;
|
|
1436
1283
|
private cachedPickerOptions;
|
|
1284
|
+
/** A catalog load under way: a second ask, or a warm-up, shares it rather than fetching again. */
|
|
1285
|
+
private pickerLoad;
|
|
1437
1286
|
private lastDiscoveryErrors;
|
|
1438
1287
|
constructor(registry: RunnerRegistry, config: IConfig, deps?: ModelResolverDeps);
|
|
1439
1288
|
static builtinOptions(): OrchestratorOption[];
|
|
1440
1289
|
modelsForRunners(runners: RunnerId[]): Promise<Partial<Record<RunnerId, DiscoveredModel[]>>>;
|
|
1441
1290
|
pickerOptions(): Promise<OrchestratorOption[]>;
|
|
1291
|
+
/**
|
|
1292
|
+
* Start loading the vendor catalogs without waiting for them, unless they
|
|
1293
|
+
* are held or loading already: an API planner whose model's window is not
|
|
1294
|
+
* known yet reads it from them on a later call, never waiting on the fetch.
|
|
1295
|
+
*/
|
|
1296
|
+
warmPickerOptions(): void;
|
|
1297
|
+
private loadPickerOptions;
|
|
1442
1298
|
/**
|
|
1443
1299
|
* Per-provider failures from the most recent `pickerOptions()` fetch, keyed
|
|
1444
1300
|
* by provider id. Empty when every configured provider's catalog loaded (or
|
|
@@ -1465,9 +1321,32 @@ declare class ModelResolver {
|
|
|
1465
1321
|
* omitted rather than guessed.
|
|
1466
1322
|
*/
|
|
1467
1323
|
contextWindowFor(source: string, model: string): number | undefined;
|
|
1324
|
+
/**
|
|
1325
|
+
* The longest reply a vendor's model is served with, from the picker
|
|
1326
|
+
* catalog already held, when that catalog states one. Reads only, like
|
|
1327
|
+
* {@link contextWindowFor}.
|
|
1328
|
+
*/
|
|
1329
|
+
maxOutputTokensFor(source: string, model: string): number | undefined;
|
|
1468
1330
|
invalidate(): void;
|
|
1469
1331
|
}
|
|
1470
1332
|
|
|
1333
|
+
interface RunnerInstallationOptions {
|
|
1334
|
+
/**
|
|
1335
|
+
* The workspace's own variables (ADR-0016), asked afresh for each auth probe
|
|
1336
|
+
* and told which root it is for, so a folder change mid-probe cannot mix one
|
|
1337
|
+
* workspace's account into another's verdict. A `.envrc` can choose another
|
|
1338
|
+
* account, so the probe must ask the same account the planner will use.
|
|
1339
|
+
*/
|
|
1340
|
+
env?: (workspace?: string) => Promise<Record<string, string>>;
|
|
1341
|
+
/**
|
|
1342
|
+
* The workspace whose account this installation judges. The verdict is
|
|
1343
|
+
* recorded under it, so a planner gate in that workspace reads it and one in
|
|
1344
|
+
* another cannot (ADR-0009).
|
|
1345
|
+
*/
|
|
1346
|
+
workspace?: () => string | undefined;
|
|
1347
|
+
/** Injectable status command runner, so tests need no real agent binary. */
|
|
1348
|
+
authExec?: RunnerAuthExec;
|
|
1349
|
+
}
|
|
1471
1350
|
/**
|
|
1472
1351
|
* Detects whether a runner's underlying CLI is actually installed on the host,
|
|
1473
1352
|
* by invoking `<command> --version`. Mirrors ModelDiscovery: injectable exec,
|
|
@@ -1477,10 +1356,15 @@ declare class ModelResolver {
|
|
|
1477
1356
|
declare class RunnerInstallation {
|
|
1478
1357
|
private cache;
|
|
1479
1358
|
private inflight;
|
|
1359
|
+
private authCache;
|
|
1360
|
+
private authInflight;
|
|
1480
1361
|
private registry;
|
|
1481
1362
|
private execImpl;
|
|
1482
1363
|
private now;
|
|
1483
|
-
|
|
1364
|
+
private env;
|
|
1365
|
+
private workspace;
|
|
1366
|
+
private authExec;
|
|
1367
|
+
constructor(registry: RunnerRegistry, execImpl?: ExecImpl, now?: () => number, options?: RunnerInstallationOptions);
|
|
1484
1368
|
/** True if the runner's CLI responds to `--version`. Cached per process. */
|
|
1485
1369
|
isInstalled(runner: string): Promise<boolean>;
|
|
1486
1370
|
/**
|
|
@@ -1497,15 +1381,21 @@ declare class RunnerInstallation {
|
|
|
1497
1381
|
* typing a real goal is the failure this exists to prevent.
|
|
1498
1382
|
*
|
|
1499
1383
|
* "Usable" is deliberately shallow: the binary answers `--version`, and the
|
|
1500
|
-
* runner has a connector to plan over.
|
|
1501
|
-
*
|
|
1502
|
-
*
|
|
1503
|
-
* first turn.
|
|
1384
|
+
* runner has a connector to plan over. A signed-out runner stays usable —
|
|
1385
|
+
* it is installed, and the user may log in from the same picker — so the
|
|
1386
|
+
* auth verdict rides beside usability, never inside it.
|
|
1504
1387
|
*/
|
|
1505
1388
|
plannerUsability(runner: string): Promise<{
|
|
1506
1389
|
usable: boolean;
|
|
1507
1390
|
reason?: string;
|
|
1391
|
+
auth?: RunnerAuth;
|
|
1508
1392
|
}>;
|
|
1393
|
+
/**
|
|
1394
|
+
* The runner's own login verdict, cached briefly and asked once when several
|
|
1395
|
+
* callers arrive together. Recorded per workspace for the synchronous planner
|
|
1396
|
+
* gate, which cannot await this.
|
|
1397
|
+
*/
|
|
1398
|
+
private authFor;
|
|
1509
1399
|
/**
|
|
1510
1400
|
* Whether the CLI can be started the way the harness planner actually starts
|
|
1511
1401
|
* it: `spawn` with no shell.
|
|
@@ -1524,6 +1414,212 @@ declare class RunnerInstallation {
|
|
|
1524
1414
|
clear(): void;
|
|
1525
1415
|
}
|
|
1526
1416
|
|
|
1417
|
+
/** What one acquisition found. `owner` is a key to compare accounts by, never shown or logged. */
|
|
1418
|
+
type AccountLimitReading =
|
|
1419
|
+
/** A full read: it replaces every bucket and window known before. `followUp` asks for one more, coalesced. */
|
|
1420
|
+
{
|
|
1421
|
+
kind: 'limits';
|
|
1422
|
+
owner: string;
|
|
1423
|
+
plan?: string;
|
|
1424
|
+
buckets: AccountLimitBucket[];
|
|
1425
|
+
followUp?: boolean;
|
|
1426
|
+
}
|
|
1427
|
+
/**
|
|
1428
|
+
* A transient failure; `owner` when the account was still seen signed in
|
|
1429
|
+
* before it failed, `retryAfterMs` when the service said how long to wait.
|
|
1430
|
+
*/
|
|
1431
|
+
| {
|
|
1432
|
+
kind: 'failed';
|
|
1433
|
+
owner?: string;
|
|
1434
|
+
retryAfterMs?: number;
|
|
1435
|
+
}
|
|
1436
|
+
/** The account changed while it was being read: what was read may be the old one's. */
|
|
1437
|
+
| {
|
|
1438
|
+
kind: 'account_changed';
|
|
1439
|
+
} | {
|
|
1440
|
+
kind: 'signed_out' | 'unsupported' | 'not_installed';
|
|
1441
|
+
};
|
|
1442
|
+
/**
|
|
1443
|
+
* One runner's way of reading its account's limits. Registered with the
|
|
1444
|
+
* monitor once; the monitor alone decides when it runs, and never runs two of
|
|
1445
|
+
* its acquisitions at once.
|
|
1446
|
+
*/
|
|
1447
|
+
interface AccountLimitCollector {
|
|
1448
|
+
/** The runner id the snapshot is filed under, and what a task's assignment is matched against. */
|
|
1449
|
+
readonly harness: string;
|
|
1450
|
+
readonly label: string;
|
|
1451
|
+
/** The one model provider its limits meter, when the runner serves others too (`AccountLimitSnapshot.provider`). */
|
|
1452
|
+
readonly provider?: string;
|
|
1453
|
+
/** The effective auth and config the reads see; a change clears what was read under the old one. */
|
|
1454
|
+
scope(): string;
|
|
1455
|
+
/** Must settle on its own deadline; `signal` aborts it early, and its result is then ignored. */
|
|
1456
|
+
acquire(signal: AbortSignal): Promise<AccountLimitReading>;
|
|
1457
|
+
}
|
|
1458
|
+
type AccountLimitListener = (snapshots: readonly AccountLimitSnapshot[]) => void;
|
|
1459
|
+
interface AccountLimitMonitorOptions {
|
|
1460
|
+
/** One per runner, in the order surfaces list them. */
|
|
1461
|
+
collectors: readonly AccountLimitCollector[];
|
|
1462
|
+
/** The clock reads are stamped with; timers are the platform's, so a test fakes both together. */
|
|
1463
|
+
now?: () => number;
|
|
1464
|
+
}
|
|
1465
|
+
/**
|
|
1466
|
+
* Every installed runner's account limits, owned once per host above any
|
|
1467
|
+
* panel, task or planner (the planner footer and each task log only
|
|
1468
|
+
* subscribe). It decides when each collector runs — on request, about once a
|
|
1469
|
+
* minute while in the foreground, again when a reported window resets — and
|
|
1470
|
+
* never runs two acquisitions of one account at once.
|
|
1471
|
+
*
|
|
1472
|
+
* It believes only the newest acquisition of the scope it started under: an
|
|
1473
|
+
* answer that arrives after a newer start, a scope change, an account change
|
|
1474
|
+
* or dispose is dropped. A full read replaces what was known; a failure keeps
|
|
1475
|
+
* the last read, marked stale, only when the same account was seen; anything
|
|
1476
|
+
* else forgets it. Nothing is persisted: a new host starts knowing nothing.
|
|
1477
|
+
*/
|
|
1478
|
+
declare class AccountLimitMonitor {
|
|
1479
|
+
private readonly entries;
|
|
1480
|
+
private readonly listeners;
|
|
1481
|
+
private readonly now;
|
|
1482
|
+
private foreground;
|
|
1483
|
+
private disposed;
|
|
1484
|
+
private published;
|
|
1485
|
+
constructor(options: AccountLimitMonitorOptions);
|
|
1486
|
+
snapshots(): readonly AccountLimitSnapshot[];
|
|
1487
|
+
/** Hear every change; the returned function stops it. */
|
|
1488
|
+
subscribe(listener: AccountLimitListener): () => void;
|
|
1489
|
+
/**
|
|
1490
|
+
* Read now, or as soon as the spacing between reads allows; with no
|
|
1491
|
+
* harness, every one. Asks made while a read is out become one follow-up.
|
|
1492
|
+
*/
|
|
1493
|
+
refresh(harness?: string): void;
|
|
1494
|
+
/**
|
|
1495
|
+
* A surface connected. It is drawn what is known, so only an account that
|
|
1496
|
+
* is not being read and was not read within the poll interval is read again:
|
|
1497
|
+
* a webview made ready just after a focused start does not read twice.
|
|
1498
|
+
*/
|
|
1499
|
+
surfaceConnected(): void;
|
|
1500
|
+
/**
|
|
1501
|
+
* Something spent from the account — a model call, a task's turn — so a
|
|
1502
|
+
* read would show more. Folded into the next poll, or the backoff after a
|
|
1503
|
+
* failure, so a busy planner does not read the account on every call; in
|
|
1504
|
+
* the background, where nothing polls, into the read coming back makes.
|
|
1505
|
+
*/
|
|
1506
|
+
invalidate(harness?: string): void;
|
|
1507
|
+
/** Polling runs only in the foreground; coming back reads at once. */
|
|
1508
|
+
setForeground(active: boolean): void;
|
|
1509
|
+
dispose(): void;
|
|
1510
|
+
private each;
|
|
1511
|
+
private request;
|
|
1512
|
+
/**
|
|
1513
|
+
* When the last read started, never later than now: a wall clock set back
|
|
1514
|
+
* since would put it ahead, and every wait measured from it would grow by
|
|
1515
|
+
* the step, focus and refresh included.
|
|
1516
|
+
*/
|
|
1517
|
+
private lastStart;
|
|
1518
|
+
/** How long after one read the next poll comes: a minute, longer for an account with nothing to show, backed off after failures. */
|
|
1519
|
+
private interval;
|
|
1520
|
+
/** The auth or config the reads see has changed: what was read under the old one, or is being read, is not this one's. */
|
|
1521
|
+
private fenceScopeChange;
|
|
1522
|
+
private schedule;
|
|
1523
|
+
private clearTimer;
|
|
1524
|
+
private start;
|
|
1525
|
+
private apply;
|
|
1526
|
+
/** After an acquisition: the follow-up it owes, else the next poll. */
|
|
1527
|
+
private next;
|
|
1528
|
+
/** At the earliest future reset the share shown belongs to a window that is over: stale until read again. */
|
|
1529
|
+
private watchResets;
|
|
1530
|
+
private clearResetTimer;
|
|
1531
|
+
private forget;
|
|
1532
|
+
private show;
|
|
1533
|
+
private collect;
|
|
1534
|
+
}
|
|
1535
|
+
|
|
1536
|
+
interface CodexAccountLimitOptions {
|
|
1537
|
+
/** The manifest's `app-server` launch. */
|
|
1538
|
+
command?: string;
|
|
1539
|
+
args?: string[];
|
|
1540
|
+
timeoutMs?: number;
|
|
1541
|
+
/** Installed, not enabled: an account's limits are worth showing before Codex is given a task. */
|
|
1542
|
+
isInstalled: () => Promise<boolean>;
|
|
1543
|
+
/** The workspace the planner and its tasks run in; its environment can choose another account than the host's (ADR-0016). */
|
|
1544
|
+
workspaceRoot?: () => string | undefined;
|
|
1545
|
+
/** Tests inject the process boundary; the real call stays on the defaults. */
|
|
1546
|
+
deps?: Partial<AgentProcessDeps>;
|
|
1547
|
+
}
|
|
1548
|
+
/**
|
|
1549
|
+
* Codex's account limits, read the way its own clients read them:
|
|
1550
|
+
* `initialize` → `initialized` → `account/read` → `account/rateLimits/read`,
|
|
1551
|
+
* on a short-lived `app-server` that is taken down after every read. Nothing
|
|
1552
|
+
* here opens a thread, starts a turn, logs in or out, or asks Codex to
|
|
1553
|
+
* refresh its token, and Codex's `auth.json` is never read.
|
|
1554
|
+
*
|
|
1555
|
+
* It runs from the temp directory, so a project's config and hooks are not
|
|
1556
|
+
* run on every poll, but with the workspace's environment on top of the
|
|
1557
|
+
* host's, as the planner and its tasks run: a `CODEX_HOME` the workspace sets
|
|
1558
|
+
* decides whose account it is, not the host's.
|
|
1559
|
+
*/
|
|
1560
|
+
declare function codexAccountLimitCollector(options: CodexAccountLimitOptions): AccountLimitCollector;
|
|
1561
|
+
|
|
1562
|
+
interface ClaudeAccountLimitOptions {
|
|
1563
|
+
timeoutMs?: number;
|
|
1564
|
+
/** Installed, not enabled: an account's limits are worth showing before Claude Code is given a task. */
|
|
1565
|
+
isInstalled: () => Promise<boolean>;
|
|
1566
|
+
/** The workspace the planner and its tasks run in; its environment can choose another account than the host's (ADR-0016). */
|
|
1567
|
+
workspaceRoot?: () => string | undefined;
|
|
1568
|
+
/** Tests inject the process boundary; the real call stays on the defaults. */
|
|
1569
|
+
deps?: Partial<AgentProcessDeps>;
|
|
1570
|
+
}
|
|
1571
|
+
/**
|
|
1572
|
+
* Claude Code's plan limits, read the way the Agent SDK reads them: the
|
|
1573
|
+
* `initialize` and `get_usage` control requests, on a process of its own
|
|
1574
|
+
* started for nothing else and taken down after every read. Nothing here
|
|
1575
|
+
* writes a user message, so no model is called, and nothing logs in or out,
|
|
1576
|
+
* resumes or saves a session, or reads a credential: the CLI uses its own
|
|
1577
|
+
* login, as it would for a planner.
|
|
1578
|
+
*
|
|
1579
|
+
* It runs from an empty directory of its own, so no project's settings or
|
|
1580
|
+
* hooks run on every poll, but with the workspace's environment on top of the
|
|
1581
|
+
* host's, as the planner and its tasks run: a `CLAUDE_CONFIG_DIR` the
|
|
1582
|
+
* workspace sets decides whose account it is, not the host's.
|
|
1583
|
+
*/
|
|
1584
|
+
declare function claudeAccountLimitCollector(options: ClaudeAccountLimitOptions): AccountLimitCollector;
|
|
1585
|
+
|
|
1586
|
+
interface OpenCodeGoLoginReaderDeps {
|
|
1587
|
+
homedir?: () => string;
|
|
1588
|
+
/** How long one read of the database may take, worker and all. */
|
|
1589
|
+
timeoutMs?: number;
|
|
1590
|
+
/** The worker boundary; a test counts what it starts. */
|
|
1591
|
+
spawnWorker?: (source: string, options: WorkerOptions) => Worker;
|
|
1592
|
+
/** Node options the worker starts with: a test turns SQLite off to stand for a runtime without it. */
|
|
1593
|
+
workerExecArgv?: string[];
|
|
1594
|
+
}
|
|
1595
|
+
|
|
1596
|
+
interface OpenCodeGoAccountLimitOptions {
|
|
1597
|
+
/** Installed, not enabled: an account's limits are worth showing before OpenCode is given a task. */
|
|
1598
|
+
isInstalled: () => Promise<boolean>;
|
|
1599
|
+
/** The workspace the planner and its tasks run in; its environment can point OpenCode at another store (ADR-0016). */
|
|
1600
|
+
workspaceRoot?: () => string | undefined;
|
|
1601
|
+
/** Tests inject the network, the environment and the store's location; the real call stays on the defaults. */
|
|
1602
|
+
deps?: {
|
|
1603
|
+
fetch?: typeof fetch;
|
|
1604
|
+
now?: () => number;
|
|
1605
|
+
env?: () => NodeJS.ProcessEnv;
|
|
1606
|
+
workspaceEnv?: (root: string) => Promise<Record<string, string>>;
|
|
1607
|
+
reader?: OpenCodeGoLoginReaderDeps;
|
|
1608
|
+
timeoutMs?: number;
|
|
1609
|
+
};
|
|
1610
|
+
}
|
|
1611
|
+
/**
|
|
1612
|
+
* OpenCode Go's plan windows — five hours, the week and the plan month — for
|
|
1613
|
+
* the login OpenCode would pay for a Go model with (ADR-0051). The login is
|
|
1614
|
+
* read from OpenCode's own store, the one it selects and nothing else, and
|
|
1615
|
+
* sent only to OpenCode's fixed quota addresses: no OpenCode process is
|
|
1616
|
+
* started, no model is called, nothing is refreshed, written or kept.
|
|
1617
|
+
*
|
|
1618
|
+
* The limits meter `opencode-go/…` models only, so a task OpenCode runs on
|
|
1619
|
+
* another provider is not shown them.
|
|
1620
|
+
*/
|
|
1621
|
+
declare function openCodeGoAccountLimitCollector(options: OpenCodeGoAccountLimitOptions): AccountLimitCollector;
|
|
1622
|
+
|
|
1527
1623
|
/** The first of {@link findInstalledAgents}; null when none is usable. */
|
|
1528
1624
|
declare function findInstalledPlanner(installation: Pick<RunnerInstallation, 'plannerUsability'>): Promise<PlannerBackendId | null>;
|
|
1529
1625
|
/**
|
|
@@ -1619,6 +1715,8 @@ declare function providerForRunner(runner: RunnerId): PlannerBackendId | null;
|
|
|
1619
1715
|
interface PlannerUsability {
|
|
1620
1716
|
usable: boolean;
|
|
1621
1717
|
reason?: string;
|
|
1718
|
+
/** The runner's own login verdict, beside usability: a signed-out agent is still offered. */
|
|
1719
|
+
auth?: RunnerAuth;
|
|
1622
1720
|
}
|
|
1623
1721
|
/**
|
|
1624
1722
|
* One entry of the planner backend list (ADR-0009). `id` is the
|
|
@@ -1633,6 +1731,8 @@ interface PlannerBackendEntry {
|
|
|
1633
1731
|
runner?: string;
|
|
1634
1732
|
usable: boolean;
|
|
1635
1733
|
reason?: string;
|
|
1734
|
+
/** Set for a harness planner whose login status was asked; never a gate on `usable`. */
|
|
1735
|
+
auth?: RunnerAuth;
|
|
1636
1736
|
}
|
|
1637
1737
|
/** The detail a usable harness planner is always shown with. */
|
|
1638
1738
|
declare const HARNESS_PLANNER_REASON = "coding agent \u00B7 no API key needed";
|
|
@@ -1691,7 +1791,8 @@ declare const ORDEWELL_SETTABLE_ENV: readonly string[];
|
|
|
1691
1791
|
*
|
|
1692
1792
|
* - The approval-mode and pre-approved-scope variables switch the consent gate
|
|
1693
1793
|
* off, so every later command runs unprompted; the web-read budget bounds
|
|
1694
|
-
* how much a planner may send out unasked in Full
|
|
1794
|
+
* how much a planner may send out unasked in Full; the effect allowlist
|
|
1795
|
+
* pre-approves script tasks that change real systems (ADR-0035).
|
|
1695
1796
|
* - The settings-path override is honoured by the settings service, which
|
|
1696
1797
|
* creates directories recursively when persisting — admitting it turns the
|
|
1697
1798
|
* same write into an arbitrary-path file write.
|
|
@@ -1730,10 +1831,205 @@ declare function supportsTaskMode(runner: string): boolean;
|
|
|
1730
1831
|
/** The adapter that drives one task. Throws {@link TaskModeUnsupportedError} for a runner without a connector. */
|
|
1731
1832
|
declare function createTaskAdapter(runner: string, deps: AgentProcessDeps): TaskModeAgentAdapter;
|
|
1732
1833
|
|
|
1834
|
+
interface RunnerCommand {
|
|
1835
|
+
command: string;
|
|
1836
|
+
args: string[];
|
|
1837
|
+
/**
|
|
1838
|
+
* Variables set over the workspace's own (ADR-0016), so they win. Handed the
|
|
1839
|
+
* workspace's, for a runner whose value merges into one of them.
|
|
1840
|
+
*/
|
|
1841
|
+
env?: (workspace: Record<string, string>) => Record<string, string>;
|
|
1842
|
+
/**
|
|
1843
|
+
* Names this launch must not inherit from the host or the workspace — the
|
|
1844
|
+
* credentials a native-shell planner keeps out of its process (ADR-0036 N2.2).
|
|
1845
|
+
*/
|
|
1846
|
+
envDrop?: (name: string) => boolean;
|
|
1847
|
+
}
|
|
1848
|
+
interface RunnerExit {
|
|
1849
|
+
code: number | null;
|
|
1850
|
+
signal: string | null;
|
|
1851
|
+
}
|
|
1852
|
+
/**
|
|
1853
|
+
* The one runner process a structured adapter drives (ADR-0018), whatever its
|
|
1854
|
+
* protocol: launched under the cleaned environment in its own process group,
|
|
1855
|
+
* its output decoded as UTF-8, its stderr tail kept for the failure message,
|
|
1856
|
+
* its end observable, and its whole tree killed on dispose.
|
|
1857
|
+
*
|
|
1858
|
+
* Constructed before it is started, so an adapter can tie a resource to
|
|
1859
|
+
* {@link ended} while it is still deciding what to launch.
|
|
1860
|
+
*/
|
|
1861
|
+
declare class RunnerProcess {
|
|
1862
|
+
private readonly deps;
|
|
1863
|
+
/** Resolves when the process ends — or fails to spawn — so a handshake can lose the race instead of waiting out its timeout. */
|
|
1864
|
+
readonly ended: Promise<void>;
|
|
1865
|
+
private markEnded;
|
|
1866
|
+
private child;
|
|
1867
|
+
/** Disposed before, or while, it launched: nothing may be spawned for an owner that has gone. */
|
|
1868
|
+
private disposed;
|
|
1869
|
+
private exitStatus;
|
|
1870
|
+
/** The process itself reported its end, before its pipes drained; see {@link hasExited}. */
|
|
1871
|
+
private exitReported;
|
|
1872
|
+
private stderrTail;
|
|
1873
|
+
private spawnEnv;
|
|
1874
|
+
/** Stdout readers' end-of-stream flushes, for an end the pipe itself never reports. */
|
|
1875
|
+
private readonly stdoutEnds;
|
|
1876
|
+
constructor(deps: AgentProcessDeps);
|
|
1877
|
+
/**
|
|
1878
|
+
* Launch the process, then run the adapter's `handshake` on it. A handshake
|
|
1879
|
+
* that throws takes the process down with it: no caller keeps an adapter
|
|
1880
|
+
* whose start threw, so a process left running here — a refused handshake,
|
|
1881
|
+
* one that timed out — would have no owner.
|
|
1882
|
+
*
|
|
1883
|
+
* `command` is asked for only once `cwd` is known to exist, and `handshake`
|
|
1884
|
+
* is called in the same tick as the spawn, so a listener it attaches hears
|
|
1885
|
+
* the process's first output.
|
|
1886
|
+
*/
|
|
1887
|
+
start(cwd: string, command: (workspace: Record<string, string>) => RunnerCommand, handshake: (child: ChildProcess) => Promise<void>): Promise<void>;
|
|
1888
|
+
private launch;
|
|
1889
|
+
/**
|
|
1890
|
+
* Hear the process's stdout as text, until the returned function is called.
|
|
1891
|
+
* A read can end inside a multibyte character; decoding each chunk alone
|
|
1892
|
+
* turns both halves into U+FFFD.
|
|
1893
|
+
*
|
|
1894
|
+
* `onEnd`, when given, fires once the stream has ended — after the decoder's
|
|
1895
|
+
* own remainder is handed over. Its job is the framing layer's leftover: a
|
|
1896
|
+
* pipe can close with a complete line still buffered but unterminated, and
|
|
1897
|
+
* nothing else will come to flush it.
|
|
1898
|
+
*/
|
|
1899
|
+
readStdout(onText: (text: string) => void, onEnd?: () => void): () => void;
|
|
1900
|
+
/** The environment the process was spawned under, for any side process a handshake needs. */
|
|
1901
|
+
get env(): NodeJS.ProcessEnv;
|
|
1902
|
+
/** How the process ended; null while it runs. */
|
|
1903
|
+
get exit(): RunnerExit | null;
|
|
1904
|
+
/**
|
|
1905
|
+
* Whether the process has ended, for any reason. Unlike {@link exit} this is
|
|
1906
|
+
* true from its own 'exit', not only once 'close' has drained the pipes: a
|
|
1907
|
+
* runner that has exited can take no further turn even while a descendant
|
|
1908
|
+
* holds its stdout or stderr.
|
|
1909
|
+
*/
|
|
1910
|
+
get hasExited(): boolean;
|
|
1911
|
+
/** The exit code a listener is told: -1 for a signal or a spawn failure. */
|
|
1912
|
+
get exitCode(): number;
|
|
1913
|
+
/** How the process ended, as the end of a sentence. */
|
|
1914
|
+
describeExit(): string;
|
|
1915
|
+
/** Fail-safe contract: a dead runner reports its own last words, never an empty bubble. */
|
|
1916
|
+
withStderrTail(headline: string): string;
|
|
1917
|
+
/**
|
|
1918
|
+
* Tree-wide, because the direct child may be a CLI whose shells, MCP servers
|
|
1919
|
+
* and test runs would outlive it — or, on Windows, the cmd.exe shim rather
|
|
1920
|
+
* than the runner. The forced follow-up is scheduled and unref'd, so a
|
|
1921
|
+
* disposed runner is never the reason the host refuses to exit.
|
|
1922
|
+
*/
|
|
1923
|
+
dispose(): void;
|
|
1924
|
+
private end;
|
|
1925
|
+
private appendStderr;
|
|
1926
|
+
}
|
|
1927
|
+
|
|
1928
|
+
/**
|
|
1929
|
+
* The launcher a harness's own shell runs through (ADR-0036 N2).
|
|
1930
|
+
*
|
|
1931
|
+
* Claude Code names one program in `CLAUDE_CODE_SHELL_PREFIX` and hands it the
|
|
1932
|
+
* whole command string as one argument, so the program is a script: its fixed
|
|
1933
|
+
* part is this session's sandbox launch, and its last argument is the command.
|
|
1934
|
+
* A harness that takes a shell instead (OpenCode's `shell`) can name the same
|
|
1935
|
+
* script the same way.
|
|
1936
|
+
*/
|
|
1937
|
+
interface NativeShellLauncher {
|
|
1938
|
+
/** `CLAUDE_CODE_SHELL_PREFIX`: the script's path. */
|
|
1939
|
+
prefix: string;
|
|
1940
|
+
/**
|
|
1941
|
+
* `CLAUDE_CODE_TMPDIR`: a short per-session directory, writable in the
|
|
1942
|
+
* profile. Claude Code writes the shell's working directory there after
|
|
1943
|
+
* every command, and warns when the path passes about 30 bytes.
|
|
1944
|
+
*/
|
|
1945
|
+
tmpdir: string;
|
|
1946
|
+
/** The harness settings `env` block that names both (N2). */
|
|
1947
|
+
env: Record<string, string>;
|
|
1948
|
+
/** Removes the script and its directory; the next process gets its own. */
|
|
1949
|
+
remove(): void;
|
|
1950
|
+
}
|
|
1951
|
+
/** The shell a command runs in: the user's own, `/bin/zsh` on the one platform N5 offers. */
|
|
1952
|
+
declare function nativeShellInvocation(platform: NodeJS.Platform, env?: NodeJS.ProcessEnv): {
|
|
1953
|
+
shell: string;
|
|
1954
|
+
args: string[];
|
|
1955
|
+
};
|
|
1956
|
+
/**
|
|
1957
|
+
* Build the launcher for one planner process. The script lives in the OS's own
|
|
1958
|
+
* temporary directory, outside every directory the sealed profile can read or
|
|
1959
|
+
* write, so a command cannot rewrite what the next one starts through. Its
|
|
1960
|
+
* short temp folder is under `/tmp` instead, because the harness warns past
|
|
1961
|
+
* about thirty bytes and `/private/tmp` on macOS keeps the path short; the
|
|
1962
|
+
* profile is given only that folder, never the script.
|
|
1963
|
+
*/
|
|
1964
|
+
declare function createNativeShellLauncher(opts: {
|
|
1965
|
+
workspace: string;
|
|
1966
|
+
sandbox: PlannerShellSandbox;
|
|
1967
|
+
platform?: NodeJS.Platform;
|
|
1968
|
+
env?: NodeJS.ProcessEnv;
|
|
1969
|
+
}): Promise<NativeShellLauncher>;
|
|
1970
|
+
|
|
1971
|
+
/**
|
|
1972
|
+
* What every structured adapter owes the one runner process it drives
|
|
1973
|
+
* (ADR-0018 L1), whatever it speaks to it: the {@link RunnerProcess}, whether
|
|
1974
|
+
* it is still alive, who hears it end, how a dead one is reported, and what the
|
|
1975
|
+
* process owns being freed with it.
|
|
1976
|
+
*
|
|
1977
|
+
* Stdio line framing sits on top of this for Claude Code and Codex; OpenCode,
|
|
1978
|
+
* an HTTP server process, uses it without any framing.
|
|
1979
|
+
*/
|
|
1980
|
+
declare abstract class ProcessLifecycle {
|
|
1981
|
+
protected deps: AgentProcessDeps;
|
|
1982
|
+
protected process: ChildProcess | null;
|
|
1983
|
+
/** What this process is to the user — a planner or a task's runner — for the words a failure is reported in. */
|
|
1984
|
+
protected role: 'planner' | 'task';
|
|
1985
|
+
protected readonly runner: RunnerProcess;
|
|
1986
|
+
/**
|
|
1987
|
+
* What the process owns, by name: the MCP config file holding its token, the
|
|
1988
|
+
* sealed shell launcher and its sandbox. One registry rather than a field
|
|
1989
|
+
* and a cleanup per adapter, so a resource an adapter claims cannot be the
|
|
1990
|
+
* one its cleanup forgot.
|
|
1991
|
+
*/
|
|
1992
|
+
private readonly owned;
|
|
1993
|
+
private disposed;
|
|
1994
|
+
constructor(deps: AgentProcessDeps);
|
|
1995
|
+
/** Fail-safe contract: a dead process reports its own last words, never an empty bubble. */
|
|
1996
|
+
protected abstract exitMessage(): string;
|
|
1997
|
+
get exited(): boolean;
|
|
1998
|
+
/** Resolves when the process ends, so a handshake can lose the race instead of waiting out its timeout. */
|
|
1999
|
+
protected get processEnded(): Promise<void>;
|
|
2000
|
+
/** Whether {@link dispose} has run, for a loop that must stop once the process is gone. */
|
|
2001
|
+
protected get isDisposed(): boolean;
|
|
2002
|
+
onProcessExit(listener: (code: number, lastWords?: string) => void): void;
|
|
2003
|
+
/**
|
|
2004
|
+
* Launch the process and run `handshake` on it. A start that throws takes
|
|
2005
|
+
* the process down and frees what the adapter owns with it: no caller keeps
|
|
2006
|
+
* an adapter whose start threw.
|
|
2007
|
+
*/
|
|
2008
|
+
protected startProcess(cwd: string, command: (workspace: Record<string, string>) => RunnerCommand, handshake: (child: ChildProcess) => Promise<void>): Promise<void>;
|
|
2009
|
+
/**
|
|
2010
|
+
* Hand `release` to the process: it runs once, when the process ends or the
|
|
2011
|
+
* adapter is disposed, whichever comes first. A second claim on a name frees
|
|
2012
|
+
* the first, so a process launched again does not leak its predecessor's.
|
|
2013
|
+
* A claim made after the adapter was disposed is freed at once.
|
|
2014
|
+
*/
|
|
2015
|
+
protected own(name: string, release: () => void): void;
|
|
2016
|
+
/** Prepare this planner's own shell (ADR-0036 N2) and own it, or null when the start did not ask for one. */
|
|
2017
|
+
protected ownNativeShell(opts: AgentStartOptions): Promise<NativeShellLauncher | null>;
|
|
2018
|
+
/**
|
|
2019
|
+
* Frees what the process owns, then ends its whole process tree. Idempotent:
|
|
2020
|
+
* every path that gives up on the process — a stop, a refused start, a
|
|
2021
|
+
* turn's abort — ends here.
|
|
2022
|
+
*/
|
|
2023
|
+
dispose(): void;
|
|
2024
|
+
private freeOwned;
|
|
2025
|
+
}
|
|
2026
|
+
|
|
1733
2027
|
interface SpawnSpec {
|
|
1734
2028
|
command: string;
|
|
1735
2029
|
args: string[];
|
|
1736
2030
|
env?: Record<string, string>;
|
|
2031
|
+
/** Names the launch must not inherit from the host or the workspace (ADR-0036 N2.2). */
|
|
2032
|
+
envDrop?: (name: string) => boolean;
|
|
1737
2033
|
}
|
|
1738
2034
|
/**
|
|
1739
2035
|
* Shared plumbing for the agents that speak newline-delimited JSON over stdio.
|
|
@@ -1746,16 +2042,13 @@ interface SpawnSpec {
|
|
|
1746
2042
|
*
|
|
1747
2043
|
* Subclasses own their agent's protocol: what to spawn, how to phrase a user
|
|
1748
2044
|
* turn, and how to read one protocol line. Everything below — line framing,
|
|
1749
|
-
* turn lifecycle, abort — is the same for all of them
|
|
1750
|
-
*
|
|
2045
|
+
* turn lifecycle, abort — is the same for all of them; the process and what it
|
|
2046
|
+
* owns are {@link ProcessLifecycle}'s.
|
|
1751
2047
|
*/
|
|
1752
|
-
declare abstract class StdioAgentAdapter implements AgentAdapter {
|
|
1753
|
-
protected deps: AgentProcessDeps;
|
|
2048
|
+
declare abstract class StdioAgentAdapter extends ProcessLifecycle implements AgentAdapter {
|
|
1754
2049
|
abstract readonly agentId: string;
|
|
1755
|
-
protected process: ChildProcess | null;
|
|
1756
2050
|
protected sessionId: string | null;
|
|
1757
2051
|
private readonly stdout;
|
|
1758
|
-
private readonly runner;
|
|
1759
2052
|
/** Set for the duration of a turn. Outside one, events are buffered rather than dropped. */
|
|
1760
2053
|
private turnEmit;
|
|
1761
2054
|
/** Set for the duration of a turn. Pinged on every raw line, whether or not `handleLine` turns it into an event. */
|
|
@@ -1776,9 +2069,6 @@ declare abstract class StdioAgentAdapter implements AgentAdapter {
|
|
|
1776
2069
|
private hadTurn;
|
|
1777
2070
|
/** A task's session, which wants what the agent says on its own after a turn closed; a planner registers none and drops it. */
|
|
1778
2071
|
private outOfTurnListener;
|
|
1779
|
-
private disposed;
|
|
1780
|
-
/** What this process is to the user — a planner or a task's runner — for the words a failure is reported in. */
|
|
1781
|
-
protected role: 'planner' | 'task';
|
|
1782
2072
|
constructor(deps: AgentProcessDeps);
|
|
1783
2073
|
/**
|
|
1784
2074
|
* The command line that starts this agent in its read-only mode, given the
|
|
@@ -1795,6 +2085,12 @@ declare abstract class StdioAgentAdapter implements AgentAdapter {
|
|
|
1795
2085
|
/** Protocol handshake, if the agent needs one before it accepts a turn. */
|
|
1796
2086
|
protected handshake(_opts: AgentStartOptions): Promise<void>;
|
|
1797
2087
|
start(opts: AgentStartOptions): Promise<void>;
|
|
2088
|
+
/**
|
|
2089
|
+
* Spawn `spec`, read its protocol, then run `handshake`. {@link start} is a
|
|
2090
|
+
* planner's or a task's launch; a launch that is neither — a query that
|
|
2091
|
+
* never opens a turn — comes through here with its own command line.
|
|
2092
|
+
*/
|
|
2093
|
+
protected launch(cwd: string, spec: (workspace: Record<string, string>) => SpawnSpec, handshake: () => Promise<void>): Promise<void>;
|
|
1798
2094
|
/**
|
|
1799
2095
|
* Every protocol line goes to `handleLine`, turn or no turn: an agent's
|
|
1800
2096
|
* handshake and its session-id announcement both arrive before the first
|
|
@@ -1807,24 +2103,34 @@ declare abstract class StdioAgentAdapter implements AgentAdapter {
|
|
|
1807
2103
|
* to the open turn, or held for the first one.
|
|
1808
2104
|
*/
|
|
1809
2105
|
protected announce(event: AgentEvent): void;
|
|
1810
|
-
/** Resolves when the process ends, so a handshake can lose the race instead of waiting out its timeout. */
|
|
1811
|
-
protected get processEnded(): Promise<void>;
|
|
1812
2106
|
/** The environment the agent was spawned under, for any side process a handshake needs. */
|
|
1813
2107
|
protected get spawnEnv(): NodeJS.ProcessEnv;
|
|
1814
2108
|
send(message: string, onEvent: (event: AgentEvent) => void, signal?: AbortSignal, onActivity?: () => void): Promise<void>;
|
|
1815
2109
|
onOutOfTurn(listener: (event: AgentEvent) => void): void;
|
|
1816
2110
|
nativeSessionId(): string | null;
|
|
1817
|
-
get exited(): boolean;
|
|
1818
|
-
onProcessExit(listener: (code: number, lastWords?: string) => void): void;
|
|
1819
2111
|
dispose(): void;
|
|
1820
2112
|
/** Write one raw protocol line to the agent. */
|
|
1821
2113
|
protected writeLine(payload: unknown): void;
|
|
1822
|
-
/** Fail-safe contract: a dead agent reports its own last words, never an empty bubble. */
|
|
1823
2114
|
protected exitMessage(): string;
|
|
1824
2115
|
/** Parse a protocol line, ignoring the non-JSON banners some CLIs print. */
|
|
1825
2116
|
protected static parse<T>(line: string): T | null;
|
|
1826
2117
|
}
|
|
1827
2118
|
|
|
2119
|
+
/**
|
|
2120
|
+
* What one control request came to: its answer's payload as the CLI sent it,
|
|
2121
|
+
* the CLI's refusal in its own words, or no answer in time — with the
|
|
2122
|
+
* process's stderr tail when it ended instead.
|
|
2123
|
+
*/
|
|
2124
|
+
type ClaudeControlAnswer = {
|
|
2125
|
+
kind: 'answered';
|
|
2126
|
+
response: unknown;
|
|
2127
|
+
} | {
|
|
2128
|
+
kind: 'refused';
|
|
2129
|
+
error: string;
|
|
2130
|
+
} | {
|
|
2131
|
+
kind: 'silent';
|
|
2132
|
+
lastWords?: string;
|
|
2133
|
+
};
|
|
1828
2134
|
declare class ClaudeCodeAdapter extends StdioAgentAdapter implements TaskModeAgentAdapter {
|
|
1829
2135
|
readonly agentId = "claude-code";
|
|
1830
2136
|
private controlCount;
|
|
@@ -1833,10 +2139,15 @@ declare class ClaudeCodeAdapter extends StdioAgentAdapter implements TaskModeAge
|
|
|
1833
2139
|
/** An interrupt was sent during the current turn, so an aborted result is that interrupt, not a failure. */
|
|
1834
2140
|
private interruptRequested;
|
|
1835
2141
|
private readonly permissions;
|
|
2142
|
+
private readOnlySite;
|
|
2143
|
+
/** The sealed launcher this process's shell goes through, when the opt-in is on (ADR-0036 N2). */
|
|
2144
|
+
private nativeShell;
|
|
1836
2145
|
/** This turn's runs of reply text, each a text block named `<message id>:<block index>`. */
|
|
1837
2146
|
private replyRuns;
|
|
1838
2147
|
/** The model answering the planner's current message, and the message's id, as its `message_start` named them. */
|
|
1839
2148
|
private plannerModel;
|
|
2149
|
+
/** The CLI's version, from its first `init`; the native-shell check reads it (ADR-0036 N2). */
|
|
2150
|
+
private installedVersion;
|
|
1840
2151
|
/**
|
|
1841
2152
|
* The id the turn runs as, as `init` names it. A `[1m]` variant is the
|
|
1842
2153
|
* selected id, while a message names the API's canonical id without it.
|
|
@@ -1879,8 +2190,6 @@ declare class ClaudeCodeAdapter extends StdioAgentAdapter implements TaskModeAge
|
|
|
1879
2190
|
private requestedMode;
|
|
1880
2191
|
/** The session `--resume` asked for, until the CLI's `init` shows it was taken up. */
|
|
1881
2192
|
private pendingResume;
|
|
1882
|
-
/** The `--mcp-config` file of the running process, which holds its token; removed with the process. */
|
|
1883
|
-
private mcpConfig;
|
|
1884
2193
|
/** Whether this process was given the server, so its tools' requests are Ordewell's own. */
|
|
1885
2194
|
private givenOrdewell;
|
|
1886
2195
|
/** The `CLAUDE_CONFIG_DIR` a planner runs under, where the CLI saves its long tool results. */
|
|
@@ -1889,6 +2198,8 @@ declare class ClaudeCodeAdapter extends StdioAgentAdapter implements TaskModeAge
|
|
|
1889
2198
|
private readonly steers;
|
|
1890
2199
|
/** The last turn's `result` ended it, so a steer's echo now opens a turn the CLI started for that message. */
|
|
1891
2200
|
private turnClosed;
|
|
2201
|
+
/** The model is working in a turn the CLI opened itself, after the last one closed: a background wake. */
|
|
2202
|
+
private runnerTurn;
|
|
1892
2203
|
/** The task's commands as the CLI last listed them, and what its `init` said of them (#66). */
|
|
1893
2204
|
private listedCommands;
|
|
1894
2205
|
private skillNames;
|
|
@@ -1908,8 +2219,16 @@ declare class ClaudeCodeAdapter extends StdioAgentAdapter implements TaskModeAge
|
|
|
1908
2219
|
* `init`, which can be another `/model`'s.
|
|
1909
2220
|
*/
|
|
1910
2221
|
private modelCommands;
|
|
2222
|
+
/**
|
|
2223
|
+
* Prepare the native shell before the process starts, or fail the start
|
|
2224
|
+
* rather than run it outside a sandbox. The launcher is a file this process
|
|
2225
|
+
* owns: `CLAUDE_CODE_SHELL_PREFIX` can only name a program, and Claude Code
|
|
2226
|
+
* hands it the whole command as one argument (ADR-0036 N2).
|
|
2227
|
+
*/
|
|
2228
|
+
start(opts: AgentStartOptions): Promise<void>;
|
|
1911
2229
|
protected spawnSpec(opts: AgentStartOptions, workspace: Record<string, string>): SpawnSpec;
|
|
1912
2230
|
sessionCost(): RunnerSessionCost | null;
|
|
2231
|
+
version(): string | null;
|
|
1913
2232
|
/**
|
|
1914
2233
|
* A cleared conversation's totals start again from zero, so what follows is
|
|
1915
2234
|
* all new spend, even for a resume that had no count kept.
|
|
@@ -1920,8 +2239,8 @@ declare class ClaudeCodeAdapter extends StdioAgentAdapter implements TaskModeAge
|
|
|
1920
2239
|
savedOutput(abs: string): boolean;
|
|
1921
2240
|
/**
|
|
1922
2241
|
* A task's run: the manifest decides what its mode and effort mean
|
|
1923
|
-
* (ADR-0001)
|
|
1924
|
-
*
|
|
2242
|
+
* (ADR-0001). Read-only tasks withhold native writes and shell tools
|
|
2243
|
+
* (ADR-0046); other tasks keep the runner's native tools. The prompt is its
|
|
1925
2244
|
* first turn, and the contract is where the CLI's own compaction cannot
|
|
1926
2245
|
* summarise it away. `--permission-prompt-tool stdio` routes the questions the mode
|
|
1927
2246
|
* leaves open to the control channel, where the adapter must answer them;
|
|
@@ -1937,21 +2256,18 @@ declare class ClaudeCodeAdapter extends StdioAgentAdapter implements TaskModeAge
|
|
|
1937
2256
|
private plannerServers;
|
|
1938
2257
|
/** The file holding the token lives exactly as long as the process that reads it. */
|
|
1939
2258
|
private ordewellServerArgs;
|
|
1940
|
-
|
|
1941
|
-
/**
|
|
1942
|
-
* Under `--permission-mode plan` the CLI runs Sonnet for the `haiku` alias,
|
|
1943
|
-
* though it runs a full id as given: a read-only task would silently run a
|
|
1944
|
-
* dearer model than its plan names (ADR-0001). The CLI's own list says what
|
|
1945
|
-
* the alias resolves to now; that id is pinned before the first turn.
|
|
1946
|
-
*/
|
|
1947
|
-
protected handshake(opts: AgentStartOptions): Promise<void>;
|
|
2259
|
+
protected handshake(): Promise<void>;
|
|
1948
2260
|
/**
|
|
1949
2261
|
* What `-p` can run. The CLI lists commands only its TUI runs (`init`'s
|
|
1950
2262
|
* `terminal_slash_commands`) and internal ones named `__…` all the same.
|
|
1951
2263
|
*/
|
|
1952
|
-
commands(): RunnerCommand[];
|
|
1953
|
-
/**
|
|
1954
|
-
|
|
2264
|
+
commands(): RunnerCommand$1[];
|
|
2265
|
+
/**
|
|
2266
|
+
* Asks the CLI itself, which reports `pending` until its connection attempt
|
|
2267
|
+
* settles. A process that exited ends the wait at once: its report is gone
|
|
2268
|
+
* with it, and no answer would ever come.
|
|
2269
|
+
*/
|
|
2270
|
+
mcpAttached(): Promise<AttachState>;
|
|
1955
2271
|
/**
|
|
1956
2272
|
* Claude Code's soft interrupt: the turn stops, the process and its session
|
|
1957
2273
|
* stay. The CLI acknowledges on the control channel, then closes the turn
|
|
@@ -1975,6 +2291,17 @@ declare class ClaudeCodeAdapter extends StdioAgentAdapter implements TaskModeAge
|
|
|
1975
2291
|
* with the message unread.
|
|
1976
2292
|
*/
|
|
1977
2293
|
steer(id: string, text: string): Promise<boolean>;
|
|
2294
|
+
/**
|
|
2295
|
+
* Launch the process as an account query rather than a planner or a task,
|
|
2296
|
+
* from `cwd`, and ask it who is signed in (`initialize`). Then
|
|
2297
|
+
* {@link queryUsage} asks what the plan's limits stand at. Both go on the
|
|
2298
|
+
* control channel and no user message is ever written, so no model is
|
|
2299
|
+
* called and no turn opens. The caller ends input and disposes.
|
|
2300
|
+
*/
|
|
2301
|
+
openAccountQuery(cwd: string, timeoutMs: number): Promise<ClaudeControlAnswer>;
|
|
2302
|
+
/** The plan's limits, on a process {@link openAccountQuery} opened. */
|
|
2303
|
+
queryUsage(timeoutMs: number): Promise<ClaudeControlAnswer>;
|
|
2304
|
+
private controlAnswer;
|
|
1978
2305
|
/** Send a control request and wait for its answer; null when none came in time or the process ended. */
|
|
1979
2306
|
private control;
|
|
1980
2307
|
/**
|
|
@@ -2173,6 +2500,8 @@ declare class CodexAdapter extends StdioAgentAdapter implements TaskModeAgentAda
|
|
|
2173
2500
|
private sandbox;
|
|
2174
2501
|
/** A planner on a host where no sandbox starts: Codex's own shell is off, and `run_command` is its only one (ADR-0033). */
|
|
2175
2502
|
private ownShellOff;
|
|
2503
|
+
/** A read-only task's: every MCP server Codex would start beside Ordewell's, each switched off for its thread (ADR-0046). */
|
|
2504
|
+
private withheldServers;
|
|
2176
2505
|
/** The Ordewell server's startup state, as Codex last reported it for this thread. */
|
|
2177
2506
|
private mcpStartup;
|
|
2178
2507
|
private mcpStartupSettled;
|
|
@@ -2203,9 +2532,17 @@ declare class CodexAdapter extends StdioAgentAdapter implements TaskModeAgentAda
|
|
|
2203
2532
|
* would pretend it was resumed.
|
|
2204
2533
|
*/
|
|
2205
2534
|
private openThread;
|
|
2206
|
-
commands(): RunnerCommand[];
|
|
2535
|
+
commands(): RunnerCommand$1[];
|
|
2207
2536
|
invokeCommand(name: string, args: string, onEvent: (event: AgentEvent) => void, signal?: AbortSignal): Promise<void>;
|
|
2208
2537
|
private loadCommands;
|
|
2538
|
+
/**
|
|
2539
|
+
* The MCP servers Codex's own configuration would start, every layer of it,
|
|
2540
|
+
* less Ordewell's. A read-only task may change nothing, and a user's server
|
|
2541
|
+
* can: one set to approve its tools runs them under any approval policy, so
|
|
2542
|
+
* none of them starts (ADR-0046), as Claude's and OpenCode's deny theirs.
|
|
2543
|
+
* Not knowing them, the task does not start.
|
|
2544
|
+
*/
|
|
2545
|
+
private configuredServers;
|
|
2209
2546
|
private requestThread;
|
|
2210
2547
|
private threadParams;
|
|
2211
2548
|
/**
|
|
@@ -2213,7 +2550,7 @@ declare class CodexAdapter extends StdioAgentAdapter implements TaskModeAgentAda
|
|
|
2213
2550
|
* has tried to connect (ADR-0022, S4). A report that came before this was
|
|
2214
2551
|
* asked is kept, so asking late still gets the answer.
|
|
2215
2552
|
*/
|
|
2216
|
-
mcpAttached(): Promise<
|
|
2553
|
+
mcpAttached(): Promise<AttachState>;
|
|
2217
2554
|
private effort;
|
|
2218
2555
|
/**
|
|
2219
2556
|
* `turn/interrupt` names the turn as well as the thread, so an interrupt
|
|
@@ -2341,7 +2678,7 @@ declare class CodexAdapter extends StdioAgentAdapter implements TaskModeAgentAda
|
|
|
2341
2678
|
|
|
2342
2679
|
declare const CODEX_SANDBOX_DOCS = "https://github.com/ordewell/ordewell/blob/main/docs/troubleshooting.md#codex-sandbox-unavailable-on-this-host";
|
|
2343
2680
|
/** The one line a surface shows next to the runner list while Codex's sandboxed modes are off. */
|
|
2344
|
-
declare const CODEX_SANDBOX_OFF_LINE = "Codex sandbox unavailable on this host:
|
|
2681
|
+
declare const CODEX_SANDBOX_OFF_LINE = "Codex sandbox unavailable on this host: Guarded mode is off";
|
|
2345
2682
|
/**
|
|
2346
2683
|
* The line a runner or mode list shows, and the page that explains it, when
|
|
2347
2684
|
* the catalog says Codex's sandboxed modes are off. Null when nothing is.
|
|
@@ -2399,20 +2736,18 @@ declare class CodexSandboxAvailability {
|
|
|
2399
2736
|
* detail, never the final reply. A task turn is posted asynchronously and read
|
|
2400
2737
|
* entirely from the stream — see {@link sendTask}.
|
|
2401
2738
|
*/
|
|
2402
|
-
declare class OpenCodeAdapter implements TaskModeAgentAdapter {
|
|
2403
|
-
private deps;
|
|
2739
|
+
declare class OpenCodeAdapter extends ProcessLifecycle implements TaskModeAgentAdapter {
|
|
2404
2740
|
readonly agentId = "opencode";
|
|
2405
2741
|
private nativeCommands;
|
|
2406
2742
|
private readonly nativeSkills;
|
|
2407
2743
|
private manualCompaction;
|
|
2408
2744
|
private loaded;
|
|
2409
|
-
private process;
|
|
2410
2745
|
private baseUrl;
|
|
2746
|
+
/** The server's version from `/api/info`; null on 1.x, which does not report one (ADR-0036 N2). */
|
|
2747
|
+
private serverVersion;
|
|
2411
2748
|
/** Sent on every request to a task's server, which a per-task password secures. */
|
|
2412
2749
|
private authorization;
|
|
2413
2750
|
private sessionId;
|
|
2414
|
-
private readonly runner;
|
|
2415
|
-
private disposed;
|
|
2416
2751
|
private planner;
|
|
2417
2752
|
private task;
|
|
2418
2753
|
/** The last assistant message already settled — the baseline {@link recoverReply} measures a new reply against. */
|
|
@@ -2429,9 +2764,8 @@ declare class OpenCodeAdapter implements TaskModeAgentAdapter {
|
|
|
2429
2764
|
private v2;
|
|
2430
2765
|
/** The Ordewell server this process was configured with; null when none was given or its config could not be merged. */
|
|
2431
2766
|
private ordewell;
|
|
2432
|
-
|
|
2433
|
-
private
|
|
2434
|
-
get exited(): boolean;
|
|
2767
|
+
/** The sealed launcher this planner's own shell goes through, when the opt-in is on (ADR-0036 N2). */
|
|
2768
|
+
private nativeShell;
|
|
2435
2769
|
start(opts: AgentStartOptions): Promise<void>;
|
|
2436
2770
|
private launch;
|
|
2437
2771
|
/**
|
|
@@ -2443,7 +2777,7 @@ declare class OpenCodeAdapter implements TaskModeAgentAdapter {
|
|
|
2443
2777
|
private serverAddress;
|
|
2444
2778
|
/** From the server's address to an open session — the 2.x API's, or a 1.x one created or resumed. */
|
|
2445
2779
|
private connect;
|
|
2446
|
-
commands(): RunnerCommand[];
|
|
2780
|
+
commands(): RunnerCommand$1[];
|
|
2447
2781
|
private loadCommands;
|
|
2448
2782
|
invokeCommand(name: string, args: string, onEvent: (event: AgentEvent) => void, signal?: AbortSignal): Promise<void>;
|
|
2449
2783
|
private emitLoaded;
|
|
@@ -2455,9 +2789,25 @@ declare class OpenCodeAdapter implements TaskModeAgentAdapter {
|
|
|
2455
2789
|
* to the turn before, and {@link pollStatus} stands behind the stream,
|
|
2456
2790
|
* which can miss a status frame. No request is held open for the turn, so
|
|
2457
2791
|
* fetch's 300s header timeout, the planner's reason for
|
|
2458
|
-
* {@link recoverReply}, never applies
|
|
2792
|
+
* {@link recoverReply}, never applies — except to a native command, whose
|
|
2793
|
+
* POST is held and is followed by {@link heldPost}.
|
|
2459
2794
|
*/
|
|
2460
2795
|
private sendTask;
|
|
2796
|
+
/**
|
|
2797
|
+
* The POST of a native command, or null when it was refused before sending
|
|
2798
|
+
* (and said so). Unlike `prompt_async`, `/command` and `/summarize` answer
|
|
2799
|
+
* only when the turn is done, so the request carries no deadline.
|
|
2800
|
+
*/
|
|
2801
|
+
private commandPost;
|
|
2802
|
+
/**
|
|
2803
|
+
* How a command turn's held POST came out. A socket that died under it says
|
|
2804
|
+
* nothing about the turn — the server works on regardless, as it does for
|
|
2805
|
+
* the planner's {@link recoverReply} — so that, like the session going idle
|
|
2806
|
+
* first, leaves the turn to the idle wait. Only a server's refusal, or a
|
|
2807
|
+
* transport that failed with the session never seen working, is the
|
|
2808
|
+
* message not having been taken.
|
|
2809
|
+
*/
|
|
2810
|
+
private heldPost;
|
|
2461
2811
|
/**
|
|
2462
2812
|
* The prompt that carries a task message: the mode as the agent, the task
|
|
2463
2813
|
* model and effort, and only `question` withheld. A steer names its own
|
|
@@ -2500,7 +2850,6 @@ declare class OpenCodeAdapter implements TaskModeAgentAdapter {
|
|
|
2500
2850
|
* interrupted, because the request is remembered.
|
|
2501
2851
|
*/
|
|
2502
2852
|
interrupt(timeoutMs: number): Promise<boolean>;
|
|
2503
|
-
onProcessExit(listener: (code: number, lastWords?: string) => void): void;
|
|
2504
2853
|
answerPermission(id: string, decision: ApprovalDecision): boolean | Promise<boolean>;
|
|
2505
2854
|
/**
|
|
2506
2855
|
* OpenCode 2.x replaced the 1.x HTTP surface rather than extending it, and
|
|
@@ -2508,7 +2857,6 @@ declare class OpenCodeAdapter implements TaskModeAgentAdapter {
|
|
|
2508
2857
|
* answers with anything else — keeps the 1.x protocol this class speaks.
|
|
2509
2858
|
*/
|
|
2510
2859
|
private v2Version;
|
|
2511
|
-
private role;
|
|
2512
2860
|
/**
|
|
2513
2861
|
* Turn one settled assistant message into events. The settled response is
|
|
2514
2862
|
* authoritative: it names the assistant message, so its parts are the ones
|
|
@@ -2572,37 +2920,55 @@ declare class OpenCodeAdapter implements TaskModeAgentAdapter {
|
|
|
2572
2920
|
/** `/event` for one turn — see {@link openEventStream}. Load-bearing for {@link onPermissionAsked}. */
|
|
2573
2921
|
private openStream;
|
|
2574
2922
|
private json;
|
|
2923
|
+
/** `timeoutMs` null is for a turn's own POST, which the server answers when the turn is done. */
|
|
2575
2924
|
private request;
|
|
2576
2925
|
private headers;
|
|
2577
2926
|
nativeSessionId(): string | null;
|
|
2927
|
+
version(): string | null;
|
|
2578
2928
|
unusableProjectServers(): ProjectMcpServer[];
|
|
2579
2929
|
/** 2.x only: a 1.x server's saved output was never checked, so it is asked about as any outside read. */
|
|
2580
2930
|
savedOutput(abs: string): boolean;
|
|
2581
|
-
/**
|
|
2582
|
-
|
|
2931
|
+
/**
|
|
2932
|
+
* Asks the server, which lists every MCP server it has with the state of its
|
|
2933
|
+
* connection. On 2.x, connected once the model would be offered the tools.
|
|
2934
|
+
*/
|
|
2935
|
+
mcpAttached(): Promise<AttachState>;
|
|
2583
2936
|
/** 2.x lists its servers as `{ name, status: { status } }`, and only once it has started connecting them. */
|
|
2584
2937
|
private v2McpStatus;
|
|
2585
2938
|
dispose(): void;
|
|
2586
|
-
|
|
2939
|
+
protected exitMessage(): string;
|
|
2587
2940
|
}
|
|
2588
2941
|
|
|
2589
|
-
interface MappedTool {
|
|
2590
|
-
tool: ResearchToolType;
|
|
2591
|
-
/** The agent's own name, kept whenever it differs from the member it mapped to. */
|
|
2592
|
-
toolLabel?: string;
|
|
2593
|
-
}
|
|
2594
2942
|
/**
|
|
2595
|
-
*
|
|
2596
|
-
*
|
|
2943
|
+
* Whether a harness planner may be offered its own shell (ADR-0036 N2, N4), and
|
|
2944
|
+
* why not when it cannot. The table below is the live checks and nothing more:
|
|
2945
|
+
* a harness or version it does not name has not been checked, so it keeps
|
|
2946
|
+
* `run_command` alone. A new harness release is not handed an older release's
|
|
2947
|
+
* checks; it waits for its own.
|
|
2597
2948
|
*/
|
|
2598
|
-
|
|
2949
|
+
type NativeShellOffer = {
|
|
2950
|
+
offered: true;
|
|
2951
|
+
}
|
|
2952
|
+
/** A whole sentence, shown once per session and in the setting's description. */
|
|
2953
|
+
| {
|
|
2954
|
+
offered: false;
|
|
2955
|
+
reason: string;
|
|
2956
|
+
};
|
|
2599
2957
|
/**
|
|
2600
|
-
*
|
|
2601
|
-
*
|
|
2602
|
-
*
|
|
2603
|
-
*
|
|
2958
|
+
* What to tell the user about the opt-in for this harness. `version` is the
|
|
2959
|
+
* one the harness reported: Claude Code's `init` line, or an OpenCode 2.x
|
|
2960
|
+
* server's `/api/info`. Null means it reported none — Claude Code before its
|
|
2961
|
+
* first `init`, or OpenCode 1.x, which does not answer with one.
|
|
2962
|
+
*
|
|
2963
|
+
* Linux is deliberately not offered yet: N2 asks for checks on the installed
|
|
2964
|
+
* version, the checks were run on macOS, and bubblewrap passing is a sandbox
|
|
2965
|
+
* probe rather than a live check of either harness's shell.
|
|
2604
2966
|
*/
|
|
2605
|
-
declare function
|
|
2967
|
+
declare function nativeShellOffer(input: {
|
|
2968
|
+
runner: string;
|
|
2969
|
+
version: string | null;
|
|
2970
|
+
platform?: NodeJS.Platform;
|
|
2971
|
+
}): NativeShellOffer;
|
|
2606
2972
|
|
|
2607
2973
|
interface PlannerBackendOptions {
|
|
2608
2974
|
/** The planner provider configured now. */
|
|
@@ -2796,10 +3162,15 @@ type PlannerUsageMessage = Extract<SessionMessage, {
|
|
|
2796
3162
|
*/
|
|
2797
3163
|
declare class PlannerUsageLedger {
|
|
2798
3164
|
private readonly sessionWindows;
|
|
3165
|
+
private readonly contextStatus;
|
|
2799
3166
|
private usage;
|
|
2800
3167
|
private windows;
|
|
2801
|
-
/**
|
|
2802
|
-
|
|
3168
|
+
/**
|
|
3169
|
+
* `sessionWindows` serves the window of a planner model whose backend
|
|
3170
|
+
* reports none; `contextStatus`, what an API planner's automatic compaction
|
|
3171
|
+
* does for its model now — undefined on a harness planner.
|
|
3172
|
+
*/
|
|
3173
|
+
constructor(sessionWindows?: SessionWindows, contextStatus?: () => PlannerContextStatus | undefined);
|
|
2803
3174
|
/** Fold one model call's record into the totals; returns the running ledger. */
|
|
2804
3175
|
record(record: UsageRecord): PlannerUsage;
|
|
2805
3176
|
/** Adopt a persisted ledger (a reopened session) or start from zero. */
|
|
@@ -2814,12 +3185,15 @@ declare class PlannerUsageLedger {
|
|
|
2814
3185
|
message(turnId?: string): PlannerUsageMessage;
|
|
2815
3186
|
}
|
|
2816
3187
|
|
|
3188
|
+
type PlannerCompactionMessage = Extract<SessionMessage, {
|
|
3189
|
+
type: 'planner_compaction';
|
|
3190
|
+
}>;
|
|
2817
3191
|
interface SessionEventRelayDeps {
|
|
2818
3192
|
broadcast: SessionBroadcaster;
|
|
2819
3193
|
/** Where isolation notices go, for a host whose notifications are not seen by the user. */
|
|
2820
3194
|
onNotice?: (notice: SessionNotice) => void;
|
|
2821
3195
|
store: Pick<PlanStore, 'allTasks' | 'snapshot'>;
|
|
2822
|
-
orchestrator: Pick<TaskOrchestrator, 'getIdleSince' | 'getQueuedTaskMessages' | 'getMergeGate' | 'runMergeView'>;
|
|
3196
|
+
orchestrator: Pick<TaskOrchestrator, 'getIdleSince' | 'getCompletionReceipt' | 'getQueuedTaskMessages' | 'getMergeGate' | 'holdReason' | 'runMergeView' | 'activity'>;
|
|
2823
3197
|
runs: Pick<IsolationRunController, 'taskIsolation'>;
|
|
2824
3198
|
/** Shared with the Session, which snapshots, restores and clears it. */
|
|
2825
3199
|
usage: PlannerUsageLedger;
|
|
@@ -2863,6 +3237,8 @@ declare class SessionEventRelay {
|
|
|
2863
3237
|
private statusOwed;
|
|
2864
3238
|
/** The planner's requests announced and not yet settled, as they were announced: a surface joining now is owed them. */
|
|
2865
3239
|
private readonly announced;
|
|
3240
|
+
/** The planner compaction started and not yet ended, as it was announced: a surface joining now is owed it too. */
|
|
3241
|
+
private compacting;
|
|
2866
3242
|
constructor(deps: SessionEventRelayDeps);
|
|
2867
3243
|
/** `plan` is read per event: a Session with no plan (or mid-reset) announces nothing about tasks. */
|
|
2868
3244
|
observer(plan: () => LegacyPlanState | null): RelayObserver;
|
|
@@ -2887,6 +3263,8 @@ declare class SessionEventRelay {
|
|
|
2887
3263
|
announcedApprovals(): Extract<SessionMessage, {
|
|
2888
3264
|
type: 'approval_request';
|
|
2889
3265
|
}>[];
|
|
3266
|
+
/** The planner compaction running now, as its start was announced; undefined when none is. */
|
|
3267
|
+
currentCompaction(): PlannerCompactionMessage | undefined;
|
|
2890
3268
|
executionComplete(plan: LegacyPlanState | null): void;
|
|
2891
3269
|
/** `turnId`: the planner turn whose commit this is, when one is. */
|
|
2892
3270
|
planGenerated(plan: LegacyPlanState | null, goal: string, turnId?: string): void;
|
|
@@ -2912,6 +3290,22 @@ declare function listTaskLogAttempts(location: TaskLogLocation, taskId: string):
|
|
|
2912
3290
|
* ever overwritten.
|
|
2913
3291
|
*/
|
|
2914
3292
|
declare function openTaskLog(location: TaskLogLocation, taskId: string, attempt?: number): TaskLogFile;
|
|
3293
|
+
/**
|
|
3294
|
+
* Where a script task attempt's whole output goes, with its directory ready.
|
|
3295
|
+
* The caller writes the file; it is named for the attempt's number so it sits
|
|
3296
|
+
* beside the log, and is no attempt of its own.
|
|
3297
|
+
*/
|
|
3298
|
+
declare function prepareTaskOutputFile(location: TaskLogLocation, taskId: string, attempt: number): string;
|
|
3299
|
+
/** Where a read-only attempt's saved patch is kept, beside its log (ADR-0050). */
|
|
3300
|
+
declare function taskPatchFile(location: TaskLogLocation, taskId: string, attempt: number): string;
|
|
3301
|
+
/**
|
|
3302
|
+
* Keep a read-only attempt's patch beside its log, in place of one it saved
|
|
3303
|
+
* before (ADR-0050). Written whole under another name first, so a reader
|
|
3304
|
+
* never finds half a patch. Returns where it is.
|
|
3305
|
+
*/
|
|
3306
|
+
declare function saveTaskPatch(location: TaskLogLocation, taskId: string, attempt: number, patch: Buffer): string;
|
|
3307
|
+
/** A saved patch, or undefined when that attempt kept none. */
|
|
3308
|
+
declare function readTaskPatch(location: TaskLogLocation, taskId: string, attempt: number): Buffer | undefined;
|
|
2915
3309
|
/**
|
|
2916
3310
|
* One attempt's events, in order; empty when it has no log. A line that does
|
|
2917
3311
|
* not parse is skipped — the last one, most likely, cut off by a crash
|
|
@@ -2949,12 +3343,27 @@ declare class TaskLogRecorder {
|
|
|
2949
3343
|
* An entry the session did not emit, written into the log of the attempt
|
|
2950
3344
|
* that runs `sessionId` and sent at once: what Ordewell made of one of its
|
|
2951
3345
|
* events once that settled. Dropped once the task's next attempt started.
|
|
3346
|
+
* With no session — a user task's completion has none — the entry opens an
|
|
3347
|
+
* attempt log of its own, so a reader of the task's logs finds it like any other.
|
|
2952
3348
|
*/
|
|
2953
|
-
note(sessionId: string, taskId: string, entry: TaskLogEvent): void;
|
|
3349
|
+
note(sessionId: string | undefined, taskId: string, entry: TaskLogEvent): void;
|
|
3350
|
+
private writeAlone;
|
|
2954
3351
|
/** Start a new attempt's log for `session`, opening with the skills it was given, and keep it until the session exits. */
|
|
2955
3352
|
record(taskId: string, session: IRunnerSession, skills?: readonly TaskSkillSnapshot[], attemptNumber?: number): void;
|
|
2956
3353
|
}
|
|
2957
3354
|
|
|
3355
|
+
/**
|
|
3356
|
+
* How a surface's direct edit is admitted. The task card offers its editors
|
|
3357
|
+
* only on a task that has not started, so its edit must not land on one the
|
|
3358
|
+
* scheduler claimed while discovery or the skill check was still running.
|
|
3359
|
+
* Other direct callers (the TUI, the API, the runner's own model switch) keep
|
|
3360
|
+
* the wider direct-edit contract and pass nothing.
|
|
3361
|
+
*/
|
|
3362
|
+
interface TaskEditOptions {
|
|
3363
|
+
/** Refuse the edit once the task is live or its status has left the unstarted set. */
|
|
3364
|
+
requireUnstarted?: boolean;
|
|
3365
|
+
}
|
|
3366
|
+
|
|
2958
3367
|
/**
|
|
2959
3368
|
* Options for plan generation. Progress is not overridable: every planner
|
|
2960
3369
|
* progress event is translated to a SessionMessage inside the Session and
|
|
@@ -2970,8 +3379,10 @@ interface SessionRuntimeSettings {
|
|
|
2970
3379
|
modelAllowlist?: Record<string, string[]>;
|
|
2971
3380
|
/** Absent means the user never chose, and `config.enabledRunners` (the host's defaults) decides. */
|
|
2972
3381
|
enabledRunners?: RunnerId[];
|
|
2973
|
-
/** The user's run settings (ADR-0030); absent means every default. */
|
|
3382
|
+
/** The user's saved run settings (ADR-0030), which seed a new session; absent means every default. */
|
|
2974
3383
|
run?: GlobalRunSettings;
|
|
3384
|
+
/** Whether an API planner compacts its own context before a call that would not fit; absent means on. */
|
|
3385
|
+
plannerAutoCompaction?: boolean;
|
|
2975
3386
|
}
|
|
2976
3387
|
declare function sessionRuntimeSettings(settings: UserSettings): SessionRuntimeSettings;
|
|
2977
3388
|
/** Where a fork landed: the new session's id, and what adopting it needs. */
|
|
@@ -2997,6 +3408,8 @@ interface SessionDeps {
|
|
|
2997
3408
|
config: IConfig;
|
|
2998
3409
|
notifications: INotification;
|
|
2999
3410
|
runner: IRunner;
|
|
3411
|
+
/** What runs script tasks' bodies (ADR-0035); the real {@link ScriptRunner} unless a test supplies one. */
|
|
3412
|
+
scriptRunner?: IRunner;
|
|
3000
3413
|
registry: RunnerRegistry;
|
|
3001
3414
|
/** Resolves the workspace root for the orchestrator (lazy — VS Code can change it). */
|
|
3002
3415
|
workspaceRoot: () => string;
|
|
@@ -3008,7 +3421,11 @@ interface SessionDeps {
|
|
|
3008
3421
|
onNotice?: (notice: SessionNotice) => void;
|
|
3009
3422
|
/** Shared across sessions — sole producer of model catalogs and routing lists. */
|
|
3010
3423
|
modelResolver: ModelResolver;
|
|
3011
|
-
/**
|
|
3424
|
+
/**
|
|
3425
|
+
* Live runtime settings (enabled runners). Its run values seed a session
|
|
3426
|
+
* when it opens; a later change reaches an open session through
|
|
3427
|
+
* {@link Session.applyRunSettings}.
|
|
3428
|
+
*/
|
|
3012
3429
|
settings: () => SessionRuntimeSettings;
|
|
3013
3430
|
/**
|
|
3014
3431
|
* Host-assigned session id. When set, every persist writes under this id so
|
|
@@ -3038,10 +3455,27 @@ interface SessionDeps {
|
|
|
3038
3455
|
isolation?: IWorktreeIsolation;
|
|
3039
3456
|
/** Persistence seam. Defaults to the saved-session store under the workspace. */
|
|
3040
3457
|
saveSession?: SaveSession;
|
|
3458
|
+
/**
|
|
3459
|
+
* The host whose lease the session holds while it is open (ADR-0049).
|
|
3460
|
+
* Defaults to this process's when saves go to the session store; a session
|
|
3461
|
+
* given its own `saveSession` owns nothing on disk, so it holds no lease
|
|
3462
|
+
* unless given a host too.
|
|
3463
|
+
*/
|
|
3464
|
+
leaseHost?: LeaseHost;
|
|
3041
3465
|
/** Where a structured task's log is saved (ADR-0018, P1). Defaults to a file per attempt beside the session's. */
|
|
3042
3466
|
openTaskLog?: (location: TaskLogLocation, taskId: string, attempt?: number) => TaskLogFile;
|
|
3043
3467
|
/** The Ordewell MCP server a harness planner's tools are served from (ADR-0022). Defaults to the process's one. */
|
|
3044
3468
|
mcpServer?: OrdewellMcpServer;
|
|
3469
|
+
/**
|
|
3470
|
+
* What carries web reads (ADR-0027): the pinned transport, real DNS and the
|
|
3471
|
+
* process-wide cache and search provider unless a test fakes the network.
|
|
3472
|
+
*/
|
|
3473
|
+
web?: {
|
|
3474
|
+
transport?: WebTransport;
|
|
3475
|
+
resolveHost?: ResolveAll;
|
|
3476
|
+
cache?: WebResponseCache;
|
|
3477
|
+
searchProvider?: ISearchProvider;
|
|
3478
|
+
};
|
|
3045
3479
|
}
|
|
3046
3480
|
/**
|
|
3047
3481
|
* The composition root: builds every collaborator a Session drives and wires
|
|
@@ -3078,6 +3512,8 @@ interface SessionParts {
|
|
|
3078
3512
|
fetcher: IWebFetcher;
|
|
3079
3513
|
skillsService: Pick<SkillsService, 'findSkill' | 'listSkills' | 'searchedDirs' | 'forRoot'>;
|
|
3080
3514
|
saveSession: SaveSession;
|
|
3515
|
+
/** Its lease, told by the Session what to do when another host takes it (ADR-0049). */
|
|
3516
|
+
lease: (onLost: (held: SessionHeld) => void) => SessionLease;
|
|
3081
3517
|
/** The conversation's host is the Session itself, so only the Session can make it. */
|
|
3082
3518
|
conversation: (host: PlannerConversationHost) => PlannerConversation;
|
|
3083
3519
|
}
|
|
@@ -3094,6 +3530,7 @@ interface SessionParts {
|
|
|
3094
3530
|
* (setModels, setRunnerList, …) stay on the host; Session never emits them.
|
|
3095
3531
|
*/
|
|
3096
3532
|
declare class Session {
|
|
3533
|
+
readonly research: ResearchTasks;
|
|
3097
3534
|
private readonly backend;
|
|
3098
3535
|
private readonly usage;
|
|
3099
3536
|
private readonly windows;
|
|
@@ -3115,22 +3552,37 @@ declare class Session {
|
|
|
3115
3552
|
* supervisor has first.
|
|
3116
3553
|
*/
|
|
3117
3554
|
private sentHandoff;
|
|
3555
|
+
/** The effect allowlist rules already warned about as ignored, so each is said once, not on every script. */
|
|
3556
|
+
private readonly ignoredEffectRules;
|
|
3118
3557
|
/** The run was forgotten and no surface has been told yet; see {@link announceClosed}. */
|
|
3119
3558
|
private closedUnannounced;
|
|
3120
|
-
/** The edit the open planner turn holds, as last announced: a surface that joins mid-turn is shown it. */
|
|
3121
|
-
private sentHeld;
|
|
3122
3559
|
private readonly notifications;
|
|
3123
3560
|
private readonly onNotice?;
|
|
3124
3561
|
private readonly modelResolver;
|
|
3125
3562
|
private readonly fsAdapter;
|
|
3126
3563
|
private readonly approvals;
|
|
3564
|
+
/** What the user, and the planner for research, approved to run; kept by {@link ApprovalRecord}, saved on the plan. */
|
|
3565
|
+
private readonly record;
|
|
3566
|
+
/** Approval was withdrawn and no plan broadcast has carried it to the surfaces yet; see {@link withdrawalOwed}. */
|
|
3567
|
+
private withdrawalUnannounced;
|
|
3127
3568
|
private readonly approvalPolicy;
|
|
3128
3569
|
private readonly taskLogs;
|
|
3129
3570
|
private readonly fetcher;
|
|
3130
3571
|
private readonly settingsFn;
|
|
3572
|
+
/**
|
|
3573
|
+
* This session's copy of the user's run settings (ADR-0030), seeded when it
|
|
3574
|
+
* opens. Another session's change writes the file but does not move this one.
|
|
3575
|
+
*/
|
|
3576
|
+
private runSettingsValue;
|
|
3131
3577
|
private readonly save;
|
|
3578
|
+
/** One live host per session (ADR-0049): no save, and no run, without it. */
|
|
3579
|
+
private readonly lease;
|
|
3580
|
+
/** The host a save was refused for, so the refusal is said once rather than at every save. */
|
|
3581
|
+
private saveRefusedFor;
|
|
3132
3582
|
/** User controls in flight; see {@link withSave}. */
|
|
3133
3583
|
private controlsInFlight;
|
|
3584
|
+
/** A whole-plan start opening; a second Execute joins it rather than resetting the run under it. */
|
|
3585
|
+
private runOpening;
|
|
3134
3586
|
private unsubObserver;
|
|
3135
3587
|
private readonly hostSessionId?;
|
|
3136
3588
|
private currentSessionId;
|
|
@@ -3139,6 +3591,8 @@ declare class Session {
|
|
|
3139
3591
|
private readonly turns;
|
|
3140
3592
|
/** Destroyed: a turn that waited for the planner to be found must not open on it. */
|
|
3141
3593
|
private closed;
|
|
3594
|
+
/** Destroyed and let go of its lease for good: whatever settles later neither saves nor holds the session. */
|
|
3595
|
+
private leaseReleased;
|
|
3142
3596
|
/**
|
|
3143
3597
|
* Turns PlanTurns does not open, waiting at the planner gate, each ended
|
|
3144
3598
|
* with why it must not open: a Stop, a newer goal, or its plan scope ending.
|
|
@@ -3151,9 +3605,9 @@ declare class Session {
|
|
|
3151
3605
|
private readonly supervision;
|
|
3152
3606
|
/** The open planner turn's, or the last one's once it settled; see {@link openTurn}. */
|
|
3153
3607
|
private turnEffects;
|
|
3154
|
-
/** Every turn's effects with starts still owed: a turn's may still be running its starts when the next opens. */
|
|
3155
|
-
private readonly owingEffects;
|
|
3156
3608
|
private unlistenApprovals;
|
|
3609
|
+
/** The one check of a planner's change to the plan; an Act supervisor's edits meet its guard. */
|
|
3610
|
+
private readonly planChanges;
|
|
3157
3611
|
private readonly plannerTools;
|
|
3158
3612
|
constructor(parts: SessionParts);
|
|
3159
3613
|
/**
|
|
@@ -3162,13 +3616,7 @@ declare class Session {
|
|
|
3162
3616
|
* tools come here; see {@link ExecutionCommands}.
|
|
3163
3617
|
*/
|
|
3164
3618
|
execute(command: ExecutionCommand, actor: ExecutionActor): Promise<CommandOutcome>;
|
|
3165
|
-
|
|
3166
|
-
/**
|
|
3167
|
-
* Run one planner turn with its own {@link TurnEffects}, settled in a
|
|
3168
|
-
* `finally`: a turn that throws — stopped, failed, discarded — still
|
|
3169
|
-
* reports what it deferred as not done, rather than the next turn
|
|
3170
|
-
* silently forgetting it.
|
|
3171
|
-
*/
|
|
3619
|
+
/** Run one planner turn with its own {@link TurnEffects}, which only a turn that lands hands back. */
|
|
3172
3620
|
private openTurn;
|
|
3173
3621
|
/**
|
|
3174
3622
|
* Autorun (ADR-0030): a plan the planner submitted in the turn that just
|
|
@@ -3183,62 +3631,55 @@ declare class Session {
|
|
|
3183
3631
|
*/
|
|
3184
3632
|
private executionHost;
|
|
3185
3633
|
/**
|
|
3186
|
-
*
|
|
3187
|
-
*
|
|
3188
|
-
*
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
|
|
3196
|
-
|
|
3634
|
+
* The script task a `run_script` call would add (ADR-0035), checked as the
|
|
3635
|
+
* planner's own add is, against the plan as it stands, the turn's committed
|
|
3636
|
+
* edits included. A supervisor's is held to the oscillation guard its edits
|
|
3637
|
+
* are held to, and marked as its own.
|
|
3638
|
+
*/
|
|
3639
|
+
private draftScript;
|
|
3640
|
+
/** A drafted script task into the plan now, unapproved: the seam approves it once its start is consented to. */
|
|
3641
|
+
private addScript;
|
|
3642
|
+
/** Settles once the task's attempt is over — it ended, was stopped or left the plan — or after `ms`, or as `signal` aborts. */
|
|
3643
|
+
private awaitEnd;
|
|
3644
|
+
/** A task's result is owed to the planner (ADR-0037, R2): saved on the task, so a restart still owes it. */
|
|
3645
|
+
private oweReport;
|
|
3646
|
+
/** The end of a task's output as a report carries it: the live capture while it lasts, else the tail its verdict kept. */
|
|
3647
|
+
private reportTail;
|
|
3197
3648
|
/** The open planner turn is the supervisor's, acting at Act: its edits and added tasks are its own (ADR-0029). */
|
|
3198
3649
|
private supervisorEditing;
|
|
3199
3650
|
/**
|
|
3200
|
-
*
|
|
3201
|
-
*
|
|
3202
|
-
*
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
|
|
3206
|
-
*
|
|
3207
|
-
*
|
|
3208
|
-
* ops the turn already holds, which `ops` join; errors are numbered by `ops`.
|
|
3651
|
+
* What every planner change is checked against (`PlanChangeCheck`), as it
|
|
3652
|
+
* is submitted and as it commits: the live catalog and plan, and the
|
|
3653
|
+
* handles the open turn's committed edits gave. A change may put a task
|
|
3654
|
+
* only on the runners enabled now (`assignableRunners`), one set at both
|
|
3655
|
+
* ends, so what was accepted cannot be refused at commit unless the catalog
|
|
3656
|
+
* moved; the plan's own runners' modes are read too, for a task left on one
|
|
3657
|
+
* switched off since. `guarded`: the change meets the supervisor's
|
|
3658
|
+
* oscillation guard.
|
|
3209
3659
|
*/
|
|
3210
|
-
private
|
|
3660
|
+
private changeScope;
|
|
3211
3661
|
/** A line from Ordewell itself, kept in the transcript where it happened. */
|
|
3212
3662
|
private systemNote;
|
|
3213
3663
|
/** A message to the user in the supervisor's voice, kept in the transcript where it happened. */
|
|
3214
3664
|
private supervisorNote;
|
|
3215
3665
|
/**
|
|
3216
3666
|
* Who the open planner turn speaks for at the seam: the supervisor in a
|
|
3217
|
-
* wake-up turn, at its level as of this call, else the user's turn
|
|
3667
|
+
* wake-up turn, at its level as of this call, else the user's turn — which a
|
|
3668
|
+
* report turn for a task that turn started acts as (ADR-0037, R3).
|
|
3218
3669
|
*/
|
|
3219
3670
|
private turnActor;
|
|
3220
|
-
/**
|
|
3671
|
+
/** Whether the commits Ordewell writes carry the Planned-with trailer now; the user's setting, not the run's copy, so a change reaches the next landing. */
|
|
3672
|
+
plannedWithTrailer(): boolean;
|
|
3673
|
+
/** The run settings this session shows and starts its runs with (ADR-0030): its own copy, not the file's. */
|
|
3674
|
+
runSettings(): GlobalRunSettings;
|
|
3675
|
+
/** The user's run settings as they stand for this session (ADR-0030). */
|
|
3221
3676
|
private userRunSettings;
|
|
3222
3677
|
/** A call at the seam, in the transcript where it happened and on every surface at once. */
|
|
3223
3678
|
private recordExecution;
|
|
3224
|
-
/**
|
|
3225
|
-
* Whether the user approved this task to run (ADR-0029, ADR-0035): it was in
|
|
3226
|
-
* the plan they executed, or they started it, added it or let it start since,
|
|
3227
|
-
* and it has been in the plan ever since. The one reading of the approval
|
|
3228
|
-
* record — the seam and the scheduler both ask it.
|
|
3229
|
-
*/
|
|
3679
|
+
/** Whether the user approved this task to run; see {@link ApprovalRecord.isApproved}. */
|
|
3230
3680
|
isApproved(taskId: string): boolean;
|
|
3231
|
-
/** A task the scheduler leaves for the user to approve; see {@link waitsForApproval}. */
|
|
3681
|
+
/** A task the scheduler leaves for the user to approve; see {@link ApprovalRecord.waitsForApproval}. */
|
|
3232
3682
|
waitsForApproval(taskId: string): boolean;
|
|
3233
|
-
/** What the user approved to run (ADR-0029): a start of their own approves the task and its subtasks. */
|
|
3234
|
-
private approve;
|
|
3235
|
-
/**
|
|
3236
|
-
* A task that leaves the plan takes its approval with it, whichever route
|
|
3237
|
-
* removed it: an edit, a merge or split, a whole plan that leaves it out.
|
|
3238
|
-
* Approval is of the task the user saw, and a planner may later write a new
|
|
3239
|
-
* task under the same id (ADR-0029).
|
|
3240
|
-
*/
|
|
3241
|
-
private keepApprovals;
|
|
3242
3683
|
/**
|
|
3243
3684
|
* Answer an outstanding approval. Every surface funnels here — the web
|
|
3244
3685
|
* server's HTTP route, the VS Code webview, the TUI prompt — so the decision
|
|
@@ -3251,14 +3692,34 @@ declare class Session {
|
|
|
3251
3692
|
announcedApprovals(): Extract<SessionMessage, {
|
|
3252
3693
|
type: 'approval_request';
|
|
3253
3694
|
}>[];
|
|
3695
|
+
/**
|
|
3696
|
+
* The planner compaction in flight, as its start was announced, for a
|
|
3697
|
+
* surface that joins or reconnects while it runs; undefined when none is.
|
|
3698
|
+
*/
|
|
3699
|
+
plannerCompaction(): Extract<SessionMessage, {
|
|
3700
|
+
type: 'planner_compaction';
|
|
3701
|
+
}> | undefined;
|
|
3254
3702
|
/** Scopes the user granted this session — surfaced so a UI can show what is already allowed. */
|
|
3255
3703
|
approvedScopes(): string[];
|
|
3256
3704
|
/** The stable id this session persists under — matches the host's id when one was provided. */
|
|
3257
3705
|
get sessionId(): string;
|
|
3706
|
+
/**
|
|
3707
|
+
* The workspace whose account this session's planner gate judges, so a host
|
|
3708
|
+
* can re-probe it before a turn without keeping a second copy.
|
|
3709
|
+
*/
|
|
3710
|
+
get workspaceRoot(): string;
|
|
3711
|
+
/** The planner this session's own gate reads — not whatever the host's config says now. */
|
|
3712
|
+
get plannerProvider(): PlannerBackendId;
|
|
3258
3713
|
/** Where this session's structured task logs are saved (ADR-0018, P1). */
|
|
3259
3714
|
get taskLogLocation(): TaskLogLocation;
|
|
3260
3715
|
/** The attempts of a task that have a saved log, oldest first. */
|
|
3261
3716
|
taskLogAttempts(taskId: string): number[];
|
|
3717
|
+
/**
|
|
3718
|
+
* Mark tasks a saved plan has no attempted flag for but whose logs prove an
|
|
3719
|
+
* attempt ran. Only AI and script tasks: a manual task's completion wrote a
|
|
3720
|
+
* handoff log, which is not a chat.
|
|
3721
|
+
*/
|
|
3722
|
+
private creditLoggedAttempts;
|
|
3262
3723
|
/** One attempt's saved log, for `replayTaskLog` — what a reopened task view shows. */
|
|
3263
3724
|
taskLog(taskId: string, attempt: number): TaskLogEvent[];
|
|
3264
3725
|
get executionLog(): ReadonlyArray<TaskSnapshot>;
|
|
@@ -3286,13 +3747,32 @@ declare class Session {
|
|
|
3286
3747
|
private persist;
|
|
3287
3748
|
/** A new plan on a long-lived Session gets its own persisted identity (unless the host fixed one). */
|
|
3288
3749
|
private remintSessionId;
|
|
3750
|
+
/**
|
|
3751
|
+
* Null while this Session may save its session and run in its isolation
|
|
3752
|
+
* run; otherwise the host that holds it (ADR-0049). Claims the lease when
|
|
3753
|
+
* no live host holds it, as a new session's first save does.
|
|
3754
|
+
*/
|
|
3755
|
+
heldElsewhere(): SessionHeld | null;
|
|
3756
|
+
/**
|
|
3757
|
+
* A new plan under the host's fixed id writes that session's file: refused
|
|
3758
|
+
* before any planner turn while another host has it open (ADR-0049). A
|
|
3759
|
+
* minted id is new, and is claimed at its first save.
|
|
3760
|
+
*/
|
|
3761
|
+
private claimHostSession;
|
|
3762
|
+
private saveRefused;
|
|
3763
|
+
/**
|
|
3764
|
+
* Another host took the session over, judging this one gone (ADR-0049). Its
|
|
3765
|
+
* runners must not work on beside that host's, in the worktrees that host
|
|
3766
|
+
* now prepares, so the run here stops.
|
|
3767
|
+
*/
|
|
3768
|
+
private leaseLost;
|
|
3289
3769
|
/**
|
|
3290
3770
|
* The plan scope ends: everything that belongs to the plan this Session
|
|
3291
3771
|
* holds goes, so nothing of it reaches the next one — a new plan, another
|
|
3292
3772
|
* session adopted, or the Session closed. Its run is stopped, the planner
|
|
3293
|
-
* turn in flight is abandoned with everything it held,
|
|
3294
|
-
*
|
|
3295
|
-
*
|
|
3773
|
+
* turn in flight is abandoned with everything it held, and the
|
|
3774
|
+
* conversation, supervision, usage ledger, execution log and planner
|
|
3775
|
+
* prompts are cleared. A new plan on the same
|
|
3296
3776
|
* Session keeps the scopes the user granted (`keepGrants`); a session
|
|
3297
3777
|
* boundary does not (ADR-0008).
|
|
3298
3778
|
*/
|
|
@@ -3331,9 +3811,9 @@ declare class Session {
|
|
|
3331
3811
|
* A task is running right now. Deliberately live work, not the scheduler's
|
|
3332
3812
|
* armed flag: a run paused on a user task, a hold or a cancellation has
|
|
3333
3813
|
* nothing executing, and reporting it as executing is what left the plan
|
|
3334
|
-
* unstartable after its last live task was cancelled.
|
|
3814
|
+
* unstartable after its last live task was cancelled. See
|
|
3815
|
+
* {@link TaskOrchestrator.hasLiveWork}: a spawned runner, not merely an armed scheduler.
|
|
3335
3816
|
*/
|
|
3336
|
-
/** See {@link TaskOrchestrator.hasLiveWork} — a spawned runner, not merely an armed scheduler. */
|
|
3337
3817
|
get isExecuting(): boolean;
|
|
3338
3818
|
get status(): 'approved' | 'running' | 'completed';
|
|
3339
3819
|
/**
|
|
@@ -3365,6 +3845,11 @@ declare class Session {
|
|
|
3365
3845
|
* that read the wait as idle sent a follow-up as a new goal.
|
|
3366
3846
|
*/
|
|
3367
3847
|
get isPlannerBusy(): boolean;
|
|
3848
|
+
/**
|
|
3849
|
+
* The planner turn answering right now, if one is: a surface whose stream
|
|
3850
|
+
* lost that turn's end reads this back to tell a stale gate from a live one.
|
|
3851
|
+
*/
|
|
3852
|
+
get plannerTurnId(): string | undefined;
|
|
3368
3853
|
/**
|
|
3369
3854
|
* Stop the planner turn in flight. It still settles — a backend hands back
|
|
3370
3855
|
* what it had — and ends as stopped. A turn still waiting at the planner
|
|
@@ -3379,6 +3864,8 @@ declare class Session {
|
|
|
3379
3864
|
* answers, the enabled default is a stale guess a request must not freeze.
|
|
3380
3865
|
*/
|
|
3381
3866
|
private chosenRunners;
|
|
3867
|
+
/** Whether a first turn for `requested` would be refused for want of an enabled runner: a host calls it before it replaces a live session. */
|
|
3868
|
+
assertRunnersEnabled(requested: RunnerId[] | undefined): void;
|
|
3382
3869
|
generatePlan(goal: string, runners?: RunnerId[], options?: GeneratePlanOptions): Promise<LegacyPlanState>;
|
|
3383
3870
|
/**
|
|
3384
3871
|
* Kick off the planner conversation (ADR-0002): research + the first planner
|
|
@@ -3428,23 +3915,31 @@ declare class Session {
|
|
|
3428
3915
|
private saveFork;
|
|
3429
3916
|
/**
|
|
3430
3917
|
* Condense the conversation on the user's say-so: a hidden planner turn
|
|
3431
|
-
* summarises it, and the summary
|
|
3432
|
-
* exchanges
|
|
3918
|
+
* summarises it, and the summary stands in for everything but the last two
|
|
3919
|
+
* exchanges in the planner's context, the transcript keeping every message.
|
|
3920
|
+
* Conversation only — the tasks, and any run
|
|
3433
3921
|
* executing them, are untouched. Atomic: a failed or stopped turn changes
|
|
3434
3922
|
* nothing.
|
|
3435
3923
|
*/
|
|
3436
3924
|
compactConversation(signal?: AbortSignal): Promise<ConversationCompaction>;
|
|
3437
3925
|
rewindTargets(): RewindTarget[];
|
|
3438
|
-
/**
|
|
3926
|
+
/**
|
|
3927
|
+
* A plan the planner submitted through its tool, already checked against
|
|
3928
|
+
* the live catalog: committed now, in the turn the call was made in
|
|
3929
|
+
* (ADR-0022 P2), and answered with the tasks it holds.
|
|
3930
|
+
*/
|
|
3439
3931
|
private submitPlanFromTool;
|
|
3440
3932
|
/**
|
|
3441
|
-
* A task edit the planner made through its tool
|
|
3442
|
-
* catalog
|
|
3443
|
-
*
|
|
3444
|
-
*
|
|
3445
|
-
*
|
|
3933
|
+
* A task edit the planner made through its tool, checked against the live
|
|
3934
|
+
* catalog and committed now, in the turn the call was made in, as a batch
|
|
3935
|
+
* of its own: whole or not at all, against the plan as it stands
|
|
3936
|
+
* (ADR-0022 P2). An edit to a running or completed task is refused, with
|
|
3937
|
+
* what would be accepted. Answered with the tasks it added and the task
|
|
3938
|
+
* each handle it gave names, for a later call to read or start them by.
|
|
3446
3939
|
*/
|
|
3447
3940
|
private editPlanFromTool;
|
|
3941
|
+
/** Tasks as a planner tool's answer names them: by id and by the reference the plan gives each now. */
|
|
3942
|
+
private taskHeads;
|
|
3448
3943
|
/** Whether the planner conversation is live (started and not yet committed to a plan). */
|
|
3449
3944
|
get isConversationActive(): boolean;
|
|
3450
3945
|
/**
|
|
@@ -3464,12 +3959,10 @@ declare class Session {
|
|
|
3464
3959
|
private skillsAt;
|
|
3465
3960
|
private conversationOpening;
|
|
3466
3961
|
/**
|
|
3467
|
-
* Load planner-produced tasks,
|
|
3468
|
-
*
|
|
3469
|
-
*
|
|
3470
|
-
*
|
|
3471
|
-
* task the user cancelled would be re-armed and re-spawned by the re-tick
|
|
3472
|
-
* that follows, and a retry after the edit would run the task alone.
|
|
3962
|
+
* Load planner-produced tasks, as the check they landed through resolved
|
|
3963
|
+
* them against the catalog read live: it may have changed since planning
|
|
3964
|
+
* started. The scheduler adopts them into the run under way, or as the plan
|
|
3965
|
+
* the next run starts from (`adoptEdit`).
|
|
3473
3966
|
*
|
|
3474
3967
|
* A whole-plan commit is the planner restating every task, so it is laid
|
|
3475
3968
|
* over the plan's execution state rather than replacing it: a planner that
|
|
@@ -3478,17 +3971,20 @@ declare class Session {
|
|
|
3478
3971
|
* tasks, and `rearm`, the one op meant to change a status, must stand.
|
|
3479
3972
|
*/
|
|
3480
3973
|
private adoptPlannerTasks;
|
|
3974
|
+
private adoptResearch;
|
|
3481
3975
|
private preparePlannerTaskUpdates;
|
|
3482
3976
|
/**
|
|
3483
3977
|
* PRD mode: when the planner writes the full markdown PRD, save it to
|
|
3484
3978
|
* .scratch/<slug>/PRD.md (Matt Pocock to-prd convention) and keep it on the plan.
|
|
3485
3979
|
*/
|
|
3486
3980
|
private capturePrd;
|
|
3981
|
+
/** Merge the run settings this session owns, ignoring a field it does not know from a client's body. */
|
|
3982
|
+
private mergeRunSettings;
|
|
3487
3983
|
/**
|
|
3488
3984
|
* The user changed run settings in this session (ADR-0030), which the host
|
|
3489
3985
|
* has already saved: the run under way takes them at once, in either
|
|
3490
3986
|
* direction — the wake-up turn under way too, since the seam reads the run's
|
|
3491
|
-
* level at each call. Other sessions
|
|
3987
|
+
* level at each call. Other sessions keep the values they opened with.
|
|
3492
3988
|
*/
|
|
3493
3989
|
applyRunSettings(changes: Partial<GlobalRunSettings>): void;
|
|
3494
3990
|
private idlePlan;
|
|
@@ -3497,7 +3993,8 @@ declare class Session {
|
|
|
3497
3993
|
* Execute while a run is under way (#95): the seam has approved every task,
|
|
3498
3994
|
* as executing does, and the run takes them in. A run the scheduler was not
|
|
3499
3995
|
* driving, one task started on its own, becomes the plan's run, as Execute
|
|
3500
|
-
* would make it.
|
|
3996
|
+
* would make it. The planner's run_plan joins with `approved` 0: the
|
|
3997
|
+
* scheduler starts only approved tasks, so `left` tasks still wait.
|
|
3501
3998
|
*/
|
|
3502
3999
|
private joinRun;
|
|
3503
4000
|
private startOneTask;
|
|
@@ -3511,6 +4008,16 @@ declare class Session {
|
|
|
3511
4008
|
reschedule(): Promise<void>;
|
|
3512
4009
|
private restartTask;
|
|
3513
4010
|
private resumeTask;
|
|
4011
|
+
/**
|
|
4012
|
+
* The user's Retry compaction of a planner paused on its context (ADR-0002):
|
|
4013
|
+
* the paused turn opens again on the inputs it kept. On the live context it
|
|
4014
|
+
* condenses what it can, then sends the held input once; with the live
|
|
4015
|
+
* context gone — a reload, another provider — a turn that only read starts
|
|
4016
|
+
* again from the transcript. One whose calls changed something is refused,
|
|
4017
|
+
* the pause kept, since no note could stop an effect running twice. Settles
|
|
4018
|
+
* with the plan the turn lands, or paused again on; a Stop ends the pause.
|
|
4019
|
+
*/
|
|
4020
|
+
retryPlannerCompaction(signal?: AbortSignal): Promise<LegacyPlanState>;
|
|
3514
4021
|
/**
|
|
3515
4022
|
* Keep what waits on the planner's usage limit from being sent at the reset:
|
|
3516
4023
|
* it goes with the user's next message instead. False when nothing waits on
|
|
@@ -3612,6 +4119,13 @@ declare class Session {
|
|
|
3612
4119
|
stopExecution(): void;
|
|
3613
4120
|
/** Something will start without being asked again; see {@link TaskOrchestrator.startsPending}. */
|
|
3614
4121
|
get startsPending(): boolean;
|
|
4122
|
+
/**
|
|
4123
|
+
* What the run is doing — starting, running, scheduled, resumable, and
|
|
4124
|
+
* whether it advances on its own — for a surface or a guard that must tell a
|
|
4125
|
+
* start on its way from real execution.
|
|
4126
|
+
* See {@link TaskOrchestrator.activity}.
|
|
4127
|
+
*/
|
|
4128
|
+
get activity(): RunActivity;
|
|
3615
4129
|
/**
|
|
3616
4130
|
* Run a user control and save what it changed before any surface hears of
|
|
3617
4131
|
* it. Not a status hold, as {@link saved} is: these await spawns and git, so
|
|
@@ -3634,31 +4148,27 @@ declare class Session {
|
|
|
3634
4148
|
* reschedule they owe.
|
|
3635
4149
|
*/
|
|
3636
4150
|
private mutatePlan;
|
|
4151
|
+
/** The plan to every surface, with the approvals it holds now. */
|
|
4152
|
+
private announcePlan;
|
|
4153
|
+
/**
|
|
4154
|
+
* Approval was taken from a task, by a rule that runs wherever the tree
|
|
4155
|
+
* changes (ADR-0029). A mutation that is under way announces the plan as it
|
|
4156
|
+
* ends, and that broadcast carries this; one that is not, a load or a route
|
|
4157
|
+
* that announces nothing of the plan, is followed by one of its own as soon
|
|
4158
|
+
* as the synchronous work is done, so no surface keeps showing the task
|
|
4159
|
+
* approved.
|
|
4160
|
+
*/
|
|
4161
|
+
private withdrawalOwed;
|
|
3637
4162
|
/** Patch one task's fields, checked as the planner's task ops are; see {@link PlanEditor.updateTask}. */
|
|
3638
|
-
updateTask(taskId: string, changes: Partial<Task
|
|
4163
|
+
updateTask(taskId: string, changes: Partial<Task>, options?: TaskEditOptions): Promise<LegacyPlanState | null>;
|
|
3639
4164
|
/** Move one task onto a different runner, re-deriving what is scoped to it; see {@link PlanEditor.setTaskRunner}. */
|
|
3640
|
-
setTaskRunner(taskId: string, runner: RunnerId): Promise<LegacyPlanState | null>;
|
|
4165
|
+
setTaskRunner(taskId: string, runner: RunnerId, options?: TaskEditOptions): Promise<LegacyPlanState | null>;
|
|
3641
4166
|
/** Replace one task's dependency list, under the same guard as a field patch; see {@link PlanEditor.setTaskDependencies}. */
|
|
3642
|
-
setTaskDependencies(taskId: string, dependencies: string[]): Promise<LegacyPlanState | null>;
|
|
4167
|
+
setTaskDependencies(taskId: string, dependencies: string[], options?: TaskEditOptions): Promise<LegacyPlanState | null>;
|
|
3643
4168
|
/** Delete one task, cancelling its runner first if it runs; see {@link PlanEditor.removeTask}. */
|
|
3644
4169
|
removeTask(taskId: string): Promise<LegacyPlanState | null>;
|
|
3645
4170
|
/** Add one task, deriving what the caller left unset; see {@link PlanEditor.addTask}. */
|
|
3646
4171
|
addTask(draft: Partial<Task>): Promise<LegacyPlanState | null>;
|
|
3647
|
-
/**
|
|
3648
|
-
* Planner-driven merge: validate compatibility up front, then ask the planner
|
|
3649
|
-
* LLM to produce a single "merge" taskOps op combining the selected tasks.
|
|
3650
|
-
* Goes through the same conversation loop + validated-atomic-edit + corrective
|
|
3651
|
-
* retry flow as every other task_ops edit (ADR-0002). Throws on a
|
|
3652
|
-
* pre-flight compatibility failure so the host surfaces an inline error
|
|
3653
|
-
* before any LLM call.
|
|
3654
|
-
*/
|
|
3655
|
-
requestMerge(taskIds: string[], options?: GeneratePlanOptions): Promise<LegacyPlanState>;
|
|
3656
|
-
/**
|
|
3657
|
-
* Planner-driven split: ask the planner LLM to decompose one task into a
|
|
3658
|
-
* sequence of smaller tasks. The model generates the breakdown (no manual
|
|
3659
|
-
* per-task specs from the user). Same conversation-loop/repair path as merge.
|
|
3660
|
-
*/
|
|
3661
|
-
requestSplit(taskId: string, options?: GeneratePlanOptions): Promise<LegacyPlanState>;
|
|
3662
4172
|
loadPlan(plan: LegacyPlanState, goal: string, workspace: string, opts?: {
|
|
3663
4173
|
sessionId?: string;
|
|
3664
4174
|
persist?: boolean;
|
|
@@ -3716,6 +4226,20 @@ declare class AlreadyExecutingError extends Error {
|
|
|
3716
4226
|
constructor();
|
|
3717
4227
|
}
|
|
3718
4228
|
|
|
4229
|
+
type ParsedCommand = {
|
|
4230
|
+
ok: true;
|
|
4231
|
+
command: ExecutionCommand;
|
|
4232
|
+
} | {
|
|
4233
|
+
ok: false;
|
|
4234
|
+
message: string;
|
|
4235
|
+
};
|
|
4236
|
+
/**
|
|
4237
|
+
* An `ExecutionCommand` out of a request body, or the sentence saying what is
|
|
4238
|
+
* wrong with it. Only the command's own fields are kept, so a body cannot carry
|
|
4239
|
+
* anything the seam does not read.
|
|
4240
|
+
*/
|
|
4241
|
+
declare function parseExecutionCommand(body: unknown): ParsedCommand;
|
|
4242
|
+
|
|
3719
4243
|
/**
|
|
3720
4244
|
* Where Ordewell keeps machine-global data (settings, daemon tokens, caches,
|
|
3721
4245
|
* credentials). A single home for everything not tied to a project directory,
|
|
@@ -3730,6 +4254,9 @@ declare function globalDataDir(): string;
|
|
|
3730
4254
|
* on disk, which would otherwise permanently skip lifting anything added to
|
|
3731
4255
|
* this list later (`.env` did exactly that: real API keys stranded in the old
|
|
3732
4256
|
* dir because the settings.json move had already made the new dir exist).
|
|
4257
|
+
*
|
|
4258
|
+
* Best-effort: a home it cannot write (read-only, full disk) must not take the
|
|
4259
|
+
* CLI down before `--help`, and the old file stays where it is.
|
|
3733
4260
|
*/
|
|
3734
4261
|
declare function migrateOldConfigDir(): void;
|
|
3735
4262
|
|
|
@@ -3801,7 +4328,8 @@ declare class VerdictEngine {
|
|
|
3801
4328
|
/**
|
|
3802
4329
|
* Attach to a spawned session. The runner's `task_complete` call on the
|
|
3803
4330
|
* attempt's token is the only completion evidence (ADR-0022, V2); a session
|
|
3804
|
-
* that exits before one gets a failed verdict.
|
|
4331
|
+
* that exits before one gets a failed verdict. A script task's session has
|
|
4332
|
+
* no runner to call it: its exit status is the evidence instead (ADR-0035).
|
|
3805
4333
|
*
|
|
3806
4334
|
* Returns the attempt's generation, what {@link signalComplete} is checked against.
|
|
3807
4335
|
*/
|
|
@@ -3812,6 +4340,12 @@ declare class VerdictEngine {
|
|
|
3812
4340
|
* earlier call already settled it.
|
|
3813
4341
|
*/
|
|
3814
4342
|
signalComplete(taskId: string, generation: number, report: TaskCompleteArgs): void;
|
|
4343
|
+
/**
|
|
4344
|
+
* A script task's exit status (ADR-0035): its one evidence, as a runner's
|
|
4345
|
+
* `task_complete` call is a runner's. It settles the attempt unless that
|
|
4346
|
+
* attempt is no longer the task's current one.
|
|
4347
|
+
*/
|
|
4348
|
+
signalScriptExit(taskId: string, generation: number, exit: ScriptExit): void;
|
|
3815
4349
|
/** The runner was told something after its evidence so far, so only what it reports from here counts. */
|
|
3816
4350
|
private supersede;
|
|
3817
4351
|
private acceptVerdict;
|
|
@@ -3851,6 +4385,7 @@ declare class BufferedTaskOutputSource implements TaskOutputSource {
|
|
|
3851
4385
|
reset(): void;
|
|
3852
4386
|
finalText(taskId: string): string;
|
|
3853
4387
|
report(taskId: string): string | undefined;
|
|
4388
|
+
handoff(taskId: string): StoredHandoff | undefined;
|
|
3854
4389
|
liveTail(taskId: string, opts: LiveTailOptions): LiveTail | null;
|
|
3855
4390
|
private append;
|
|
3856
4391
|
}
|
|
@@ -3881,11 +4416,12 @@ declare abstract class AbstractRunnerSession implements IRunnerSession {
|
|
|
3881
4416
|
abstract queued(): QueuedTaskMessage[];
|
|
3882
4417
|
abstract interrupt(): Promise<void>;
|
|
3883
4418
|
abstract nativeSessionId(): string | null;
|
|
3884
|
-
abstract commands(): RunnerCommand[];
|
|
4419
|
+
abstract commands(): RunnerCommand$1[];
|
|
3885
4420
|
abstract invokeCommand(name: string, args?: string): string;
|
|
3886
4421
|
abstract answerPermission(id: string, decision: ApprovalDecision): boolean | Promise<boolean>;
|
|
3887
4422
|
abstract onTaskComplete(listener: (report: TaskCompleteArgs) => void): void;
|
|
3888
4423
|
abstract onToolCheckpoint(handler: (question: string, signal: AbortSignal) => Promise<CheckpointAnswer>): void;
|
|
4424
|
+
abstract onScriptExit(listener: (exit: ScriptExit) => void): void;
|
|
3889
4425
|
}
|
|
3890
4426
|
declare abstract class AbstractRunner<S extends IRunnerSession> implements IRunner {
|
|
3891
4427
|
protected sessions: Map<string, S>;
|
|
@@ -3912,11 +4448,17 @@ interface SessionLaunch {
|
|
|
3912
4448
|
createAdapter: (runner: string, deps: AgentProcessDeps) => TaskModeAgentAdapter;
|
|
3913
4449
|
startOptions: TaskStartOptions;
|
|
3914
4450
|
interruptGraceMs: number;
|
|
3915
|
-
/** Where this attempt's task tools are served (ADR-0022). */
|
|
4451
|
+
/** Where this attempt's task tools are served (ADR-0022), and a read-only attempt's shell and web reads (ADR-0046) and patch (ADR-0050). */
|
|
3916
4452
|
tools: {
|
|
3917
4453
|
server: OrdewellMcpServer;
|
|
3918
4454
|
scope: TaskTokenScope;
|
|
4455
|
+
shell?: TaskShell;
|
|
4456
|
+
savePatch?: (signal: AbortSignal) => Promise<McpToolReply>;
|
|
4457
|
+
webReads?: TaskWebReads;
|
|
3919
4458
|
};
|
|
4459
|
+
checkHandoff: (completion: TaskCompleteArgs) => HandoffCheck<TaskCompleteArgs>;
|
|
4460
|
+
readTask?: (args: ReadTaskArgs) => McpToolReply;
|
|
4461
|
+
applyPatch?: (args: ApplyPatchArgs) => Promise<McpToolReply>;
|
|
3920
4462
|
onNotice?: (message: string) => void;
|
|
3921
4463
|
}
|
|
3922
4464
|
/**
|
|
@@ -3974,12 +4516,14 @@ declare class StructuredSession extends AbstractRunnerSession {
|
|
|
3974
4516
|
* Start the runner with the attempt's tools attached and send the task's
|
|
3975
4517
|
* prompt as its first turn. `task_complete` is the only way a task reports
|
|
3976
4518
|
* it is done, so a runner without the tools is never sent the task: it is
|
|
3977
|
-
* killed and respawned once, and a second
|
|
4519
|
+
* killed and respawned once, and a second miss is a timeout the task holds.
|
|
3978
4520
|
*/
|
|
3979
4521
|
start(prompt: string): Promise<void>;
|
|
3980
4522
|
getOutput(): string;
|
|
3981
4523
|
onTaskComplete(listener: (report: TaskCompleteArgs) => void): void;
|
|
3982
4524
|
onToolCheckpoint(handler: (question: string, signal: AbortSignal) => Promise<CheckpointAnswer>): void;
|
|
4525
|
+
/** A runner's model reports through `task_complete`; only a script task's session ends on its exit status (ADR-0035). */
|
|
4526
|
+
onScriptExit(): void;
|
|
3983
4527
|
/**
|
|
3984
4528
|
* The runner on a fresh token, attached or respawned once (ADR-0025). Done
|
|
3985
4529
|
* once the runner reports the server connected — or once the session ended
|
|
@@ -4015,7 +4559,7 @@ declare class StructuredSession extends AbstractRunnerSession {
|
|
|
4015
4559
|
onTurnEnd(listener: (reason: StructuredTurnEnd) => void): void;
|
|
4016
4560
|
onEvent(listener: (event: StructuredEvent) => void): void;
|
|
4017
4561
|
sendMessage(text: string, from?: TaskMessageFrom): string;
|
|
4018
|
-
commands(): RunnerCommand[];
|
|
4562
|
+
commands(): RunnerCommand$1[];
|
|
4019
4563
|
invokeCommand(name: string, args?: string): string;
|
|
4020
4564
|
private enqueue;
|
|
4021
4565
|
/**
|
|
@@ -4117,25 +4661,6 @@ declare class StructuredRunner extends AbstractRunner<StructuredSession> {
|
|
|
4117
4661
|
spawn(opts: RunnerSpawnOptions): Promise<IRunnerSession>;
|
|
4118
4662
|
}
|
|
4119
4663
|
|
|
4120
|
-
/** Whether a task can be continued in its saved runner session (ADR-0018, K1), and in which. */
|
|
4121
|
-
type Continuability = {
|
|
4122
|
-
ok: true;
|
|
4123
|
-
sessionId: string;
|
|
4124
|
-
} | {
|
|
4125
|
-
ok: false;
|
|
4126
|
-
reason: string;
|
|
4127
|
-
};
|
|
4128
|
-
/**
|
|
4129
|
-
* The rule every surface offers Continue by and the orchestrator enforces: a
|
|
4130
|
-
* completed, failed or skipped task, or one paused on a usage limit, whose last
|
|
4131
|
-
* attempt left a session id behind. A conflict is resolved by its repair, not a
|
|
4132
|
-
* new turn — Retry covers it.
|
|
4133
|
-
*/
|
|
4134
|
-
declare function continuability(task: Task): Continuability;
|
|
4135
|
-
declare function canContinue(task: Task): boolean;
|
|
4136
|
-
|
|
4137
|
-
declare function stripAnsi(text: string): string;
|
|
4138
|
-
|
|
4139
4664
|
/**
|
|
4140
4665
|
* cmd.exe's command-line buffer. A longer line is truncated rather than
|
|
4141
4666
|
* rejected, which would corrupt a planner's system prompt or a task's prompt
|
|
@@ -4199,6 +4724,16 @@ declare class EmbeddedNewlineError extends Error {
|
|
|
4199
4724
|
readonly command: string;
|
|
4200
4725
|
constructor(command: string);
|
|
4201
4726
|
}
|
|
4727
|
+
/**
|
|
4728
|
+
* Thrown when only a batch shim resolved for an argument holding a double
|
|
4729
|
+
* quote. cmd.exe flips its quote state at every `"`, whether or not a backslash
|
|
4730
|
+
* precedes it, so the quote ends the quoting we added and the rest of the
|
|
4731
|
+
* argument is read as commands: `--model "x\" & calc & \"y"` runs `calc`.
|
|
4732
|
+
*/
|
|
4733
|
+
declare class BatchQuoteError extends Error {
|
|
4734
|
+
readonly command: string;
|
|
4735
|
+
constructor(command: string);
|
|
4736
|
+
}
|
|
4202
4737
|
/**
|
|
4203
4738
|
* Thrown when `command` cannot be resolved to a real file. Kept distinguishable
|
|
4204
4739
|
* from `WorkspaceNotFoundError` (utils/workspace) even though both a missing
|
|
@@ -4245,15 +4780,185 @@ declare function windowsCommandLine(file: string, args: string[]): string;
|
|
|
4245
4780
|
* a `.ps1` beside a too-long `.cmd` still raises.
|
|
4246
4781
|
*
|
|
4247
4782
|
* A line break does reorder them: cmd.exe cannot carry one at any length, so a
|
|
4248
|
-
* `.ps1` beside a `.cmd` wins, and a lone `.cmd` raises.
|
|
4783
|
+
* `.ps1` beside a `.cmd` wins, and a lone `.cmd` raises. So does a double
|
|
4784
|
+
* quote, which cmd.exe cannot carry safely.
|
|
4249
4785
|
*
|
|
4250
4786
|
* @throws {CommandLineTooLongError} when the selected route's buffer cannot
|
|
4251
4787
|
* carry the arguments.
|
|
4252
4788
|
* @throws {EmbeddedNewlineError} when the arguments span lines and only the
|
|
4253
4789
|
* batch route resolved.
|
|
4790
|
+
* @throws {BatchQuoteError} when an argument holds a double quote and only the
|
|
4791
|
+
* batch route resolved.
|
|
4254
4792
|
*/
|
|
4255
4793
|
declare function planDirectLaunch(command: string, args: string[], deps?: LaunchDeps): Promise<LaunchPlan>;
|
|
4256
4794
|
|
|
4795
|
+
/**
|
|
4796
|
+
* What runs a script task's attempt, where a runner id would name a coding
|
|
4797
|
+
* agent: no registered runner does, and no model is involved (ADR-0035).
|
|
4798
|
+
*/
|
|
4799
|
+
declare const SCRIPT_RUNNER = "script";
|
|
4800
|
+
type ScriptSpawnFn = (file: string, args: string[], options: {
|
|
4801
|
+
cwd: string;
|
|
4802
|
+
env: NodeJS.ProcessEnv;
|
|
4803
|
+
stdio: ['ignore', 'pipe', 'pipe'];
|
|
4804
|
+
detached: boolean;
|
|
4805
|
+
shell: boolean;
|
|
4806
|
+
windowsVerbatimArguments?: boolean;
|
|
4807
|
+
windowsHide: true;
|
|
4808
|
+
}) => ChildProcess;
|
|
4809
|
+
/** Every OS touchpoint is injectable, and production uses the defaults. */
|
|
4810
|
+
interface ScriptRunnerDeps {
|
|
4811
|
+
spawn?: ScriptSpawnFn;
|
|
4812
|
+
platform?: NodeJS.Platform;
|
|
4813
|
+
/** The PATH steps run under. Defaults to the augmented PATH a runner gets. */
|
|
4814
|
+
resolvePath?: () => Promise<string>;
|
|
4815
|
+
/** The interpreter a `script` body runs in. Defaults to the research shell (ADR-0011). */
|
|
4816
|
+
shell?: () => ResearchShell;
|
|
4817
|
+
isDirectory?: (dir: string) => boolean;
|
|
4818
|
+
/** How the launch seam looks a program up on Windows (ADR-0010); the real filesystem and environment unless set. */
|
|
4819
|
+
launch?: Pick<LaunchDeps, 'exists' | 'comSpec' | 'powerShell' | 'pathExt'>;
|
|
4820
|
+
/**
|
|
4821
|
+
* Where an attempt's whole output is streamed, beside its task log: the log
|
|
4822
|
+
* keeps only the ends of a long output, and a failure is often in the
|
|
4823
|
+
* middle. Prepares the file's directory and returns its path; none is kept
|
|
4824
|
+
* without it.
|
|
4825
|
+
*/
|
|
4826
|
+
fullOutputFile?: (taskId: string, attempt: number) => string;
|
|
4827
|
+
/** The most characters that file keeps; the {@link FULL_OUTPUT_MAX_CHARS} guard unless a test sets one. */
|
|
4828
|
+
fullOutputMaxChars?: number;
|
|
4829
|
+
}
|
|
4830
|
+
interface ScriptSessionSetup {
|
|
4831
|
+
body: ScriptBody;
|
|
4832
|
+
cwd: string;
|
|
4833
|
+
env: NodeJS.ProcessEnv;
|
|
4834
|
+
spawn: ScriptSpawnFn;
|
|
4835
|
+
platform: NodeJS.Platform;
|
|
4836
|
+
launch: LaunchDeps;
|
|
4837
|
+
shell: () => ResearchShell;
|
|
4838
|
+
fullOutput?: {
|
|
4839
|
+
file: string;
|
|
4840
|
+
maxChars: number;
|
|
4841
|
+
};
|
|
4842
|
+
}
|
|
4843
|
+
/**
|
|
4844
|
+
* One attempt of a script task (ADR-0035): its body run at the workspace root
|
|
4845
|
+
* with no model. `commands` run in order with no shell, each program resolved
|
|
4846
|
+
* through the launch seam (ADR-0010), stopping at the first that fails; a
|
|
4847
|
+
* `script` runs once, in the research shell's interpreter. Each step's command,
|
|
4848
|
+
* output and exit status are its events, which are the task's log. Its end is
|
|
4849
|
+
* handed on as the attempt's evidence ({@link onScriptExit}), and only then
|
|
4850
|
+
* does the session exit.
|
|
4851
|
+
*
|
|
4852
|
+
* Every step leads its own process group, so the time limit, a stop and the
|
|
4853
|
+
* task's end reach whatever it started in that group. A process that leaves
|
|
4854
|
+
* the group (`setsid`, `setpgrp`) is out of reach of a group signal, and once
|
|
4855
|
+
* its parent exits nothing ties it to the step: holding it is the work of a
|
|
4856
|
+
* boundary around the task, a container or a lease (#97, #99), not of a signal.
|
|
4857
|
+
*/
|
|
4858
|
+
declare class ScriptSession extends AbstractRunnerSession {
|
|
4859
|
+
private readonly setup;
|
|
4860
|
+
private readonly events;
|
|
4861
|
+
private readonly endListeners;
|
|
4862
|
+
private readonly steps;
|
|
4863
|
+
private readonly children;
|
|
4864
|
+
private child;
|
|
4865
|
+
private output;
|
|
4866
|
+
private running;
|
|
4867
|
+
private stopped;
|
|
4868
|
+
private timedOut;
|
|
4869
|
+
private errorTail;
|
|
4870
|
+
private logged;
|
|
4871
|
+
private logTail;
|
|
4872
|
+
private omitted;
|
|
4873
|
+
private full;
|
|
4874
|
+
private markGone;
|
|
4875
|
+
private readonly gone;
|
|
4876
|
+
constructor(id: string, taskId: string, setup: ScriptSessionSetup);
|
|
4877
|
+
/** Whoever spawned it attaches its listeners when the spawn resolves, so the body starts a macrotask later. */
|
|
4878
|
+
begin(): void;
|
|
4879
|
+
private run;
|
|
4880
|
+
private runStep;
|
|
4881
|
+
/**
|
|
4882
|
+
* An argument vector is never joined into a shell string: on POSIX it is
|
|
4883
|
+
* exec'd as written, and on Windows the launch seam finds the program the
|
|
4884
|
+
* way CreateProcess will not. A script goes to the research shell's
|
|
4885
|
+
* interpreter, the one the planner's own commands use.
|
|
4886
|
+
*/
|
|
4887
|
+
private launchOf;
|
|
4888
|
+
private spawnStep;
|
|
4889
|
+
private expire;
|
|
4890
|
+
private print;
|
|
4891
|
+
private printError;
|
|
4892
|
+
private openFullOutput;
|
|
4893
|
+
private saveOutput;
|
|
4894
|
+
/** Resolves once the file is on disk, so a reader of the exit finds it whole. */
|
|
4895
|
+
private closeFullOutput;
|
|
4896
|
+
/** Streamed into the log until the step's head is full; past it, only a tail is kept, for {@link flushLogTail}. */
|
|
4897
|
+
private logOutput;
|
|
4898
|
+
private flushLogTail;
|
|
4899
|
+
private emit;
|
|
4900
|
+
/** Ends the step under way and every one after it; resolves once the session has exited. */
|
|
4901
|
+
stop(): Promise<void>;
|
|
4902
|
+
kill(): void;
|
|
4903
|
+
getOutput(): string;
|
|
4904
|
+
/** Nothing reads a step's input. */
|
|
4905
|
+
write(): void;
|
|
4906
|
+
turnState(): 'working' | 'idle';
|
|
4907
|
+
/** A script has no turns. */
|
|
4908
|
+
onTurnEnd(): void;
|
|
4909
|
+
onEvent(listener: (event: StructuredEvent) => void): void;
|
|
4910
|
+
sendMessage(): string;
|
|
4911
|
+
forceSend(): string;
|
|
4912
|
+
forceSendQueued(): boolean;
|
|
4913
|
+
removeQueued(): boolean;
|
|
4914
|
+
queued(): QueuedTaskMessage[];
|
|
4915
|
+
/** There is no turn to interrupt: Stop ends a script. */
|
|
4916
|
+
interrupt(): Promise<void>;
|
|
4917
|
+
nativeSessionId(): string | null;
|
|
4918
|
+
commands(): RunnerCommand$1[];
|
|
4919
|
+
invokeCommand(): string;
|
|
4920
|
+
answerPermission(): boolean;
|
|
4921
|
+
/** With no runner, nothing calls `task_complete`: the exit status is the evidence. */
|
|
4922
|
+
onTaskComplete(): void;
|
|
4923
|
+
onToolCheckpoint(): void;
|
|
4924
|
+
onScriptExit(listener: (exit: ScriptExit) => void): void;
|
|
4925
|
+
}
|
|
4926
|
+
/**
|
|
4927
|
+
* Starts script task attempts (ADR-0035), as a runner starts a coding agent's,
|
|
4928
|
+
* so the task log, the merge gate, the Merge-all exclusion and the
|
|
4929
|
+
* tracked-file check meet one the way they meet an ops task. It reads only the
|
|
4930
|
+
* spawn's `script` body, `cwd` and `env`: there is no model, mode or prompt.
|
|
4931
|
+
* The step environment is the one a runner gets — the host's, cleaned, under
|
|
4932
|
+
* the workspace's own variables (ADR-0016).
|
|
4933
|
+
*/
|
|
4934
|
+
declare class ScriptRunner extends AbstractRunner<ScriptSession> {
|
|
4935
|
+
private readonly deps;
|
|
4936
|
+
private spawned;
|
|
4937
|
+
constructor(deps?: ScriptRunnerDeps);
|
|
4938
|
+
spawn(opts: RunnerSpawnOptions): Promise<IRunnerSession>;
|
|
4939
|
+
/** An attempt with no number has no place to keep a file: a log would not know which attempt it was. */
|
|
4940
|
+
private fullOutputFor;
|
|
4941
|
+
}
|
|
4942
|
+
|
|
4943
|
+
/** Whether a task can be continued in its saved runner session (ADR-0018, K1), and in which. */
|
|
4944
|
+
type Continuability = {
|
|
4945
|
+
ok: true;
|
|
4946
|
+
sessionId: string;
|
|
4947
|
+
} | {
|
|
4948
|
+
ok: false;
|
|
4949
|
+
reason: string;
|
|
4950
|
+
};
|
|
4951
|
+
/**
|
|
4952
|
+
* The rule every surface offers Continue by and the orchestrator enforces: a
|
|
4953
|
+
* completed, failed or skipped task, or one paused on a usage limit, whose last
|
|
4954
|
+
* attempt left a session id behind. A conflict is resolved by its repair, not a
|
|
4955
|
+
* new turn — Retry covers it.
|
|
4956
|
+
*/
|
|
4957
|
+
declare function continuability(task: Task): Continuability;
|
|
4958
|
+
declare function canContinue(task: Task): boolean;
|
|
4959
|
+
|
|
4960
|
+
declare function stripAnsi(text: string): string;
|
|
4961
|
+
|
|
4257
4962
|
/**
|
|
4258
4963
|
* A workspace path that does not exist, or exists but is not a directory.
|
|
4259
4964
|
* Checked at every surface that starts a planner or spawns an agent inside
|
|
@@ -4443,6 +5148,15 @@ declare const OPENCODE_MANIFEST: RunnerManifest;
|
|
|
4443
5148
|
|
|
4444
5149
|
declare const STATE_DIR = ".ordewell";
|
|
4445
5150
|
declare function ensureDir(dir: string): void;
|
|
5151
|
+
/**
|
|
5152
|
+
* Replace `filePath` with `content` in one step. Writing in place truncates
|
|
5153
|
+
* the old bytes first, so a crash, power loss or a full disk mid-write leaves
|
|
5154
|
+
* an empty or half-written file where the last good one was — silent loss of
|
|
5155
|
+
* the only copy, for a session or a saved plan. The bytes go to a fresh temp
|
|
5156
|
+
* file beside the target and a rename swaps it in; within one directory that
|
|
5157
|
+
* is atomic, so a reader sees the old file or the new one.
|
|
5158
|
+
*/
|
|
5159
|
+
declare function writeFileAtomic(filePath: string, content: string): void;
|
|
4446
5160
|
declare function getStateDir(baseDir?: string): string;
|
|
4447
5161
|
/**
|
|
4448
5162
|
* Ignores the state directory's contents except this file and `skills/`, so a
|
|
@@ -4559,4 +5273,9 @@ declare const DEFAULT_MAX_PARALLEL = 5;
|
|
|
4559
5273
|
*/
|
|
4560
5274
|
declare function parseMaxParallel(value: unknown): number | null;
|
|
4561
5275
|
|
|
4562
|
-
|
|
5276
|
+
/** The numeric components of a version, or null when it cannot be read. */
|
|
5277
|
+
declare function parseVersion(version: string): number[] | null;
|
|
5278
|
+
/** Negative, zero or positive as `a` is older than, the same as, or newer than `b`; an unreadable version sorts oldest. */
|
|
5279
|
+
declare function compareVersions(a: string, b: string): number;
|
|
5280
|
+
|
|
5281
|
+
export { ALL_PROVIDERS, AbstractRunner, AbstractRunnerSession, AccountLimitBucket, type AccountLimitCollector, type AccountLimitListener, AccountLimitMonitor, type AccountLimitMonitorOptions, type AccountLimitReading, AccountLimitSnapshot, type Adr0013IsolationRun, type Adr0013PlanIsolation, type Adr0013TaskRecord, AgentAdapter, AgentEvent, AgentProcessDeps, AgentStartOptions, AiProvider, AlreadyExecutingError, ApprovalAnswer, ApprovalDecision, ApprovalModeSetting, ApprovalPolicy, AssignmentScope, BaseAiService, BaseConfig, BaseFileSystem, BashOptions, BatchQuoteError, BufferedTaskOutputSource, type ByPlannerBackend, CLAUDE_CODE_MANIFEST, CLI_PROVIDERS, CMD_EXE_MAX_COMMAND_LINE, CODEX_SANDBOX_DOCS, CODEX_SANDBOX_OFF_LINE, type CachedPage, type CappedRows, CheckpointAnswer, type CheckpointListener, type ClaudeAccountLimitOptions, ClaudeCodeAdapter, type CodexAccountLimitOptions, CodexAdapter, CodexSandboxAvailability, CommandLineTooLongError, CommandOutcome, type ConfiguredPlanner, ConsoleLogger, ContextCollector, type Continuability, ConversationCompaction, type ConversationFork, ConversationRequest, type ConversationRewind, ConversationTurn, DAEMON_SUBPROTOCOL, DAEMON_TOKEN_SUBPROTOCOL_PREFIX, DEFAULT_MAX_PARALLEL, type DirEntry, DiscoveredModel, DuckDuckGoSearchProvider, type EffectRules, EmbeddedNewlineError, type EnvAdmission, EnvConfig, type ExecImpl, ExecutableNotFoundError, ExecutionActor, ExecutionCommand, FindSymbolOptions, GREP_PCRE_PROBE_ARGS, GeminiService, type GitExecFn, GlobOptions, GlobalRunSettings, type GrepInvocation, GrepOptions, type GrepRegex, HARNESS_PLANNER_REASON, HandoffCheck, type HasBinFn, HttpWebFetcher, type HttpWebFetcherOptions, IAiService, IApproval, IConfig, IFileSystem, IIsolationPreview, type ILogger, INotification, IRunner, IRunnerSession, type ISearchProvider, IWorktreeIsolation, IsolationTaskStatus, IsolationView, type KillTreeDeps, type LaunchDeps, type LaunchPlan, LeaseHost, LegacyPlanState, LiveTail, LiveTailOptions, McpToolReply, ModelResolver, type ModelResolverDeps, type NativeShellLauncher, type NativeShellOffer, NoPlanError, OPENCODE_MANIFEST, ORDEWELL_SETTABLE_ENV, OpenAiService, OpenCodeAdapter, type OpenCodeGoAccountLimitOptions, OrchestratorObserver, OrchestratorOption, OrdewellMcpServer, PROVIDER_CREDENTIAL_ENV, PROVIDER_DETECT_PRIORITY, PROVIDER_LABEL, PROVIDER_PRIORITY, PROVIDER_SHORT_LABEL, type ParsedCommand, PendingApproval, PendingApprovals, type PingFetch, PlanEditError, PlanIsolation, type PlanRequest, PlanState, PlanStore, Planner, PlannerAllowlist, type PlannerBackendEntry, PlannerBackendId, type PlannerChoice, PlannerModelCandidate, type PlannerModelLookup, PlannerModelRecall, type PlannerModelSource, PlannerModelStore, type PlannerSelectionChange, type PlannerSelectionCurrent, type PlannerSelectionResult, type PlannerSelectionState, PlannerShellSandbox, PlannerToolHandler, type PlannerUsability, PlannerUsage, type PrdBlock, ProviderModelLists, type ProviderRegistration, QueuedTaskMessage, ReadFileOpts, ReadTaskArgs, ReportedWindow, type ResearchChat, ResearchLogEntry, ResearchShell, type ResearchTurn, type ResolvedChoice, type ResolvedPlanner, RewindTarget, RunActivity, RunMergeView, RunView, RunnerApprovals, RunnerAuth, RunnerAuthExec, RunnerCommand$1 as RunnerCommand, RunnerId, RunnerInstallation, type RunnerInstallationOptions, RunnerManifest, RunnerModeInfo, RunnerRegistry, RunnerSessionCost, type RunnerSpawnOptions, SCRIPT_RUNNER, SETTINGS_ENV_ALLOWLIST, SETTINGS_ENV_REFUSED, STATE_DIR, STATE_DIR_IGNORE, STOPPED_TOOL_RESULT, SYMBOL_LANGUAGES, type SaveSession, type SavedState, ScriptBody, ScriptExit, ScriptRunner, ScriptSession, type SearchHit, type SearchOutcome, type SearchPage, type SearchTransport, Session, SessionBroadcaster, type SessionDeps, SessionHeld, SessionLease, SessionMessage, SessionMeta, SessionNotFoundError, SessionNotice, type SessionPlanner, type SessionRuntimeSettings, ShellLaunch, SkillsService, type SpawnSpec, StdioAgentAdapter, StoredHandoff, StructuredEvent, StructuredRunner, type StructuredRunnerDeps, StructuredSession, StructuredTurnEnd, Task, TaskCompleteArgs, TaskControlError, type TaskEditOptions, TaskLogEvent, type TaskLogFile, type TaskLogLocation, TaskLogRecorder, type TaskLogRecorderDeps, TaskMessageFrom, TaskModeAgentAdapter, TaskOrchestrator, TaskOutputSource, TaskQueryCatalog, TaskRunnerFlags, TaskShell, TaskShellSite, TaskStartOptions, TaskTokenScope, type TokenCarriers, type ToolCall, ToolOutcome, type ToolResult, UsageRecord, UserSettings, VERSION_CHECK_NOTICE, VERSION_CHECK_URL, VerdictEngine, type VerdictListener, type VersionCheck, type VersionCheckOptions, WINDOWS_MAX_COMMAND_LINE, WebRead, WebReadDecision, type WebResponse, WebResponseCache, type WebResponseCacheOptions, type WebTransport, type WorkspaceCheckDeps, WorkspaceNotAProjectError, WorkspaceNotFoundError, type WorkspaceProjectCheckDeps, type WorktreeIsolationDeps, admitSettingsEnv, applyHeadLimit, assertWorkspaceExists, assertWorkspaceIsProject, augmentedPath, bearerHeaderValue, buildFallbackGrepArgs, buildGlobArgs, buildGrepArgs, canContinue, claudeAccountLimitCollector, clearAugmentedPathCache, clearDaemonToken, clearState, clipboardCopyCommand, codexAccountLimitCollector, codexSandboxNotice, compareVersions, configuredProviders, continuability, createIsolationPreview, createNativeShellLauncher, createSession, createTaskAdapter, createWorktreeIsolation, daemonTokenPath, defaultEnabledRunners, defaultLogger, definitionPattern, deleteSession, detectInstalledPlanner, discoverGeminiModels, effectRuleFor, ensureDir, ensurePrivateDir, ensureStateDirIgnored, extractPrdBlock, extractPresentedToken, filterFallbackByAnchoredInclude, findInstalledPlanner, formatSearchOutput, getLatestSession, getProviderMeta, getStateDir, globalDataDir, grantScopeFor, grepRegexFromProbe, idSegment, includeGlobFor, installedPlannerAnswered, installedPlannerDetected, isApiProvider, isCliProvider, isExecutableResolved, isOpenAiProvider, isPlannerBackend, isVendorModelFor, isolationViewOfPlan, killTree, languageForId, listSessions, listTaskLogAttempts, listTree, loadSession, loadSessionPlanState, loadState, looksLikeChallenge, migrateOldConfigDir, migratePlanIsolation, mintDaemonToken, mintSessionId, nativeShellInvocation, nativeShellOffer, normalizeGeminiModel, openCodeGoAccountLimitCollector, openTaskLog, parseEffectAllowlist, parseExecutionCommand, parseMaxParallel, parseSearchHits, parseVersion, planDirectLaunch, plannerBackendEntries, prefixModelId, prepareTaskOutputFile, providerForRunner, readDaemonToken, readTaskLog, readTaskPatch, recordInstalledPlanner, recordedInstalledPlanner, referencePattern, removedPluginNotice, resetInstalledPlanner, resolveProviderFromPrefix, resolveTaskRunnerFlags, resolveWithin, runnerForProvider, sanitizeSlug, savePrdMarkdown, saveSession, saveState, saveTaskPatch, selectPlanner, sessionDataDir, sessionRuntimeSettings, sharedSearchProvider, sharedWebResponseCache, startVersionCheck, stateExists, stripAnsi, stripModelPrefix, supportsTaskMode, taskPatchFile, tokenSubprotocols, tokensMatch, wellKnownBinDirs, windowsCommandLine, withPath, writeFileAtomic, writePrivateFile };
|