@ordewell/core 0.6.3 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/README.md +1 -1
  2. package/dist/{IFileSystem-DQEKyC6H.d.ts → IFileSystem-D4ADfTrX.d.ts} +1 -1
  3. package/dist/{IFileSystem-Qj2MWHn_.d.mts → IFileSystem-DgpX0BU7.d.mts} +1 -1
  4. package/dist/{ModeResolver-ByNpC0EP.d.ts → ModeResolver-BEcRAz1c.d.ts} +3 -3
  5. package/dist/{ModeResolver-rqaY_4Ex.d.mts → ModeResolver-Cv01ZDd9.d.mts} +3 -3
  6. package/dist/{Task-xqdxugt2.d.mts → Task-CoKhvBa1.d.mts} +275 -2
  7. package/dist/{Task-xqdxugt2.d.ts → Task-CoKhvBa1.d.ts} +275 -2
  8. package/dist/{chunk-M4KXBEFJ.mjs → chunk-J3YSTPCE.mjs} +41 -41
  9. package/dist/chunk-J3YSTPCE.mjs.map +1 -0
  10. package/dist/{chunk-I6U3PVHL.mjs → chunk-LSGY7AIZ.mjs} +74 -23
  11. package/dist/chunk-LSGY7AIZ.mjs.map +1 -0
  12. package/dist/{chunk-JRZPSNRO.mjs → chunk-YU4UKKKI.mjs} +1 -1
  13. package/dist/chunk-YU4UKKKI.mjs.map +1 -0
  14. package/dist/index.d.mts +250 -34
  15. package/dist/index.d.ts +250 -34
  16. package/dist/index.js +2011 -670
  17. package/dist/index.js.map +1 -1
  18. package/dist/index.mjs +1650 -365
  19. package/dist/index.mjs.map +1 -1
  20. package/dist/order-labels.d.mts +2 -1
  21. package/dist/order-labels.d.ts +2 -1
  22. package/dist/{parsing-DDZ1rUYa.d.mts → parsing-B4OCHH1_.d.mts} +24 -3
  23. package/dist/{parsing-COPG8-Ep.d.ts → parsing-DMdOq-BV.d.ts} +24 -3
  24. package/dist/parsing.d.mts +4 -3
  25. package/dist/parsing.d.ts +4 -3
  26. package/dist/parsing.js +36 -38
  27. package/dist/parsing.js.map +1 -1
  28. package/dist/parsing.mjs +2 -2
  29. package/dist/{plan-utils-Br8UAoiu.d.ts → plan-utils-BdYPRBno.d.ts} +28 -3
  30. package/dist/{plan-utils-DMgajMvd.d.mts → plan-utils-CD1Xu65s.d.mts} +28 -3
  31. package/dist/plan-utils.d.mts +4 -3
  32. package/dist/plan-utils.d.ts +4 -3
  33. package/dist/plan-utils.js +111 -58
  34. package/dist/plan-utils.js.map +1 -1
  35. package/dist/plan-utils.mjs +8 -2
  36. package/dist/testing.d.mts +11 -2
  37. package/dist/testing.d.ts +11 -2
  38. package/dist/testing.js +17 -0
  39. package/dist/testing.js.map +1 -1
  40. package/dist/testing.mjs +17 -0
  41. package/dist/testing.mjs.map +1 -1
  42. package/package.json +4 -2
  43. package/dist/chunk-I6U3PVHL.mjs.map +0 -1
  44. package/dist/chunk-JRZPSNRO.mjs.map +0 -1
  45. package/dist/chunk-M4KXBEFJ.mjs.map +0 -1
@@ -1,5 +1,6 @@
1
1
  import { ChildProcess } from 'child_process';
2
2
  import { EventEmitter } from 'events';
3
+ import { z } from 'zod/v4';
3
4
 
4
5
  /**
5
6
  * Why isolated execution is unavailable for a workspace. The orchestrator needs
@@ -914,6 +915,248 @@ interface IApproval {
914
915
  /** Denies everything. The safe default when a surface wires no approval channel. */
915
916
  declare const DENY_ALL: IApproval;
916
917
 
