@selesai/code 0.13.12 → 0.13.14
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/CHANGELOG.md +9 -0
- package/dist/extensions/pi-subagents/CHANGELOG.md +77 -1
- package/dist/extensions/pi-subagents/VISION.md +12 -1
- package/dist/extensions/pi-subagents/docs/agents.md +13 -6
- package/dist/extensions/pi-subagents/docs/configuration.md +35 -9
- package/dist/extensions/pi-subagents/docs/extension-api.md +1 -1
- package/dist/extensions/pi-subagents/docs/missions.md +1 -1
- package/dist/extensions/pi-subagents/docs/models.md +6 -6
- package/dist/extensions/pi-subagents/docs/observability.md +6 -3
- package/dist/extensions/pi-subagents/docs/tool-reference.md +3 -3
- package/dist/extensions/pi-subagents/docs/watchdog.md +92 -114
- package/dist/extensions/pi-subagents/docs/workflows.md +1 -1
- package/dist/extensions/pi-subagents/install.mjs +1 -2
- package/dist/extensions/pi-subagents/package.json +1 -1
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/constraints-and-recipes.md +1 -1
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/execution-controls.md +6 -6
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/management-authoring-rpc.md +2 -2
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/multi-lane-orchestration.md +1 -1
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/prompting-and-roles.md +4 -4
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/review-and-validation.md +1 -1
- package/dist/extensions/pi-subagents/src/agents/agent-management.ts +41 -4
- package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +3 -0
- package/dist/extensions/pi-subagents/src/agents/agents.ts +120 -124
- package/dist/extensions/pi-subagents/src/agents/runtime-agent-registry.ts +5 -1
- package/dist/extensions/pi-subagents/src/api/preflight.ts +4 -0
- package/dist/extensions/pi-subagents/src/api/shared-types.ts +3 -0
- package/dist/extensions/pi-subagents/src/extension/config.ts +20 -0
- package/dist/extensions/pi-subagents/src/extension/public-execution.ts +1 -0
- package/dist/extensions/pi-subagents/src/extension/schemas.ts +6 -2
- package/dist/extensions/pi-subagents/src/extension/tool-description.ts +1 -1
- package/dist/extensions/pi-subagents/src/inspectors/herdr/inspector-runner.ts +19 -13
- package/dist/extensions/pi-subagents/src/runs/background/active-async-capacity.ts +26 -8
- package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +103 -23
- package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +6 -2
- package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +18 -2
- package/dist/extensions/pi-subagents/src/runs/background/notify.ts +54 -3
- package/dist/extensions/pi-subagents/src/runs/background/process-terminal.ts +16 -0
- package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +22 -2
- package/dist/extensions/pi-subagents/src/runs/background/scheduled-runs.ts +63 -6
- package/dist/extensions/pi-subagents/src/runs/background/steering.ts +4 -1
- package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +69 -12
- package/dist/extensions/pi-subagents/src/runs/background/wait-completions.ts +13 -0
- package/dist/extensions/pi-subagents/src/runs/background/wait-tool.ts +3 -1
- package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +21 -8
- package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +59 -6
- package/dist/extensions/pi-subagents/src/runs/shared/acceptance.ts +95 -18
- package/dist/extensions/pi-subagents/src/runs/shared/async-status-projection.ts +11 -43
- package/dist/extensions/pi-subagents/src/runs/shared/capability-ceiling.ts +1 -0
- package/dist/extensions/pi-subagents/src/runs/shared/dynamic-fanout.ts +1 -1
- package/dist/extensions/pi-subagents/src/runs/shared/lane-metadata.ts +24 -3
- package/dist/extensions/pi-subagents/src/runs/shared/parallel-handoff.ts +4 -0
- package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +2 -6
- package/dist/extensions/pi-subagents/src/runs/shared/permissions.ts +1 -0
- package/dist/extensions/pi-subagents/src/runs/shared/pi-args.ts +33 -18
- package/dist/extensions/pi-subagents/src/runs/shared/pi-spawn.ts +73 -37
- package/dist/extensions/pi-subagents/src/runs/shared/structured-output.ts +33 -6
- package/dist/extensions/pi-subagents/src/runs/shared/subagent-control.ts +4 -2
- package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +20 -3
- package/dist/extensions/pi-subagents/src/runs/shared/task-intent.ts +21 -7
- package/dist/extensions/pi-subagents/src/runs/shared/tool-timeout.ts +1 -1
- package/dist/extensions/pi-subagents/src/runs/shared/worktree.ts +467 -63
- package/dist/extensions/pi-subagents/src/shared/atomic-json.ts +3 -1
- package/dist/extensions/pi-subagents/src/shared/fork-context.ts +0 -12
- package/dist/extensions/pi-subagents/src/shared/fork-session-cwd.ts +27 -0
- package/dist/extensions/pi-subagents/src/shared/launch-contract.ts +3 -0
- package/dist/extensions/pi-subagents/src/shared/types.ts +42 -4
- package/dist/extensions/pi-subagents/src/shared/utils.ts +18 -7
- package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +1 -1
- package/dist/extensions/pi-subagents/src/slash/subagents-admin.ts +26 -12
- package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +61 -2
- package/dist/extensions/pi-subagents/src/tui/fleet.ts +12 -7
- package/dist/extensions/pi-subagents/src/tui/render.ts +227 -14
- package/dist/extensions/pi-subagents/src/watchdog/child-status.ts +56 -34
- package/dist/extensions/pi-subagents/src/watchdog/diff-tool.ts +77 -0
- package/dist/extensions/pi-subagents/src/watchdog/emission-guard.ts +5 -3
- package/dist/extensions/pi-subagents/src/watchdog/guidance.ts +20 -0
- package/dist/extensions/pi-subagents/src/watchdog/register-child.ts +16 -13
- package/dist/extensions/pi-subagents/src/watchdog/register-main.ts +10 -9
- package/dist/extensions/pi-subagents/src/watchdog/render.ts +4 -5
- package/dist/extensions/pi-subagents/src/watchdog/review.ts +15 -4
- package/dist/extensions/pi-subagents/src/watchdog/rules.ts +70 -0
- package/dist/extensions/pi-subagents/src/watchdog/runtime.ts +75 -92
- package/dist/extensions/pi-subagents/src/watchdog/scope.ts +2 -1
- package/dist/extensions/pi-subagents/src/watchdog/settings.ts +48 -104
- package/dist/extensions/pi-subagents/src/watchdog/types.ts +18 -32
- package/dist/extensions/pi-subagents/src/watchdog/warning-format.ts +0 -1
- package/dist/extensions/pi-subagents/src/workflows/chat-progress.ts +3 -2
- package/dist/extensions/pi-subagents/src/workflows/workflow-checklist.ts +439 -0
- package/dist/extensions/pi-subagents/src/workflows/workflow-preflight.ts +28 -1
- package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +335 -21
- package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +4 -1
- package/dist/extensions/pi-subagents/test/integration/async-status.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/integration/fork-context-execution.test.ts +22 -18
- package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +0 -1
- package/dist/extensions/pi-subagents/test/integration/render-widget.test.ts +21 -18
- package/dist/extensions/pi-subagents/test/integration/single-execution.test.ts +307 -22
- package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +1 -0
- package/dist/extensions/pi-subagents/test/support/helpers.ts +25 -0
- package/dist/extensions/pi-subagents/test/support/isolated-temp-root.mjs +15 -4
- package/dist/extensions/pi-subagents/test/support/mock-pi-script.mjs +17 -2
- package/dist/extensions/pi-subagents/test/unit/acceptance.test.ts +96 -15
- package/dist/extensions/pi-subagents/test/unit/active-async-capacity.test.ts +53 -5
- package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +20 -0
- package/dist/extensions/pi-subagents/test/unit/agent-management.test.ts +221 -8
- package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +45 -24
- package/dist/extensions/pi-subagents/test/unit/agent-scan-dirs.test.ts +133 -0
- package/dist/extensions/pi-subagents/test/unit/async-execution.test.ts +28 -2
- package/dist/extensions/pi-subagents/test/unit/async-interrupt-action.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/async-resume.test.ts +2 -0
- package/dist/extensions/pi-subagents/test/unit/async-retention.test.ts +4 -1
- package/dist/extensions/pi-subagents/test/unit/async-status-projection.test.ts +18 -4
- package/dist/extensions/pi-subagents/test/unit/atomic-json.test.ts +16 -0
- package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +38 -0
- package/dist/extensions/pi-subagents/test/unit/default-extensions.test.ts +2 -2
- package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +21 -0
- package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +19 -6
- package/dist/extensions/pi-subagents/test/unit/get-final-output.test.ts +26 -0
- package/dist/extensions/pi-subagents/test/unit/herdr-inspector.test.ts +22 -1
- package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +2 -6
- package/dist/extensions/pi-subagents/test/unit/notify.test.ts +66 -1
- package/dist/extensions/pi-subagents/test/unit/pi-args-permission-system.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +116 -10
- package/dist/extensions/pi-subagents/test/unit/pi-spawn.test.ts +136 -18
- package/dist/extensions/pi-subagents/test/unit/preflight.test.ts +20 -0
- package/dist/extensions/pi-subagents/test/unit/process-terminal.test.ts +22 -0
- package/dist/extensions/pi-subagents/test/unit/profiles.test.ts +1 -0
- package/dist/extensions/pi-subagents/test/unit/project-panes-public-api.test.ts +8 -0
- package/dist/extensions/pi-subagents/test/unit/render-helpers.test.ts +127 -48
- package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +68 -0
- package/dist/extensions/pi-subagents/test/unit/runtime-agent-registration.test.ts +17 -0
- package/dist/extensions/pi-subagents/test/unit/scheduled-runs.test.ts +88 -0
- package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +4 -2
- package/dist/extensions/pi-subagents/test/unit/scripted-workflow.test.ts +9 -9
- package/dist/extensions/pi-subagents/test/unit/steering-action.test.ts +2 -2
- package/dist/extensions/pi-subagents/test/unit/steering.test.ts +9 -3
- package/dist/extensions/pi-subagents/test/unit/subagent-control.test.ts +22 -9
- package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +91 -8
- package/dist/extensions/pi-subagents/test/unit/task-intent.test.ts +27 -0
- package/dist/extensions/pi-subagents/test/unit/temp-paths.test.ts +50 -0
- package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +0 -1
- package/dist/extensions/pi-subagents/test/unit/tool-timeout.test.ts +2 -2
- package/dist/extensions/pi-subagents/test/unit/wait-completions.test.ts +34 -0
- package/dist/extensions/pi-subagents/test/unit/wait-subscriptions.test.ts +1 -2
- package/dist/extensions/pi-subagents/test/unit/watchdog-child-status.test.ts +73 -13
- package/dist/extensions/pi-subagents/test/unit/watchdog-diff-tool.test.ts +79 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-permission-arbiter.test.ts +2 -4
- package/dist/extensions/pi-subagents/test/unit/watchdog-render.test.ts +7 -8
- package/dist/extensions/pi-subagents/test/unit/watchdog-review.test.ts +48 -3
- package/dist/extensions/pi-subagents/test/unit/watchdog-rules.test.ts +37 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-runtime.test.ts +36 -118
- package/dist/extensions/pi-subagents/test/unit/watchdog-scope.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/watchdog-settings.test.ts +37 -14
- package/dist/extensions/pi-subagents/test/unit/workflow-chat-progress.test.ts +45 -26
- package/dist/extensions/pi-subagents/test/unit/workflow-checklist.test.ts +223 -0
- package/dist/extensions/pi-subagents/test/unit/workflow-launch-params.test.ts +50 -1
- package/dist/extensions/pi-subagents/test/unit/workflow-preflight.test.ts +22 -0
- package/dist/extensions/pi-subagents/test/unit/worktree.test.ts +136 -4
- package/dist/extensions/pi-zentui/README.md +19 -5
- package/dist/extensions/pi-zentui/docs/configuration.md +37 -9
- package/dist/extensions/pi-zentui/extensions/zentui/config.ts +29 -0
- package/dist/extensions/pi-zentui/extensions/zentui/index.ts +31 -2
- package/dist/extensions/pi-zentui/extensions/zentui/prototype-patch-registry.ts +55 -11
- package/dist/extensions/pi-zentui/extensions/zentui/settings-command.ts +115 -3
- package/dist/extensions/pi-zentui/extensions/zentui/settings-previews.ts +119 -2
- package/dist/extensions/pi-zentui/extensions/zentui/thinking-experimental.ts +1768 -0
- package/dist/extensions/pi-zentui/extensions/zentui/thinking-status.ts +69 -0
- package/dist/extensions/pi-zentui/extensions/zentui/thinking-steps.ts +155 -0
- package/dist/extensions/pi-zentui/extensions/zentui/ui.ts +2 -1
- package/dist/extensions/pi-zentui/extensions/zentui/user-message-osc.ts +16 -2
- package/dist/extensions/pi-zentui/extensions/zentui/user-message-styles.ts +1 -1
- package/dist/extensions/pi-zentui/test/config-load-lifecycle.test.ts +124 -0
- package/dist/extensions/pi-zentui/test/config.test.ts +82 -2
- package/dist/extensions/pi-zentui/test/editor-viewport-indicators.test.ts +19 -4
- package/dist/extensions/pi-zentui/test/extension-compliance.test.ts +58 -9
- package/dist/extensions/pi-zentui/test/package-contents.mjs +33 -0
- package/dist/extensions/pi-zentui/test/prototype-patch-registry.test.ts +131 -0
- package/dist/extensions/pi-zentui/test/responsive-dependencies.test.ts +4 -4
- package/dist/extensions/pi-zentui/test/settings-command.test.ts +289 -7
- package/dist/extensions/pi-zentui/test/settings-previews.test.ts +106 -0
- package/dist/extensions/pi-zentui/test/thinking-experimental-docs.test.ts +51 -0
- package/dist/extensions/pi-zentui/test/thinking-experimental-loader-diagnostics.mjs +54 -0
- package/dist/extensions/pi-zentui/test/thinking-experimental-missing-export.test.ts +44 -0
- package/dist/extensions/pi-zentui/test/thinking-experimental-rows.test.ts +297 -0
- package/dist/extensions/pi-zentui/test/thinking-experimental-tui.mjs +2329 -0
- package/dist/extensions/pi-zentui/test/thinking-experimental.test.ts +1668 -0
- package/dist/extensions/pi-zentui/test/thinking-status.test.ts +85 -0
- package/dist/extensions/pi-zentui/test/thinking-steps.test.ts +122 -0
- package/dist/extensions/pi-zentui/test/user-message-osc.test.ts +58 -0
- package/dist/skills/brandkit/SKILL.md +0 -2
- package/dist/skills/{industrial-brutalist-ui → brutalist}/SKILL.md +1 -3
- package/dist/skills/gpt-taste/SKILL.md +0 -2
- package/dist/skills/image-to-code/SKILL.md +0 -2
- package/dist/skills/imagegen-frontend-mobile/SKILL.md +0 -2
- package/dist/skills/imagegen-frontend-web/SKILL.md +0 -2
- package/dist/skills/{minimalist-ui → minimalist}/SKILL.md +1 -3
- package/dist/skills/{full-output-enforcement → output}/SKILL.md +1 -3
- package/dist/skills/{redesign-existing-projects → redesign}/SKILL.md +1 -3
- package/dist/skills/{high-end-visual-design → soft}/SKILL.md +1 -3
- package/dist/skills/stitch/DESIGN.md +121 -0
- package/dist/skills/{stitch-design-taste → stitch}/SKILL.md +1 -3
- package/dist/skills/{design-taste-frontend → taste}/SKILL.md +1 -3
- package/dist/skills/{design-taste-frontend-v1 → taste-v1}/SKILL.md +2 -4
- package/package.json +1 -1
|
@@ -28,6 +28,7 @@ import { normalizePublicSubagentExecution, validateWorkflowCapacityOverrides } f
|
|
|
28
28
|
import { runSync } from "./execution.ts";
|
|
29
29
|
import { handleWatchdogToolAction, WATCHDOG_TOOL_ACTIONS } from "../../watchdog/tool-actions.ts";
|
|
30
30
|
import type { MainWatchdogRuntime } from "../../watchdog/runtime.ts";
|
|
31
|
+
import { applyWatchdogLaunchRules } from "../../watchdog/rules.ts";
|
|
31
32
|
import { buildModelCandidates, normalizeParentModel, resolveEffectiveSubagentModel, resolveModelOrigin, type ModelOrigin, type ParentModel } from "../shared/model-fallback.ts";
|
|
32
33
|
import { formatRetainedChildren, listRetainedChildren } from "../background/retained-children.ts";
|
|
33
34
|
import { resolveModelScopesForAgent, type ModelScopeConfig } from "../shared/model-scope.ts";
|
|
@@ -51,7 +52,7 @@ import { acquireActiveAsyncCapacity, ActiveAsyncCapacityError, getActiveAsyncCap
|
|
|
51
52
|
import { isScheduledRunAction } from "../background/scheduled-runs.ts";
|
|
52
53
|
import { enqueueChainAppendRequest, readPendingChainAppendRequests, runnerStepOutputNames } from "../background/chain-append.ts";
|
|
53
54
|
import { ChainOutputValidationError, validateChainOutputBindingsWithContext } from "../shared/chain-outputs.ts";
|
|
54
|
-
import { normalizeGateAcceptance, validateExecutionAcceptance } from "../shared/acceptance.ts";
|
|
55
|
+
import { normalizeGateAcceptance, resolveAcceptanceReportMode, validateExecutionAcceptance } from "../shared/acceptance.ts";
|
|
55
56
|
import { canPreferFork, createForkContextResolver, forkedChildRequiresThinkingOff, resolveSubagentLaunchContext } from "../../shared/fork-context.ts";
|
|
56
57
|
import { createPrunedForkSessionWriter } from "../../shared/pruned-fork.ts";
|
|
57
58
|
import { resolveCurrentSessionId } from "../../shared/session-identity.ts";
|
|
@@ -394,6 +395,7 @@ export interface SubagentParamsLike {
|
|
|
394
395
|
agentContract?: AgentContract;
|
|
395
396
|
at?: string;
|
|
396
397
|
every?: string;
|
|
398
|
+
sessionOnly?: boolean;
|
|
397
399
|
on?: string | number;
|
|
398
400
|
timezone?: string;
|
|
399
401
|
overlap?: "skip";
|
|
@@ -1314,6 +1316,9 @@ function appendStepToAsyncChain(input: {
|
|
|
1314
1316
|
waitToolEnabled: input.deps.waitToolEnabled,
|
|
1315
1317
|
waitToolDefaultTimeoutMs: input.deps.waitToolDefaultTimeoutMs,
|
|
1316
1318
|
contextForAgent: contextPolicy.contextForAgent,
|
|
1319
|
+
worktreeBaseDir: input.deps.config.worktreeBaseDir,
|
|
1320
|
+
worktreeProvider: input.deps.config.worktreeProvider,
|
|
1321
|
+
worktreeBranchPrefix: input.deps.config.worktreeBranchPrefix,
|
|
1317
1322
|
asyncDir: resolved.location.asyncDir,
|
|
1318
1323
|
validateOutputBindings: false,
|
|
1319
1324
|
capabilityCeiling: intersectSubagentCapabilityCeilings(status.capabilityCeiling, resolveCurrentSubagentCapabilityCeiling(asyncCtx.currentSessionId)),
|
|
@@ -1687,6 +1692,8 @@ async function resumeExternalJobFollowUp(input: {
|
|
|
1687
1692
|
worktreeSetupHook: input.deps.config.worktreeSetupHook,
|
|
1688
1693
|
worktreeSetupHookTimeoutMs: input.deps.config.worktreeSetupHookTimeoutMs,
|
|
1689
1694
|
worktreeBaseDir: input.deps.config.worktreeBaseDir,
|
|
1695
|
+
worktreeProvider: input.deps.config.worktreeProvider,
|
|
1696
|
+
worktreeBranchPrefix: input.deps.config.worktreeBranchPrefix,
|
|
1690
1697
|
controlConfig: resolveControlConfig(input.deps.config.control, undefined),
|
|
1691
1698
|
controlIntercomTarget: input.intercomBridge.active ? input.intercomBridge.orchestratorTarget : undefined,
|
|
1692
1699
|
childIntercomTarget: input.intercomBridge.active ? (agent, index) => resolveSubagentIntercomTarget(runId, agent, index) : undefined,
|
|
@@ -1943,6 +1950,8 @@ async function resumeAsyncRun(input: {
|
|
|
1943
1950
|
worktreeSetupHook: input.deps.config.worktreeSetupHook,
|
|
1944
1951
|
worktreeSetupHookTimeoutMs: input.deps.config.worktreeSetupHookTimeoutMs,
|
|
1945
1952
|
worktreeBaseDir: input.deps.config.worktreeBaseDir,
|
|
1953
|
+
worktreeProvider: input.deps.config.worktreeProvider,
|
|
1954
|
+
worktreeBranchPrefix: input.deps.config.worktreeBranchPrefix,
|
|
1946
1955
|
controlConfig: resolveControlConfig(input.deps.config.control, input.params.control),
|
|
1947
1956
|
controlIntercomTarget: intercomBridge.active ? intercomBridge.orchestratorTarget : undefined,
|
|
1948
1957
|
childIntercomTarget: intercomBridge.active ? (agent, index) => resolveSubagentIntercomTarget(runId, agent, index) : undefined,
|
|
@@ -2056,9 +2065,13 @@ async function resumeAsyncRun(input: {
|
|
|
2056
2065
|
worktreeSetupHook: input.deps.config.worktreeSetupHook,
|
|
2057
2066
|
worktreeSetupHookTimeoutMs: input.deps.config.worktreeSetupHookTimeoutMs,
|
|
2058
2067
|
worktreeBaseDir: input.deps.config.worktreeBaseDir,
|
|
2059
|
-
|
|
2068
|
+
worktreeProvider: input.deps.config.worktreeProvider,
|
|
2069
|
+
worktreeBranchPrefix: input.deps.config.worktreeBranchPrefix,
|
|
2070
|
+
// A retained async child already owns the recorded worktree. Resume it in
|
|
2071
|
+
// place rather than allocating a second provider worktree around it.
|
|
2072
|
+
worktree: input.params.worktree === true && !("managedWorktree" in target && target.managedWorktree === true),
|
|
2060
2073
|
lane: input.params.lane ?? recoveryDescriptor?.lane,
|
|
2061
|
-
controlConfig:
|
|
2074
|
+
controlConfig: resolveRevivalControlConfig({ globalConfig: input.deps.config.control, requestedControl: input.params.control, recoveryControlConfig: recoveryDescriptor?.controlConfig }),
|
|
2062
2075
|
intercomBridge: input.params.intercomBridge ?? recoveryDescriptor?.intercomBridge,
|
|
2063
2076
|
controlIntercomTarget: intercomBridge.active ? intercomBridge.orchestratorTarget : undefined,
|
|
2064
2077
|
childIntercomTarget: intercomBridge.active ? (agent, index) => resolveSubagentIntercomTarget(runId, agent, index) : undefined,
|
|
@@ -3218,6 +3231,8 @@ async function runAsyncPath(data: ExecutionContextData, deps: ExecutorDeps): Pro
|
|
|
3218
3231
|
source: modelOrigin === "explicit" ? "explicit" : "inherited",
|
|
3219
3232
|
});
|
|
3220
3233
|
const modelOverrideFromParent = modelOrigin === "inherited";
|
|
3234
|
+
const launchRuleError = applyWatchdogLaunchRules({ cwd: effectiveCwd, agent: a.name, model: modelOverride ?? (parentModel && `${parentModel.provider}/${parentModel.id}`), warn: (violation) => deps.watchdog?.displayRuleWarning(violation) });
|
|
3235
|
+
if (launchRuleError) return toExecutionErrorResult(params, new Error(launchRuleError), data.contextPolicy.contextSummary);
|
|
3221
3236
|
const asyncResult = executeAsyncSingle(id, compactOptional<Parameters<typeof executeAsyncSingle>[1]>({
|
|
3222
3237
|
agent: params.agent!,
|
|
3223
3238
|
task: shouldForkAgent(contextPolicy, params.agent!) ? wrapForkTask(params.task ?? "") : (params.task ?? ""),
|
|
@@ -3255,6 +3270,8 @@ async function runAsyncPath(data: ExecutionContextData, deps: ExecutorDeps): Pro
|
|
|
3255
3270
|
worktreeSetupHook: deps.config.worktreeSetupHook,
|
|
3256
3271
|
worktreeSetupHookTimeoutMs: deps.config.worktreeSetupHookTimeoutMs,
|
|
3257
3272
|
worktreeBaseDir: deps.config.worktreeBaseDir,
|
|
3273
|
+
worktreeProvider: deps.config.worktreeProvider,
|
|
3274
|
+
worktreeBranchPrefix: deps.config.worktreeBranchPrefix,
|
|
3258
3275
|
controlConfig,
|
|
3259
3276
|
intercomBridge: params.intercomBridge,
|
|
3260
3277
|
controlIntercomTarget,
|
|
@@ -3291,6 +3308,10 @@ function createSingleWorktreeSetup(
|
|
|
3291
3308
|
setupHook: ExtensionConfig["worktreeSetupHook"],
|
|
3292
3309
|
setupHookTimeoutMs: ExtensionConfig["worktreeSetupHookTimeoutMs"],
|
|
3293
3310
|
baseDir: ExtensionConfig["worktreeBaseDir"],
|
|
3311
|
+
provider: ExtensionConfig["worktreeProvider"],
|
|
3312
|
+
branchPrefix: ExtensionConfig["worktreeBranchPrefix"],
|
|
3313
|
+
label?: string,
|
|
3314
|
+
task?: string,
|
|
3294
3315
|
beforeCreate?: (setup: WorktreeSetup) => void,
|
|
3295
3316
|
): { setup?: WorktreeSetup; errorResult?: AgentToolResult<Details> } {
|
|
3296
3317
|
if (!enabled) return {};
|
|
@@ -3302,6 +3323,10 @@ function createSingleWorktreeSetup(
|
|
|
3302
3323
|
? { hookPath: setupHook, ...(setupHookTimeoutMs === undefined ? {} : { timeoutMs: setupHookTimeoutMs }) }
|
|
3303
3324
|
: undefined,
|
|
3304
3325
|
baseDir,
|
|
3326
|
+
provider,
|
|
3327
|
+
branchPrefix,
|
|
3328
|
+
labels: [label],
|
|
3329
|
+
tasks: [task],
|
|
3305
3330
|
beforeCreate,
|
|
3306
3331
|
})),
|
|
3307
3332
|
};
|
|
@@ -3643,6 +3668,8 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
3643
3668
|
},
|
|
3644
3669
|
);
|
|
3645
3670
|
const modelOverrideFromParent = modelOrigin === "inherited";
|
|
3671
|
+
const launchRuleError = applyWatchdogLaunchRules({ cwd: effectiveCwd, agent: agentConfig.name, model: modelOverride ?? (parentModel && `${parentModel.provider}/${parentModel.id}`), warn: (violation) => deps.watchdog?.displayRuleWarning(violation) });
|
|
3672
|
+
if (launchRuleError) return toExecutionErrorResult(params, new Error(launchRuleError), data.contextPolicy.contextSummary);
|
|
3646
3673
|
let skillOverride: string[] | false | undefined = normalizeSkillInput(params.skill);
|
|
3647
3674
|
let readsOverride: string[] | false | undefined = params.reads;
|
|
3648
3675
|
const rawOutput = params.output !== undefined ? params.output : agentConfig.output;
|
|
@@ -3662,6 +3689,10 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
3662
3689
|
deps.config.worktreeSetupHook,
|
|
3663
3690
|
deps.config.worktreeSetupHookTimeoutMs,
|
|
3664
3691
|
deps.config.worktreeBaseDir,
|
|
3692
|
+
deps.config.worktreeProvider,
|
|
3693
|
+
deps.config.worktreeBranchPrefix,
|
|
3694
|
+
params.lane?.key ?? params.workflowKey,
|
|
3695
|
+
task,
|
|
3665
3696
|
(plannedSetup) => {
|
|
3666
3697
|
pendingHandoff = writePendingParallelHandoff({
|
|
3667
3698
|
manifestPath: parallelHandoffPath(artifactsDir, runId),
|
|
@@ -3691,7 +3722,7 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
3691
3722
|
return { content: [{ type: "text", text: validationError }], isError: true, details: { mode: "single", results: [] } };
|
|
3692
3723
|
}
|
|
3693
3724
|
const structuredRuntime = params.outputSchema
|
|
3694
|
-
? createStructuredOutputRuntime(params.outputSchema, artifactConfig.enabled ? path.join(artifactsDir, "structured-output", runId) : undefined, {
|
|
3725
|
+
? createStructuredOutputRuntime(params.outputSchema, artifactConfig.enabled ? path.join(artifactsDir, "structured-output", runId) : undefined, { acceptanceReport: resolveAcceptanceReportMode(params.acceptance) })
|
|
3695
3726
|
: undefined;
|
|
3696
3727
|
// Reads: caller override > agent defaultReads > none. `~`/`~/` expand to home;
|
|
3697
3728
|
// absolute paths pass through; relative paths resolve against the child cwd.
|
|
@@ -4164,6 +4195,10 @@ function workflowOutputPathMappingSummary(children: WorkflowScriptChildResult[])
|
|
|
4164
4195
|
return mappings.length > 0 ? ` Output path mappings: ${mappings.join("; ")}.` : "";
|
|
4165
4196
|
}
|
|
4166
4197
|
|
|
4198
|
+
function workflowDetailsResults(children: WorkflowScriptChildResult[]): SingleResult[] {
|
|
4199
|
+
return children.flatMap((child) => (child.results ?? []).map((result) => result.workflowKey ? result : { ...result, workflowKey: child.key }));
|
|
4200
|
+
}
|
|
4201
|
+
|
|
4167
4202
|
function workflowSteerReceipt(key: string, result: AgentToolResult<Details>): WorkflowSteerResult {
|
|
4168
4203
|
const steering = result.details.steering;
|
|
4169
4204
|
const error = result.content.map((part) => part.type === "text" ? part.text : "").filter(Boolean).join("\n") || undefined;
|
|
@@ -4409,6 +4444,7 @@ export function prepareWorkflowLaunchParams(
|
|
|
4409
4444
|
if (output !== undefined && typeof output !== "string" && typeof output !== "boolean") throw new Error("output must be a path string or boolean.");
|
|
4410
4445
|
const outputMode = Object.hasOwn(childParams, "outputMode") ? childParams.outputMode : workflowDefaults.outputMode;
|
|
4411
4446
|
if (outputMode !== undefined && outputMode !== "inline" && outputMode !== "file-only") throw new Error("outputMode must be 'inline' or 'file-only'.");
|
|
4447
|
+
const control = mergeWorkflowControlOverrides(workflowDefaults.control, childParams.control as ControlConfig | undefined);
|
|
4412
4448
|
return {
|
|
4413
4449
|
action: "resume",
|
|
4414
4450
|
id: childParams.resume.trim(),
|
|
@@ -4427,14 +4463,17 @@ export function prepareWorkflowLaunchParams(
|
|
|
4427
4463
|
...(options.missionDetached ? { mission: false } : {}),
|
|
4428
4464
|
...(timeoutMs !== undefined ? { timeoutMs: timeoutMs as number } : {}),
|
|
4429
4465
|
...(toolBudget !== undefined ? { toolBudget: toolBudget as ToolBudgetConfig } : {}),
|
|
4466
|
+
...(control !== undefined ? { control } : {}),
|
|
4430
4467
|
...(intercomBridge !== undefined ? { intercomBridge: intercomBridge as IntercomBridgeConfig } : {}),
|
|
4431
4468
|
...(capabilityCeiling ? { capabilityCeiling } : {}),
|
|
4432
4469
|
};
|
|
4433
4470
|
}
|
|
4471
|
+
const control = mergeWorkflowControlOverrides(workflowDefaults.control, childParams.control as ControlConfig | undefined);
|
|
4434
4472
|
const launchParams = {
|
|
4435
4473
|
...workflowDefaults,
|
|
4436
4474
|
async: options.externalAsyncRequired === true && childParams.async === undefined && workflowDefaults.async === undefined ? true : false,
|
|
4437
4475
|
...childParams,
|
|
4476
|
+
...(control !== undefined ? { control } : {}),
|
|
4438
4477
|
...(options.externalAsyncRequired === true && childParams.async === undefined && workflowDefaults.async === undefined ? { workflowAwaitAsync: true } : {}),
|
|
4439
4478
|
...(options.missionDetached ? { mission: false } : {}),
|
|
4440
4479
|
workflowParentRunId: parentWorkflowRunId,
|
|
@@ -4453,6 +4492,17 @@ export function prepareWorkflowLaunchParams(
|
|
|
4453
4492
|
return normalizedGate.params;
|
|
4454
4493
|
}
|
|
4455
4494
|
|
|
4495
|
+
function mergeWorkflowControlOverrides(workflowControl: ControlConfig | undefined, childControl: ControlConfig | undefined): ControlConfig | undefined {
|
|
4496
|
+
if (childControl === undefined) return workflowControl;
|
|
4497
|
+
if (workflowControl === undefined) return childControl;
|
|
4498
|
+
return { ...workflowControl, ...childControl };
|
|
4499
|
+
}
|
|
4500
|
+
|
|
4501
|
+
export function resolveRevivalControlConfig(input: { globalConfig?: ControlConfig; requestedControl?: ControlConfig; recoveryControlConfig?: ResolvedControlConfig }): ResolvedControlConfig {
|
|
4502
|
+
if (input.requestedControl === undefined) return input.recoveryControlConfig ?? resolveControlConfig(input.globalConfig, undefined);
|
|
4503
|
+
return resolveControlConfig(input.recoveryControlConfig ?? input.globalConfig, input.requestedControl);
|
|
4504
|
+
}
|
|
4505
|
+
|
|
4456
4506
|
type GateParamsNormalizationResult =
|
|
4457
4507
|
| { ok: true; params: SubagentParamsLike }
|
|
4458
4508
|
| { ok: false; error: string };
|
|
@@ -5519,7 +5569,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
5519
5569
|
const displayText = appendWorkflowOutputWarning(workflowText, outputWarning);
|
|
5520
5570
|
return attachWorkflowMission(withRunFanoutBudget({
|
|
5521
5571
|
content: [{ type: "text", text: displayText }],
|
|
5522
|
-
details: compactOptional<Details>({ mode: "workflow", runId: _id, results: workflow.children
|
|
5572
|
+
details: compactOptional<Details>({ mode: "workflow", runId: _id, results: workflowDetailsResults(workflow.children), ...(workflowPreflight ? { preflight: workflowPreflight } : {}), workflowChildren, totalChildUsage: sumResultsUsage(workflowResults), totalCost: sumResultsCost(workflowResults), usageBudget: usageBudgetState(workflowUsageBudget.budget, sumResultsCost(workflowResults)), workflow: { value: workflow.value, trace: finalPreflightTrace, emits: workflow.emits, console: workflow.console, ...(workflowResource ? { resource: workflowResource.provenance } : {}), ...(finalPreflightWarnings.length ? { preflightWarnings: finalPreflightWarnings } : {}), receipt }, chatProgress }),
|
|
5523
5573
|
}, workflowFanoutBudget));
|
|
5524
5574
|
} catch (error) {
|
|
5525
5575
|
const partial = error instanceof WorkflowScriptError ? error.partial : { trace: [], emits: [], console: [], children: [] };
|
|
@@ -5546,7 +5596,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
5546
5596
|
return attachWorkflowMission(withRunFanoutBudget({
|
|
5547
5597
|
content: [{ type: "text", text: displayText }],
|
|
5548
5598
|
isError: true,
|
|
5549
|
-
details: compactOptional<Details>({ mode: "workflow", runId: _id, results: partial.children
|
|
5599
|
+
details: compactOptional<Details>({ mode: "workflow", runId: _id, results: workflowDetailsResults(partial.children), ...(workflowPreflight ? { preflight: workflowPreflight } : {}), workflowChildren, totalChildUsage: sumResultsUsage(workflowResults), totalCost: sumResultsCost(workflowResults), usageBudget: usageBudgetState(workflowUsageBudget.budget, sumResultsCost(workflowResults)), workflow: { trace: finalPreflightTrace, emits: partial.emits, console: partial.console, ...(workflowResource ? { resource: workflowResource.provenance } : {}), ...(finalPreflightWarnings.length ? { preflightWarnings: finalPreflightWarnings } : {}), receipt }, chatProgress }),
|
|
5550
5600
|
}, workflowFanoutBudget));
|
|
5551
5601
|
}
|
|
5552
5602
|
}
|
|
@@ -6247,6 +6297,9 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
6247
6297
|
const canonicalParams = canonicalizeExecutionParams(effectiveParams, discoveredAgents, discovered.agentDiagnostics, unknownAgentDiagnosticContext);
|
|
6248
6298
|
if (canonicalParams.error) return buildRequestedModeError(effectiveParams, canonicalParams.error);
|
|
6249
6299
|
effectiveParams = canonicalParams.params!;
|
|
6300
|
+
if (effectiveParams.worktree === undefined && deps.config.worktree !== undefined) {
|
|
6301
|
+
effectiveParams = { ...effectiveParams, worktree: deps.config.worktree };
|
|
6302
|
+
}
|
|
6250
6303
|
const modelScope = discovered.modelScope;
|
|
6251
6304
|
effectiveParams = applySingleAgentLaunchDefaults(effectiveParams, discoveredAgents);
|
|
6252
6305
|
// An agent-level defaultContext is a preference, unlike an explicit request.
|
|
@@ -21,7 +21,9 @@ import type {
|
|
|
21
21
|
ResolvedAcceptanceGate,
|
|
22
22
|
SingleResult,
|
|
23
23
|
SubagentRunMode,
|
|
24
|
+
ChildWatchdogProgress,
|
|
24
25
|
} from "../../shared/types.ts";
|
|
26
|
+
import { unresolvedChildWatchdogBlockers } from "../../watchdog/child-status.ts";
|
|
25
27
|
import { isAgentContractV1 } from "./agent-contract.ts";
|
|
26
28
|
import { classifyTaskMutationIntent, stripSeverityCompounds, taskMayMutate } from "./task-intent.ts";
|
|
27
29
|
|
|
@@ -47,7 +49,7 @@ const VALID_EVIDENCE_KINDS: AcceptanceEvidenceKind[] = [
|
|
|
47
49
|
const VALID_EVIDENCE = new Set<AcceptanceEvidenceKind>(VALID_EVIDENCE_KINDS);
|
|
48
50
|
const ACCEPTANCE_EVIDENCE_HELP = `Supported evidence kinds: ${VALID_EVIDENCE_KINDS.join(", ")}. Example: { level: "checked", evidence: ["commands-run", "changed-files"] }.`;
|
|
49
51
|
const ACCEPTANCE_OBJECT_EXAMPLE = "Example: { level: \"checked\", evidence: [\"commands-run\", \"changed-files\"] }.";
|
|
50
|
-
const ACCEPTANCE_CONFIG_KEYS = new Set(["level", "criteria", "evidence", "verify", "review", "stopRules", "reason"]);
|
|
52
|
+
const ACCEPTANCE_CONFIG_KEYS = new Set(["level", "report", "criteria", "evidence", "verify", "review", "stopRules", "reason"]);
|
|
51
53
|
const ACCEPTANCE_GATE_KEYS = new Set(["id", "must", "evidence", "severity"]);
|
|
52
54
|
const ACCEPTANCE_VERIFY_KEYS = new Set(["id", "command", "timeoutMs", "cwd", "env", "allowFailure"]);
|
|
53
55
|
const ACCEPTANCE_REVIEW_KEYS = new Set(["agent", "focus", "required"]);
|
|
@@ -100,12 +102,13 @@ function inferLevel(input: {
|
|
|
100
102
|
const writeTask = taskMayWrite
|
|
101
103
|
|| (input.acceptanceRole === "writer" && !readOnlyTask)
|
|
102
104
|
|| (input.acceptanceRole === undefined && /\bworker\b/.test(agent) && !readOnlyTask);
|
|
103
|
-
const inferredReadOnly = readOnlyTask || (input.acceptanceRole === "read-only" && !taskMayWrite);
|
|
105
|
+
const inferredReadOnly = readOnlyTask || ((readOnlyAgent || input.acceptanceRole === "read-only") && !taskMayWrite);
|
|
104
106
|
const roleResolvesReadOnly = input.acceptanceRole !== undefined && inferredReadOnly;
|
|
107
|
+
const dynamicResolvesReadOnly = inferredReadOnly && !writeTask;
|
|
105
108
|
const keywordRiskReadOnly = input.acceptanceRole === undefined ? intent.kind === "read-only" : inferredReadOnly;
|
|
106
109
|
const risky = Boolean(input.async && writeTask)
|
|
107
|
-
|| (Boolean(input.dynamic) && !roleResolvesReadOnly)
|
|
108
|
-
|| (Boolean(input.dynamicGroup) && !roleResolvesReadOnly)
|
|
110
|
+
|| (Boolean(input.dynamic) && !roleResolvesReadOnly && !dynamicResolvesReadOnly)
|
|
111
|
+
|| (Boolean(input.dynamicGroup) && !roleResolvesReadOnly && !dynamicResolvesReadOnly)
|
|
109
112
|
|| (!keywordRiskReadOnly && /\b(?:release|migration|migrate|security|data[- ]loss|destructive|post-review|fix pass)\b/.test(task));
|
|
110
113
|
|
|
111
114
|
if (risky) {
|
|
@@ -131,7 +134,7 @@ function inferLevel(input: {
|
|
|
131
134
|
if (readOnlyAgent || readOnlyTask) {
|
|
132
135
|
reasons.push(input.acceptanceRole === "read-only" && !readOnlyTask ? "declared read-only acceptance role" : readOnlyAgent ? "read-only/reviewer-style agent" : "read-only task wording");
|
|
133
136
|
return {
|
|
134
|
-
level: "
|
|
137
|
+
level: "none",
|
|
135
138
|
reasons,
|
|
136
139
|
criteria: ["Return concrete findings with file paths and severity when applicable"],
|
|
137
140
|
evidence: ["review-findings", "residual-risks"],
|
|
@@ -146,11 +149,46 @@ function inferLevel(input: {
|
|
|
146
149
|
};
|
|
147
150
|
}
|
|
148
151
|
|
|
149
|
-
|
|
152
|
+
type AcceptanceInputNormalizationResult = { value: unknown; error?: string };
|
|
153
|
+
|
|
154
|
+
function normalizeAcceptanceValue(input: unknown, pathLabel = "acceptance"): AcceptanceInputNormalizationResult {
|
|
155
|
+
if (typeof input !== "string") return { value: input };
|
|
156
|
+
const trimmed = input.trim();
|
|
157
|
+
if (!trimmed.startsWith("{") && !trimmed.startsWith("[")) return { value: input };
|
|
158
|
+
let parsed: unknown;
|
|
159
|
+
try {
|
|
160
|
+
parsed = JSON.parse(trimmed);
|
|
161
|
+
} catch (error) {
|
|
162
|
+
return {
|
|
163
|
+
value: input,
|
|
164
|
+
error: `${pathLabel} JSON string must encode a valid acceptance object: ${error instanceof Error ? error.message : String(error)}`,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
168
|
+
const kind = parsed === null ? "null" : Array.isArray(parsed) ? "an array" : typeof parsed;
|
|
169
|
+
return { value: input, error: `${pathLabel} JSON string must encode an object; got ${kind}.` };
|
|
170
|
+
}
|
|
171
|
+
return { value: parsed };
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export function normalizeAcceptanceInput(input: unknown): AcceptanceConfig {
|
|
175
|
+
const normalized = normalizeAcceptanceValue(input);
|
|
176
|
+
if (normalized.error) throw new Error(normalized.error);
|
|
177
|
+
input = normalized.value;
|
|
150
178
|
if (input === undefined || input === "auto") return { level: "auto" };
|
|
151
179
|
if (input === false) return { level: "none", reason: "disabled by deprecated false shorthand" };
|
|
152
|
-
if (typeof input === "string") return { level: input };
|
|
153
|
-
return { ...input };
|
|
180
|
+
if (typeof input === "string") return { level: input as AcceptanceConfig["level"] };
|
|
181
|
+
return { ...(input as AcceptanceConfig) };
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export type ResolvedAcceptanceReportMode = "off" | "optional" | "required";
|
|
185
|
+
|
|
186
|
+
export function resolveAcceptanceReportMode(input: unknown): ResolvedAcceptanceReportMode {
|
|
187
|
+
const normalized = normalizeAcceptanceValue(input);
|
|
188
|
+
if (normalized.error) throw new Error(normalized.error);
|
|
189
|
+
const value = normalized.value;
|
|
190
|
+
const report = value && typeof value === "object" && !Array.isArray(value) ? (value as AcceptanceConfig).report : undefined;
|
|
191
|
+
return value === false || report === "off" ? "off" : report === "on" ? "required" : "optional";
|
|
154
192
|
}
|
|
155
193
|
|
|
156
194
|
type GateAcceptanceNormalizationResult =
|
|
@@ -158,7 +196,11 @@ type GateAcceptanceNormalizationResult =
|
|
|
158
196
|
| { ok: false; error: string };
|
|
159
197
|
|
|
160
198
|
export function normalizeGateAcceptance(gate: unknown, acceptance: AcceptanceInput | undefined): GateAcceptanceNormalizationResult {
|
|
161
|
-
if (gate === undefined)
|
|
199
|
+
if (gate === undefined) {
|
|
200
|
+
if (acceptance === undefined) return { ok: true };
|
|
201
|
+
const normalized = normalizeAcceptanceValue(acceptance);
|
|
202
|
+
return normalized.error ? { ok: false, error: normalized.error } : { ok: true, acceptance: normalized.value as AcceptanceInput };
|
|
203
|
+
}
|
|
162
204
|
if (typeof gate !== "string" || !gate.trim()) return { ok: false, error: "gate must be a non-empty command string." };
|
|
163
205
|
if (acceptance !== undefined) return { ok: false, error: "gate cannot be combined with acceptance; use one gate command or acceptance.verify." };
|
|
164
206
|
return { ok: true, acceptance: { level: "verified", verify: [{ id: "gate", command: gate.trim() }] } };
|
|
@@ -168,6 +210,10 @@ function explicitAcceptanceCanDisable(explicit: AcceptanceConfig): boolean {
|
|
|
168
210
|
return explicit.level === "none" && typeof explicit.reason === "string" && explicit.reason.trim().length > 0;
|
|
169
211
|
}
|
|
170
212
|
|
|
213
|
+
function explicitAcceptanceRequestsPolicy(explicit: AcceptanceConfig): boolean {
|
|
214
|
+
return (explicit.level !== undefined && explicit.level !== "auto") || Object.keys(explicit).some((key) => key !== "level");
|
|
215
|
+
}
|
|
216
|
+
|
|
171
217
|
function unsupportedEvidenceKindMessage(pathLabel: string, item: unknown): string {
|
|
172
218
|
const value = typeof item === "string" ? ` "${item}"` : "";
|
|
173
219
|
return `${pathLabel}${value} is not a supported evidence kind. ${ACCEPTANCE_EVIDENCE_HELP}`;
|
|
@@ -177,6 +223,9 @@ export function validateAcceptanceInput(input: unknown, pathLabel = "acceptance"
|
|
|
177
223
|
const errors: string[] = [];
|
|
178
224
|
if (input === undefined) return errors;
|
|
179
225
|
if (input === false) return errors;
|
|
226
|
+
const normalized = normalizeAcceptanceValue(input, pathLabel);
|
|
227
|
+
if (normalized.error) return [normalized.error];
|
|
228
|
+
input = normalized.value;
|
|
180
229
|
if (typeof input === "string") {
|
|
181
230
|
if (input === "reviewed") errors.push(`${pathLabel} ${EXPLICIT_REVIEWED_UNAVAILABLE}`);
|
|
182
231
|
else if (!VALID_LEVELS.has(input as AcceptanceLevel)) errors.push(`${pathLabel} has invalid level '${input}'.`);
|
|
@@ -197,6 +246,9 @@ export function validateAcceptanceInput(input: unknown, pathLabel = "acceptance"
|
|
|
197
246
|
} else if (value.level !== undefined && (typeof value.level !== "string" || !VALID_LEVELS.has(value.level as AcceptanceLevel))) {
|
|
198
247
|
errors.push(`${pathLabel}.level must be one of auto, none, attested, checked, verified.`);
|
|
199
248
|
}
|
|
249
|
+
if (value.report !== undefined && value.report !== "on" && value.report !== "off") {
|
|
250
|
+
errors.push(`${pathLabel}.report must be on or off.`);
|
|
251
|
+
}
|
|
200
252
|
if (value.level === "none" && (typeof value.reason !== "string" || !value.reason.trim())) {
|
|
201
253
|
errors.push(`${pathLabel}.reason is required when level is none.`);
|
|
202
254
|
}
|
|
@@ -304,29 +356,45 @@ export function validateAcceptanceInput(input: unknown, pathLabel = "acceptance"
|
|
|
304
356
|
|
|
305
357
|
export function validateExecutionAcceptance(input: {
|
|
306
358
|
acceptance?: unknown;
|
|
307
|
-
|
|
359
|
+
outputSchema?: unknown;
|
|
360
|
+
tasks?: Array<{ acceptance?: unknown; outputSchema?: unknown }>;
|
|
308
361
|
chain?: Array<{
|
|
309
362
|
acceptance?: unknown;
|
|
310
|
-
|
|
363
|
+
outputSchema?: unknown;
|
|
364
|
+
parallel?: Array<{ acceptance?: unknown; outputSchema?: unknown }> | { acceptance?: unknown; outputSchema?: unknown };
|
|
311
365
|
}>;
|
|
312
366
|
}): string[] {
|
|
313
367
|
const errors = validateAcceptanceInput(input.acceptance, "acceptance");
|
|
368
|
+
errors.push(...validateAcceptanceReportMode(input.acceptance, input.outputSchema, "acceptance"));
|
|
314
369
|
for (const [index, task] of (input.tasks ?? []).entries()) {
|
|
315
370
|
errors.push(...validateAcceptanceInput(task.acceptance, `tasks[${index}].acceptance`));
|
|
371
|
+
errors.push(...validateAcceptanceReportMode(task.acceptance, task.outputSchema, `tasks[${index}].acceptance`));
|
|
316
372
|
}
|
|
317
373
|
for (const [stepIndex, step] of (input.chain ?? []).entries()) {
|
|
318
374
|
errors.push(...validateAcceptanceInput(step.acceptance, `chain[${stepIndex}].acceptance`));
|
|
375
|
+
errors.push(...validateAcceptanceReportMode(step.acceptance, step.outputSchema, `chain[${stepIndex}].acceptance`));
|
|
319
376
|
if (Array.isArray(step.parallel)) {
|
|
320
377
|
for (const [taskIndex, task] of step.parallel.entries()) {
|
|
321
378
|
errors.push(...validateAcceptanceInput(task.acceptance, `chain[${stepIndex}].parallel[${taskIndex}].acceptance`));
|
|
379
|
+
errors.push(...validateAcceptanceReportMode(task.acceptance, task.outputSchema, `chain[${stepIndex}].parallel[${taskIndex}].acceptance`));
|
|
322
380
|
}
|
|
323
381
|
} else if (step.parallel) {
|
|
324
382
|
errors.push(...validateAcceptanceInput(step.parallel.acceptance, `chain[${stepIndex}].parallel.acceptance`));
|
|
383
|
+
errors.push(...validateAcceptanceReportMode(step.parallel.acceptance, step.parallel.outputSchema, `chain[${stepIndex}].parallel.acceptance`));
|
|
325
384
|
}
|
|
326
385
|
}
|
|
327
386
|
return errors;
|
|
328
387
|
}
|
|
329
388
|
|
|
389
|
+
function validateAcceptanceReportMode(acceptance: unknown, outputSchema: unknown, pathLabel: string): string[] {
|
|
390
|
+
const normalized = normalizeAcceptanceValue(acceptance, pathLabel);
|
|
391
|
+
if (normalized.error) return [];
|
|
392
|
+
acceptance = normalized.value;
|
|
393
|
+
if (!acceptance || typeof acceptance !== "object" || Array.isArray(acceptance)) return [];
|
|
394
|
+
if (!("report" in acceptance)) return [];
|
|
395
|
+
return outputSchema === undefined ? [`${pathLabel}.report requires outputSchema.`] : [];
|
|
396
|
+
}
|
|
397
|
+
|
|
330
398
|
function normalizeCriteria(criteria: Array<string | { id?: string; must?: string; evidence?: AcceptanceEvidenceKind[]; severity?: "required" | "recommended" }> | undefined, evidence: AcceptanceEvidenceKind[]): ResolvedAcceptanceGate[] {
|
|
331
399
|
return (criteria ?? []).map((criterion, index): ResolvedAcceptanceGate => {
|
|
332
400
|
if (typeof criterion === "string") {
|
|
@@ -376,12 +444,13 @@ export function resolveEffectiveAcceptance(input: {
|
|
|
376
444
|
};
|
|
377
445
|
}
|
|
378
446
|
const inferred = inferLevel(input);
|
|
447
|
+
const inferredLevel = inferred.level === "none" && explicitAcceptanceRequestsPolicy(explicit) ? "attested" : inferred.level;
|
|
379
448
|
const level = explicitAcceptanceCanDisable(explicit)
|
|
380
449
|
? "none"
|
|
381
450
|
: explicitLevel === "auto"
|
|
382
|
-
?
|
|
383
|
-
: (LEVEL_RANK[explicitLevel] >= LEVEL_RANK[
|
|
384
|
-
const evidence = unique([...(level ===
|
|
451
|
+
? inferredLevel
|
|
452
|
+
: (LEVEL_RANK[explicitLevel] >= LEVEL_RANK[inferredLevel] ? explicitLevel : inferredLevel);
|
|
453
|
+
const evidence = unique([...(level === inferredLevel ? inferred.evidence : requiredEvidenceForLevel(level)), ...(explicit.evidence ?? [])]);
|
|
385
454
|
const criteria = normalizeCriteria(
|
|
386
455
|
(explicit.criteria?.length ? explicit.criteria : inferred.criteria) as Array<string | { id?: string; must?: string; evidence?: AcceptanceEvidenceKind[]; severity?: "required" | "recommended" }>,
|
|
387
456
|
evidence,
|
|
@@ -391,8 +460,8 @@ export function resolveEffectiveAcceptance(input: {
|
|
|
391
460
|
level,
|
|
392
461
|
explicit: input.explicit !== undefined,
|
|
393
462
|
inferredReason: inferred.reasons,
|
|
394
|
-
criteria,
|
|
395
|
-
evidence,
|
|
463
|
+
criteria: level === "none" ? [] : criteria,
|
|
464
|
+
evidence: level === "none" ? [] : evidence,
|
|
396
465
|
verify: explicit.verify ?? [],
|
|
397
466
|
review,
|
|
398
467
|
stopRules: explicit.stopRules ?? [],
|
|
@@ -851,7 +920,7 @@ function validateStringArrayField(errors: string[], value: unknown, pathLabel: s
|
|
|
851
920
|
}
|
|
852
921
|
}
|
|
853
922
|
|
|
854
|
-
function validateAcceptanceReport(value: unknown, pathLabel = ""): { report?: AcceptanceReport; errors: string[] } {
|
|
923
|
+
export function validateAcceptanceReport(value: unknown, pathLabel = ""): { report?: AcceptanceReport; errors: string[] } {
|
|
855
924
|
const normalized = normalizeAcceptanceReportValue(value, pathLabel);
|
|
856
925
|
value = normalized.value;
|
|
857
926
|
pathLabel = normalized.pathLabel;
|
|
@@ -1293,6 +1362,7 @@ export async function evaluateAcceptance(input: {
|
|
|
1293
1362
|
reportOptional?: boolean;
|
|
1294
1363
|
artifactsDir?: string;
|
|
1295
1364
|
runId?: string;
|
|
1365
|
+
watchdog?: ChildWatchdogProgress;
|
|
1296
1366
|
}): Promise<AcceptanceLedger> {
|
|
1297
1367
|
const acceptance = input.acceptance;
|
|
1298
1368
|
const initialStatus = acceptance.level === "none" ? "not-required" : "claimed";
|
|
@@ -1308,9 +1378,16 @@ export async function evaluateAcceptance(input: {
|
|
|
1308
1378
|
};
|
|
1309
1379
|
if (acceptance.level === "none") return ledger;
|
|
1310
1380
|
|
|
1381
|
+
if (input.watchdog) {
|
|
1382
|
+
const unresolved = unresolvedChildWatchdogBlockers(input.watchdog);
|
|
1383
|
+
ledger.runtimeChecks.push(unresolved.length
|
|
1384
|
+
? { id: "watchdog-blocker", status: "failed", message: `Unresolved watchdog blocker: ${unresolved[0]!.summary}` }
|
|
1385
|
+
: { id: "watchdog-blocker", status: "passed", message: "No unresolved watchdog blockers." });
|
|
1386
|
+
}
|
|
1387
|
+
|
|
1311
1388
|
const parsed: AcceptanceReportParseResult = input.reportError
|
|
1312
1389
|
? { error: input.reportError }
|
|
1313
|
-
: input.report
|
|
1390
|
+
: input.report !== undefined
|
|
1314
1391
|
? (() => {
|
|
1315
1392
|
const validation = validateAcceptanceReport(input.report);
|
|
1316
1393
|
return validation.report
|
|
@@ -2,6 +2,7 @@ import { sanitizeDisplayText, truncateDisplayText } from "../../shared/display-t
|
|
|
2
2
|
import { formatModelThinking } from "../../shared/formatters.ts";
|
|
3
3
|
import type { AsyncJobState, AsyncJobStep, HostStepFreshnessV1, HostStepMonitorKind, HostStepNodeV1, HostStepState, HostStepVerdict, NestedRunSummary, NestedStepSummary, SubagentRunMode, WorkflowGraphSnapshot, WorkflowPreflightLaneV1, WorkflowPreflightV1 } from "../../shared/types.ts";
|
|
4
4
|
import { HOST_STEP_MAX_COUNT, HOST_STEP_MAX_DETAIL_CHARS, HOST_STEP_MAX_LABEL_CHARS, HOST_STEP_MAX_PROVIDER_CHARS, HOST_STEP_MAX_REASON_CHARS, HOST_STEP_MAX_REF_CHARS, HOST_STEP_MAX_ROLE_CHARS, HOST_STEP_MAX_TARGET_CHARS, hostStepReportName, parseHostStepNode, validHostStepNodes } from "./host-step-status.ts";
|
|
5
|
+
import { workflowPreflightLaneForRuntimeKey } from "../../workflows/workflow-preflight.ts";
|
|
5
6
|
import { workflowGraphStageNodes } from "./workflow-graph.ts";
|
|
6
7
|
|
|
7
8
|
export const ASYNC_STATUS_SNAPSHOT_KIND = "pi-subagents.async-status-snapshot";
|
|
@@ -472,7 +473,7 @@ function projectWorkflowGraphRow(node: WorkflowGraphSnapshot["nodes"][number], p
|
|
|
472
473
|
};
|
|
473
474
|
}
|
|
474
475
|
|
|
475
|
-
/** Project
|
|
476
|
+
/** Project authoritative workflow facts into compact rows, annotated by preflight hints. */
|
|
476
477
|
export function projectAsyncWorkflowRows(
|
|
477
478
|
steps: readonly AsyncJobStep[] | undefined,
|
|
478
479
|
hostStepsOrPreflight?: readonly HostStepNodeV1[] | WorkflowGraphSnapshot | WorkflowPreflightV1,
|
|
@@ -482,7 +483,8 @@ export function projectAsyncWorkflowRows(
|
|
|
482
483
|
const graph = isWorkflowGraph(hostStepsOrPreflight) ? hostStepsOrPreflight : undefined;
|
|
483
484
|
const hostSteps = isWorkflowPreflight(hostStepsOrPreflight) || graph ? undefined : hostStepsOrPreflight;
|
|
484
485
|
const loaded = steps ?? [];
|
|
485
|
-
const
|
|
486
|
+
const preflightForKey = (key: string, groupKeys: readonly (string | undefined)[] = []): WorkflowPreflightLaneV1 | undefined =>
|
|
487
|
+
workflowPreflightLaneForRuntimeKey(preflight, key, groupKeys);
|
|
486
488
|
if (graph) {
|
|
487
489
|
const loadedIndexesByKey = new Map<string, number[]>();
|
|
488
490
|
for (const [index, step] of loaded.entries()) {
|
|
@@ -493,7 +495,6 @@ export function projectAsyncWorkflowRows(
|
|
|
493
495
|
}
|
|
494
496
|
const consumed = new Set<number>();
|
|
495
497
|
const childRows: AsyncStatusWorkflowRow[] = [];
|
|
496
|
-
for (const lane of preflight?.lanes ?? []) declared.set(lane.key, lane);
|
|
497
498
|
const graphStages = workflowGraphStageNodes(graph);
|
|
498
499
|
const graphKeys = new Set(graphStages.map((node) => node.id));
|
|
499
500
|
const graphPhaseByNodeId = new Map<string, string>();
|
|
@@ -502,60 +503,27 @@ export function projectAsyncWorkflowRows(
|
|
|
502
503
|
if (graphKeys.has(nodeId) && !graphPhaseByNodeId.has(nodeId)) graphPhaseByNodeId.set(nodeId, phase.title);
|
|
503
504
|
}
|
|
504
505
|
}
|
|
505
|
-
const graphLaneKeys = new Set(graphPhaseByNodeId.values());
|
|
506
|
-
const preflightForNode = (node: WorkflowGraphSnapshot["nodes"][number]): WorkflowPreflightLaneV1 | undefined => {
|
|
507
|
-
const phaseTitle = graphPhaseByNodeId.get(node.id);
|
|
508
|
-
return declared.get(node.id) ?? (node.phase ? declared.get(node.phase) : undefined) ?? (phaseTitle ? declared.get(phaseTitle) : undefined);
|
|
509
|
-
};
|
|
510
506
|
for (const node of graphStages) {
|
|
507
|
+
const lane = preflightForKey(node.id, [node.phase, graphPhaseByNodeId.get(node.id)]);
|
|
511
508
|
const indexes = (loadedIndexesByKey.get(node.id) ?? []).filter((index) => !consumed.has(index));
|
|
512
|
-
if (indexes.length > 0) {
|
|
513
|
-
for (const index of indexes) {
|
|
514
|
-
consumed.add(index);
|
|
515
|
-
childRows.push(projectLoadedWorkflowRow(loaded[index]!, index, preflightForNode(node)));
|
|
516
|
-
}
|
|
517
|
-
} else {
|
|
518
|
-
childRows.push(projectWorkflowGraphRow(node, preflightForNode(node)));
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
for (const lane of preflight?.lanes ?? []) {
|
|
522
|
-
if (graphKeys.has(lane.key) || graphLaneKeys.has(lane.key)) continue;
|
|
523
|
-
const indexes = (loadedIndexesByKey.get(lane.key) ?? []).filter((index) => !consumed.has(index));
|
|
524
509
|
if (indexes.length > 0) {
|
|
525
510
|
for (const index of indexes) {
|
|
526
511
|
consumed.add(index);
|
|
527
512
|
childRows.push(projectLoadedWorkflowRow(loaded[index]!, index, lane));
|
|
528
513
|
}
|
|
529
514
|
} else {
|
|
530
|
-
childRows.push(
|
|
515
|
+
childRows.push(projectWorkflowGraphRow(node, lane));
|
|
531
516
|
}
|
|
532
517
|
}
|
|
533
518
|
for (const [index, step] of loaded.entries()) {
|
|
534
|
-
if (!consumed.has(index)) childRows.push(projectLoadedWorkflowRow(step, index, step.workflowKey ?
|
|
519
|
+
if (!consumed.has(index)) childRows.push(projectLoadedWorkflowRow(step, index, step.workflowKey ? preflightForKey(step.workflowKey, [step.phase]) : undefined));
|
|
535
520
|
}
|
|
536
521
|
return [...childRows, ...validHostStepList(graph).map(hostStepRow)];
|
|
537
522
|
}
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
const consumed = new Set<number>();
|
|
543
|
-
const childRows: AsyncStatusWorkflowRow[] = [];
|
|
544
|
-
for (const lane of preflight?.lanes ?? []) {
|
|
545
|
-
declared.set(lane.key, lane);
|
|
546
|
-
const index = loadedIndexByKey.get(lane.key);
|
|
547
|
-
if (index === undefined) {
|
|
548
|
-
childRows.push({ name: lane.key, state: "planned", preflight: lane });
|
|
549
|
-
continue;
|
|
550
|
-
}
|
|
551
|
-
consumed.add(index);
|
|
552
|
-
childRows.push(projectLoadedWorkflowRow(loaded[index]!, index, lane));
|
|
553
|
-
}
|
|
554
|
-
for (const [index, step] of loaded.entries()) {
|
|
555
|
-
if (consumed.has(index)) continue;
|
|
556
|
-
childRows.push(projectLoadedWorkflowRow(step, index, step.workflowKey ? declared.get(step.workflowKey) : undefined));
|
|
557
|
-
}
|
|
558
|
-
return [...childRows, ...validHostStepList(hostSteps).map(hostStepRow)];
|
|
523
|
+
return [
|
|
524
|
+
...loaded.map((step, index) => projectLoadedWorkflowRow(step, index, step.workflowKey ? preflightForKey(step.workflowKey, [step.phase]) : undefined)),
|
|
525
|
+
...validHostStepList(hostSteps).map(hostStepRow),
|
|
526
|
+
];
|
|
559
527
|
}
|
|
560
528
|
|
|
561
529
|
function projectLoadedWorkflowRow(step: AsyncJobStep, index: number, preflight?: WorkflowPreflightLaneV1): AsyncStatusWorkflowRow {
|
|
@@ -50,7 +50,7 @@ const DYNAMIC_PARALLEL_KEYS = new Set(["agent", "task", "phase", "label", "outpu
|
|
|
50
50
|
const RUNNER_DYNAMIC_PARALLEL_KEYS = new Set([
|
|
51
51
|
...DYNAMIC_PARALLEL_KEYS,
|
|
52
52
|
"outputName", "structured", "inheritProjectContext", "inheritGlobalContext", "inheritSkills", "skills", "outputPath", "namespaceOutputPath", "maxSubagentDepth", "timeoutMs", "waitToolEnabled", "waitToolDefaultTimeoutMs",
|
|
53
|
-
"structuredOutput", "structuredOutputSchema", "tools", "allowNestedSubagents", "extensions", "subagentOnlyExtensions", "mcpDirectTools", "mutationTools", "capabilityCeiling", "completionGuard", "systemPrompt",
|
|
53
|
+
"structuredOutput", "structuredOutputSchema", "tools", "excludeTools", "allowNestedSubagents", "extensions", "subagentOnlyExtensions", "mcpDirectTools", "mutationTools", "capabilityCeiling", "completionGuard", "systemPrompt",
|
|
54
54
|
"systemPromptMode", "thinking", "modelCandidates", "sessionFile", "effectiveAcceptance", "acceptanceInput", "acceptanceRole", "parentSessionId", "launchResolvedExtensions", "requestedCwd",
|
|
55
55
|
]);
|
|
56
56
|
const DYNAMIC_COLLECT_KEYS = new Set(["as", "outputSchema"]);
|