918
+ /**
919
+ * The tools of the Ordewell MCP server, per token role (ADR-0022), and the
920
+ * handler interfaces the session side implements to answer them.
921
+ *
922
+ * Every handler method is optional so each tool can be wired on its own; one
923
+ * left unset answers its call with a "not available" error rather than
924
+ * disappearing from `tools/list`, so the list a runner sees never depends on
925
+ * how far the wiring has got.
926
+ */
927
+ declare const taskCompleteInput: z.ZodObject<{
928
+ status: z.ZodEnum<{
929
+ failed: "failed";
930
+ blocked: "blocked";
931
+ done: "done";
932
+ }>;
933
+ summary: z.ZodString;
934
+ reason: z.ZodOptional<z.ZodString>;
935
+ }, z.core.$strip>;
936
+ declare const checkpointInput: z.ZodObject<{
937
+ question: z.ZodString;
938
+ }, z.core.$strip>;
939
+ declare const listRunnersInput: z.ZodObject<{}, z.core.$strip>;
940
+ declare const listModelsInput: z.ZodObject<{
941
+ runner: z.ZodString;
942
+ }, z.core.$strip>;
943
+ declare const submitPlanInput: z.ZodObject<{
944
+ tasks: z.ZodArray<z.ZodObject<{
945
+ id: z.ZodOptional<z.ZodString>;
946
+ order: z.ZodOptional<z.ZodNumber>;
947
+ title: z.ZodString;
948
+ description: z.ZodOptional<z.ZodString>;
949
+ type: z.ZodOptional<z.ZodEnum<{
950
+ user: "user";
951
+ ai: "ai";
952
+ }>>;
953
+ dependencies: z.ZodOptional<z.ZodArray<z.ZodString>>;
954
+ prompt: z.ZodOptional<z.ZodString>;
955
+ userSteps: z.ZodOptional<z.ZodArray<z.ZodObject<{
956
+ order: z.ZodOptional<z.ZodNumber>;
957
+ instruction: z.ZodString;
958
+ }, z.core.$loose>>>;
959
+ assignedRunner: z.ZodOptional<z.ZodString>;
960
+ assignedModel: z.ZodOptional<z.ZodObject<{
961
+ modelId: z.ZodString;
962
+ modelLabel: z.ZodOptional<z.ZodString>;
963
+ thinkingEffort: z.ZodOptional<z.ZodString>;
964
+ }, z.core.$loose>>;
965
+ taskMode: z.ZodOptional<z.ZodString>;
966
+ autonomy: z.ZodOptional<z.ZodEnum<{
967
+ AFK: "AFK";
968
+ HITL: "HITL";
969
+ }>>;
970
+ sliceType: z.ZodOptional<z.ZodEnum<{
971
+ AFK: "AFK";
972
+ HITL: "HITL";
973
+ }>>;
974
+ ops: z.ZodOptional<z.ZodBoolean>;
975
+ userStoriesCovered: z.ZodOptional<z.ZodArray<z.ZodString>>;
976
+ subtasks: z.ZodOptional<z.ZodArray<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
977
+ }, z.core.$loose>>;
978
+ }, z.core.$strip>;
979
+ declare const editPlanInput: z.ZodObject<{
980
+ ops: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
981
+ op: z.ZodLiteral<"update">;
982
+ taskId: z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>;
983
+ changes: z.ZodRecord<z.ZodString, z.ZodUnknown>;
984
+ }, z.core.$strip>, z.ZodObject<{
985
+ op: z.ZodLiteral<"add">;
986
+ task: z.ZodRecord<z.ZodString, z.ZodUnknown>;
987
+ handle: z.ZodOptional<z.ZodString>;
988
+ }, z.core.$strip>, z.ZodObject<{
989
+ op: z.ZodLiteral<"remove">;
990
+ taskId: z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>;
991
+ }, z.core.$strip>, z.ZodObject<{
992
+ op: z.ZodLiteral<"reorder">;
993
+ taskIds: z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>;
994
+ }, z.core.$strip>, z.ZodObject<{
995
+ op: z.ZodLiteral<"merge">;
996
+ taskIds: z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>;
997
+ merged: z.ZodRecord<z.ZodString, z.ZodUnknown>;
998
+ handle: z.ZodOptional<z.ZodString>;
999
+ }, z.core.$strip>, z.ZodObject<{
1000
+ op: z.ZodLiteral<"split">;
1001
+ taskId: z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>;
1002
+ parts: z.ZodArray<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
1003
+ handle: z.ZodOptional<z.ZodString>;
1004
+ }, z.core.$strip>, z.ZodObject<{
1005
+ op: z.ZodLiteral<"rearm">;
1006
+ taskId: z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>;
1007
+ changes: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
1008
+ }, z.core.$strip>]>>;
1009
+ }, z.core.$strip>;
1010
+ declare const taskQueryInput: z.ZodObject<{
1011
+ tasks: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>>;
1012
+ fields: z.ZodOptional<z.ZodArray<z.ZodEnum<{
1013
+ description: "description";
1014
+ prompt: "prompt";
1015
+ userSteps: "userSteps";
1016
+ verdict: "verdict";
1017
+ outputSummary: "outputSummary";
1018
+ userStoriesCovered: "userStoriesCovered";
1019
+ }>>>;
1020
+ catalog: z.ZodOptional<z.ZodBoolean>;
1021
+ }, z.core.$strip>;
1022
+ declare const taskOutputInput: z.ZodObject<{
1023
+ task: z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>;
1024
+ lines: z.ZodOptional<z.ZodNumber>;
1025
+ since: z.ZodOptional<z.ZodNumber>;
1026
+ }, z.core.$strip>;
1027
+ type TaskCompleteArgs = z.infer<typeof taskCompleteInput>;
1028
+ type CheckpointArgs = z.infer<typeof checkpointInput>;
1029
+ type ListRunnersArgs = z.infer<typeof listRunnersInput>;
1030
+ type ListModelsArgs = z.infer<typeof listModelsInput>;
1031
+ type SubmitPlanArgs = z.infer<typeof submitPlanInput>;
1032
+ type EditPlanArgs = z.infer<typeof editPlanInput>;
1033
+ type TaskQueryArgs = z.infer<typeof taskQueryInput>;
1034
+ type TaskOutputArgs = z.infer<typeof taskOutputInput>;
1035
+ /** What a handler answers with. `isError` marks a refusal the caller should act on. */
1036
+ interface McpToolReply {
1037
+ text: string;
1038
+ isError?: boolean;
1039
+ }
1040
+ /**
1041
+ * How a checkpoint call ended. `withdrawn` is the attempt going away under it
1042
+ * (verdict, cancel, retry, stop) or the call being refused, not a verdict on
1043
+ * the question.
1044
+ */
1045
+ type CheckpointAnswer = {
1046
+ kind: 'continue';
1047
+ } | {
1048
+ kind: 'rejected';
1049
+ reason: string;
1050
+ } | {
1051
+ kind: 'withdrawn';
1052
+ why: string;
1053
+ };
1054
+ interface McpToolContext {
1055
+ /** Aborts when the token is revoked or the caller cancels — a waiting handler must stop. */
1056
+ signal: AbortSignal;
1057
+ }
1058
+ type Run<A> = (args: A, context: McpToolContext) => Promise<McpToolReply>;
1059
+ interface TaskToolHandler {
1060
+ taskComplete?: Run<TaskCompleteArgs>;
1061
+ checkpoint?: Run<CheckpointArgs>;
1062
+ }
1063
+ interface PlannerToolHandler {
1064
+ listRunners?: Run<ListRunnersArgs>;
1065
+ listModels?: Run<ListModelsArgs>;
1066
+ submitPlan?: Run<SubmitPlanArgs>;
1067
+ editPlan?: Run<EditPlanArgs>;
1068
+ taskQuery?: Run<TaskQueryArgs>;
1069
+ taskOutput?: Run<TaskOutputArgs>;
1070
+ }
1071
+ interface McpTool<H> {
1072
+ name: string;
1073
+ description: string;
1074
+ inputSchema: {
1075
+ type: 'object';
1076
+ [key: string]: unknown;
1077
+ };
1078
+ annotations?: {
1079
+ readOnlyHint: boolean;
1080
+ };
1081
+ /** Validate `args` and hand them to the handler's method for this tool. */
1082
+ call(handler: H, args: unknown, context: McpToolContext): Promise<McpToolReply>;
1083
+ }
1084
+ declare const TASK_TOOLS: readonly McpTool<TaskToolHandler>[];
1085
+ declare const PLANNER_TOOLS: readonly McpTool<PlannerToolHandler>[];
1086
+
1087
+ /**
1088
+ * The Ordewell MCP server (ADR-0022): one loopback listener per process,
1089
+ * shared by every session in it, where the caller's token alone decides which
1090
+ * tools it sees and which session and task its calls reach.
1091
+ */
1092
+ declare const ORDEWELL_MCP_PATH = "/mcp";
1093
+ interface OrdewellMcpServerOptions {
1094
+ /** How often a call that is still waiting tells its caller so. */
1095
+ heartbeatMs?: number;
1096
+ }
1097
+ interface TaskTokenScope {
1098
+ sessionId: string;
1099
+ taskId: string;
1100
+ /** The attempt generation the token is good for; a later attempt gets a new token. */
1101
+ attempt: number;
1102
+ }
1103
+ interface PlannerTokenScope {
1104
+ sessionId: string;
1105
+ }
1106
+ /** Where a runner reaches the server and what it presents there. Never put either half in a prompt. */
1107
+ interface McpCredential {
1108
+ url: string;
1109
+ token: string;
1110
+ }
1111
+ declare class OrdewellMcpServer {
1112
+ private readonly grants;
1113
+ private http;
1114
+ private listening;
1115
+ private boundUrl;
1116
+ private boundHost;
1117
+ private readonly heartbeatMs;
1118
+ constructor(options?: OrdewellMcpServerOptions);
1119
+ /** The listener's URL, once the first token has started it. */
1120
+ get url(): string | undefined;
1121
+ issueTaskToken(scope: TaskTokenScope, handler?: TaskToolHandler): Promise<McpCredential>;
1122
+ issuePlannerToken(scope: PlannerTokenScope, handler?: PlannerToolHandler): Promise<McpCredential>;
1123
+ /** Refuse every later request carrying `token`, and abort the calls it has in flight. */
1124
+ revoke(token: string): void;
1125
+ dispose(): Promise<void>;
1126
+ private issue;
1127
+ private start;
1128
+ private handle;
1129
+ }
1130
+ /** The process's one server, which the daemon and the extension host hand to every session they build. */
1131
+ declare function sharedMcpServer(): OrdewellMcpServer;
1132
+
1133
+ /** The server's name in every runner's MCP configuration, and so in its tool names (`mcp__ordewell__*`). */
1134
+ declare const ORDEWELL_MCP_SERVER_NAME = "ordewell";
1135
+ interface McpClientConfig {
1136
+ name: typeof ORDEWELL_MCP_SERVER_NAME;
1137
+ url: string;
1138
+ headers: Record<string, string>;
1139
+ }
1140
+ /**
1141
+ * The one shape every runner adapter renders its own MCP configuration from.
1142
+ * The token travels only in `headers`: the adapter writes it to an owner-only
1143
+ * file or an environment variable, never a prompt or a process argument
1144
+ * (ADR-0022, A4/A5).
1145
+ */
1146
+ declare function mcpClientConfig(credential: McpCredential): McpClientConfig;
1147
+ /** A runner's MCP configuration on disk, and the way to take it back off. */
1148
+ interface OwnerOnlyFile {
1149
+ path: string;
1150
+ /** Delete the file. Idempotent. */
1151
+ remove(): void;
1152
+ }
1153
+ /**
1154
+ * Write a configuration that carries a token where only the user can read it,
1155
+ * for a runner that takes its MCP servers from a file (ADR-0022, A5). The
1156
+ * directory is private too, so the name cannot be raced before the mode lands.
1157
+ */
1158
+ declare function ownerOnlyConfigFile(fileName: string, contents: string): OwnerOnlyFile;
1159
+
917
1160
  /**
918
1161
  * The harness-planner transport contract (ADR-0009).
919
1162
  *
@@ -1065,6 +1308,8 @@ interface PlannerStartOptions extends AgentStartCommon {
1065
1308
  systemPrompt: string;
1066
1309
  /** Variant / reasoning effort id from that model's `variants` list. */
1067
1310
  effort?: string;
1311
+ /** The Ordewell MCP server to inject, pre-authorized (ADR-0022). Only for an adapter with {@link AgentAdapter.mcpAttached}. */
1312
+ mcp?: McpClientConfig;
1068
1313
  }
1069
1314
  /**
1070
1315
  * What a runner manifest says the task's mode and effort mean (ADR-0001),
@@ -1085,6 +1330,12 @@ interface TaskStartOptions extends AgentStartCommon {
1085
1330
  /** The task's runner mode id, as the plan names it. */
1086
1331
  mode: string;
1087
1332
  flags: TaskRunnerFlags;
1333
+ /**
1334
+ * The Ordewell MCP server and this attempt's token (ADR-0022). An adapter
1335
+ * that can inject it does, with its tools pre-approved; one that cannot
1336
+ * ignores it, and the task completes by its marker.
1337
+ */
1338
+ mcp?: McpClientConfig;
1088
1339
  }
1089
1340
  /**
1090
1341
  * The explicit start switch. Discriminated so that a read-only planner and a
@@ -1120,6 +1371,12 @@ interface AgentAdapter {
1120
1371
  nativeSessionId(): string | null;
1121
1372
  /** Kill the process and release its resources. Idempotent. */
1122
1373
  dispose(): void;
1374
+ /**
1375
+ * Whether the Ordewell MCP server passed in {@link PlannerStartOptions.mcp}
1376
+ * is connected, as the runner itself reports it (ADR-0022, S4). Absent on an
1377
+ * adapter that cannot inject the server at all.
1378
+ */
1379
+ mcpAttached?(): Promise<boolean>;
1123
1380
  }
1124
1381
  /** What an adapter adds to run a task rather than a planner (ADR-0018). */
1125
1382
  interface TaskModeAgentAdapter extends AgentAdapter {
@@ -1787,6 +2044,17 @@ interface StructuredSessionCapability {
1787
2044
  * when it is no longer open — answered, withdrawn, or never asked.
1788
2045
  */
1789
2046
  answerPermission(id: string, decision: ApprovalDecision): boolean;
2047
+ /**
2048
+ * The runner's `task_complete` calls on this attempt's token (ADR-0022):
2049
+ * completion evidence beside the marker, for `VerdictEngine` to weigh.
2050
+ */
2051
+ onTaskComplete(listener: (report: TaskCompleteArgs) => void): void;
2052
+ /**
2053
+ * Answers the runner's `checkpoint` calls (ADR-0022, V5): the call stays
2054
+ * open until the returned promise settles, and its result is the answer.
2055
+ * `signal` aborts when the caller goes away.
2056
+ */
2057
+ onToolCheckpoint(handler: (question: string, signal: AbortSignal) => Promise<CheckpointAnswer>): void;
1790
2058
  }
1791
2059
  declare function isStructuredSession(session: ITerminalSession): session is ITerminalSession & StructuredSessionCapability;
1792
2060
 
@@ -1827,6 +2095,11 @@ interface ITerminalRunner {
1827
2095
  * which is why a continue refuses one.
1828
2096
  */
1829
2097
  resumeSessionId?: string;
2098
+ /**
2099
+ * Which run of the task this is, from 1. A structured runner binds the
2100
+ * attempt's MCP token to it (ADR-0022, A2).
2101
+ */
2102
+ attempt?: number;
1830
2103
  }): Promise<ITerminalSession>;
1831
2104
  stop(sessionId: string): void;
1832
2105
  stopAll(): void;
@@ -1840,7 +2113,7 @@ interface UserStep {
1840
2113
  }
1841
2114
  /** One deterministic signal gathered while verifying a completed task. */
1842
2115
  interface VerificationCheck {
1843
- name: 'exit_code' | 'completion_marker' | 'manual';
2116
+ name: 'exit_code' | 'completion_marker' | 'task_complete' | 'manual';
1844
2117
  passed: boolean;
1845
2118
  /** A check that did not apply. Skipped checks don't affect the verdict. */
1846
2119
  skipped: boolean;
@@ -2199,4 +2472,4 @@ interface ValidationContext {
2199
2472
  type ValidationCheck = (ctx: ValidationContext) => ValidationResult;
2200
2473
  declare function warningsText(w: PlanModificationWarnings): string | null;
2201
2474
 
2202
- export { type IsolationRun as $, AbstractRunner as A, type BlockingPrompt as B, CMD_EXE_MAX_COMMAND_LINE as C, DENY_ALL as D, EmbeddedNewlineError as E, type FetchAllProviderModelsOptions as F, HeadlessSession as G, HeadlessRunner as H, type IApproval as I, type IConfig as J, type IPluginStore as K, type ITerminalRunner as L, type ITerminalSession as M, type IWorktreeIsolation as N, type IntegrationDisposal as O, type IsolationAvailability as P, type IsolationHandoff as Q, type IsolationHandoffRepo as R, type IsolationInactiveReason as S, type IsolationLandedTask as T, type IsolationLanding as U, type IsolationMergeBlock as V, type IsolationMergeBlockReason as W, type IsolationMergeResult as X, type IsolationOutcome as Y, type IsolationPruneResult as Z, type IsolationRepo as _, AbstractTerminalSession as a, type TaskModelAssignment as a$, type IsolationTaskRecord as a0, type IsolationTaskRepo as a1, type IsolationTaskStatus as a2, type IsolationView as a3, type LaunchDeps as a4, type LaunchPlan as a5, type LegacyPlanState as a6, LineBuffer as a7, type Message as a8, ModelCatalog as a9, type ResearchLogEntry as aA, type ResearchProgress as aB, type ResearchStep as aC, type ResearchStepOutcome as aD, type ResearchToolType as aE, type ResolveContext as aF, type RunnerId as aG, type RunnerInvocation as aH, type RunnerPluginManifest as aI, RunnerRegistry as aJ, type RunnerSpawnOptions as aK, type RunnerTransport as aL, type RunnerVersionProbe as aM, type StreamEvent as aN, type StreamStepEvent as aO, type StreamThinkingEvent as aP, type StructuredEvent as aQ, type StructuredSessionCapability as aR, type StructuredTurnEnd as aS, type SubagentLogEntry as aT, type SubagentOutcome as aU, type Task as aV, type TaskIsolation as aW, type TaskIsolationState as aX, type TaskMode as aY, type TaskModeAgentAdapter as aZ, TaskModeUnsupportedError as a_, type ModelShortcut as aa, ORCHESTRATOR_SHORTCUTS as ab, type OrchestratorOption as ac, type PlanIsolation as ad, type PlanModificationWarnings as ae, type PlanState as af, type PlanStatus as ag, type PlannerStartOptions as ah, type PlannerUsage as ai, type PluginCloneFn as aj, type PluginEntry as ak, type PluginFeatures as al, type PluginMode as am, type PluginModelDiscovery as an, type PluginRunnerDef as ao, type PreparedLaunch as ap, type PreparedTask as aq, type ProviderCredentialSource as ar, type ProviderModelLists as as, type ProviderModelsResult as at, type PtySize as au, type PtyWrapOptions as av, type QueuedMessage as aw, type QueuedTaskMessage as ax, type RepairEvidence as ay, type RepoGroupLayout as az, type ActiveTaskSession as b, windowsCommandLine as b$, type TaskOutputSummary as b0, type TaskRunnerFlags as b1, type TaskSnapshot as b2, type TaskStartOptions as b3, type TaskStatus as b4, type TaskTransport as b5, type TaskType as b6, type TaskWithParent as b7, type ThinkingBlock as b8, type TreeSnapshot as b9, isGranted as bA, isMeasured as bB, isReservedRunnerName as bC, isRunnerApproval as bD, isRunnerTransport as bE, isStructuredSession as bF, keepExecutionState as bG, knownModelId as bH, migrateLegacyPlan as bI, migratePlanState as bJ, migrateTask as bK, partedPromptUsage as bL, planDirectLaunch as bM, planShellLaunch as bN, plannerContextFill as bO, posixShellQuote as bP, removeTaskFromPlan as bQ, renumberTasks as bR, resolveModelShortcut as bS, resolveProvider as bT, stripAnsi as bU, toApprovalDecision as bV, toOrchestratorOptions as bW, updateTaskInPlan as bX, usageLine as bY, validateModifiedPlan as bZ, warningsText as b_, type UsageLine as ba, type UsageRecord as bb, type UsageTotals as bc, type UserPromptEntry as bd, type UserStep as be, type ValidationCheck as bf, type ValidationContext as bg, type ValidationResult as bh, type Verdict as bi, type VerificationCheck as bj, WINDOWS_MAX_COMMAND_LINE as bk, addPlannerUsage as bl, addTaskToPlan as bm, addUsage as bn, approvalScopes as bo, buildShellInvocation as bp, collectProviderCredentials as bq, createEmptyPlan as br, createTask as bs, emptyWarnings as bt, enabledRunners as bu, fetchAllProviderModels as bv, flattenTasks as bw, flattenTasksWithParents as bx, isAwaitingReason as by, isExecutableResolved as bz, type AgentAdapter as c, wrapWithPty as c0, type AgentAdapterFactory as d, type AgentEvent as e, type AgentProcessDeps as f, type AgentStartOptions as g, type AiProvider as h, type AllProviderModels as i, type ApprovalAnswer as j, type ApprovalDecision as k, type ApprovalKind as l, type ApprovalMode as m, ApprovalPolicy as n, type ApprovalPolicyOptions as o, type ApprovalRequest as p, type ApprovalSource as q, type AwaitingReason as r, type CatalogModel as s, CommandLineTooLongError as t, type ConversationMessage as u, type DiscoveredMode as v, type DiscoveredModel as w, type DiscoveryCommand as x, ExecutableNotFoundError as y, type HeadlessRunnerDeps as z };
2475
+ export { type IsolationOutcome as $, AbstractRunner as A, type BlockingPrompt as B, CMD_EXE_MAX_COMMAND_LINE as C, DENY_ALL as D, type EditPlanArgs as E, EmbeddedNewlineError as F, ExecutableNotFoundError as G, type FetchAllProviderModelsOptions as H, HeadlessRunner as I, type HeadlessRunnerDeps as J, HeadlessSession as K, type IApproval as L, type IConfig as M, type IPluginStore as N, type ITerminalRunner as O, type ITerminalSession as P, type IWorktreeIsolation as Q, type IntegrationDisposal as R, type IsolationAvailability as S, type IsolationHandoff as T, type IsolationHandoffRepo as U, type IsolationInactiveReason as V, type IsolationLandedTask as W, type IsolationLanding as X, type IsolationMergeBlock as Y, type IsolationMergeBlockReason as Z, type IsolationMergeResult as _, AbstractTerminalSession as a, type RunnerSpawnOptions as a$, type IsolationPruneResult as a0, type IsolationRepo as a1, type IsolationRun as a2, type IsolationTaskRecord as a3, type IsolationTaskRepo as a4, type IsolationTaskStatus as a5, type IsolationView as a6, type LaunchDeps as a7, type LaunchPlan as a8, type LegacyPlanState as a9, type PluginCloneFn as aA, type PluginEntry as aB, type PluginFeatures as aC, type PluginMode as aD, type PluginModelDiscovery as aE, type PluginRunnerDef as aF, type PreparedLaunch as aG, type PreparedTask as aH, type ProviderCredentialSource as aI, type ProviderModelLists as aJ, type ProviderModelsResult as aK, type PtySize as aL, type PtyWrapOptions as aM, type QueuedMessage as aN, type QueuedTaskMessage as aO, type RepairEvidence as aP, type RepoGroupLayout as aQ, type ResearchLogEntry as aR, type ResearchProgress as aS, type ResearchStep as aT, type ResearchStepOutcome as aU, type ResearchToolType as aV, type ResolveContext as aW, type RunnerId as aX, type RunnerInvocation as aY, type RunnerPluginManifest as aZ, RunnerRegistry as a_, LineBuffer as aa, type ListModelsArgs as ab, type ListRunnersArgs as ac, type McpClientConfig as ad, type McpCredential as ae, type McpTool as af, type McpToolContext as ag, type McpToolReply as ah, type Message as ai, ModelCatalog as aj, type ModelShortcut as ak, ORCHESTRATOR_SHORTCUTS as al, ORDEWELL_MCP_PATH as am, ORDEWELL_MCP_SERVER_NAME as an, type OrchestratorOption as ao, OrdewellMcpServer as ap, type OwnerOnlyFile as aq, PLANNER_TOOLS as ar, type PlanIsolation as as, type PlanModificationWarnings as at, type PlanState as au, type PlanStatus as av, type PlannerStartOptions as aw, type PlannerTokenScope as ax, type PlannerToolHandler as ay, type PlannerUsage as az, type ActiveTaskSession as b, isRunnerApproval as b$, type RunnerTransport as b0, type RunnerVersionProbe as b1, type StreamEvent as b2, type StreamStepEvent as b3, type StreamThinkingEvent as b4, type StructuredEvent as b5, type StructuredSessionCapability as b6, type StructuredTurnEnd as b7, type SubagentLogEntry as b8, type SubagentOutcome as b9, type UsageTotals as bA, type UserPromptEntry as bB, type UserStep as bC, type ValidationCheck as bD, type ValidationContext as bE, type ValidationResult as bF, type Verdict as bG, type VerificationCheck as bH, WINDOWS_MAX_COMMAND_LINE as bI, addPlannerUsage as bJ, addTaskToPlan as bK, addUsage as bL, approvalScopes as bM, buildShellInvocation as bN, collectProviderCredentials as bO, createEmptyPlan as bP, createTask as bQ, emptyWarnings as bR, enabledRunners as bS, fetchAllProviderModels as bT, flattenTasks as bU, flattenTasksWithParents as bV, isAwaitingReason as bW, isExecutableResolved as bX, isGranted as bY, isMeasured as bZ, isReservedRunnerName as b_, type SubmitPlanArgs as ba, TASK_TOOLS as bb, type Task as bc, type TaskCompleteArgs as bd, type TaskIsolation as be, type TaskIsolationState as bf, type TaskMode as bg, type TaskModeAgentAdapter as bh, TaskModeUnsupportedError as bi, type TaskModelAssignment as bj, type TaskOutputArgs as bk, type TaskOutputSummary as bl, type TaskQueryArgs as bm, type TaskRunnerFlags as bn, type TaskSnapshot as bo, type TaskStartOptions as bp, type TaskStatus as bq, type TaskTokenScope as br, type TaskToolHandler as bs, type TaskTransport as bt, type TaskType as bu, type TaskWithParent as bv, type ThinkingBlock as bw, type TreeSnapshot as bx, type UsageLine as by, type UsageRecord as bz, type AgentAdapter as c, isRunnerTransport as c0, isStructuredSession as c1, keepExecutionState as c2, knownModelId as c3, mcpClientConfig as c4, migrateLegacyPlan as c5, migratePlanState as c6, migrateTask as c7, ownerOnlyConfigFile as c8, partedPromptUsage as c9, planDirectLaunch as ca, planShellLaunch as cb, plannerContextFill as cc, posixShellQuote as cd, removeTaskFromPlan as ce, renumberTasks as cf, resolveModelShortcut as cg, resolveProvider as ch, sharedMcpServer as ci, stripAnsi as cj, toApprovalDecision as ck, toOrchestratorOptions as cl, updateTaskInPlan as cm, usageLine as cn, validateModifiedPlan as co, warningsText as cp, windowsCommandLine as cq, wrapWithPty as cr, type AgentAdapterFactory as d, type AgentEvent as e, type AgentProcessDeps as f, type AgentStartOptions as g, type AiProvider as h, type AllProviderModels as i, type ApprovalAnswer as j, type ApprovalDecision as k, type ApprovalKind as l, type ApprovalMode as m, ApprovalPolicy as n, type ApprovalPolicyOptions as o, type ApprovalRequest as p, type ApprovalSource as q, type AwaitingReason as r, type CatalogModel as s, type CheckpointAnswer as t, type CheckpointArgs as u, CommandLineTooLongError as v, type ConversationMessage as w, type DiscoveredMode as x, type DiscoveredModel as y, type DiscoveryCommand as z };
@@ -6,7 +6,7 @@ import {
6
6
  extractObjectsWithKey,
7
7
  stripModelNoise,
8
8
  stripTrailingCommas
9
- } from "./chunk-JRZPSNRO.mjs";
9
+ } from "./chunk-YU4UKKKI.mjs";
10
10
 
11
11
  // src/services/ModeResolver.ts
12
12
  function runnerModesFrom(registry, runners) {
@@ -39,13 +39,14 @@ function filteredBuildModes(modes, autonomousDefault) {
39
39
  return buildModes;
40
40
  }
41
41
  function autonomyLevelLabel(autonomous) {
42
- return autonomous ? "Full auto" : "Auto";
42
+ return autonomous ? "Full" : "Guarded";
43
43
  }
44
44
  function parseAutonomyLevel(arg) {
45
45
  switch (arg?.trim().toLowerCase()) {
46
46
  case "full":
47
47
  case "on":
48
48
  return true;
49
+ case "guarded":
49
50
  case "auto":
50
51
  case "off":
51
52
  return false;
@@ -125,25 +126,37 @@ function parsePlanObject(json, raw, runners, runnerModes, autonomousDefault = tr
125
126
  const detail = err instanceof Error ? err.message : String(err);
126
127
  throw new PlanParseError(`Plan response was not valid JSON: ${detail}`, raw);
127
128
  }
128
- if (!parsed || typeof parsed !== "object" || !Array.isArray(parsed.tasks)) {
129
- throw new PlanParseError("Invalid plan: missing tasks array", raw);
129
+ const result = validatePlanTasks(parsed, runners, runnerModes, autonomousDefault);
130
+ if (result.ok) return result.tasks;
131
+ const [first] = result.errors;
132
+ throw new PlanParseError(first.message, raw, { semantic: first.taskId !== void 0 });
133
+ }
134
+ function validatePlanTasks(obj, runners, runnerModes, autonomousDefault = true) {
135
+ const rawTasks = isRecord(obj) ? obj.tasks : void 0;
136
+ if (!Array.isArray(rawTasks)) {
137
+ return { ok: false, errors: [{ field: "tasks", message: "Invalid plan: missing tasks array" }] };
130
138
  }
131
- const rawTasks = parsed.tasks;
132
139
  if (rawTasks.length === 0) {
133
- throw new PlanParseError("Plan contained no tasks", raw);
140
+ return { ok: false, errors: [{ field: "tasks", message: "Plan contained no tasks" }] };
134
141
  }
135
- const tasks = rawTasks.map((t) => parseTask(t, runners, runnerModes, autonomousDefault));
136
- validateVerticalSliceShape(tasks, raw);
142
+ const tasks = rawTasks.map((t) => parseTask(asRecord(t), runners, runnerModes, autonomousDefault));
143
+ const errors = verticalSliceErrors(tasks);
137
144
  for (const t of tasks) {
138
145
  if (!runners.includes(t.assignedRunner)) {
139
- throw new PlanParseError(
140
- `Task "${t.title}" has invalid assignedRunner "${t.assignedRunner}". Expected one of: ${runners.join(", ")}`,
141
- raw,
142
- { semantic: true }
143
- );
146
+ errors.push({
147
+ taskId: t.id,
148
+ field: "assignedRunner",
149
+ message: `Task "${t.title}" has invalid assignedRunner "${t.assignedRunner}". Expected one of: ${runners.join(", ")}`
150
+ });
144
151
  }
145
152
  }
146
- return tasks;
153
+ return errors.length > 0 ? { ok: false, errors } : { ok: true, tasks };
154
+ }
155
+ function isRecord(value) {
156
+ return typeof value === "object" && value !== null && !Array.isArray(value);
157
+ }
158
+ function asRecord(value) {
159
+ return isRecord(value) ? value : {};
147
160
  }
148
161
  function looksLikePlanAttempt(raw) {
149
162
  const { matches, sawUnbalanced } = extractObjectsWithKey(raw, PLAN_ENVELOPE_KEY);
@@ -168,12 +181,12 @@ function parseTask(raw, runners, runnerModes, autonomousDefault = true, inherite
168
181
  // description/title — same fallback TaskOps.applyTaskOps uses for `add`, so
169
182
  // a task never silently ends up unschedulable (getReadyTasks requires prompt).
170
183
  prompt: raw.prompt ? String(raw.prompt) : description || title || void 0,
171
- userSteps: Array.isArray(raw.userSteps) ? raw.userSteps.map((s) => ({
184
+ userSteps: Array.isArray(raw.userSteps) ? raw.userSteps.map(asRecord).map((s) => ({
172
185
  order: Number(s.order ?? 0),
173
186
  instruction: String(s.instruction ?? ""),
174
187
  completed: false
175
188
  })) : void 0,
176
- subtasks: Array.isArray(raw.subtasks) ? raw.subtasks.map((s) => parseTask(s, runners, runnerModes, autonomousDefault, { sliceType, autonomy })) : [],
189
+ subtasks: Array.isArray(raw.subtasks) ? raw.subtasks.map((s) => parseTask(asRecord(s), runners, runnerModes, autonomousDefault, { sliceType, autonomy })) : [],
177
190
  assignedModel: raw.assignedModel ? {
178
191
  modelId: String(raw.assignedModel.modelId ?? ""),
179
192
  modelLabel: String(raw.assignedModel.modelLabel ?? ""),
@@ -194,42 +207,28 @@ function parseTask(raw, runners, runnerModes, autonomousDefault = true, inherite
194
207
  ops: !inherited && taskType === "ai" && raw.ops === true
195
208
  });
196
209
  }
197
- function validateVerticalSliceShape(tasks, raw, parentTitle) {
210
+ function verticalSliceErrors(tasks, parentTitle) {
198
211
  const where = (t) => parentTitle ? `subtask "${t.title}" of "${parentTitle}"` : `Task "${t.title}"`;
199
- const semantic = { semantic: true };
212
+ const errors = [];
200
213
  for (const t of tasks) {
214
+ const fail = (field, message) => errors.push({ taskId: t.id, field, message });
201
215
  if (!t.sliceType) {
202
- throw new PlanParseError(
203
- `${where(t)} is missing sliceType. Every task must specify sliceType ("AFK" or "HITL").`,
204
- raw,
205
- semantic
206
- );
216
+ fail("sliceType", `${where(t)} is missing sliceType. Every task must specify sliceType ("AFK" or "HITL").`);
207
217
  }
208
218
  if (t.type === "ai" && !t.autonomy) {
209
- throw new PlanParseError(
210
- `AI ${where(t)} is missing autonomy. Every AI task must specify autonomy ("AFK" or "HITL").`,
211
- raw,
212
- semantic
213
- );
219
+ fail("autonomy", `AI ${where(t)} is missing autonomy. Every AI task must specify autonomy ("AFK" or "HITL").`);
214
220
  }
215
221
  if (t.autonomy === "AFK" && t.userSteps && t.userSteps.length > 0) {
216
- throw new PlanParseError(
217
- `${where(t)} has autonomy "AFK" but contains userSteps. AFK tasks must not have user touchpoints.`,
218
- raw,
219
- semantic
220
- );
222
+ fail("userSteps", `${where(t)} has autonomy "AFK" but contains userSteps. AFK tasks must not have user touchpoints.`);
221
223
  }
222
- if (t.type === "user" && t.sliceType !== "HITL") {
223
- throw new PlanParseError(
224
- `User ${where(t)} has sliceType "${t.sliceType}". User tasks must have sliceType "HITL".`,
225
- raw,
226
- semantic
227
- );
224
+ if (t.type === "user" && t.sliceType && t.sliceType !== "HITL") {
225
+ fail("sliceType", `User ${where(t)} has sliceType "${t.sliceType}". User tasks must have sliceType "HITL".`);
228
226
  }
229
227
  if (t.subtasks.length > 0) {
230
- validateVerticalSliceShape(t.subtasks, raw, t.title);
228
+ errors.push(...verticalSliceErrors(t.subtasks, t.title));
231
229
  }
232
230
  }
231
+ return errors;
233
232
  }
234
233
  function checkUniqueIds(ctx) {
235
234
  const seen = /* @__PURE__ */ new Set();
@@ -407,6 +406,7 @@ export {
407
406
  buildModeGuide,
408
407
  resolveTaskMode,
409
408
  parsePlanJson,
409
+ validatePlanTasks,
410
410
  looksLikePlanAttempt,
411
411
  checkUniqueIds,
412
412
  checkNoCycles,
@@ -416,4 +416,4 @@ export {
416
416
  validatePlanModification,
417
417
  parsePartialPlan
418
418
  };
419
- //# sourceMappingURL=chunk-M4KXBEFJ.mjs.map
419
+ //# sourceMappingURL=chunk-J3YSTPCE.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/services/ModeResolver.ts","../src/services/PlanValidator.ts","../src/services/PartialPlanParser.ts"],"sourcesContent":["import type { RunnerId } from '../models/Task';\n\nexport interface RunnerModeInfo {\n id: string;\n label: string;\n description: string;\n autonomous?: boolean;\n safe?: boolean;\n}\n\n/** The slice of RunnerRegistry this module needs — structural, so nothing here depends on the plugin layer. */\nexport interface ManifestLookup {\n getManifest(runner: RunnerId): { modes?: RunnerModeInfo[] } | undefined;\n}\n\n/**\n * A runner's modes are declared only in its manifest, never through a service,\n * so every caller that needs them fuses registry and runner list by hand. This\n * is that fusion, in one place: the planner prompt, the mode pickers on each\n * surface, and the runner-change retarget all read modes the same way.\n *\n * A runner with no modes maps to `[]` rather than being dropped — callers\n * distinguish \"declares no modes\" from \"not asked about\".\n */\nexport function runnerModesFrom(registry: ManifestLookup, runners: RunnerId[]): Record<RunnerId, RunnerModeInfo[]> {\n return Object.fromEntries(runners.map((r) => [r, registry.getManifest(r)?.modes ?? []] as const));\n}\n\n/**\n * Find the mode ID a runner resolves to under the given toggle state.\n * Tag-based first (autonomous/safe); falls back to positional last non-plan\n * if no tag is present on any mode (degrades gracefully on untagged manifests).\n * Returns undefined if `modes` is empty or undefined.\n */\nexport function resolveDefaultMode(\n modes: RunnerModeInfo[] | undefined,\n autonomousDefault = true,\n): string | undefined {\n if (!modes || modes.length === 0) return undefined;\n const tag: 'autonomous' | 'safe' = autonomousDefault ? 'autonomous' : 'safe';\n const tagged = modes.find((m) => m[tag]);\n if (tagged) return tagged.id;\n for (let i = modes.length - 1; i >= 0; i--) {\n if (modes[i].id !== 'plan') return modes[i].id;\n }\n return undefined;\n}\n\nfunction isDefaultMode(m: RunnerModeInfo, autonomousDefault: boolean): boolean {\n return autonomousDefault ? !!m.autonomous : !!m.safe;\n}\n\nfunction modeConflictsWithToggle(\n mode: RunnerModeInfo,\n autonomousDefault: boolean,\n): boolean {\n if (autonomousDefault) return !!mode.safe && !mode.autonomous;\n return !!mode.autonomous && !mode.safe;\n}\n\n/**\n * Build modes compatible with the current toggle. Plan is excluded from the\n * build-mode list (it is never a default for implementation tasks). Modes\n * tagged exclusively for the OPPOSITE toggle are hidden — the LLM cannot see\n * or select them. A dual-tagged mode (both autonomous + safe) is shown under\n * either toggle.\n */\nexport function filteredBuildModes(modes: RunnerModeInfo[], autonomousDefault: boolean): RunnerModeInfo[] {\n const buildModes = modes.filter((m) => m.id !== 'plan' && !modeConflictsWithToggle(m, autonomousDefault));\n const defaultIdx = buildModes.findIndex((m) => isDefaultMode(m, autonomousDefault));\n if (defaultIdx > 0) {\n const [def] = buildModes.splice(defaultIdx, 1);\n buildModes.unshift(def);\n }\n return buildModes;\n}\n\n/** The user-facing name of the `autonomousMode` boolean's two states. */\nexport function autonomyLevelLabel(autonomous: boolean): 'Full' | 'Guarded' {\n return autonomous ? 'Full' : 'Guarded';\n}\n\n/** `full`/`guarded` name the levels; `on`/`off` and `auto` are older words for them. Null for anything else. */\nexport function parseAutonomyLevel(arg: string | undefined): boolean | null {\n switch (arg?.trim().toLowerCase()) {\n case 'full': case 'on': return true;\n case 'guarded': case 'auto': case 'off': return false;\n default: return null;\n }\n}\n\nexport function buildModeGuide(\n runnerModes: Record<RunnerId, RunnerModeInfo[]>,\n autonomousDefault = true,\n): string {\n const lines: string[] = [];\n for (const [runnerId, modes] of Object.entries(runnerModes)) {\n if (!modes || modes.length === 0) continue;\n const filtered = filteredBuildModes(modes, autonomousDefault);\n if (filtered.length === 0) continue;\n const modeStr = filtered\n .map((m) => {\n const tag = isDefaultMode(m, autonomousDefault) ? ' (DEFAULT)' : '';\n return `${m.id}${tag} (${m.description})`;\n })\n .join(', ');\n lines.push(`- ${runnerId}: ${modeStr}`);\n }\n if (lines.length === 0) return '';\n\n return [\n `Autonomy level: ${autonomyLevelLabel(autonomousDefault)}.`,\n 'AVAILABLE MODES PER RUNNER:',\n ...lines,\n '',\n 'For each AI task, use the mode marked (DEFAULT) unless the task needs a different compatible mode listed above. Avoid the \"plan\" mode (read-only) unless the user explicitly requested analysis-only.',\n ].join('\\n');\n}\n\nexport function resolveTaskMode(\n emittedMode: string | undefined,\n runnerId: RunnerId,\n runnerModes: Record<RunnerId, RunnerModeInfo[]> | undefined,\n autonomousDefault = true,\n): string {\n const rawMode = (emittedMode as string) || 'build';\n\n if (!runnerModes) return rawMode === 'plan' ? 'plan' : 'build';\n\n const modes = runnerModes[runnerId];\n\n if (!modes || modes.length === 0) return rawMode;\n\n // A missing mode is an invalid emission, not a request for legacy `build` —\n // which on Codex aliases the workspace-write sandbox, not full access.\n if (!emittedMode) return resolveDefaultMode(modes, autonomousDefault) ?? 'build';\n\n const validIds = new Set(modes.map((m) => m.id));\n\n if (rawMode === 'build' || validIds.has(rawMode)) {\n if (rawMode === 'plan' || rawMode === 'build') return rawMode;\n const modeObj = modes.find((m) => m.id === rawMode);\n if (modeObj && modeConflictsWithToggle(modeObj, autonomousDefault)) {\n const fallback = resolveDefaultMode(modes, autonomousDefault);\n return fallback ?? 'build';\n }\n return rawMode;\n }\n\n const fallback = resolveDefaultMode(modes, autonomousDefault);\n return fallback ?? 'build';\n}\n","import { Task, createTask, TaskModelAssignment, RunnerId, type ValidationContext, type ValidationResult } from '../models/Task';\nimport { extractObjectsWithKey, stripTrailingCommas, escapeControlCharsInStrings, PlanParseError, PLAN_ENVELOPE_KEY } from './JsonExtractor';\nimport { resolveTaskMode, type RunnerModeInfo } from './ModeResolver';\n\nexport function parsePlanJson(\n raw: string,\n runners: RunnerId[],\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>,\n autonomousDefault = true,\n): Task[] {\n const { matches, fallback, sawUnbalanced } = extractObjectsWithKey(raw, PLAN_ENVELOPE_KEY);\n\n // A reply can carry several tasks-keyed objects — a schema echo from the\n // prompt, an inline draft, then the real plan. The model's LAST emission is\n // its final answer, so candidates are tried back to front and the first one\n // that fully parses and validates wins.\n const candidates = matches.length > 0 ? [...matches].reverse() : [fallback.json];\n\n let lastError: PlanParseError | null = null;\n for (const json of candidates) {\n try {\n return parsePlanObject(json, raw, runners, runnerModes, autonomousDefault);\n } catch (err) {\n if (!(err instanceof PlanParseError)) throw err;\n // Prefer surfacing the error from the most plan-like candidate: the\n // last one carrying a tasks key (tried first).\n if (!lastError) lastError = err;\n }\n }\n\n // No usable tasks object anywhere, but an object ran off the end of the\n // text: the plan was almost certainly cut off mid-stream.\n if (matches.length === 0 && sawUnbalanced) {\n throw new PlanParseError(\n 'Plan response appears truncated — the model likely hit its output length limit before finishing the JSON.',\n raw,\n { truncated: true },\n );\n }\n throw lastError ?? new PlanParseError('Invalid plan: missing tasks array', raw);\n}\n\nfunction parsePlanObject(\n json: string,\n raw: string,\n runners: RunnerId[],\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>,\n autonomousDefault = true,\n): Task[] {\n const cleaned = stripTrailingCommas(escapeControlCharsInStrings(json));\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(cleaned);\n } catch (err) {\n const detail = err instanceof Error ? err.message : String(err);\n throw new PlanParseError(`Plan response was not valid JSON: ${detail}`, raw);\n }\n\n const result = validatePlanTasks(parsed, runners, runnerModes, autonomousDefault);\n if (result.ok) return result.tasks;\n const [first] = result.errors;\n // An envelope problem (no tasks array, an empty one) keeps the generic\n // re-emit; only a rule broken by a task is worth naming in the corrective.\n throw new PlanParseError(first.message, raw, { semantic: first.taskId !== undefined });\n}\n\n/** One reason a plan was refused, pinned to the task and field it is about. */\nexport interface PlanTaskError {\n /** Absent when the envelope itself is wrong rather than one of its tasks. */\n taskId?: string;\n field: string;\n message: string;\n}\n\nexport type PlanTasksResult = { ok: true; tasks: Task[] } | { ok: false; errors: PlanTaskError[] };\n\n/**\n * Every check a plan's tasks must pass, on an already-parsed `{ tasks }`\n * object — what a plan is held to whichever channel it arrived on. All\n * problems are reported, in the order the text path has always met them, so\n * the first is the one its corrective names.\n */\nexport function validatePlanTasks(\n obj: unknown,\n runners: RunnerId[],\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>,\n autonomousDefault = true,\n): PlanTasksResult {\n const rawTasks = isRecord(obj) ? obj.tasks : undefined;\n if (!Array.isArray(rawTasks)) {\n return { ok: false, errors: [{ field: 'tasks', message: 'Invalid plan: missing tasks array' }] };\n }\n if (rawTasks.length === 0) {\n return { ok: false, errors: [{ field: 'tasks', message: 'Plan contained no tasks' }] };\n }\n\n const tasks = rawTasks.map((t) => parseTask(asRecord(t), runners, runnerModes, autonomousDefault));\n\n const errors = verticalSliceErrors(tasks);\n for (const t of tasks) {\n if (!runners.includes(t.assignedRunner)) {\n errors.push({\n taskId: t.id,\n field: 'assignedRunner',\n message: `Task \"${t.title}\" has invalid assignedRunner \"${t.assignedRunner}\". Expected one of: ${runners.join(', ')}`,\n });\n }\n }\n\n return errors.length > 0 ? { ok: false, errors } : { ok: true, tasks };\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n// A non-object entry reads as an empty task, so the shape checks name it\n// instead of the parser throwing a TypeError out of the validator.\nfunction asRecord(value: unknown): Record<string, unknown> {\n return isRecord(value) ? value : {};\n}\n\n/**\n * Whether a reply that failed {@link parsePlanJson} actually LOOKED like a\n * plan attempt — a balanced tasks-keyed object, or JSON that got cut off.\n * Distinguishes \"the model tried to emit a plan and botched it\" (worth a\n * corrective retry) from prose that merely mentions `\"tasks\"` (leave alone).\n */\nexport function looksLikePlanAttempt(raw: string): boolean {\n const { matches, sawUnbalanced } = extractObjectsWithKey(raw, PLAN_ENVELOPE_KEY);\n if (matches.length > 0) return true;\n return sawUnbalanced && raw.includes(`\"${PLAN_ENVELOPE_KEY}\"`);\n}\n\n/**\n * The parent's slice classification, handed to `ai` subtasks that omit their\n * own. Budget models emit sub-steps as bare `{id, order, title, description,\n * type}` — neither prompt has ever shown a populated `subtasks` entry — and the\n * recursive slice contract then rejected the whole plan. Inheriting invents no\n * information: an `ai` sub-step of an AFK slice is AFK. Deliberately NOT a\n * blanket `'AFK'` default, which would silently strip a human gate the planner\n * intended (`sliceType` is what puts ORDEWELL_CHECKPOINT in the runner prompt,\n * and subtasks are schedulable — PlanStore.rebuild flattens them into\n * _allTasks). `type: 'user'` subtasks inherit nothing and must still declare\n * HITL themselves.\n */\ntype InheritedSlice = { sliceType?: Task['sliceType']; autonomy?: Task['autonomy'] };\n\nfunction parseTask(\n raw: Record<string, unknown>,\n runners: RunnerId[],\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>,\n autonomousDefault = true,\n inherited?: InheritedSlice,\n): Task {\n const assignedRunner = typeof raw.assignedRunner === 'string' ? raw.assignedRunner : (runners[0] ?? 'claude-code');\n const taskType = (raw.type === 'user' ? 'user' : 'ai') as Task['type'];\n const title = String(raw.title ?? '');\n const description = String(raw.description ?? '');\n // Explicit child values always win; inheritance only fills a gap, and only\n // for `ai` tasks.\n const autonomy = taskType === 'ai' && typeof raw.autonomy === 'string' && (raw.autonomy === 'AFK' || raw.autonomy === 'HITL')\n ? raw.autonomy\n : (taskType === 'ai' ? inherited?.autonomy : undefined);\n const sliceType = typeof raw.sliceType === 'string' && (raw.sliceType === 'HITL' || raw.sliceType === 'AFK')\n ? raw.sliceType\n : (taskType === 'ai' ? inherited?.sliceType : undefined);\n return createTask({\n id: String(raw.id ?? ''),\n order: Number(raw.order ?? 0),\n title,\n description,\n type: taskType,\n dependencies: Array.isArray(raw.dependencies)\n ? raw.dependencies.map(String)\n : [],\n // The planner sometimes omits `prompt` on an AI task while still filling in\n // description/title — same fallback TaskOps.applyTaskOps uses for `add`, so\n // a task never silently ends up unschedulable (getReadyTasks requires prompt).\n prompt: raw.prompt ? String(raw.prompt) : (description || title || undefined),\n userSteps: Array.isArray(raw.userSteps)\n ? raw.userSteps.map(asRecord).map((s) => ({\n order: Number(s.order ?? 0),\n instruction: String(s.instruction ?? ''),\n completed: false,\n }))\n : undefined,\n subtasks: Array.isArray(raw.subtasks)\n ? raw.subtasks.map((s: unknown) =>\n parseTask(asRecord(s), runners, runnerModes, autonomousDefault, { sliceType, autonomy }))\n : [],\n assignedModel: raw.assignedModel\n ? {\n modelId: String((raw.assignedModel as Record<string, unknown>).modelId ?? ''),\n modelLabel: String((raw.assignedModel as Record<string, unknown>).modelLabel ?? ''),\n thinkingEffort: (raw.assignedModel as Record<string, unknown>).thinkingEffort as TaskModelAssignment['thinkingEffort'],\n }\n : undefined,\n assignedRunner,\n thinkingEffort: raw.thinkingEffort ? String(raw.thinkingEffort) : undefined,\n taskMode: resolveTaskMode(\n raw.taskMode !== undefined ? String(raw.taskMode) : undefined,\n assignedRunner,\n runnerModes,\n autonomousDefault,\n ),\n autonomy,\n sliceType,\n userStoriesCovered: Array.isArray(raw.userStoriesCovered)\n ? raw.userStoriesCovered.map(String)\n : undefined,\n // A subtask runs with its parent, so only a top-level AI task carries it (ADR-0020).\n ops: !inherited && taskType === 'ai' && raw.ops === true,\n });\n}\n\nfunction verticalSliceErrors(tasks: Task[], parentTitle?: string): PlanTaskError[] {\n // Without this the message names a title that appears nowhere in the plan's\n // top-level `tasks` array, and neither the corrective nor a human can find\n // the offending object.\n const where = (t: Task) => (parentTitle ? `subtask \"${t.title}\" of \"${parentTitle}\"` : `Task \"${t.title}\"`);\n const errors: PlanTaskError[] = [];\n\n for (const t of tasks) {\n const fail = (field: string, message: string) => errors.push({ taskId: t.id, field, message });\n\n if (!t.sliceType) {\n fail('sliceType', `${where(t)} is missing sliceType. Every task must specify sliceType (\"AFK\" or \"HITL\").`);\n }\n\n if (t.type === 'ai' && !t.autonomy) {\n fail('autonomy', `AI ${where(t)} is missing autonomy. Every AI task must specify autonomy (\"AFK\" or \"HITL\").`);\n }\n\n if (t.autonomy === 'AFK' && t.userSteps && t.userSteps.length > 0) {\n fail('userSteps', `${where(t)} has autonomy \"AFK\" but contains userSteps. AFK tasks must not have user touchpoints.`);\n }\n\n if (t.type === 'user' && t.sliceType && t.sliceType !== 'HITL') {\n fail('sliceType', `User ${where(t)} has sliceType \"${t.sliceType}\". User tasks must have sliceType \"HITL\".`);\n }\n\n if (t.subtasks.length > 0) {\n errors.push(...verticalSliceErrors(t.subtasks, t.title));\n }\n }\n return errors;\n}\n\nexport function checkUniqueIds(ctx: ValidationContext): ValidationResult {\n const seen = new Set<string>();\n const errors: string[] = [];\n for (const t of ctx.newPending) {\n if (seen.has(t.id)) {\n errors.push(`Duplicate task ID in modified plan: ${t.id}`);\n }\n seen.add(t.id);\n }\n return { valid: errors.length === 0, errors };\n}\n\nexport function checkNoCycles(ctx: ValidationContext): ValidationResult {\n const ids = new Set(ctx.newPending.map((t) => t.id));\n const adj = new Map<string, string[]>();\n for (const t of ctx.newPending) {\n adj.set(t.id, t.dependencies.filter((d) => ids.has(d)));\n }\n\n const visited = new Set<string>();\n const inStack = new Set<string>();\n const errors: string[] = [];\n\n function dfs(node: string): boolean {\n if (inStack.has(node)) {\n errors.push(`Cycle detected in task dependencies involving task: ${node}`);\n return true;\n }\n if (visited.has(node)) return false;\n visited.add(node);\n inStack.add(node);\n for (const dep of adj.get(node) ?? []) {\n if (dfs(dep)) return true;\n }\n inStack.delete(node);\n return false;\n }\n\n for (const id of ids) {\n if (dfs(id)) break;\n }\n\n return { valid: errors.length === 0, errors };\n}\n\nexport function checkDepsResolve(ctx: ValidationContext): ValidationResult {\n const existingIds = new Set<string>();\n for (const t of ctx.executionLog) existingIds.add(t.id);\n for (const t of ctx.newPending) existingIds.add(t.id);\n\n const errors: string[] = [];\n for (const t of ctx.newPending) {\n for (const dep of t.dependencies) {\n if (!existingIds.has(dep)) {\n errors.push(`Task \"${t.title}\" depends on \"${dep}\" which is not in the execution log or pending tasks`);\n }\n }\n }\n return { valid: errors.length === 0, errors };\n}\n\nexport function checkImmutableLog(ctx: ValidationContext): ValidationResult {\n const logIds = new Map(ctx.executionLog.map((t) => [t.id, t]));\n\n const errors: string[] = [];\n\n for (const t of ctx.newPending) {\n const logEntry = logIds.get(t.id);\n if (logEntry) {\n if (logEntry.status === 'completed' && logEntry.finalized) {\n errors.push(`Task \"${t.id}\" was already completed in the execution log and cannot be re-added`);\n }\n }\n }\n\n return { valid: errors.length === 0, errors };\n}\n\nexport function checkInProgress(ctx: ValidationContext): ValidationResult {\n const oldInProgress = new Map(\n ctx.oldPending.filter((t) => t.status === 'in_progress').map((t) => [t.id, t])\n );\n const newIds = new Set(ctx.newPending.map((t) => t.id));\n const errors: string[] = [];\n\n for (const [id, oldTask] of oldInProgress) {\n if (!newIds.has(id)) {\n errors.push(`In-progress task \"${oldTask.title}\" was removed from the modified plan`);\n continue;\n }\n const newTask = ctx.newPending.find((t) => t.id === id)!;\n if (newTask.prompt !== oldTask.prompt || newTask.assignedModel?.modelId !== oldTask.assignedModel?.modelId) {\n errors.push(`In-progress task \"${oldTask.title}\" was modified in the new plan`);\n }\n const oldDeps = new Set(oldTask.dependencies);\n const newDeps = new Set(newTask.dependencies);\n if (oldDeps.size !== newDeps.size || [...oldDeps].some((d) => !newDeps.has(d))) {\n errors.push(`In-progress task \"${oldTask.title}\" had dependencies modified`);\n }\n }\n\n return { valid: errors.length === 0, errors };\n}\n\nexport function validatePlanModification(ctx: ValidationContext): ValidationResult {\n const checks = [\n checkUniqueIds,\n checkNoCycles,\n checkDepsResolve,\n checkImmutableLog,\n checkInProgress,\n ];\n const allErrors: string[] = [];\n for (const check of checks) {\n const result = check(ctx);\n allErrors.push(...result.errors);\n }\n return { valid: allErrors.length === 0, errors: allErrors };\n}\n","import { stripModelNoise } from './JsonExtractor';\n\n/** A task as seen in a still-streaming plan: its title (possibly partial) and whether its object has closed. */\nexport interface PartialPlanTask {\n title: string;\n status: 'streaming' | 'complete';\n /** Assigned model label, once it has streamed in — for the live row's chip. */\n model?: string;\n /** Task mode (\"build\"|\"plan\"), once it has streamed in — for the live row's chip. */\n mode?: string;\n}\n\n/**\n * Parse a partial (still-streaming) plan-JSON string into an ordered list of task\n * rows for the live progress view. Pure and lenient: it walks the characters of the\n * `tasks` array, emitting one row per task object once it has opened, with the title\n * read incrementally and the status flipping to `complete` when the object's brace\n * closes. The currently-streaming object stays `streaming` even with a partial title.\n * The React view is a thin renderer over this — it never parses JSON itself.\n */\nexport function parsePartialPlan(partial: string): PartialPlanTask[] {\n const text = stripModelNoise(partial);\n const arrayStart = findTasksArrayStart(text);\n if (arrayStart === -1) return [];\n\n const tasks: PartialPlanTask[] = [];\n let depth = 0; // brace depth relative to a task object (0 = between objects)\n let objText = ''; // accumulated text of the in-progress task object\n let inString = false;\n let escaped = false;\n\n for (let i = arrayStart; i < text.length; i++) {\n const ch = text[i];\n if (depth > 0) objText += ch;\n\n if (inString) {\n if (escaped) escaped = false;\n else if (ch === '\\\\') escaped = true;\n else if (ch === '\"') inString = false;\n continue;\n }\n if (ch === '\"') { inString = true; continue; }\n if (ch === ']' && depth === 0) break; // end of the tasks array\n if (ch === '{') {\n if (depth === 0) objText = '{';\n depth++;\n } else if (ch === '}') {\n depth--;\n if (depth === 0) {\n tasks.push(rowFromObject(objText, 'complete'));\n objText = '';\n }\n }\n }\n\n // A task object that opened but never closed is the row currently streaming in.\n if (depth > 0) tasks.push(rowFromObject(objText, 'streaming'));\n return tasks;\n}\n\n/** Index just after the `[` that opens the top-level `tasks` array, or -1 if not present yet. */\nfunction findTasksArrayStart(text: string): number {\n const key = /\"tasks\"\\s*:\\s*\\[/.exec(text);\n return key ? key.index + key[0].length : -1;\n}\n\n/** Build a live row from a (possibly unterminated) task-object fragment. */\nfunction rowFromObject(objText: string, status: PartialPlanTask['status']): PartialPlanTask {\n const model = stringField(objText, 'modelLabel');\n const mode = stringField(objText, 'taskMode');\n return {\n title: titleFromObject(objText),\n status,\n ...(model ? { model } : {}),\n ...(mode ? { mode } : {}),\n };\n}\n\n/** Read the `title` value out of a (possibly unterminated) task-object fragment. */\nfunction titleFromObject(objText: string): string {\n const m = /\"title\"\\s*:\\s*\"((?:[^\"\\\\]|\\\\.)*)/.exec(objText);\n if (!m) return '';\n // The captured group may include a trailing closing quote's content only up to an\n // unescaped quote; for a completed value that's the whole title, for a streaming\n // one it's whatever has arrived so far.\n return m[1].replace(/\\\\\"/g, '\"');\n}\n\n/** Read a fully-streamed (closing-quote present) string field's value, or undefined. */\nfunction stringField(objText: string, key: string): string | undefined {\n const m = new RegExp(`\"${key}\"\\\\s*:\\\\s*\"((?:[^\"\\\\\\\\]|\\\\\\\\.)*)\"`).exec(objText);\n return m ? m[1].replace(/\\\\\"/g, '\"') : undefined;\n}\n"],"mappings":"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","names":["fallback"]}