@mediadatafusion/pi-workflow-suite 0.0.15 → 0.0.17
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 +20 -0
- package/README.md +6 -6
- package/VERSION +1 -1
- package/config/prompts/mission-repair.md +3 -1
- package/config/prompts/workflow-repair.md +4 -2
- package/extensions/workflow-model-router.ts +84 -51
- package/extensions/workflow-modes.ts +334 -59
- package/package.json +13 -2
- package/scripts/verify-live.sh +46 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,26 @@
|
|
|
2
2
|
|
|
3
3
|
All notable public releases will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [0.0.17] - 2026-06-10
|
|
6
|
+
|
|
7
|
+
### Improved
|
|
8
|
+
|
|
9
|
+
- Improved package metadata to better reflect the suite's workflow modes, configuration surfaces, and orchestration features.
|
|
10
|
+
|
|
11
|
+
## [0.0.16] - 2026-06-09
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- Fixed Plan Mode recovery so interrupted or resumed workflows return to the correct state more reliably.
|
|
16
|
+
- Fixed Standard Mode completion cleanup to prevent stale active-status indicators after work is complete.
|
|
17
|
+
- Fixed workflow preset behavior so presets preserve user-selected model-routing preferences.
|
|
18
|
+
- Improved compaction recovery for continued workflow sessions.
|
|
19
|
+
- Refined repair flow handling so advisory follow-up notes do not unnecessarily block continued progress.
|
|
20
|
+
|
|
21
|
+
### Improved
|
|
22
|
+
|
|
23
|
+
- Improved overall workflow reliability across Plan, Standard, and repair flows.
|
|
24
|
+
|
|
5
25
|
## [0.0.15] - 2026-06-09
|
|
6
26
|
|
|
7
27
|
### Improved
|
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
[](#installation) [](#quick-start) [](#core-commands) [](#settings-reference)
|
|
6
6
|
|
|
7
|
-
**Workflow Suite Version:** `v0.0.
|
|
7
|
+
**Workflow Suite Version:** `v0.0.17`
|
|
8
8
|
|
|
9
9
|
## Overview
|
|
10
10
|
|
|
@@ -1007,8 +1007,8 @@ pi install -l npm:@mediadatafusion/pi-workflow-suite
|
|
|
1007
1007
|
### Installing specific versions
|
|
1008
1008
|
|
|
1009
1009
|
```bash
|
|
1010
|
-
pi install npm:@mediadatafusion/pi-workflow-suite@0.0.
|
|
1011
|
-
pi install -l npm:@mediadatafusion/pi-workflow-suite@0.0.
|
|
1010
|
+
pi install npm:@mediadatafusion/pi-workflow-suite@0.0.17
|
|
1011
|
+
pi install -l npm:@mediadatafusion/pi-workflow-suite@0.0.17
|
|
1012
1012
|
```
|
|
1013
1013
|
|
|
1014
1014
|
An unversioned install follows normal update behavior: `pi update` and `pi update --extensions` will pick up new package releases. A versioned install pins the package to that version. Pinned package specs are intentionally skipped by Pi's normal package update commands. To move a pinned install to a newer version, reinstall with the desired version. To switch back to latest tracking, use the unversioned install command without `@<version>`.
|
|
@@ -1214,10 +1214,10 @@ See `docs/TROUBLESHOOTING.md` for detailed diagnostics.
|
|
|
1214
1214
|
|
|
1215
1215
|
## Versioning
|
|
1216
1216
|
|
|
1217
|
-
The current preparation version is `v0.0.
|
|
1217
|
+
The current preparation version is `v0.0.17`. Version information is intentionally aligned across:
|
|
1218
1218
|
|
|
1219
|
-
- `VERSION` (`v0.0.
|
|
1220
|
-
- `package.json` (`0.0.
|
|
1219
|
+
- `VERSION` (`v0.0.17`),
|
|
1220
|
+
- `package.json` (`0.0.17`),
|
|
1221
1221
|
- `package-lock.json`,
|
|
1222
1222
|
- this README,
|
|
1223
1223
|
- Workflow Suite settings/about output.
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
v0.0.
|
|
1
|
+
v0.0.17
|
|
@@ -4,7 +4,7 @@ MANDATORY STRUCTURED HANDOFF: call workflow_repair_result before final response
|
|
|
4
4
|
|
|
5
5
|
You are PI MISSION MODE REPAIR EXECUTOR.
|
|
6
6
|
|
|
7
|
-
Repair
|
|
7
|
+
Repair concrete validator-identified failures for the current mission milestone and keep going while fixes are in-scope and non-destructive. Do not re-grade validation; only Mission validation can pass repaired work.
|
|
8
8
|
|
|
9
9
|
Rules:
|
|
10
10
|
- Only fix concrete issues directly related to the failed milestone validation.
|
|
@@ -32,6 +32,8 @@ Use only these exact installed agent names when calling the subagent tool. Do no
|
|
|
32
32
|
- Do not create arbitrary repository-root files. A root file is allowed only when the mission plan, user request, or validator finding names that exact root path.
|
|
33
33
|
- If a current-task-created file is in the wrong location but contains recoverable work, move or rename it to the correct approved location instead of deleting it.
|
|
34
34
|
- Treat untracked, unexpected, or ambiguous files as possibly user-owned; do not delete, overwrite, move, or clean them without explicit approval for that exact file.
|
|
35
|
+
- Do not set `needsUserApproval` for advisory-only follow-up, credential rotation recommendations, preserved ambiguous files, manual QA still needed, or pre-existing project debt. Put those in the summary/safety notes and let revalidation run.
|
|
36
|
+
- Set `needsUserApproval` only when a concrete hard-safety action or artifact disposition should pause automatic revalidation.
|
|
35
37
|
- Keep file writes sequential unless workflow settings explicitly allow safe scoped parallel edits.
|
|
36
38
|
- Preserve checkpoint integrity and disclose moved, preserved, deleted, root, and possibly user-owned files.
|
|
37
39
|
|
|
@@ -6,7 +6,7 @@ You are PI WORKFLOW REPAIR MODE.
|
|
|
6
6
|
|
|
7
7
|
Available tools in repair mode: edit, write, bash, workflow_diagram, workflow_progress, workflow_repair_result. The workflow_repair_result tool IS registered and active. If you cannot see it in your tool list, re-check — it is available. You MUST call it with your repair summary before finishing. Do not output a prose-only repair report; use the typed handoff tool.
|
|
8
8
|
|
|
9
|
-
Repair
|
|
9
|
+
Repair concrete validator-identified failed validation items for the approved Plan Mode workflow and keep going while fixes are in-scope and non-destructive. Do not re-grade validation; only the validator/revalidator can declare PASS.
|
|
10
10
|
|
|
11
11
|
Rules:
|
|
12
12
|
- The approved plan is still the execution contract.
|
|
@@ -14,11 +14,13 @@ Rules:
|
|
|
14
14
|
- Do not perform unrelated refactors.
|
|
15
15
|
- Do not commit, push, deploy, or mutate databases.
|
|
16
16
|
- Do not edit secrets, auth/session files, runtime logs/state, `.env`, `.factory`, or `.cursor` files.
|
|
17
|
-
- Stop and report if the repair requires destructive, out-of-scope, secret-adjacent, deployment, database, or otherwise risky action.
|
|
17
|
+
- Stop and report if the repair requires destructive, out-of-scope, secret-adjacent, deployment, database, protected runtime/auth/session, or otherwise truly risky action.
|
|
18
18
|
- Do not create arbitrary repository-root files. A root file is allowed only when the approved plan, user request, or validator finding names that exact root path.
|
|
19
19
|
- If a current-task-created file is in the wrong location but contains recoverable work, move or rename it to the correct approved location instead of deleting it.
|
|
20
20
|
- Treat untracked, unexpected, or ambiguous files as possibly user-owned; do not delete, overwrite, move, or clean them without explicit approval for that exact file.
|
|
21
21
|
- If the validation finding is only manual/visual/browser verification or says no code repair is needed, do not change code; summarize manual QA/revalidation readiness.
|
|
22
|
+
- Do not set `needsUserApproval` for advisory-only follow-up, credential rotation recommendations, preserved ambiguous files, manual QA still needed, or pre-existing project debt. Put those in the summary/safety notes and let revalidation run.
|
|
23
|
+
- Set `needsUserApproval` only when a concrete hard-safety action or artifact disposition should pause automatic revalidation.
|
|
22
24
|
- Use repair sub-agents aggressively for failure triage, missing-file inspection, patch planning, and validation preparation when policy allows/requires them.
|
|
23
25
|
|
|
24
26
|
## Available Sub-Agent Types
|
|
@@ -280,8 +280,8 @@ export interface WorkflowPresetBundle {
|
|
|
280
280
|
description?: string;
|
|
281
281
|
planning?: Partial<WorkflowSettings["planning"]>;
|
|
282
282
|
workflow?: Partial<WorkflowSettings["workflow"]>;
|
|
283
|
-
standard?: Partial<Omit<WorkflowSettings["standard"], "models"
|
|
284
|
-
missions?: Partial<Omit<WorkflowSettings["missions"], "models">>;
|
|
283
|
+
standard?: Partial<Omit<WorkflowSettings["standard"], "models" | "useSharedExecutorModel" | "useStandardSpecificModels" | "modelRole">>;
|
|
284
|
+
missions?: Partial<Omit<WorkflowSettings["missions"], "models" | "useMissionSpecificModels">>;
|
|
285
285
|
subagents?: Partial<WorkflowSettings["subagents"]>;
|
|
286
286
|
ui?: Partial<WorkflowSettings["ui"]>;
|
|
287
287
|
}
|
|
@@ -801,29 +801,55 @@ interface UpdateSettingsOptions {
|
|
|
801
801
|
preserveActivePreset?: boolean;
|
|
802
802
|
}
|
|
803
803
|
|
|
804
|
-
export const
|
|
804
|
+
export const WORKFLOW_CUSTOM_PRESET_MARKER = "custom";
|
|
805
|
+
|
|
806
|
+
function standardSettingsWithoutModelRouting(standard?: Partial<WorkflowSettings["standard"]>): Partial<WorkflowSettings["standard"]> {
|
|
807
|
+
const {
|
|
808
|
+
models: _ignoredModels,
|
|
809
|
+
useSharedExecutorModel: _ignoredUseSharedExecutorModel,
|
|
810
|
+
useStandardSpecificModels: _ignoredUseStandardSpecificModels,
|
|
811
|
+
modelRole: _ignoredModelRole,
|
|
812
|
+
...standardWithoutModelRouting
|
|
813
|
+
} = standard ?? {};
|
|
814
|
+
return standardWithoutModelRouting;
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
function missionSettingsWithoutModelRouting(missions?: Partial<WorkflowSettings["missions"]>): Partial<WorkflowSettings["missions"]> {
|
|
818
|
+
const {
|
|
819
|
+
models: _ignoredModels,
|
|
820
|
+
useMissionSpecificModels: _ignoredUseMissionSpecificModels,
|
|
821
|
+
...missionsWithoutModelRouting
|
|
822
|
+
} = missions ?? {};
|
|
823
|
+
return missionsWithoutModelRouting;
|
|
824
|
+
}
|
|
805
825
|
|
|
806
826
|
function presetOwnedSettingsSignature(settings: WorkflowSettings): string {
|
|
807
|
-
const { models: _ignoredStandardModels, ...standardWithoutModels } = settings.standard;
|
|
808
|
-
const { models: _ignoredMissionModels, ...missionsWithoutModels } = settings.missions;
|
|
809
827
|
return JSON.stringify({
|
|
810
828
|
planning: settings.planning,
|
|
811
829
|
workflow: settings.workflow,
|
|
812
|
-
standard:
|
|
813
|
-
missions:
|
|
830
|
+
standard: standardSettingsWithoutModelRouting(settings.standard),
|
|
831
|
+
missions: missionSettingsWithoutModelRouting(settings.missions),
|
|
814
832
|
subagents: settings.subagents,
|
|
815
833
|
});
|
|
816
834
|
}
|
|
817
835
|
|
|
818
836
|
function applyActivePresetOverlay(settings: WorkflowSettings): WorkflowSettings {
|
|
819
|
-
const active = settings.presets?.activePreset ??
|
|
820
|
-
if (active ===
|
|
837
|
+
const active = settings.presets?.activePreset ?? WORKFLOW_CUSTOM_PRESET_MARKER;
|
|
838
|
+
if (active === WORKFLOW_CUSTOM_PRESET_MARKER) return settings;
|
|
821
839
|
const preset = workflowPresetCatalog(settings)[active];
|
|
822
840
|
if (!preset) return settings;
|
|
823
841
|
const defaults = defaultWorkflowSettings();
|
|
824
842
|
const normalized = normalizeWorkflowPresetBundle(preset);
|
|
825
|
-
const
|
|
826
|
-
|
|
843
|
+
const currentStandardModelRouting = {
|
|
844
|
+
models: settings.standard.models,
|
|
845
|
+
useSharedExecutorModel: settings.standard.useSharedExecutorModel,
|
|
846
|
+
useStandardSpecificModels: settings.standard.useStandardSpecificModels,
|
|
847
|
+
modelRole: settings.standard.modelRole,
|
|
848
|
+
};
|
|
849
|
+
const currentMissionModelRouting = {
|
|
850
|
+
models: settings.missions.models,
|
|
851
|
+
useMissionSpecificModels: settings.missions.useMissionSpecificModels,
|
|
852
|
+
};
|
|
827
853
|
return {
|
|
828
854
|
...settings,
|
|
829
855
|
planning: normalized.planning ? { ...settings.planning, ...normalized.planning } : settings.planning,
|
|
@@ -833,9 +859,9 @@ function applyActivePresetOverlay(settings: WorkflowSettings): WorkflowSettings
|
|
|
833
859
|
...settings.standard,
|
|
834
860
|
...normalized.standard,
|
|
835
861
|
subagents: { ...(defaults.standard.subagents ?? {}), ...(settings.standard.subagents ?? {}), ...(normalized.standard.subagents ?? {}) },
|
|
836
|
-
|
|
862
|
+
...currentStandardModelRouting,
|
|
837
863
|
},
|
|
838
|
-
missions: normalized.missions ? { ...settings.missions, ...normalized.missions,
|
|
864
|
+
missions: normalized.missions ? { ...settings.missions, ...normalized.missions, ...currentMissionModelRouting } : settings.missions,
|
|
839
865
|
subagents: normalized.subagents ? { ...settings.subagents, ...normalized.subagents } : settings.subagents,
|
|
840
866
|
presets: settings.presets,
|
|
841
867
|
};
|
|
@@ -923,12 +949,12 @@ export function createProjectSettingsOverride(cwd: string): SettingsWriteResult
|
|
|
923
949
|
export function updateSettings(cwd: string, requestedScope: WorkflowSettingsScope | undefined, updater: (settings: WorkflowSettings) => void, options: UpdateSettingsOptions = {}): SettingsWriteResult {
|
|
924
950
|
const target = getWriteTarget(cwd, requestedScope);
|
|
925
951
|
const settings = target.scope === "global" ? loadGlobalSettings() : loadEffectiveSettings(cwd).settings;
|
|
926
|
-
const beforePreset = settings.presets?.activePreset ??
|
|
952
|
+
const beforePreset = settings.presets?.activePreset ?? WORKFLOW_CUSTOM_PRESET_MARKER;
|
|
927
953
|
const beforePresetOwned = presetOwnedSettingsSignature(settings);
|
|
928
954
|
updater(settings);
|
|
929
955
|
const afterPresetOwned = presetOwnedSettingsSignature(settings);
|
|
930
|
-
if (!options.preserveActivePreset && beforePreset !==
|
|
931
|
-
settings.presets = { ...(settings.presets ?? {}), activePreset:
|
|
956
|
+
if (!options.preserveActivePreset && beforePreset !== WORKFLOW_CUSTOM_PRESET_MARKER && settings.presets?.activePreset === beforePreset && beforePresetOwned !== afterPresetOwned) {
|
|
957
|
+
settings.presets = { ...(settings.presets ?? {}), activePreset: WORKFLOW_CUSTOM_PRESET_MARKER, items: { ...(settings.presets?.items ?? {}) } };
|
|
932
958
|
}
|
|
933
959
|
saveSettingsFile(target.file, settings);
|
|
934
960
|
return { settings, scope: target.scope, file: target.file };
|
|
@@ -941,7 +967,7 @@ export function builtInWorkflowPresets(): Record<string, WorkflowPresetBundle> {
|
|
|
941
967
|
description: "Fast end-to-end Plan/Mission/Standard workflow with minimal ceremony, automatic validation when work runs, low safe repair retries, and one-worker sub-agent support.",
|
|
942
968
|
planning: { depth: "fast", clarificationMode: "auto", maxClarificationQuestions: 2, interactiveClarificationEnabled: true, clarificationQualityGate: false, useSubagentsBeforeClarification: true },
|
|
943
969
|
workflow: { offerReviewerBeforeExecute: false, autoRunReviewerBeforeExecute: false, offerValidationAfterExecute: true, autoRunValidationAfterExecute: true, validateAfterExecution: true, requirePlanApprovalBeforeExecute: false, requireApprovalBeforeExecution: false, autoRepairReviewFailures: false, autoRepairValidationFailures: true, reviewRetryMode: "off", validationRetryMode: "safe_only", maxReviewRetriesPerPlan: 0, maxReviewRetriesPerWorkflow: 0, maxValidationRetriesPerPlan: 1, maxValidationRetriesPerWorkflow: 2, pauseAfterReviewFailure: true, pauseAfterValidationFailure: false, planProgressEnabled: true, planRuntimeEnabled: true, planShowProgressBar: true },
|
|
944
|
-
standard: { enabled: true, autoTodoEnabled: true, todoProgressVisible: true, todoTriggerMode: "auto", clarificationEnabled: true, clarificationMode: "auto", maxClarificationQuestions: 1, interactiveClarificationEnabled: true, clarificationTiming: "after_initial_analysis", clarificationQualityGate: false, allowClarificationWithoutAnalysis: false, useSubagentsBeforeClarification: false, allowSubagents: true, subagentScope: "user", subagents: { planningPolicy: "forced", executionPolicy: "forced", repairPolicy: "forced", reviewPolicy: "auto", validationPolicy: "forced", autoUseDuringPlanning: true, autoUseDuringExecution: true, autoUseDuringRepair: true, autoUseDuringReview: true, autoUseDuringValidation: true, minPlanningWorkersForDeep: 1, minPlanningWorkersForMaximum: 1, minExecutionWorkersForDeep: 1, minExecutionWorkersForMaximum: 1, minRepairWorkersForDeep: 1, minRepairWorkersForMaximum: 1, minReviewWorkersForDeep: 1, minReviewWorkersForMaximum: 1, minValidationWorkersForDeep: 1, minValidationWorkersForMaximum: 1 }, statusWidgetVisible: true
|
|
970
|
+
standard: { enabled: true, autoTodoEnabled: true, todoProgressVisible: true, todoTriggerMode: "auto", clarificationEnabled: true, clarificationMode: "auto", maxClarificationQuestions: 1, interactiveClarificationEnabled: true, clarificationTiming: "after_initial_analysis", clarificationQualityGate: false, allowClarificationWithoutAnalysis: false, useSubagentsBeforeClarification: false, allowSubagents: true, subagentScope: "user", subagents: { planningPolicy: "forced", executionPolicy: "forced", repairPolicy: "forced", reviewPolicy: "auto", validationPolicy: "forced", autoUseDuringPlanning: true, autoUseDuringExecution: true, autoUseDuringRepair: true, autoUseDuringReview: true, autoUseDuringValidation: true, minPlanningWorkersForDeep: 1, minPlanningWorkersForMaximum: 1, minExecutionWorkersForDeep: 1, minExecutionWorkersForMaximum: 1, minRepairWorkersForDeep: 1, minRepairWorkersForMaximum: 1, minReviewWorkersForDeep: 1, minReviewWorkersForMaximum: 1, minValidationWorkersForDeep: 1, minValidationWorkersForMaximum: 1 }, statusWidgetVisible: true },
|
|
945
971
|
missions: { defaultAutonomy: "approval_gated", requireValidationPerMilestone: true, autoRunAfterApproval: true, continueAcrossMilestones: true, pauseBetweenMilestones: false, clarificationMode: "auto", maxClarificationQuestions: 2, planningDepth: "fast", useSubagentsBeforeClarification: true, autoRepairReviewFailures: false, reviewRetryMode: "off", maxReviewRetriesPerMission: 0, autoRepairValidationFailures: true, validationRetryMode: "safe_only", maxValidationRetriesPerMilestone: 1, maxValidationRetriesPerMission: 2, finalValidationEnabled: false, autoRepairFinalValidationFailures: false, maxFinalValidationRetries: 0, subagentPolicy: "forced", minWorkersForDeep: 1, minWorkersForMaximum: 1 },
|
|
946
972
|
subagents: { planningPolicy: "forced", executionPolicy: "forced", repairPolicy: "forced", reviewPolicy: "auto", validationPolicy: "forced", autoUseDuringPlanning: true, autoUseDuringExecution: true, autoUseDuringRepair: true, autoUseDuringReview: true, autoUseDuringValidation: true, minPlanningWorkersForDeep: 1, minPlanningWorkersForMaximum: 1, minExecutionWorkersForDeep: 1, minExecutionWorkersForMaximum: 1, minRepairWorkersForDeep: 1, minRepairWorkersForMaximum: 1, minReviewWorkersForDeep: 1, minReviewWorkersForMaximum: 1, minValidationWorkersForDeep: 1, minValidationWorkersForMaximum: 1, allowBackgroundSubagents: false },
|
|
947
973
|
},
|
|
@@ -950,7 +976,7 @@ export function builtInWorkflowPresets(): Record<string, WorkflowPresetBundle> {
|
|
|
950
976
|
description: "Default end-to-end workflow with useful clarification, automatic execution/validation after approval, safe repair retries, and balanced worker support.",
|
|
951
977
|
planning: { depth: "standard", clarificationMode: "auto", maxClarificationQuestions: 3, interactiveClarificationEnabled: true, clarificationQualityGate: true, useSubagentsBeforeClarification: true },
|
|
952
978
|
workflow: { offerReviewerBeforeExecute: false, autoRunReviewerBeforeExecute: false, offerValidationAfterExecute: true, autoRunValidationAfterExecute: true, validateAfterExecution: true, requirePlanApprovalBeforeExecute: false, requireApprovalBeforeExecution: false, autoRepairReviewFailures: true, autoRepairValidationFailures: true, reviewRetryMode: "safe_only", validationRetryMode: "safe_only", maxReviewRetriesPerPlan: 2, maxReviewRetriesPerWorkflow: 4, maxValidationRetriesPerPlan: 2, maxValidationRetriesPerWorkflow: 4, pauseAfterReviewFailure: false, pauseAfterValidationFailure: false, planProgressEnabled: true, planRuntimeEnabled: true, planShowProgressBar: true },
|
|
953
|
-
standard: { enabled: true, autoTodoEnabled: true, todoProgressVisible: true, todoTriggerMode: "auto", clarificationEnabled: true, clarificationMode: "auto", maxClarificationQuestions: 1, interactiveClarificationEnabled: true, clarificationTiming: "after_initial_analysis", clarificationQualityGate: true, allowClarificationWithoutAnalysis: false, useSubagentsBeforeClarification: false, allowSubagents: true, subagentScope: "user", subagents: { planningPolicy: "forced", executionPolicy: "forced", repairPolicy: "forced", reviewPolicy: "forced", validationPolicy: "forced", autoUseDuringPlanning: true, autoUseDuringExecution: true, autoUseDuringRepair: true, autoUseDuringReview: true, autoUseDuringValidation: true, minPlanningWorkersForDeep: 1, minPlanningWorkersForMaximum: 1, minExecutionWorkersForDeep: 2, minExecutionWorkersForMaximum: 2, minRepairWorkersForDeep: 2, minRepairWorkersForMaximum: 2, minReviewWorkersForDeep: 2, minReviewWorkersForMaximum: 2, minValidationWorkersForDeep: 2, minValidationWorkersForMaximum: 2 }, statusWidgetVisible: true
|
|
979
|
+
standard: { enabled: true, autoTodoEnabled: true, todoProgressVisible: true, todoTriggerMode: "auto", clarificationEnabled: true, clarificationMode: "auto", maxClarificationQuestions: 1, interactiveClarificationEnabled: true, clarificationTiming: "after_initial_analysis", clarificationQualityGate: true, allowClarificationWithoutAnalysis: false, useSubagentsBeforeClarification: false, allowSubagents: true, subagentScope: "user", subagents: { planningPolicy: "forced", executionPolicy: "forced", repairPolicy: "forced", reviewPolicy: "forced", validationPolicy: "forced", autoUseDuringPlanning: true, autoUseDuringExecution: true, autoUseDuringRepair: true, autoUseDuringReview: true, autoUseDuringValidation: true, minPlanningWorkersForDeep: 1, minPlanningWorkersForMaximum: 1, minExecutionWorkersForDeep: 2, minExecutionWorkersForMaximum: 2, minRepairWorkersForDeep: 2, minRepairWorkersForMaximum: 2, minReviewWorkersForDeep: 2, minReviewWorkersForMaximum: 2, minValidationWorkersForDeep: 2, minValidationWorkersForMaximum: 2 }, statusWidgetVisible: true },
|
|
954
980
|
missions: { defaultAutonomy: "approval_gated", requireValidationPerMilestone: true, autoRunAfterApproval: true, continueAcrossMilestones: true, pauseBetweenMilestones: false, clarificationMode: "auto", maxClarificationQuestions: 3, planningDepth: "standard", useSubagentsBeforeClarification: true, autoRepairReviewFailures: true, reviewRetryMode: "safe_only", maxReviewRetriesPerMission: 2, autoRepairValidationFailures: true, validationRetryMode: "safe_only", maxValidationRetriesPerMilestone: 2, maxValidationRetriesPerMission: 6, finalValidationEnabled: false, autoRepairFinalValidationFailures: false, maxFinalValidationRetries: 1, subagentPolicy: "forced", minWorkersForDeep: 1, minWorkersForMaximum: 1 },
|
|
955
981
|
subagents: { planningPolicy: "forced", executionPolicy: "forced", repairPolicy: "forced", reviewPolicy: "forced", validationPolicy: "forced", autoUseDuringPlanning: true, autoUseDuringExecution: true, autoUseDuringRepair: true, autoUseDuringReview: true, autoUseDuringValidation: true, minPlanningWorkersForDeep: 1, minPlanningWorkersForMaximum: 1, minExecutionWorkersForDeep: 2, minExecutionWorkersForMaximum: 2, minRepairWorkersForDeep: 2, minRepairWorkersForMaximum: 2, minReviewWorkersForDeep: 2, minReviewWorkersForMaximum: 2, minValidationWorkersForDeep: 2, minValidationWorkersForMaximum: 2, allowBackgroundSubagents: false },
|
|
956
982
|
},
|
|
@@ -959,7 +985,7 @@ export function builtInWorkflowPresets(): Record<string, WorkflowPresetBundle> {
|
|
|
959
985
|
description: "Careful end-to-end workflow for risky or codebase-heavy work with stronger clarification, manual Plan review, automatic validation, final mission validation, and larger worker teams.",
|
|
960
986
|
planning: { depth: "deep", clarificationMode: "always_for_nontrivial", maxClarificationQuestions: 5, interactiveClarificationEnabled: true, clarificationQualityGate: true, useSubagentsBeforeClarification: true },
|
|
961
987
|
workflow: { offerReviewerBeforeExecute: false, autoRunReviewerBeforeExecute: false, offerValidationAfterExecute: true, autoRunValidationAfterExecute: true, validateAfterExecution: true, requirePlanApprovalBeforeExecute: false, requireApprovalBeforeExecution: false, autoRepairReviewFailures: true, autoRepairValidationFailures: true, reviewRetryMode: "safe_only", validationRetryMode: "safe_only", maxReviewRetriesPerPlan: 3, maxReviewRetriesPerWorkflow: 6, maxValidationRetriesPerPlan: 3, maxValidationRetriesPerWorkflow: 6, pauseAfterReviewFailure: false, pauseAfterValidationFailure: false, planProgressEnabled: true, planRuntimeEnabled: true, planShowProgressBar: true },
|
|
962
|
-
standard: { enabled: true, autoTodoEnabled: true, todoProgressVisible: true, todoTriggerMode: "auto", clarificationEnabled: true, clarificationMode: "auto", maxClarificationQuestions: 2, interactiveClarificationEnabled: true, clarificationTiming: "after_initial_analysis", clarificationQualityGate: true, allowClarificationWithoutAnalysis: false, useSubagentsBeforeClarification: true, allowSubagents: true, subagentScope: "user", subagents: { planningPolicy: "forced", executionPolicy: "forced", repairPolicy: "forced", reviewPolicy: "forced", validationPolicy: "forced", autoUseDuringPlanning: true, autoUseDuringExecution: true, autoUseDuringRepair: true, autoUseDuringReview: true, autoUseDuringValidation: true, minPlanningWorkersForDeep: 2, minPlanningWorkersForMaximum: 2, minExecutionWorkersForDeep: 3, minExecutionWorkersForMaximum: 3, minRepairWorkersForDeep: 2, minRepairWorkersForMaximum: 2, minReviewWorkersForDeep: 3, minReviewWorkersForMaximum: 3, minValidationWorkersForDeep: 3, minValidationWorkersForMaximum: 3 }, statusWidgetVisible: true
|
|
988
|
+
standard: { enabled: true, autoTodoEnabled: true, todoProgressVisible: true, todoTriggerMode: "auto", clarificationEnabled: true, clarificationMode: "auto", maxClarificationQuestions: 2, interactiveClarificationEnabled: true, clarificationTiming: "after_initial_analysis", clarificationQualityGate: true, allowClarificationWithoutAnalysis: false, useSubagentsBeforeClarification: true, allowSubagents: true, subagentScope: "user", subagents: { planningPolicy: "forced", executionPolicy: "forced", repairPolicy: "forced", reviewPolicy: "forced", validationPolicy: "forced", autoUseDuringPlanning: true, autoUseDuringExecution: true, autoUseDuringRepair: true, autoUseDuringReview: true, autoUseDuringValidation: true, minPlanningWorkersForDeep: 2, minPlanningWorkersForMaximum: 2, minExecutionWorkersForDeep: 3, minExecutionWorkersForMaximum: 3, minRepairWorkersForDeep: 2, minRepairWorkersForMaximum: 2, minReviewWorkersForDeep: 3, minReviewWorkersForMaximum: 3, minValidationWorkersForDeep: 3, minValidationWorkersForMaximum: 3 }, statusWidgetVisible: true },
|
|
963
989
|
missions: { defaultAutonomy: "approval_gated", requireValidationPerMilestone: true, autoRunAfterApproval: true, continueAcrossMilestones: true, pauseBetweenMilestones: false, clarificationMode: "always_for_nontrivial", maxClarificationQuestions: 5, planningDepth: "deep", useSubagentsBeforeClarification: true, autoRepairReviewFailures: true, reviewRetryMode: "safe_only", maxReviewRetriesPerMission: 3, autoRepairValidationFailures: true, validationRetryMode: "safe_only", maxValidationRetriesPerMilestone: 3, maxValidationRetriesPerMission: 8, finalValidationEnabled: true, autoRepairFinalValidationFailures: true, maxFinalValidationRetries: 2, subagentPolicy: "forced", minWorkersForDeep: 3, minWorkersForMaximum: 3 },
|
|
964
990
|
subagents: { planningPolicy: "forced", executionPolicy: "forced", repairPolicy: "forced", reviewPolicy: "forced", validationPolicy: "forced", autoUseDuringPlanning: true, autoUseDuringExecution: true, autoUseDuringRepair: true, autoUseDuringReview: true, autoUseDuringValidation: true, minPlanningWorkersForDeep: 3, minPlanningWorkersForMaximum: 3, minExecutionWorkersForDeep: 3, minExecutionWorkersForMaximum: 3, minRepairWorkersForDeep: 2, minRepairWorkersForMaximum: 2, minReviewWorkersForDeep: 3, minReviewWorkersForMaximum: 3, minValidationWorkersForDeep: 3, minValidationWorkersForMaximum: 3, allowBackgroundSubagents: true },
|
|
965
991
|
},
|
|
@@ -968,7 +994,7 @@ export function builtInWorkflowPresets(): Record<string, WorkflowPresetBundle> {
|
|
|
968
994
|
description: "Highest-rigor end-to-end workflow with strongest clarification, automatic review/validation, final mission validation, aggressive in-scope repair, and maximum worker teams.",
|
|
969
995
|
planning: { depth: "maximum", clarificationMode: "always_for_nontrivial", maxClarificationQuestions: 5, interactiveClarificationEnabled: true, clarificationQualityGate: true, useSubagentsBeforeClarification: true },
|
|
970
996
|
workflow: { offerReviewerBeforeExecute: false, autoRunReviewerBeforeExecute: true, offerValidationAfterExecute: true, autoRunValidationAfterExecute: true, validateAfterExecution: true, requirePlanApprovalBeforeExecute: false, requireApprovalBeforeExecution: false, autoRepairReviewFailures: true, autoRepairValidationFailures: true, reviewRetryMode: "aggressive_within_scope", validationRetryMode: "aggressive_within_scope", maxReviewRetriesPerPlan: 5, maxReviewRetriesPerWorkflow: 8, maxValidationRetriesPerPlan: 5, maxValidationRetriesPerWorkflow: 8, pauseAfterReviewFailure: false, pauseAfterValidationFailure: false, planProgressEnabled: true, planRuntimeEnabled: true, planShowProgressBar: true },
|
|
971
|
-
standard: { enabled: true, autoTodoEnabled: true, todoProgressVisible: true, todoTriggerMode: "auto", clarificationEnabled: true, clarificationMode: "auto", maxClarificationQuestions: 2, interactiveClarificationEnabled: true, clarificationTiming: "after_initial_analysis", clarificationQualityGate: true, allowClarificationWithoutAnalysis: false, useSubagentsBeforeClarification: true, allowSubagents: true, subagentScope: "user", subagents: { planningPolicy: "forced", executionPolicy: "forced", repairPolicy: "forced", reviewPolicy: "forced", validationPolicy: "forced", autoUseDuringPlanning: true, autoUseDuringExecution: true, autoUseDuringRepair: true, autoUseDuringReview: true, autoUseDuringValidation: true, minPlanningWorkersForDeep: 3, minPlanningWorkersForMaximum: 3, minExecutionWorkersForDeep: 4, minExecutionWorkersForMaximum: 4, minRepairWorkersForDeep: 3, minRepairWorkersForMaximum: 3, minReviewWorkersForDeep: 4, minReviewWorkersForMaximum: 4, minValidationWorkersForDeep: 4, minValidationWorkersForMaximum: 4 }, statusWidgetVisible: true
|
|
997
|
+
standard: { enabled: true, autoTodoEnabled: true, todoProgressVisible: true, todoTriggerMode: "auto", clarificationEnabled: true, clarificationMode: "auto", maxClarificationQuestions: 2, interactiveClarificationEnabled: true, clarificationTiming: "after_initial_analysis", clarificationQualityGate: true, allowClarificationWithoutAnalysis: false, useSubagentsBeforeClarification: true, allowSubagents: true, subagentScope: "user", subagents: { planningPolicy: "forced", executionPolicy: "forced", repairPolicy: "forced", reviewPolicy: "forced", validationPolicy: "forced", autoUseDuringPlanning: true, autoUseDuringExecution: true, autoUseDuringRepair: true, autoUseDuringReview: true, autoUseDuringValidation: true, minPlanningWorkersForDeep: 3, minPlanningWorkersForMaximum: 3, minExecutionWorkersForDeep: 4, minExecutionWorkersForMaximum: 4, minRepairWorkersForDeep: 3, minRepairWorkersForMaximum: 3, minReviewWorkersForDeep: 4, minReviewWorkersForMaximum: 4, minValidationWorkersForDeep: 4, minValidationWorkersForMaximum: 4 }, statusWidgetVisible: true },
|
|
972
998
|
missions: { defaultAutonomy: "supervised_auto", requireValidationPerMilestone: true, autoRunAfterApproval: true, continueAcrossMilestones: true, pauseBetweenMilestones: false, clarificationMode: "always_for_nontrivial", maxClarificationQuestions: 6, planningDepth: "maximum", useSubagentsBeforeClarification: true, autoRepairReviewFailures: true, reviewRetryMode: "aggressive_within_scope", maxReviewRetriesPerMission: 5, autoRepairValidationFailures: true, validationRetryMode: "aggressive_within_scope", maxValidationRetriesPerMilestone: 4, maxValidationRetriesPerMission: 12, finalValidationEnabled: true, autoRepairFinalValidationFailures: true, maxFinalValidationRetries: 4, subagentPolicy: "forced", minWorkersForDeep: 4, minWorkersForMaximum: 4 },
|
|
973
999
|
subagents: { planningPolicy: "forced", executionPolicy: "forced", repairPolicy: "forced", reviewPolicy: "forced", validationPolicy: "forced", autoUseDuringPlanning: true, autoUseDuringExecution: true, autoUseDuringRepair: true, autoUseDuringReview: true, autoUseDuringValidation: true, minPlanningWorkersForDeep: 4, minPlanningWorkersForMaximum: 4, minExecutionWorkersForDeep: 4, minExecutionWorkersForMaximum: 4, minRepairWorkersForDeep: 3, minRepairWorkersForMaximum: 3, minReviewWorkersForDeep: 4, minReviewWorkersForMaximum: 4, minValidationWorkersForDeep: 4, minValidationWorkersForMaximum: 4, allowBackgroundSubagents: true },
|
|
974
1000
|
},
|
|
@@ -977,35 +1003,43 @@ export function builtInWorkflowPresets(): Record<string, WorkflowPresetBundle> {
|
|
|
977
1003
|
|
|
978
1004
|
function normalizeWorkflowPresetBundle(preset: WorkflowPresetBundle): WorkflowPresetBundle & { standard: WorkflowSettings["standard"] } {
|
|
979
1005
|
const defaults = defaultWorkflowSettings();
|
|
980
|
-
const
|
|
1006
|
+
const standardWithoutModelRouting = standardSettingsWithoutModelRouting(preset.standard as Partial<WorkflowSettings["standard"]> | undefined);
|
|
981
1007
|
return {
|
|
982
1008
|
...preset,
|
|
983
1009
|
// Legacy custom presets saved before Standard Mode do not contain a
|
|
984
1010
|
// standard section. Hydrate it from safe defaults during apply so stale
|
|
985
1011
|
// Standard settings from the previously active preset cannot leak forward.
|
|
986
|
-
standard: normalizeStandardSettings(defaults, defaults.standard,
|
|
1012
|
+
standard: normalizeStandardSettings(defaults, defaults.standard, standardWithoutModelRouting as Partial<WorkflowSettings>["standard"] | undefined),
|
|
1013
|
+
missions: missionSettingsWithoutModelRouting(preset.missions as Partial<WorkflowSettings["missions"]> | undefined),
|
|
987
1014
|
};
|
|
988
1015
|
}
|
|
989
1016
|
|
|
990
1017
|
function workflowPresetBundleWithoutUserOwnedSettings(preset: WorkflowPresetBundle): WorkflowPresetBundle {
|
|
991
1018
|
const { context: _ignoredContext, ...presetWithoutContext } = preset as WorkflowPresetBundle & { context?: unknown };
|
|
992
|
-
const { models: _ignoredStandardModels, ...standardWithoutModels } = (preset.standard ?? {}) as Partial<WorkflowSettings["standard"]>;
|
|
993
|
-
const { models: _ignoredMissionModels, ...missionsWithoutModels } = (preset.missions ?? {}) as Partial<WorkflowSettings["missions"]>;
|
|
994
1019
|
return {
|
|
995
1020
|
...presetWithoutContext,
|
|
996
|
-
standard: { ...
|
|
997
|
-
missions: { ...
|
|
1021
|
+
standard: { ...standardSettingsWithoutModelRouting(preset.standard as Partial<WorkflowSettings["standard"]> | undefined) },
|
|
1022
|
+
missions: { ...missionSettingsWithoutModelRouting(preset.missions as Partial<WorkflowSettings["missions"]> | undefined) },
|
|
998
1023
|
};
|
|
999
1024
|
}
|
|
1000
1025
|
|
|
1001
1026
|
function applyPresetBundle(settings: WorkflowSettings, preset: WorkflowPresetBundle, name: string): void {
|
|
1002
1027
|
const defaults = defaultWorkflowSettings();
|
|
1003
1028
|
const normalized = normalizeWorkflowPresetBundle(preset);
|
|
1004
|
-
const
|
|
1029
|
+
const currentStandardModelRouting = {
|
|
1030
|
+
models: settings.standard.models,
|
|
1031
|
+
useSharedExecutorModel: settings.standard.useSharedExecutorModel,
|
|
1032
|
+
useStandardSpecificModels: settings.standard.useStandardSpecificModels,
|
|
1033
|
+
modelRole: settings.standard.modelRole,
|
|
1034
|
+
};
|
|
1035
|
+
const currentMissionModelRouting = {
|
|
1036
|
+
models: settings.missions.models,
|
|
1037
|
+
useMissionSpecificModels: settings.missions.useMissionSpecificModels,
|
|
1038
|
+
};
|
|
1005
1039
|
if (normalized.planning) settings.planning = { ...settings.planning, ...normalized.planning };
|
|
1006
1040
|
if (normalized.workflow) settings.workflow = { ...settings.workflow, ...normalized.workflow };
|
|
1007
|
-
settings.standard = { ...defaults.standard, ...normalized.standard, subagents: { ...(defaults.standard.subagents ?? {}), ...(normalized.standard?.subagents ?? {}) },
|
|
1008
|
-
if (normalized.missions) settings.missions = { ...settings.missions, ...normalized.missions,
|
|
1041
|
+
settings.standard = { ...defaults.standard, ...normalized.standard, subagents: { ...(defaults.standard.subagents ?? {}), ...(normalized.standard?.subagents ?? {}) }, ...currentStandardModelRouting };
|
|
1042
|
+
if (normalized.missions) settings.missions = { ...settings.missions, ...normalized.missions, ...currentMissionModelRouting };
|
|
1009
1043
|
if (normalized.subagents) settings.subagents = { ...settings.subagents, ...normalized.subagents };
|
|
1010
1044
|
if (normalized.ui) settings.ui = { ...settings.ui, ...normalized.ui };
|
|
1011
1045
|
settings.presets = { ...(settings.presets ?? {}), activePreset: name, items: { ...(settings.presets?.items ?? {}) } };
|
|
@@ -1017,34 +1051,34 @@ export function normalizeWorkflowPresetName(name: string): string {
|
|
|
1017
1051
|
|
|
1018
1052
|
export function workflowPresetCatalog(settings: WorkflowSettings = loadGlobalSettings()): Record<string, WorkflowPresetBundle> {
|
|
1019
1053
|
const items = { ...(settings.presets?.items ?? {}) };
|
|
1020
|
-
delete items[
|
|
1054
|
+
delete items[WORKFLOW_CUSTOM_PRESET_MARKER];
|
|
1021
1055
|
return { ...builtInWorkflowPresets(), ...items };
|
|
1022
1056
|
}
|
|
1023
1057
|
|
|
1024
1058
|
export function workflowPresetNames(settings: WorkflowSettings = loadGlobalSettings()): string[] {
|
|
1025
1059
|
const builtIns = ["simple", "standard", "deep", "maximum"];
|
|
1026
1060
|
const custom = Object.keys(settings.presets?.items ?? {}).sort((a, b) => a.localeCompare(b));
|
|
1027
|
-
return [...builtIns, ...custom.filter((name) => name !==
|
|
1061
|
+
return [...builtIns, ...custom.filter((name) => name !== WORKFLOW_CUSTOM_PRESET_MARKER && !builtIns.includes(name))];
|
|
1028
1062
|
}
|
|
1029
1063
|
|
|
1030
1064
|
export function workflowPresetLabel(name: string, preset?: WorkflowPresetBundle): string {
|
|
1031
|
-
if (name ===
|
|
1065
|
+
if (name === WORKFLOW_CUSTOM_PRESET_MARKER) return "No active preset";
|
|
1032
1066
|
return preset?.displayName?.trim() || name;
|
|
1033
1067
|
}
|
|
1034
1068
|
|
|
1035
1069
|
export function workflowPresetTitle(name: string, preset?: WorkflowPresetBundle): string {
|
|
1036
|
-
if (name ===
|
|
1070
|
+
if (name === WORKFLOW_CUSTOM_PRESET_MARKER) return "No active preset";
|
|
1037
1071
|
return preset?.displayName?.trim() || name;
|
|
1038
1072
|
}
|
|
1039
1073
|
|
|
1040
1074
|
export function activeWorkflowPresetLabel(settings: WorkflowSettings): string {
|
|
1041
|
-
const active = settings.presets?.activePreset ??
|
|
1042
|
-
if (active ===
|
|
1075
|
+
const active = settings.presets?.activePreset ?? WORKFLOW_CUSTOM_PRESET_MARKER;
|
|
1076
|
+
if (active === WORKFLOW_CUSTOM_PRESET_MARKER) return "No active preset";
|
|
1043
1077
|
return workflowPresetLabel(active, workflowPresetCatalog(settings)[active]);
|
|
1044
1078
|
}
|
|
1045
1079
|
|
|
1046
1080
|
function assertValidCustomPresetName(name: string, safe: string): void {
|
|
1047
|
-
if (safe ===
|
|
1081
|
+
if (safe === WORKFLOW_CUSTOM_PRESET_MARKER) throw new Error(`Reserved workflow preset name: ${name}. Use a specific preset name instead of custom.`);
|
|
1048
1082
|
}
|
|
1049
1083
|
|
|
1050
1084
|
function sectionCoverage(section: unknown): "configured" | "missing" {
|
|
@@ -1052,9 +1086,9 @@ function sectionCoverage(section: unknown): "configured" | "missing" {
|
|
|
1052
1086
|
}
|
|
1053
1087
|
|
|
1054
1088
|
export function workflowPresetDiagnostics(name: string, preset?: WorkflowPresetBundle): string[] {
|
|
1055
|
-
if (name ===
|
|
1089
|
+
if (name === WORKFLOW_CUSTOM_PRESET_MARKER) return ["Diagnostic: reserved custom marker; no saved preset bundle is active."];
|
|
1056
1090
|
const lines: string[] = [];
|
|
1057
|
-
if (normalizeWorkflowPresetName(name) ===
|
|
1091
|
+
if (normalizeWorkflowPresetName(name) === WORKFLOW_CUSTOM_PRESET_MARKER) lines.push("Diagnostic: reserved-name collision; rename this preset before use.");
|
|
1058
1092
|
const standard = sectionCoverage(preset?.standard);
|
|
1059
1093
|
const planning = sectionCoverage(preset?.planning);
|
|
1060
1094
|
const workflow = sectionCoverage(preset?.workflow);
|
|
@@ -1084,8 +1118,8 @@ export function workflowPresetPickerLabel(name: string, preset?: WorkflowPresetB
|
|
|
1084
1118
|
}
|
|
1085
1119
|
|
|
1086
1120
|
export function workflowPresetMeaningLines(name: string, preset?: WorkflowPresetBundle): string[] {
|
|
1087
|
-
if (name ===
|
|
1088
|
-
"Name:
|
|
1121
|
+
if (name === WORKFLOW_CUSTOM_PRESET_MARKER) return [
|
|
1122
|
+
"Name: No active preset",
|
|
1089
1123
|
"Purpose: uses the current workflow settings exactly as saved; this is not a built-in speed or rigor profile.",
|
|
1090
1124
|
"Applies to: the Standard, Plan, Mission, and shared sub-agent settings currently saved in workflow-settings.json.",
|
|
1091
1125
|
"Standard Mode: uses the saved Standard Mode To Do, clarification, continuation, and sub-agent settings.",
|
|
@@ -1160,11 +1194,11 @@ export function renderWorkflowPresetCard(name: string, preset?: WorkflowPresetBu
|
|
|
1160
1194
|
}
|
|
1161
1195
|
|
|
1162
1196
|
export function renderActiveWorkflowPresetSummary(settings: WorkflowSettings): string {
|
|
1163
|
-
const active = settings.presets?.activePreset ??
|
|
1164
|
-
const preset = active ===
|
|
1197
|
+
const active = settings.presets?.activePreset ?? WORKFLOW_CUSTOM_PRESET_MARKER;
|
|
1198
|
+
const preset = active === WORKFLOW_CUSTOM_PRESET_MARKER ? undefined : workflowPresetCatalog(settings)[active];
|
|
1165
1199
|
const lines = workflowPresetMeaningLines(active, preset);
|
|
1166
1200
|
lines.push("Effective Settings: detailed current values are listed below.");
|
|
1167
|
-
if (active !==
|
|
1201
|
+
if (active !== WORKFLOW_CUSTOM_PRESET_MARKER) lines.push(`Reapply Command: /workflow presets apply ${active}`);
|
|
1168
1202
|
return lines.join("\n");
|
|
1169
1203
|
}
|
|
1170
1204
|
|
|
@@ -1184,10 +1218,10 @@ export function resolveWorkflowPresetName(settings: WorkflowSettings, input: str
|
|
|
1184
1218
|
|
|
1185
1219
|
export function renderWorkflowPresets(settings: WorkflowSettings = loadGlobalSettings()): string {
|
|
1186
1220
|
const catalog = workflowPresetCatalog(settings);
|
|
1187
|
-
const active = settings.presets?.activePreset ??
|
|
1221
|
+
const active = settings.presets?.activePreset ?? WORKFLOW_CUSTOM_PRESET_MARKER;
|
|
1188
1222
|
const names = workflowPresetNames(settings);
|
|
1189
|
-
const cards = [renderWorkflowPresetCard(
|
|
1190
|
-
return `# Workflow Presets\n\nActive Preset: ${activeWorkflowPresetLabel(settings)}\nShortcut: Ctrl+Shift+U cycles saved presets while Plan/Mission/Standard Mode is active\nSelector: /workflow presets\n\n${cards.join("\n\n") || "No presets available."}\n\nQuick commands:\n- /workflow presets list\n- /workflow presets apply <name>\n- /workflow presets next\n- /workflow presets prev\n- /workflow presets
|
|
1223
|
+
const cards = [renderWorkflowPresetCard(WORKFLOW_CUSTOM_PRESET_MARKER, undefined, active === WORKFLOW_CUSTOM_PRESET_MARKER), ...names.map((name) => renderWorkflowPresetCard(name, catalog[name], name === active))];
|
|
1224
|
+
return `# Workflow Presets\n\nActive Preset: ${activeWorkflowPresetLabel(settings)}\nShortcut: Ctrl+Shift+U cycles saved presets while Plan/Mission/Standard Mode is active\nSelector: /workflow presets\n\n${cards.join("\n\n") || "No presets available."}\n\nQuick commands:\n- /workflow presets list\n- /workflow presets apply <name>\n- /workflow presets next\n- /workflow presets prev\n- /workflow presets save <name>\n- /workflow presets create <name> from simple|standard|deep|maximum\n- /workflow presets edit <name>\n- /workflow presets rename <old> to <new>\n- /workflow presets delete <name>\n\nBuilt-in presets are package-defined and sync with the extension. User-named custom presets are saved entries in workflow-settings.json and stay in hotkey cycling. The reserved custom marker only means no built-in or user-named preset is active. Extension updates preserve workflow-settings.json and do not overwrite custom presets. Presets adjust workflow behavior only and preserve model/provider choices, API keys, auth/session files, runtime workflow state, and shared compaction settings.`;
|
|
1191
1225
|
}
|
|
1192
1226
|
|
|
1193
1227
|
export function applyWorkflowPreset(cwd: string, requestedScope: WorkflowSettingsScope | undefined, name: string): SettingsWriteResult {
|
|
@@ -1205,14 +1239,13 @@ export function saveCurrentWorkflowPreset(cwd: string, requestedScope: WorkflowS
|
|
|
1205
1239
|
assertValidCustomPresetName(name, safe);
|
|
1206
1240
|
return updateSettings(cwd, requestedScope, (settings) => {
|
|
1207
1241
|
settings.presets = { ...(settings.presets ?? {}), activePreset: safe, items: { ...(settings.presets?.items ?? {}) } };
|
|
1208
|
-
const { models: _ignoredStandardModels, ...standardPreset } = settings.standard;
|
|
1209
1242
|
settings.presets.items![safe] = {
|
|
1210
1243
|
displayName: name.trim(),
|
|
1211
1244
|
description: "Custom saved workflow preset.",
|
|
1212
1245
|
planning: { ...settings.planning },
|
|
1213
1246
|
workflow: { ...settings.workflow },
|
|
1214
|
-
standard: { ...
|
|
1215
|
-
missions: { ...settings.missions
|
|
1247
|
+
standard: { ...standardSettingsWithoutModelRouting(settings.standard) } as WorkflowPresetBundle["standard"],
|
|
1248
|
+
missions: { ...missionSettingsWithoutModelRouting(settings.missions) } as WorkflowPresetBundle["missions"],
|
|
1216
1249
|
subagents: { ...settings.subagents },
|
|
1217
1250
|
ui: { showWorkflowStatus: settings.ui.showWorkflowStatus, showPlanModeIndicator: settings.ui.showPlanModeIndicator, planTopWidgetVisible: settings.ui.planTopWidgetVisible, planBottomWidgetVisible: settings.ui.planBottomWidgetVisible, missionTopWidgetVisible: settings.ui.missionTopWidgetVisible, missionBottomWidgetVisible: settings.ui.missionBottomWidgetVisible, workflowTheme: settings.ui.workflowTheme, workflowThemeOverrides: settings.ui.workflowThemeOverrides, startupVisual: settings.ui.startupVisual, startupVisualOnSessionStart: settings.ui.startupVisualOnSessionStart, customBrandEnabled: settings.ui.customBrandEnabled, customBrandText: settings.ui.customBrandText },
|
|
1218
1251
|
};
|
|
@@ -1256,7 +1289,7 @@ export function deleteWorkflowPreset(cwd: string, requestedScope: WorkflowSettin
|
|
|
1256
1289
|
if (!resolved || builtInWorkflowPresets()[resolved]) throw new Error(`Cannot delete unknown or built-in workflow preset: ${name}`);
|
|
1257
1290
|
const items = { ...(settings.presets?.items ?? {}) };
|
|
1258
1291
|
delete items[resolved];
|
|
1259
|
-
settings.presets = { ...(settings.presets ?? {}), activePreset: settings.presets?.activePreset === resolved ?
|
|
1292
|
+
settings.presets = { ...(settings.presets ?? {}), activePreset: settings.presets?.activePreset === resolved ? WORKFLOW_CUSTOM_PRESET_MARKER : settings.presets?.activePreset, items };
|
|
1260
1293
|
}, { preserveActivePreset: true });
|
|
1261
1294
|
}
|
|
1262
1295
|
|
|
@@ -1413,7 +1446,7 @@ export function workflowSettingsConsistencyDiagnostics(settings: WorkflowSetting
|
|
|
1413
1446
|
if (settings.missions.autoRepairReviewFailures !== false && settings.missions.reviewRetryMode === "off") {
|
|
1414
1447
|
diagnostics.push("mission review auto-repair is enabled but reviewRetryMode is off — override to safe_only will be applied at runtime; set reviewRetryMode explicitly to avoid confusion");
|
|
1415
1448
|
}
|
|
1416
|
-
const activePreset = settings.presets?.activePreset ??
|
|
1449
|
+
const activePreset = settings.presets?.activePreset ?? WORKFLOW_CUSTOM_PRESET_MARKER;
|
|
1417
1450
|
if ((activePreset === "standard" || activePreset === "deep" || activePreset === "maximum")
|
|
1418
1451
|
&& (settings.missions.autoRepairReviewFailures === false || settings.missions.reviewRetryMode === "off" || (settings.missions.maxReviewRetriesPerMission ?? 0) <= 0)) {
|
|
1419
1452
|
diagnostics.push(`active preset ${activePreset} expects Mission review repair to be available, but effective Mission review repair is disabled/off/zero; reapply the preset or update missions.autoRepairReviewFailures, missions.reviewRetryMode, and missions.maxReviewRetriesPerMission`);
|
|
@@ -8,7 +8,7 @@ import { StringEnum } from "@earendil-works/pi-ai";
|
|
|
8
8
|
import type { AssistantMessage, TextContent } from "@earendil-works/pi-ai";
|
|
9
9
|
import { CustomEditor, VERSION, compact as piCompact, estimateTokens as piEstimateTokens, findCutPoint as piFindCutPoint, getAgentDir, getMarkdownTheme, type ExtensionAPI, type ExtensionContext, type FileOperations, type SessionEntry, type ToolDefinition } from "@earendil-works/pi-coding-agent";
|
|
10
10
|
import { Type } from "typebox";
|
|
11
|
-
import { activeWorkflowPresetLabel, applyMissionModelForRole, applyModelForRole, applyStandardModelForRole, applyWorkflowPreset, compactionModeLabel, createProjectSettingsOverride, createWorkflowPreset, defaultWorkflowSettings, deleteWorkflowPreset, effectivePlanApprovalRequired, effectiveReviewAutoRun, effectiveValidateAfterExecution, effectiveValidationAutoRun, effectiveRepairGate, formatRole, getDefaultWriteTarget, loadEffectiveSettings, loadGlobalSettings, loadWorkflowSettings, normalizeWorkflowPresetName, parseMissionModelRole, parseRole, parseThinkingLevel, renameWorkflowPreset, renderActiveWorkflowPresetSummary, renderStandardModelStrategy, renderWorkflowModels, renderWorkflowPresets, resolveWorkflowPresetName, roleIsConfigured, saveCurrentWorkflowPreset, setMissionModelForRole, setMissionThinkingForRole, setModelForRole, setRoleEnabled, setStandardModelForRole, setStandardThinkingForRole, setThinkingForRole, standardModelSource, standardModelSourceLabel, standardTodoTriggerModeLabel, updateSettings, workflowCompactionCheckModeLabel, workflowPresetCatalog, workflowPresetLabel, workflowPresetNames, workflowPresetPickerLabel, workflowRoleLabel, workflowSettingsConsistencyDiagnostics,
|
|
11
|
+
import { activeWorkflowPresetLabel, applyMissionModelForRole, applyModelForRole, applyStandardModelForRole, applyWorkflowPreset, compactionModeLabel, createProjectSettingsOverride, createWorkflowPreset, defaultWorkflowSettings, deleteWorkflowPreset, effectivePlanApprovalRequired, effectiveReviewAutoRun, effectiveValidateAfterExecution, effectiveValidationAutoRun, effectiveRepairGate, formatRole, getDefaultWriteTarget, loadEffectiveSettings, loadGlobalSettings, loadWorkflowSettings, normalizeWorkflowPresetName, parseMissionModelRole, parseRole, parseThinkingLevel, renameWorkflowPreset, renderActiveWorkflowPresetSummary, renderStandardModelStrategy, renderWorkflowModels, renderWorkflowPresets, resolveWorkflowPresetName, roleIsConfigured, saveCurrentWorkflowPreset, setMissionModelForRole, setMissionThinkingForRole, setModelForRole, setRoleEnabled, setStandardModelForRole, setStandardThinkingForRole, setThinkingForRole, standardModelSource, standardModelSourceLabel, standardTodoTriggerModeLabel, updateSettings, workflowCompactionCheckModeLabel, workflowPresetCatalog, workflowPresetLabel, workflowPresetNames, workflowPresetPickerLabel, workflowRoleLabel, workflowSettingsConsistencyDiagnostics, WORKFLOW_CUSTOM_PRESET_MARKER, WORKFLOW_SETTINGS_FILE, type MissionModelRole, type RoleModelSettings, type WorkflowRole, type WorkflowSettingsScope, type WorkflowStartupLogo, type WorkflowStartupLogoColorStyle, type WorkflowStartupLogoFont, type WorkflowStartupLogoShadowDirection, type WorkflowStartupVisual, type CustomBrandBaseVisual, type StandardClarificationMode, type StandardModelRole, type StandardTodoTriggerMode, type WorkflowAgentScope } from "./workflow-model-router.js";
|
|
12
12
|
import { renderHandoffProjectContext, renderWorkflowStatus, renderWorkflowSummary } from "./workflow-summary.js";
|
|
13
13
|
import { BASE_EXECUTE_TOOLS, EXECUTE_TOOLS, PLAN_TOOLS, REVIEW_TOOLS, WORKFLOW_DIAGRAM_TOOL, WORKFLOW_PLAN_RESULT_TOOL, WORKFLOW_REVIEW_RESULT_TOOL, WORKFLOW_EXECUTION_RESULT_TOOL, WORKFLOW_VALIDATION_RESULT_TOOL, WORKFLOW_REPAIR_RESULT_TOOL, WORKFLOW_PROGRESS_TOOL, MISSION_PLAN_RESULT_TOOL, MISSION_MILESTONE_RESULT_TOOL, STANDARD_HANDOFF_RESULT_TOOL, isBlockedExecuteCommand, registerToolGuard, standardSafeReadOnlyBash, VALIDATOR_TOOLS } from "./workflow-tool-guard.js";
|
|
14
14
|
import { refreshRuntimeWebTools, registerWorkflowWebTools, runtimeWebResearchGuidance, webSafePlanTools, withRuntimeWebTools } from "./workflow-web-tools.js";
|
|
@@ -1918,7 +1918,7 @@ function artifactSafetyPolicyBlock(audience: ArtifactSafetyAudience = "general")
|
|
|
1918
1918
|
: audience === "validation"
|
|
1919
1919
|
? `Validation requirement: remain read-only. Prefer text evidence over temporary files; if evidence files are unavoidable, do not write them at repository root and never repair or relocate files during validation.`
|
|
1920
1920
|
: audience === "repair"
|
|
1921
|
-
? `Repair requirement:
|
|
1921
|
+
? `Repair requirement: keep repairing concrete in-scope failures until revalidation is ready. Repair may move only current-task-created misplaced recoverable files when safe and in scope. Disclose moved, preserved, deleted, root, and possibly user-owned files in workflow_repair_result; set needsUserApproval only when a concrete hard-safety action or artifact disposition must stop automatic revalidation. Advisory follow-up, credential rotation recommendations, preserved ambiguous files, manual QA still needed, and pre-existing debt belong in summary/safety notes, not needsUserApproval. Deletion requires explicit safety evidence or approval.`
|
|
1922
1922
|
: audience === "subagent"
|
|
1923
1923
|
? `Sub-agent requirement: support workers default to read-only inspection. They must not create, delete, move, or clean files unless explicitly authorized with path-approved scope by the parent workflow.`
|
|
1924
1924
|
: `General requirement: keep artifact placement explicit, preserve recoverable content, and report uncertain cleanup for user approval.`;
|
|
@@ -1927,7 +1927,7 @@ function artifactSafetyPolicyBlock(audience: ArtifactSafetyAudience = "general")
|
|
|
1927
1927
|
|
|
1928
1928
|
function repairArtifactDispositionOutput(): string {
|
|
1929
1929
|
return `## Artifact Disposition
|
|
1930
|
-
List movedFiles, preservedFiles, deletedFiles, rootArtifacts, possiblyUserOwnedFiles, and needsUserApproval. State "none" for empty categories. Deletion is acceptable only when explicitly approved or clearly current-task-generated, unrecoverable, and non-user-owned; otherwise preserve or request approval.`;
|
|
1930
|
+
List movedFiles, preservedFiles, deletedFiles, rootArtifacts, possiblyUserOwnedFiles, and needsUserApproval. State "none" for empty categories. Set needsUserApproval only for a concrete disposition/action that should block automatic revalidation. Do not set it for advisory-only follow-up, credential rotation recommendations, preserved ambiguous files, manual QA still needed, or pre-existing debt. Deletion is acceptable only when explicitly approved or clearly current-task-generated, unrecoverable, and non-user-owned; otherwise preserve or request approval.`;
|
|
1931
1931
|
}
|
|
1932
1932
|
|
|
1933
1933
|
function phasePromptPolicyBlock(settings: ReturnType<typeof loadWorkflowSettings>, phase: SubagentPhase, label: string = phase, preflightBlock?: string): string {
|
|
@@ -2286,7 +2286,7 @@ ${professionalOutputGuidance("Plan repair")}
|
|
|
2286
2286
|
Diagram guidance:
|
|
2287
2287
|
${workflowMermaidGuidance()}
|
|
2288
2288
|
|
|
2289
|
-
Approved plan remains the execution contract. Repair
|
|
2289
|
+
Approved plan remains the execution contract. Repair concrete validator-identified failures below and keep going while fixes are in-scope and non-destructive. Do not expand scope. Do not commit. Do not push. Do not deploy. Do not change secrets, auth/session files, database schema/data, or environment files unless the user explicitly approved that exact repair. Repair mode cannot declare the work PASS; only a subsequent validator/revalidator can do that. If no safe concrete edit is appropriate because the finding involves only manual/visual/browser verification or an evidence gap, produce a no-op repair summary recommending revalidation. Do not make unsafe or out-of-scope edits solely to produce file changes. Do not mark advisory-only follow-up as needsUserApproval; preserve it in the summary and allow revalidation.
|
|
2290
2290
|
|
|
2291
2291
|
${artifactSafetyPolicyBlock("repair")}
|
|
2292
2292
|
|
|
@@ -3020,7 +3020,7 @@ function workflowActivePhaseDisplay(value: string | undefined): WorkflowActivePh
|
|
|
3020
3020
|
}
|
|
3021
3021
|
|
|
3022
3022
|
function standardActivePresentation(state: WorkflowState): boolean {
|
|
3023
|
-
return state.standardRuntime?.active === true
|
|
3023
|
+
return state.standardRuntime?.active === true;
|
|
3024
3024
|
}
|
|
3025
3025
|
|
|
3026
3026
|
function standardDisplayPhase(state: WorkflowState): string {
|
|
@@ -3209,6 +3209,16 @@ function compactionTriggerOverrideLabel(settings: ReturnType<typeof loadWorkflow
|
|
|
3209
3209
|
return typeof value === "number" ? `${value}%` : "none";
|
|
3210
3210
|
}
|
|
3211
3211
|
|
|
3212
|
+
function resetCompactionContextToPiDefault(context: ReturnType<typeof loadWorkflowSettings>["context"]): void {
|
|
3213
|
+
context.compactionMode = "pi_default";
|
|
3214
|
+
context.customCompactionEnabled = false;
|
|
3215
|
+
context.compactionAgent = "";
|
|
3216
|
+
context.customCompactionReserveTokens = DEFAULT_PI_COMPACTION_RESERVE_TOKENS;
|
|
3217
|
+
context.customCompactionKeepRecentTokens = DEFAULT_PI_COMPACTION_KEEP_RECENT_TOKENS;
|
|
3218
|
+
context.workflowCompactionCheckMode = "boundary";
|
|
3219
|
+
delete context.compactionTriggerPercent;
|
|
3220
|
+
}
|
|
3221
|
+
|
|
3212
3222
|
function effectiveWorkflowCompactionTriggerPercent(settings: ReturnType<typeof loadWorkflowSettings>, ctx: ExtensionContext, usage: { contextWindow?: number }): number {
|
|
3213
3223
|
const configured = compactionTriggerPercent(settings);
|
|
3214
3224
|
if (!customModelCompactionConfigured(settings)) return configured;
|
|
@@ -4268,7 +4278,7 @@ function standardTodoWidget(state: WorkflowState, settings: ReturnType<typeof lo
|
|
|
4268
4278
|
const done = standardTodoDoneCount(todo);
|
|
4269
4279
|
const current = standardTodoCurrentIndex(todo);
|
|
4270
4280
|
const next = todo.items.findIndex((item, index) => index > current && item.status === "pending");
|
|
4271
|
-
const status = todo.status === "active" ?
|
|
4281
|
+
const status = todo.status === "active" ? standardDisplayPhase(state) : todo.status;
|
|
4272
4282
|
return [
|
|
4273
4283
|
...progressHeaderLines("STANDARD", workflowHeaderState(status), standardTodoProgressBar(todo, settings), standardTodoRuntimeSummaryLine(state), `To Do: ${done} of ${todo.items.length}`),
|
|
4274
4284
|
`Current: ${standardTodoItemLabel(todo, current, "Standard assistance")}`,
|
|
@@ -6533,25 +6543,32 @@ function subagentActivityLines(ctx: ExtensionContext, activeSubagents: ActiveSub
|
|
|
6533
6543
|
return [title, ...fgLines, ...bgLines];
|
|
6534
6544
|
}
|
|
6535
6545
|
|
|
6546
|
+
function composeBottomProgressWidgetLines(leftLines: string[], rightLines: string[] = [], width: number): string[] {
|
|
6547
|
+
const safeWidth = Math.max(0, width);
|
|
6548
|
+
if (!rightLines.length) return leftLines.map((line) => truncateVisibleText(line, safeWidth));
|
|
6549
|
+
const reservedRightWidth = Math.min(safeWidth, Math.max(28, Math.min(36, Math.max(...rightLines.map(visibleTextWidth)))));
|
|
6550
|
+
const gapWidth = safeWidth > reservedRightWidth ? 1 : 0;
|
|
6551
|
+
const leftWidth = Math.max(0, safeWidth - reservedRightWidth - gapWidth);
|
|
6552
|
+
const rowCount = Math.max(leftLines.length, rightLines.length);
|
|
6553
|
+
return Array.from({ length: rowCount }, (_, index) => {
|
|
6554
|
+
const left = leftLines[index];
|
|
6555
|
+
const right = rightLines[index];
|
|
6556
|
+
const clippedLeft = left ? truncateVisibleText(left, leftWidth) : "";
|
|
6557
|
+
const clippedRight = right ? truncateVisibleText(right, reservedRightWidth) : "";
|
|
6558
|
+
if (!right) return truncateVisibleText(clippedLeft, safeWidth);
|
|
6559
|
+
if (!clippedLeft) {
|
|
6560
|
+
const rightOnlyGap = Math.max(0, safeWidth - visibleTextWidth(clippedRight));
|
|
6561
|
+
return truncateVisibleText(`${" ".repeat(rightOnlyGap)}${clippedRight}`, safeWidth);
|
|
6562
|
+
}
|
|
6563
|
+
const desiredGap = Math.max(gapWidth, safeWidth - visibleTextWidth(clippedLeft) - visibleTextWidth(clippedRight));
|
|
6564
|
+
return truncateVisibleText(`${clippedLeft}${" ".repeat(desiredGap)}${clippedRight}`, safeWidth);
|
|
6565
|
+
});
|
|
6566
|
+
}
|
|
6567
|
+
|
|
6536
6568
|
function bottomProgressWidget(leftLines: string[], rightLines: string[] = []): (tui: unknown, theme: unknown) => { render(width: number): string[]; invalidate(): void } {
|
|
6537
6569
|
return () => ({
|
|
6538
6570
|
render(width: number) {
|
|
6539
|
-
|
|
6540
|
-
if (!rightLines.length) return leftLines.map((line) => truncateVisibleText(line, safeWidth));
|
|
6541
|
-
const reservedRightWidth = Math.min(safeWidth, Math.max(28, Math.min(36, Math.max(...rightLines.map(visibleTextWidth)))));
|
|
6542
|
-
const gapWidth = safeWidth > reservedRightWidth ? 1 : 0;
|
|
6543
|
-
const leftWidth = Math.max(0, safeWidth - reservedRightWidth - gapWidth);
|
|
6544
|
-
const rowCount = Math.max(leftLines.length, rightLines.length);
|
|
6545
|
-
return Array.from({ length: rowCount }, (_, index) => {
|
|
6546
|
-
const left = leftLines[index];
|
|
6547
|
-
const right = rightLines[index];
|
|
6548
|
-
const clippedLeft = left ? truncateVisibleText(left, leftWidth) : "";
|
|
6549
|
-
const clippedRight = right ? truncateVisibleText(right, reservedRightWidth) : "";
|
|
6550
|
-
if (!right) return truncateVisibleText(clippedLeft, safeWidth);
|
|
6551
|
-
if (!clippedLeft) return truncateVisibleText(clippedRight, safeWidth);
|
|
6552
|
-
const desiredGap = Math.max(gapWidth, safeWidth - visibleTextWidth(clippedLeft) - visibleTextWidth(clippedRight));
|
|
6553
|
-
return truncateVisibleText(`${clippedLeft}${" ".repeat(desiredGap)}${clippedRight}`, safeWidth);
|
|
6554
|
-
});
|
|
6571
|
+
return composeBottomProgressWidgetLines(leftLines, rightLines, width);
|
|
6555
6572
|
},
|
|
6556
6573
|
invalidate() {},
|
|
6557
6574
|
});
|
|
@@ -6885,7 +6902,6 @@ function workflowArtifactOverlaps(possiblyUserOwnedPath: string, mutatedPath: st
|
|
|
6885
6902
|
}
|
|
6886
6903
|
|
|
6887
6904
|
function repairArtifactSafetyBlock(params: Record<string, unknown>): string | undefined {
|
|
6888
|
-
if (params.needsUserApproval === true) return "Typed repair result requires user approval for artifact disposition.";
|
|
6889
6905
|
const deletedFiles = workflowStringArray(params.deletedFiles);
|
|
6890
6906
|
if (deletedFiles.length > 0) return "Typed repair result reported deleted files; user review is required before revalidation.";
|
|
6891
6907
|
const possiblyUserOwned = workflowStringArray(params.possiblyUserOwnedFiles);
|
|
@@ -6898,6 +6914,12 @@ function repairArtifactSafetyBlock(params: Record<string, unknown>): string | un
|
|
|
6898
6914
|
const mutatedArtifact = mutatedArtifacts.find((artifact) => possiblyUserOwned.some((path) => workflowArtifactOverlaps(path, artifact)));
|
|
6899
6915
|
if (mutatedArtifact) return `Typed repair result changed or moved possibly user-owned file: ${mutatedArtifact}`;
|
|
6900
6916
|
}
|
|
6917
|
+
if (params.needsUserApproval === true) {
|
|
6918
|
+
const movedFiles = workflowStringArray(params.movedFiles);
|
|
6919
|
+
if (movedFiles.length > 0) return "Typed repair result requires user approval for moved file disposition.";
|
|
6920
|
+
const rootArtifacts = workflowStringArray(params.rootArtifacts);
|
|
6921
|
+
if (rootArtifacts.length > 0) return "Typed repair result requires user approval for root artifact disposition.";
|
|
6922
|
+
}
|
|
6901
6923
|
return undefined;
|
|
6902
6924
|
}
|
|
6903
6925
|
|
|
@@ -8040,7 +8062,74 @@ function missionRepairPrompt(mission: MissionState, settings: ReturnType<typeof
|
|
|
8040
8062
|
const last = mission.checkpoints[mission.checkpoints.length - 1];
|
|
8041
8063
|
const repairPrompt = readPromptFile("mission-repair.md", "Repair only the current mission milestone validation failure safely, then summarize for revalidation.");
|
|
8042
8064
|
const subagentPolicyBlock = phasePromptPolicyBlock(settings, "Repair", "Mission Repair", preflightBlock);
|
|
8043
|
-
return `${repairPrompt}
|
|
8065
|
+
return `${repairPrompt}
|
|
8066
|
+
|
|
8067
|
+
${professionalOutputGuidance("Mission repair")}
|
|
8068
|
+
|
|
8069
|
+
Mission ID: ${mission.id}
|
|
8070
|
+
Mission goal:
|
|
8071
|
+
${mission.goal}
|
|
8072
|
+
|
|
8073
|
+
Autonomy: ${mission.autonomy}
|
|
8074
|
+
Current milestone: ${milestone ? `${milestone.id} — ${milestone.title}` : "none"}
|
|
8075
|
+
Approved milestone scope:
|
|
8076
|
+
Objective: ${milestone?.objective ?? "none"}
|
|
8077
|
+
Steps:
|
|
8078
|
+
${(milestone?.steps ?? []).map((s) => `- ${s}`).join("\n") || "- none recorded"}
|
|
8079
|
+
Validation requirements:
|
|
8080
|
+
${(milestone?.validation ?? []).map((s) => `- ${s}`).join("\n") || "- none recorded"}
|
|
8081
|
+
Risks:
|
|
8082
|
+
${(milestone?.risks ?? []).map((s) => `- ${s}`).join("\n") || "- none recorded"}
|
|
8083
|
+
|
|
8084
|
+
Validation failure details:
|
|
8085
|
+
${mission.lastValidationFailure || mission.lastBlockReason || "none recorded"}
|
|
8086
|
+
|
|
8087
|
+
Retry count: ${mission.currentValidationRetry ?? 0} of ${maxValidationRetries(mission, settings)} per milestone
|
|
8088
|
+
Mission retry count: ${missionValidationRetryCount(mission)} of ${maxMissionValidationRetries(mission, settings)} total
|
|
8089
|
+
Last repair attempt: ${mission.lastRepairAttempt || "none"}
|
|
8090
|
+
Last checkpoint: ${last ? `${last.id} at ${last.timestamp} — ${last.summary}` : "none"}
|
|
8091
|
+
|
|
8092
|
+
Safety rules:
|
|
8093
|
+
- Only fix concrete validator-identified issues directly related to the failed milestone validation.
|
|
8094
|
+
- Do not re-grade validation or claim PASS; only Mission validation can pass repaired work.
|
|
8095
|
+
- If the validation finding is only manual/visual/browser verification or says no automated repair is needed, do not make changes; summarize manual QA/revalidation readiness.
|
|
8096
|
+
- Do not expand scope beyond the current approved milestone.
|
|
8097
|
+
- Do not perform destructive actions.
|
|
8098
|
+
- Do not edit secrets, auth/session/log/runtime-state files, .env, .factory, or .cursor.
|
|
8099
|
+
- Do not deploy. Do not push. Do not mutate databases.
|
|
8100
|
+
- Stop and report if repair requires destructive, out-of-scope, secret, database, deployment, or other risky action.
|
|
8101
|
+
- Keep repairing concrete in-scope failures while fixes are non-destructive.
|
|
8102
|
+
- Do not mark advisory-only follow-up as needsUserApproval; preserve credential rotation recommendations, preserved ambiguous files, manual QA still needed, and pre-existing debt in the summary/safety notes and allow revalidation.
|
|
8103
|
+
|
|
8104
|
+
${artifactSafetyPolicyBlock("repair")}
|
|
8105
|
+
|
|
8106
|
+
Settings:
|
|
8107
|
+
- validationRetryMode: ${settings.missions.validationRetryMode ?? "safe_only"}
|
|
8108
|
+
- requireApprovalForOutOfScopeRepair: ${settings.missions.requireApprovalForOutOfScopeRepair !== false}
|
|
8109
|
+
- requireApprovalForDestructiveRepair: ${settings.missions.requireApprovalForDestructiveRepair !== false}
|
|
8110
|
+
- autoRepairValidationFailures: ${settings.missions.autoRepairValidationFailures !== false}
|
|
8111
|
+
- pauseAfterValidationFailure: ${settings.missions.pauseAfterValidationFailure === true}
|
|
8112
|
+
|
|
8113
|
+
${subagentPolicyBlock}${requiredSubagentPreflightSection(preflightBlock)}
|
|
8114
|
+
|
|
8115
|
+
${subagentCapabilityTable()}
|
|
8116
|
+
|
|
8117
|
+
Diagram guidance:
|
|
8118
|
+
${workflowMermaidGuidance()}
|
|
8119
|
+
|
|
8120
|
+
Revalidation requirement:
|
|
8121
|
+
- Summarize whether the current milestone is ready for validator revalidation.
|
|
8122
|
+
- Do not mark the milestone complete yourself; Mission Mode will re-run validation according to repair/retry settings.
|
|
8123
|
+
|
|
8124
|
+
Output:
|
|
8125
|
+
# Mission Repair Summary
|
|
8126
|
+
## Repair Scope
|
|
8127
|
+
## Work Completed
|
|
8128
|
+
## Files Changed
|
|
8129
|
+
${repairArtifactDispositionOutput()}
|
|
8130
|
+
## Remaining Risks
|
|
8131
|
+
## Revalidation Readiness
|
|
8132
|
+
## Next Action`;
|
|
8044
8133
|
}
|
|
8045
8134
|
|
|
8046
8135
|
function parseMissionMilestones(text: string): MissionMilestone[] {
|
|
@@ -8570,7 +8659,7 @@ export default function workflowModes(pi: ExtensionAPI): void {
|
|
|
8570
8659
|
const reason = workflowTypedSummary(params, "Structured Standard handoff recorded.");
|
|
8571
8660
|
const patch: Partial<WorkflowState> = { standardLastAutoCheckAt: new Date().toISOString(), standardLastClarificationDecision: clarificationDecision ? standardClarificationDisplay(clarificationDecision) : undefined, standardLastClarificationReason: reason, standardLastTodoDecision: todoDecision ? standardTodoDisplay(todoDecision) : undefined, standardLastTodoReason: reason };
|
|
8572
8661
|
const todoItems = workflowStringArray(params.todoItems);
|
|
8573
|
-
if (todoItems.length && (todoDecision === "create" || todoDecision === "required")) patch.standardTodo = createStandardTodoFromTitles(state.task ?? state.originalTask ?? "Standard Mode task", todoItems) ?? state.standardTodo;
|
|
8662
|
+
if (todoItems.length && (todoDecision === "create" || todoDecision === "required") && !state.standardTodo?.items.length) patch.standardTodo = createStandardTodoFromTitles(state.task ?? state.originalTask ?? "Standard Mode task", todoItems) ?? state.standardTodo;
|
|
8574
8663
|
if (clarificationDecision === "ask") {
|
|
8575
8664
|
const questions = normalizeTypedClarificationQuestions(params.questions, Math.max(1, Math.min(2, settings.standard.maxClarificationQuestions ?? 1)));
|
|
8576
8665
|
Object.assign(patch, { standardClarificationPending: true, standardClarificationStage: "awaiting_answer", standardClarificationRequirementReason: reason, standardClarifyingQuestions: questions.length ? questions : undefined });
|
|
@@ -8883,6 +8972,7 @@ export default function workflowModes(pi: ExtensionAPI): void {
|
|
|
8883
8972
|
return;
|
|
8884
8973
|
}
|
|
8885
8974
|
if (state.mode === "standard") {
|
|
8975
|
+
finalizeStandardTerminalStateIfIdle(ctx, `user wait: ${reason}`);
|
|
8886
8976
|
setStandardRuntimeActive(ctx, false);
|
|
8887
8977
|
traceWorkflowTracking(ctx, "standard-runtime-user-wait", { reason });
|
|
8888
8978
|
return;
|
|
@@ -8906,6 +8996,7 @@ export default function workflowModes(pi: ExtensionAPI): void {
|
|
|
8906
8996
|
traceWorkflowTracking(ctx, "standard-runtime-pause-deferred", { reason });
|
|
8907
8997
|
return;
|
|
8908
8998
|
}
|
|
8999
|
+
finalizeStandardTerminalStateIfIdle(ctx, `idle pause: ${reason}`);
|
|
8909
9000
|
setStandardRuntimeActive(ctx, false);
|
|
8910
9001
|
};
|
|
8911
9002
|
const scheduleStandardRuntimeIdleCheck = (ctx: ExtensionContext, reason: string): void => {
|
|
@@ -8913,6 +9004,46 @@ export default function workflowModes(pi: ExtensionAPI): void {
|
|
|
8913
9004
|
if (state.mode === "standard") pauseStandardRuntimeIfIdle(ctx, reason);
|
|
8914
9005
|
}, 0);
|
|
8915
9006
|
};
|
|
9007
|
+
const completeStandardTodoForTerminalHandoff = (todo: StandardTodoState | undefined): StandardTodoState | undefined => {
|
|
9008
|
+
if (!todo?.items.length || todo.status === "completed" || todo.status === "blocked") return todo;
|
|
9009
|
+
const hasBlocked = todo.items.some((item) => item.status === "blocked");
|
|
9010
|
+
const items = todo.items.map((item) => item.status === "blocked" ? item : item.status === "skipped" ? item : { ...item, status: "completed" as const });
|
|
9011
|
+
return {
|
|
9012
|
+
...todo,
|
|
9013
|
+
updatedAt: new Date().toISOString(),
|
|
9014
|
+
status: hasBlocked ? "blocked" : "completed",
|
|
9015
|
+
currentItemIndex: Math.max(0, items.length - 1),
|
|
9016
|
+
items,
|
|
9017
|
+
};
|
|
9018
|
+
};
|
|
9019
|
+
const standardTerminalStatePatch = (completeTodo: boolean): Partial<WorkflowState> => {
|
|
9020
|
+
const terminalTodo = completeTodo ? completeStandardTodoForTerminalHandoff(state.standardTodo) : state.standardTodo;
|
|
9021
|
+
return {
|
|
9022
|
+
lastWorkflowHandoff: undefined,
|
|
9023
|
+
standardActivePhase: undefined,
|
|
9024
|
+
standardWorkKind: undefined,
|
|
9025
|
+
standardClarificationPending: false,
|
|
9026
|
+
standardClarificationStage: state.standardClarificationStage === "drafting" || state.standardClarificationStage === "awaiting_answer" ? undefined : state.standardClarificationStage,
|
|
9027
|
+
standardTodo: terminalTodo,
|
|
9028
|
+
standardRuntime: state.standardRuntime ? { ...state.standardRuntime, active: false, runtimeCounter: "paused" } : state.standardRuntime,
|
|
9029
|
+
};
|
|
9030
|
+
};
|
|
9031
|
+
const finalizeStandardTerminalStateIfIdle = (ctx: ExtensionContext, reason: string): boolean => {
|
|
9032
|
+
if (state.mode !== "standard") return false;
|
|
9033
|
+
if (workflowHasActiveOrPendingWork()) {
|
|
9034
|
+
traceWorkflowTracking(ctx, "standard-terminal-finalize-deferred", { reason });
|
|
9035
|
+
return false;
|
|
9036
|
+
}
|
|
9037
|
+
const hasAcceptedFinalHandoff = state.lastWorkflowHandoff?.type === STANDARD_HANDOFF_RESULT_TOOL
|
|
9038
|
+
&& state.standardClarificationStage !== "awaiting_answer";
|
|
9039
|
+
const hasStalePausedPresentation = state.standardRuntime?.active === false
|
|
9040
|
+
&& (Boolean(state.standardActivePhase) || state.standardTodo?.status === "active");
|
|
9041
|
+
if (hasStalePausedPresentation && (state.standardClarificationPending || state.standardClarificationStage === "awaiting_answer" || state.standardClarificationStage === "drafting")) return false;
|
|
9042
|
+
if (!hasAcceptedFinalHandoff && !hasStalePausedPresentation) return false;
|
|
9043
|
+
updateState(standardTerminalStatePatch(hasAcceptedFinalHandoff), ctx);
|
|
9044
|
+
traceWorkflowTracking(ctx, "standard-terminal-finalized", { reason, fromHandoff: hasAcceptedFinalHandoff, stalePresentation: hasStalePausedPresentation });
|
|
9045
|
+
return true;
|
|
9046
|
+
};
|
|
8916
9047
|
const stopSubagentActivityTicker = (): void => {
|
|
8917
9048
|
if (workflowSubagentActivityTimer) clearInterval(workflowSubagentActivityTimer);
|
|
8918
9049
|
workflowSubagentActivityTimer = undefined;
|
|
@@ -9048,20 +9179,42 @@ export default function workflowModes(pi: ExtensionAPI): void {
|
|
|
9048
9179
|
return eventText ? transientFailureReason(fallback, eventText) : fallback;
|
|
9049
9180
|
};
|
|
9050
9181
|
|
|
9182
|
+
const workflowContextRecoveryCanSend = (ctx: ExtensionContext): boolean => {
|
|
9183
|
+
if (workflowActiveToolExecutions > 0 || workflowAutoCompactionRunning) return false;
|
|
9184
|
+
try { return ctx.isIdle(); } catch { return true; }
|
|
9185
|
+
};
|
|
9186
|
+
|
|
9187
|
+
const queueContextInterruptedWorkflowPrompt = (ctx: ExtensionContext, phase: WorkflowPendingToolPhase, content: string, recover: (reason: string) => void): boolean => {
|
|
9188
|
+
if (workflowScheduledAgentTurns > 0) {
|
|
9189
|
+
recordWorkflowInternalEvent(ctx, `Context-window workflow recovery already has a queued workflow turn for ${phase}; preserving active state.`);
|
|
9190
|
+
return true;
|
|
9191
|
+
}
|
|
9192
|
+
if (workflowDeferredAutoCompaction) {
|
|
9193
|
+
clearDeferredWorkflowCompaction();
|
|
9194
|
+
rememberWorkflowCompactionCheck(`deferred proactive compaction cleared before context-window ${phase} recovery`);
|
|
9195
|
+
}
|
|
9196
|
+
recordWorkflowInternalEvent(ctx, `Context-window workflow interruption queued ${phase} recovery turn.`);
|
|
9197
|
+
queueWorkflowPrompt(pi, content, {
|
|
9198
|
+
...buildQueuedPhaseRecovery(ctx, phase, recover),
|
|
9199
|
+
initialDelayMs: workflowAutoCompactionRunning ? 3000 : 2000,
|
|
9200
|
+
isIdle: () => workflowContextRecoveryCanSend(ctx),
|
|
9201
|
+
});
|
|
9202
|
+
return true;
|
|
9203
|
+
};
|
|
9204
|
+
|
|
9051
9205
|
const recoverContextInterruptedWorkflowTurn = (event: unknown, ctx: ExtensionContext): boolean => {
|
|
9052
|
-
if (workflowActiveToolExecutions > 0) return false;
|
|
9053
9206
|
if (!planRuntimeTurnIsActive() && !missionRuntimeTurnIsActive()) return false;
|
|
9054
9207
|
if (!workflowContextInterruptionEvidence(event, ctx)) return false;
|
|
9055
9208
|
const settings = loadWorkflowSettings(ctx.cwd);
|
|
9056
9209
|
state = persistWorkflowState(state, ctx);
|
|
9057
|
-
if (state.mode === "executing")
|
|
9058
|
-
if (state.mode === "validating" || state.mode === "revalidating")
|
|
9059
|
-
if (state.mode === "repairing")
|
|
9210
|
+
if (state.mode === "executing") return queueContextInterruptedWorkflowPrompt(ctx, "Execution", executePrompt(state, settings, phasePreflightBlocks.Execution), (reason) => recoverPlanTransientHandoffFailure(ctx, "execution", reason, { phase: "Execution" }));
|
|
9211
|
+
if (state.mode === "validating" || state.mode === "revalidating") return queueContextInterruptedWorkflowPrompt(ctx, "Validation", validatePrompt(state, settings, phasePreflightBlocks.Validation), (reason) => recoverPlanTransientHandoffFailure(ctx, state.mode === "revalidating" ? "revalidation" : "validation", reason, { phase: "Validation" }));
|
|
9212
|
+
if (state.mode === "repairing") return queueContextInterruptedWorkflowPrompt(ctx, "Repair", workflowRepairPrompt(state, settings, phasePreflightBlocks.Repair), (reason) => recoverPlanTransientHandoffFailure(ctx, "repair", reason, { phase: "Repair", preserveRetry: true }));
|
|
9060
9213
|
const mission = (state.activeMissionId ? loadMissionState(state.activeMissionId) : undefined) ?? activeMission ?? loadMissionState("latest");
|
|
9061
|
-
if (state.mode === "mission_running" && mission)
|
|
9062
|
-
if ((state.mode === "mission_validating" || state.mode === "mission_revalidating") && mission)
|
|
9063
|
-
if (state.mode === "mission_repairing" && mission)
|
|
9064
|
-
if (state.mode === "mission_final_validating" && mission)
|
|
9214
|
+
if (state.mode === "mission_running" && mission) return queueContextInterruptedWorkflowPrompt(ctx, "Execution", missionRuntimePrompt(mission, settings, phasePreflightBlocks.Execution), (reason) => recoverMissionTransientHandoffFailure(ctx, "run", reason, { phase: "Execution" }));
|
|
9215
|
+
if ((state.mode === "mission_validating" || state.mode === "mission_revalidating") && mission) return queueContextInterruptedWorkflowPrompt(ctx, "Validation", missionValidationPrompt(mission, settings, state.executionSummary, phasePreflightBlocks.Validation), (reason) => recoverMissionTransientHandoffFailure(ctx, state.mode === "mission_revalidating" ? "revalidation" : "validation", reason, { phase: "Validation" }));
|
|
9216
|
+
if (state.mode === "mission_repairing" && mission) return queueContextInterruptedWorkflowPrompt(ctx, "Repair", missionRepairPrompt(mission, settings, phasePreflightBlocks.Repair), (reason) => recoverMissionTransientHandoffFailure(ctx, "repair", reason, { phase: "Repair", preserveRetry: true }));
|
|
9217
|
+
if (state.mode === "mission_final_validating" && mission) return queueContextInterruptedWorkflowPrompt(ctx, "Validation", missionFinalValidationPrompt(mission, settings, state.executionSummary, phasePreflightBlocks.Validation), (reason) => recoverMissionTransientHandoffFailure(ctx, "final_validation", reason, { phase: "Validation" }));
|
|
9065
9218
|
return false;
|
|
9066
9219
|
};
|
|
9067
9220
|
|
|
@@ -12630,6 +12783,56 @@ Use /mission status, /mission resume, /mission continue, or /mission retry.`);
|
|
|
12630
12783
|
return !workflowHasActiveOrPendingValidationWork(ctx);
|
|
12631
12784
|
}
|
|
12632
12785
|
|
|
12786
|
+
function planActiveRuntimePhase(mode = state.mode): WorkflowPendingToolPhase | undefined {
|
|
12787
|
+
if (mode === "reviewing") return "Review";
|
|
12788
|
+
if (mode === "executing") return "Execution";
|
|
12789
|
+
if (mode === "validating" || mode === "revalidating") return "Validation";
|
|
12790
|
+
if (mode === "repairing") return "Repair";
|
|
12791
|
+
return undefined;
|
|
12792
|
+
}
|
|
12793
|
+
|
|
12794
|
+
function requiredPlanRuntimePhaseTools(phase: WorkflowPendingToolPhase, settings: ReturnType<typeof loadWorkflowSettings>): string[] {
|
|
12795
|
+
if (phase === "Execution") return requiredPlanExecutionTools(settings);
|
|
12796
|
+
if (phase === "Review") return [WORKFLOW_REVIEW_RESULT_TOOL];
|
|
12797
|
+
if (phase === "Validation") return [WORKFLOW_VALIDATION_RESULT_TOOL];
|
|
12798
|
+
if (phase === "Repair") return ["edit", "write", "bash", WORKFLOW_PROGRESS_TOOL, WORKFLOW_REPAIR_RESULT_TOOL];
|
|
12799
|
+
return [WORKFLOW_PLAN_RESULT_TOOL];
|
|
12800
|
+
}
|
|
12801
|
+
|
|
12802
|
+
function missingPlanRuntimePhaseTools(phase: WorkflowPendingToolPhase, settings: ReturnType<typeof loadWorkflowSettings>): string[] {
|
|
12803
|
+
const active = new Set(pi.getActiveTools());
|
|
12804
|
+
return requiredPlanRuntimePhaseTools(phase, settings).filter((tool) => !active.has(tool));
|
|
12805
|
+
}
|
|
12806
|
+
|
|
12807
|
+
function workflowRuntimeIsIdle(ctx: ExtensionContext): boolean {
|
|
12808
|
+
try { return ctx.isIdle(); } catch { return false; }
|
|
12809
|
+
}
|
|
12810
|
+
|
|
12811
|
+
function planActiveRuntimeHasPendingWork(ctx: ExtensionContext): boolean {
|
|
12812
|
+
return workflowActiveToolExecutions > 0
|
|
12813
|
+
|| workflowScheduledAgentTurns > 0
|
|
12814
|
+
|| runningSubagentActivity()
|
|
12815
|
+
|| Boolean(pendingWorkflowToolPhase)
|
|
12816
|
+
|| workflowHasQueuedMessages(ctx)
|
|
12817
|
+
|| !workflowRuntimeIsIdle(ctx);
|
|
12818
|
+
}
|
|
12819
|
+
|
|
12820
|
+
function planActiveRuntimeIsRecoverablyStale(ctx: ExtensionContext): boolean {
|
|
12821
|
+
const phase = planActiveRuntimePhase();
|
|
12822
|
+
if (!phase) return false;
|
|
12823
|
+
if (state.mode === "validating" || state.mode === "revalidating") return planValidationRuntimeIsStale(ctx);
|
|
12824
|
+
if (planActiveRuntimeHasPendingWork(ctx)) return false;
|
|
12825
|
+
return true;
|
|
12826
|
+
}
|
|
12827
|
+
|
|
12828
|
+
function planActiveRuntimeStaleReason(ctx: ExtensionContext): string {
|
|
12829
|
+
const settings = loadWorkflowSettings(ctx.cwd);
|
|
12830
|
+
const phase = planActiveRuntimePhase();
|
|
12831
|
+
const missing = phase ? missingPlanRuntimePhaseTools(phase, settings) : [];
|
|
12832
|
+
const missingText = missing.length ? ` Missing active ${phase} tools: ${missing.join(", ")}.` : "";
|
|
12833
|
+
return `Persisted Plan mode is ${state.mode}, but no active or queued workflow work is present.${missingText}`;
|
|
12834
|
+
}
|
|
12835
|
+
|
|
12633
12836
|
async function resumeInterruptedPlanValidation(ctx: ExtensionContext, title: string): Promise<boolean> {
|
|
12634
12837
|
const settings = loadWorkflowSettings(ctx.cwd);
|
|
12635
12838
|
const revalidate = state.mode === "revalidating";
|
|
@@ -12646,6 +12849,46 @@ Use /mission status, /mission resume, /mission continue, or /mission retry.`);
|
|
|
12646
12849
|
return true;
|
|
12647
12850
|
}
|
|
12648
12851
|
|
|
12852
|
+
async function resumeInterruptedPlanExecution(ctx: ExtensionContext, title: string): Promise<boolean> {
|
|
12853
|
+
const reason = planActiveRuntimeStaleReason(ctx);
|
|
12854
|
+
recordWorkflowInternalEvent(ctx, `Recovered stale Plan execution runtime. ${reason}`);
|
|
12855
|
+
show(pi, `# ${title}\n\nRecovered interrupted Plan execution runtime. Re-arming executor for the current active step.\n\n${workflowDisplayText(reason)}`);
|
|
12856
|
+
await beginExecution(ctx, true);
|
|
12857
|
+
return true;
|
|
12858
|
+
}
|
|
12859
|
+
|
|
12860
|
+
async function resumeInterruptedPlanReview(ctx: ExtensionContext, title: string): Promise<boolean> {
|
|
12861
|
+
const reason = planActiveRuntimeStaleReason(ctx);
|
|
12862
|
+
recordWorkflowInternalEvent(ctx, `Recovered stale Plan review runtime. ${reason}`);
|
|
12863
|
+
show(pi, `# ${title}\n\nRecovered interrupted Plan review runtime. Re-running reviewer.\n\n${workflowDisplayText(reason)}`);
|
|
12864
|
+
await beginReview(ctx, true);
|
|
12865
|
+
return true;
|
|
12866
|
+
}
|
|
12867
|
+
|
|
12868
|
+
async function resumeInterruptedPlanRepair(ctx: ExtensionContext, title: string): Promise<boolean> {
|
|
12869
|
+
const reason = planActiveRuntimeStaleReason(ctx);
|
|
12870
|
+
const settings = loadWorkflowSettings(ctx.cwd);
|
|
12871
|
+
const route = await applyModelForRole(pi, ctx, "executor", { cwd: ctx.cwd });
|
|
12872
|
+
if (!route) {
|
|
12873
|
+
show(pi, `# ${title}\n\nRecovered interrupted Plan repair runtime, but the executor model could not be applied. Configure executor, then run /plan repair or /plan retry.\n\n${workflowDisplayText(reason)}`);
|
|
12874
|
+
return true;
|
|
12875
|
+
}
|
|
12876
|
+
clearPendingWorkflowToolPhase(ctx, "Repair", "resumeInterruptedPlanRepair");
|
|
12877
|
+
armWorkflowToolsForPhase(ctx, "Repair", "resumeInterruptedPlanRepair");
|
|
12878
|
+
updateState({
|
|
12879
|
+
mode: "repairing",
|
|
12880
|
+
lastRepairStatus: "running",
|
|
12881
|
+
modelsUsed: { ...(state.modelsUsed ?? {}), executor: modelLabel(route) },
|
|
12882
|
+
planProgress: workflowPlanProgressEnabled(settings)
|
|
12883
|
+
? mergePlanProgress({ ...state, mode: "repairing", lastRepairStatus: "running" }, settings, { lifecycleStatus: "repairing", repairStatus: "running", nextAction: "repair executor then validator" }, state.approvedPlan)
|
|
12884
|
+
: state.planProgress,
|
|
12885
|
+
}, ctx);
|
|
12886
|
+
recordWorkflowInternalEvent(ctx, `Recovered stale Plan repair runtime. ${reason}`);
|
|
12887
|
+
show(pi, `# ${title}\n\nRecovered interrupted Plan repair runtime. Re-arming repair executor.\n\n${workflowDisplayText(reason)}`);
|
|
12888
|
+
queueWorkflowPrompt(pi, workflowRepairPrompt(state, settings, phasePreflightBlocks.Repair), buildQueuedPhaseRecovery(ctx, "Repair", (failureReason) => recoverPlanTransientHandoffFailure(ctx, "repair", failureReason, { phase: "Repair", preserveRetry: true })));
|
|
12889
|
+
return true;
|
|
12890
|
+
}
|
|
12891
|
+
|
|
12649
12892
|
async function continueRestoredPlanRuntime(ctx: ExtensionContext, title: string, snapshot: WorkflowState): Promise<boolean> {
|
|
12650
12893
|
restorePlanRuntimeSnapshot(ctx, snapshot);
|
|
12651
12894
|
const settings = loadWorkflowSettings(ctx.cwd);
|
|
@@ -12670,9 +12913,20 @@ Use /mission status, /mission resume, /mission continue, or /mission retry.`);
|
|
|
12670
12913
|
return true;
|
|
12671
12914
|
}
|
|
12672
12915
|
if (state.mode === "executing") {
|
|
12916
|
+
if (planActiveRuntimeIsRecoverablyStale(ctx)) return resumeInterruptedPlanExecution(ctx, title);
|
|
12673
12917
|
show(pi, `# ${title}\n\nRecovered active Plan execution runtime from session history. Wait for execution completion.`);
|
|
12674
12918
|
return true;
|
|
12675
12919
|
}
|
|
12920
|
+
if (state.mode === "reviewing") {
|
|
12921
|
+
if (planActiveRuntimeIsRecoverablyStale(ctx)) return resumeInterruptedPlanReview(ctx, title);
|
|
12922
|
+
show(pi, `# ${title}\n\nRecovered active Plan review runtime from session history. Wait for reviewer completion.`);
|
|
12923
|
+
return true;
|
|
12924
|
+
}
|
|
12925
|
+
if (state.mode === "repairing") {
|
|
12926
|
+
if (planActiveRuntimeIsRecoverablyStale(ctx)) return resumeInterruptedPlanRepair(ctx, title);
|
|
12927
|
+
show(pi, `# ${title}\n\nRecovered active Plan repair runtime from session history. Wait for repair completion.`);
|
|
12928
|
+
return true;
|
|
12929
|
+
}
|
|
12676
12930
|
return false;
|
|
12677
12931
|
}
|
|
12678
12932
|
|
|
@@ -12717,7 +12971,7 @@ Use /mission status, /mission resume, /mission continue, or /mission retry.`);
|
|
|
12717
12971
|
}, ctx);
|
|
12718
12972
|
}
|
|
12719
12973
|
|
|
12720
|
-
function planRecoveryGuidance(current: WorkflowState, validationAvailable: boolean): string {
|
|
12974
|
+
function planRecoveryGuidance(current: WorkflowState, validationAvailable: boolean, activeRuntimeStale = false): string {
|
|
12721
12975
|
if (current.mode === "idle" || current.mode === "cancelled" || current.mode === "awaiting_plan_input") {
|
|
12722
12976
|
const latest = latestRecoverablePlan();
|
|
12723
12977
|
if (latest) return `No active Plan Mode workflow is loaded. Recoverable approved plan found.\n\n${recoverablePlanDetails(latest)}\n\nNext action: /plan resume to restore it, /plan continue to run it, or /p <task> to start a new plan.`;
|
|
@@ -12727,12 +12981,12 @@ Use /mission status, /mission resume, /mission continue, or /mission retry.`);
|
|
|
12727
12981
|
if (current.mode === "awaiting_clarification") return "Plan is waiting for clarification answers. Next action: reply with choices like 1A, 2C, or use /clarify questions.";
|
|
12728
12982
|
if (current.mode === "plan_draft") return "Draft plan is ready. Next action: /plan approve, /plan revise <feedback>, or /plan cancel.";
|
|
12729
12983
|
if (current.mode === "plan_approved") return "Approved plan is loaded. Next action: /plan continue, /plan revalidate, /plan revise <feedback>, or /plan cancel.";
|
|
12730
|
-
if (current.mode === "reviewing") return "Reviewer is already running. Wait for reviewer completion.";
|
|
12984
|
+
if (current.mode === "reviewing") return activeRuntimeStale ? "Reviewer appears interrupted. Next action: /plan continue to rearm reviewer." : "Reviewer is already running. Wait for reviewer completion.";
|
|
12731
12985
|
if (current.mode === "reviewed") return "Reviewer is complete. Next action: /plan continue to execute.";
|
|
12732
|
-
if (current.mode === "executing") return "Executor is already running. Wait for execution completion.";
|
|
12986
|
+
if (current.mode === "executing") return activeRuntimeStale ? "Execution appears interrupted. Next action: /plan continue to rearm executor." : "Executor is already running. Wait for execution completion.";
|
|
12733
12987
|
if (current.mode === "executed") return validationAvailable ? "Execution is complete. Next action: /plan continue to validate." : "Execution is complete and validation is not active for this workflow. Next action: /plan continue to finish.";
|
|
12734
|
-
if (current.mode === "validating" || current.mode === "revalidating") return "Validator is already running. Wait for validation result.";
|
|
12735
|
-
if (current.mode === "repairing") return "Executor is already running in repair mode. Revalidation will start after repair completes.";
|
|
12988
|
+
if (current.mode === "validating" || current.mode === "revalidating") return activeRuntimeStale ? "Validation appears interrupted. Next action: /plan continue to rearm validator." : "Validator is already running. Wait for validation result.";
|
|
12989
|
+
if (current.mode === "repairing") return activeRuntimeStale ? "Repair appears interrupted. Next action: /plan continue to rearm repair executor." : "Executor is already running in repair mode. Revalidation will start after repair completes.";
|
|
12736
12990
|
if (current.mode === "validated" && current.validationVerdict === "PASS") return "Validation passed. Next action: /plan continue to complete and return to ready state.";
|
|
12737
12991
|
if (current.mode === "validated" && current.validationVerdict === "PARTIAL PASS") return classifyValidationFailure(current.validationVerdict, current.validationReport ?? current.lastValidationFailure ?? "", { concreteRepairableIssue: current.concreteRepairableIssue, manualVerificationRequired: current.manualVerificationRequired }) === "repairable" ? "Validation partially passed with repairable issues. Next actions: /plan repair, /plan retry, /plan revalidate, or /plan revise <feedback>." : "Validation partially passed. Next action: complete manual verification, then /plan revalidate or revise if scope changed.";
|
|
12738
12992
|
if (current.mode === "validated" && (current.validationVerdict === "FAIL" || current.lastValidationFailure)) return "Validation failed. Next actions: /plan repair, /plan retry, /plan revalidate, or /plan revise <feedback>.";
|
|
@@ -12856,7 +13110,8 @@ Use /mission status, /mission resume, /mission continue, or /mission retry.`);
|
|
|
12856
13110
|
if (currentAdvancedSnapshot) restorePlanRuntimeSnapshotForResume(ctx, currentAdvancedSnapshot);
|
|
12857
13111
|
const resolved = resolveActivePlanForResume();
|
|
12858
13112
|
const allPlans = listWorkflowPlans().filter((plan) => plan.finalPlan?.trim());
|
|
12859
|
-
|
|
13113
|
+
const activeRuntimeStale = planActiveRuntimeIsRecoverablyStale(ctx);
|
|
13114
|
+
if (resolved.source === "none" && allPlans.length === 0) return show(pi, `# Plan Resume\n\n${resolved.reason ?? planRecoveryGuidance(state, validationAvailable, activeRuntimeStale)}\n\nUse /workflow plans list to see saved plans.\n\n${renderWorkflowStatus(state, pi.getActiveTools(), ctx.cwd)}`);
|
|
12860
13115
|
let selected = resolved.plan;
|
|
12861
13116
|
if (resolved.source === "history" && selected) {
|
|
12862
13117
|
const advancedSnapshot = findAdvancedPlanRuntimeSnapshot(ctx, selected);
|
|
@@ -12902,7 +13157,7 @@ Use /mission status, /mission resume, /mission continue, or /mission retry.`);
|
|
|
12902
13157
|
// Primary /plan resume surface: restore state, then let the user choose.
|
|
12903
13158
|
const showActivePlanResumeActionMenu = async (currentPlan?: SavedWorkflowPlan): Promise<void> => {
|
|
12904
13159
|
const details = currentPlan ? `\n\n${recoverablePlanDetails(currentPlan)}` : "";
|
|
12905
|
-
const summary = `# Plan Resume\n\n${currentPlan ? "Plan loaded from saved history." : state.approvedPlan ? "Current plan is loaded." : "No current plan is loaded."}${details}\n\n${planRecoveryGuidance(state, validationAvailable)}\n\n${renderWorkflowStatus(state, pi.getActiveTools(), ctx.cwd)}`;
|
|
13160
|
+
const summary = `# Plan Resume\n\n${currentPlan ? "Plan loaded from saved history." : state.approvedPlan ? "Current plan is loaded." : "No current plan is loaded."}${details}\n\n${planRecoveryGuidance(state, validationAvailable, planActiveRuntimeIsRecoverablyStale(ctx))}\n\n${renderWorkflowStatus(state, pi.getActiveTools(), ctx.cwd)}`;
|
|
12906
13161
|
show(pi, `${summary}\n\nChoose what to do.`);
|
|
12907
13162
|
if (!ctx.hasUI) return;
|
|
12908
13163
|
const hasAlternatives = allPlans.some((plan) => plan.id !== currentPlan?.id);
|
|
@@ -12990,8 +13245,20 @@ Use /mission status, /mission resume, /mission continue, or /mission retry.`);
|
|
|
12990
13245
|
if (state.mode === "planning") return show(pi, `# ${title}\n\nPlanner is already running. Wait for the draft plan or clarification request.\n\n${status}`);
|
|
12991
13246
|
if (state.mode === "awaiting_clarification") return show(pi, `# ${title}\n\nPlan is waiting for clarification answers. Next action: reply with choices like 1A, 2C, or use /clarify questions.\n\n${status}`);
|
|
12992
13247
|
if (state.mode === "plan_draft") return show(pi, `# ${title}\n\nDraft plan is ready. Next action: /plan approve, /plan revise <feedback>, or /plan cancel.\n\n${status}`);
|
|
12993
|
-
if (state.mode === "reviewing")
|
|
12994
|
-
|
|
13248
|
+
if (state.mode === "reviewing") {
|
|
13249
|
+
if (planActiveRuntimeIsRecoverablyStale(ctx)) {
|
|
13250
|
+
await resumeInterruptedPlanReview(ctx, title);
|
|
13251
|
+
return;
|
|
13252
|
+
}
|
|
13253
|
+
return show(pi, `# ${title}\n\nReviewer is already running. Wait for reviewer completion.\n\n${status}`);
|
|
13254
|
+
}
|
|
13255
|
+
if (state.mode === "executing") {
|
|
13256
|
+
if (planActiveRuntimeIsRecoverablyStale(ctx)) {
|
|
13257
|
+
await resumeInterruptedPlanExecution(ctx, title);
|
|
13258
|
+
return;
|
|
13259
|
+
}
|
|
13260
|
+
return show(pi, `# ${title}\n\nExecutor is already running. Wait for execution completion.\n\n${status}`);
|
|
13261
|
+
}
|
|
12995
13262
|
if (state.mode === "validating" || state.mode === "revalidating") {
|
|
12996
13263
|
if (planValidationRuntimeIsStale(ctx)) {
|
|
12997
13264
|
await resumeInterruptedPlanValidation(ctx, title);
|
|
@@ -12999,7 +13266,13 @@ Use /mission status, /mission resume, /mission continue, or /mission retry.`);
|
|
|
12999
13266
|
}
|
|
13000
13267
|
return show(pi, `# ${title}\n\nValidator is already running. Wait for validation result.\n\n${status}`);
|
|
13001
13268
|
}
|
|
13002
|
-
if (state.mode === "repairing")
|
|
13269
|
+
if (state.mode === "repairing") {
|
|
13270
|
+
if (planActiveRuntimeIsRecoverablyStale(ctx)) {
|
|
13271
|
+
await resumeInterruptedPlanRepair(ctx, title);
|
|
13272
|
+
return;
|
|
13273
|
+
}
|
|
13274
|
+
return show(pi, `# ${title}\n\nExecutor is already running in repair mode. Revalidation will start after repair completes.\n\n${status}`);
|
|
13275
|
+
}
|
|
13003
13276
|
|
|
13004
13277
|
if (state.mode === "plan_approved") {
|
|
13005
13278
|
if (planReviewForcedPolicyBlocked()) {
|
|
@@ -14431,11 +14704,13 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
14431
14704
|
if (!mode) continue;
|
|
14432
14705
|
if (mode === "custom_model") { await selectCompactionModel(ctx); continue; }
|
|
14433
14706
|
const r = updateSettings(ctx.cwd, undefined, (s) => {
|
|
14434
|
-
s.context
|
|
14435
|
-
|
|
14436
|
-
|
|
14707
|
+
if (mode === "pi_default") resetCompactionContextToPiDefault(s.context);
|
|
14708
|
+
else {
|
|
14709
|
+
s.context.compactionMode = mode;
|
|
14710
|
+
s.context.customCompactionEnabled = false;
|
|
14711
|
+
}
|
|
14437
14712
|
});
|
|
14438
|
-
ctx.ui.notify(`Compaction mode set to ${compactionModeLabel(mode)} in ${r.file}${mode === "pi_default" ? ";
|
|
14713
|
+
ctx.ui.notify(`Compaction mode set to ${compactionModeLabel(mode)} in ${r.file}${mode === "pi_default" ? "; custom compaction overrides reset, selected provider/model preserved" : ""}.`, "info");
|
|
14439
14714
|
} else if (choice === "Compaction Provider") {
|
|
14440
14715
|
await selectCompactionModel(ctx);
|
|
14441
14716
|
} else if (choice === "Compaction Model") {
|
|
@@ -15137,7 +15412,7 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
15137
15412
|
}
|
|
15138
15413
|
|
|
15139
15414
|
function presetUsage(): string {
|
|
15140
|
-
return "# Workflow Presets\n\nQuick use:\n- /workflow presets opens the selector\n- Ctrl+Shift+U cycles saved presets from the footer only while Plan/Mission/Standard Mode is active\n- /workflow presets list\n- /workflow presets apply <name>\n- /workflow presets next\n- /workflow presets prev\n- /workflow presets
|
|
15415
|
+
return "# Workflow Presets\n\nQuick use:\n- /workflow presets opens the selector\n- Ctrl+Shift+U cycles saved presets from the footer only while Plan/Mission/Standard Mode is active\n- /workflow presets list\n- /workflow presets apply <name>\n- /workflow presets next\n- /workflow presets prev\n- /workflow presets save <name>\n- /workflow presets create <name> from simple|standard|deep|maximum\n- /workflow presets edit <name>\n- /workflow presets rename <old> to <new>\n- /workflow presets delete <name>";
|
|
15141
15416
|
}
|
|
15142
15417
|
|
|
15143
15418
|
function presetActionMessage(title: string, name: string, resultFile?: string, scope?: string): string {
|
|
@@ -15158,7 +15433,7 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
15158
15433
|
|
|
15159
15434
|
function presetDisplayOptions(settings: ReturnType<typeof loadWorkflowSettings>): { names: string[]; options: string[] } {
|
|
15160
15435
|
const catalog = workflowPresetCatalog(settings);
|
|
15161
|
-
const active = settings.presets?.activePreset ??
|
|
15436
|
+
const active = settings.presets?.activePreset ?? WORKFLOW_CUSTOM_PRESET_MARKER;
|
|
15162
15437
|
const names = workflowPresetNames(settings);
|
|
15163
15438
|
const options = names.map((name) => `${name === active ? "●" : "○"} ${workflowPresetPickerLabel(name, catalog[name])}`);
|
|
15164
15439
|
return { names, options };
|
|
@@ -15187,17 +15462,17 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
15187
15462
|
else show(pi, presetActionMessage("Workflow Preset Applied", label, result.file, result.scope));
|
|
15188
15463
|
}
|
|
15189
15464
|
|
|
15190
|
-
async function
|
|
15191
|
-
const result = updateSettings(ctx.cwd, undefined, (s) => { s.presets = { ...(s.presets ?? {}), activePreset:
|
|
15465
|
+
async function markWorkflowPresetCustom(ctx: ExtensionContext): Promise<void> {
|
|
15466
|
+
const result = updateSettings(ctx.cwd, undefined, (s) => { s.presets = { ...(s.presets ?? {}), activePreset: WORKFLOW_CUSTOM_PRESET_MARKER, items: { ...(s.presets?.items ?? {}) } }; });
|
|
15192
15467
|
setWorkflowUi(ctx, state, activeSubagents);
|
|
15193
|
-
ctx.ui.notify(`Workflow preset marker
|
|
15468
|
+
ctx.ui.notify(`Workflow preset marker cleared in ${result.file}; workflow settings unchanged.`, "info");
|
|
15194
15469
|
}
|
|
15195
15470
|
|
|
15196
15471
|
async function cycleWorkflowPreset(ctx: ExtensionContext, direction: 1 | -1): Promise<void> {
|
|
15197
15472
|
const settings = loadWorkflowSettings(ctx.cwd);
|
|
15198
15473
|
const cycle = workflowPresetNames(settings);
|
|
15199
|
-
if (!cycle.length) return
|
|
15200
|
-
const active = settings.presets?.activePreset ??
|
|
15474
|
+
if (!cycle.length) return markWorkflowPresetCustom(ctx);
|
|
15475
|
+
const active = settings.presets?.activePreset ?? WORKFLOW_CUSTOM_PRESET_MARKER;
|
|
15201
15476
|
const currentIndex = cycle.indexOf(active);
|
|
15202
15477
|
const nextIndex = currentIndex === -1 ? (direction === 1 ? 0 : cycle.length - 1) : (currentIndex + direction + cycle.length) % cycle.length;
|
|
15203
15478
|
await applyWorkflowPresetByName(ctx, cycle[nextIndex], true);
|
|
@@ -15272,7 +15547,7 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
15272
15547
|
if (action === "select" || action === "menu" || action === "picker") return showWorkflowPresetSelector(ctx);
|
|
15273
15548
|
if (action === "list") return show(pi, renderWorkflowPresets(loadWorkflowSettings(ctx.cwd)));
|
|
15274
15549
|
if (action === "next" || action === "cycle") { await cycleWorkflowPreset(ctx, 1); return; }
|
|
15275
|
-
if (action === "
|
|
15550
|
+
if (action === "custom") { await markWorkflowPresetCustom(ctx); return; }
|
|
15276
15551
|
if (action === "prev" || action === "previous") { await cycleWorkflowPreset(ctx, -1); return; }
|
|
15277
15552
|
if (action === "apply" || action === "use") {
|
|
15278
15553
|
if (!rest) return show(pi, "# Workflow Presets\n\nUsage: /workflow presets apply <name>");
|
|
@@ -16735,10 +17010,10 @@ Pi Version: v${VERSION}
|
|
|
16735
17010
|
const mode = parseCompactionMode(value);
|
|
16736
17011
|
if (!mode) return show(pi, "# Error\n\nUsage: `/workflow-settings set context compactionMode <pi_default|custom_model|custom_agent|disabled>`");
|
|
16737
17012
|
const result = updateSettings(ctx.cwd, scope, (s) => {
|
|
16738
|
-
s.context
|
|
16739
|
-
|
|
17013
|
+
if (mode === "pi_default") resetCompactionContextToPiDefault(s.context);
|
|
17014
|
+
else s.context.compactionMode = mode;
|
|
16740
17015
|
});
|
|
16741
|
-
const triggerNote = mode === "pi_default" ? "\n\
|
|
17016
|
+
const triggerNote = mode === "pi_default" ? "\n\nCustom compaction overrides reset; selected provider/model preserved; Pi default automatic compaction behavior applies." : "";
|
|
16742
17017
|
return show(pi, updatedMessage(result.scope, result.file, "context.compactionMode", compactionModeLabel(mode)) + triggerNote);
|
|
16743
17018
|
}
|
|
16744
17019
|
if (subject === "context" && key === "customCompactionEnabled") {
|
|
@@ -17766,7 +18041,7 @@ Public workflow commands:
|
|
|
17766
18041
|
}
|
|
17767
18042
|
return;
|
|
17768
18043
|
}
|
|
17769
|
-
updateState({ lastWorkflowHandoff: undefined }, ctx);
|
|
18044
|
+
if (!finalizeStandardTerminalStateIfIdle(ctx, "typed standard final handoff")) updateState({ lastWorkflowHandoff: undefined }, ctx);
|
|
17770
18045
|
}
|
|
17771
18046
|
const autoDecision = parseStandardAutoCheckDecision(text);
|
|
17772
18047
|
const autoCheckPatch = parseStandardAutoChecks(text);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mediadatafusion/pi-workflow-suite",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.0.17",
|
|
4
|
+
"description": "Multi-agent workflow suite for Pi with Idle, Standard, Plan, and Mission modes; approval gates; reviewer and validator roles; configurable sub-agent orchestration; model routing; web search/fetch; browser checks; diagrams; compaction; settings, presets, themes, widgets, Repo Lock, repair/retry loops, checkpoints, and live-safe install tooling.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -24,9 +24,20 @@
|
|
|
24
24
|
"workflow-suite",
|
|
25
25
|
"workflow-orchestration",
|
|
26
26
|
"agent-workflow",
|
|
27
|
+
"idle-mode",
|
|
27
28
|
"plan-mode",
|
|
28
29
|
"mission-mode",
|
|
29
30
|
"standard-mode",
|
|
31
|
+
"multi-agent",
|
|
32
|
+
"approval-gates",
|
|
33
|
+
"review-validation",
|
|
34
|
+
"sub-agent-orchestration",
|
|
35
|
+
"model-routing",
|
|
36
|
+
"web-search",
|
|
37
|
+
"browser-verification",
|
|
38
|
+
"repo-lock",
|
|
39
|
+
"workflow-settings",
|
|
40
|
+
"workflow-widgets",
|
|
30
41
|
"subagents",
|
|
31
42
|
"skills",
|
|
32
43
|
"prompts",
|
package/scripts/verify-live.sh
CHANGED
|
@@ -17,6 +17,30 @@ require_file() {
|
|
|
17
17
|
fi
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
require_text() {
|
|
21
|
+
local rel="$1"
|
|
22
|
+
local needle="$2"
|
|
23
|
+
require_file "$rel"
|
|
24
|
+
if grep -Fq "$needle" "$LIVE_DIR/$rel"; then
|
|
25
|
+
printf 'verified text: %s contains %s\n' "$rel" "$needle"
|
|
26
|
+
else
|
|
27
|
+
printf 'missing expected text in %s: %s\n' "$LIVE_DIR/$rel" "$needle" >&2
|
|
28
|
+
missing=1
|
|
29
|
+
fi
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
require_absent_text() {
|
|
33
|
+
local rel="$1"
|
|
34
|
+
local needle="$2"
|
|
35
|
+
require_file "$rel"
|
|
36
|
+
if grep -Fq "$needle" "$LIVE_DIR/$rel"; then
|
|
37
|
+
printf 'unexpected text in %s: %s\n' "$LIVE_DIR/$rel" "$needle" >&2
|
|
38
|
+
missing=1
|
|
39
|
+
else
|
|
40
|
+
printf 'verified absent text: %s does not contain %s\n' "$rel" "$needle"
|
|
41
|
+
fi
|
|
42
|
+
}
|
|
43
|
+
|
|
20
44
|
warn_path() {
|
|
21
45
|
local rel="$1"
|
|
22
46
|
local message="$2"
|
|
@@ -74,6 +98,24 @@ require_file "extensions/workflow-tool-guard.ts"
|
|
|
74
98
|
require_file "extensions/workflow-model-router.ts"
|
|
75
99
|
require_file "extensions/subagent/index.ts"
|
|
76
100
|
require_file "extensions/subagent/agents.ts"
|
|
101
|
+
require_file "package.json"
|
|
102
|
+
require_file "VERSION"
|
|
103
|
+
|
|
104
|
+
require_text "package.json" '"./extensions/workflow-modes.ts"'
|
|
105
|
+
require_text "package.json" '"./extensions/subagent/index.ts"'
|
|
106
|
+
require_text "package.json" '"./config/prompts"'
|
|
107
|
+
require_text "package.json" '"!*.md"'
|
|
108
|
+
require_absent_text "package.json" '"effect":'
|
|
109
|
+
|
|
110
|
+
require_text "extensions/workflow-tool-guard.ts" 'export const WORKFLOW_PLAN_RESULT_TOOL = "workflow_plan_result";'
|
|
111
|
+
require_text "extensions/workflow-tool-guard.ts" 'export const WORKFLOW_REVIEW_RESULT_TOOL = "workflow_review_result";'
|
|
112
|
+
require_text "extensions/workflow-tool-guard.ts" 'export const WORKFLOW_EXECUTION_RESULT_TOOL = "workflow_execution_result";'
|
|
113
|
+
require_text "extensions/workflow-tool-guard.ts" 'export const WORKFLOW_VALIDATION_RESULT_TOOL = "workflow_validation_result";'
|
|
114
|
+
require_text "extensions/workflow-tool-guard.ts" 'export const WORKFLOW_REPAIR_RESULT_TOOL = "workflow_repair_result";'
|
|
115
|
+
require_text "extensions/workflow-tool-guard.ts" 'export const MISSION_PLAN_RESULT_TOOL = "mission_plan_result";'
|
|
116
|
+
require_text "extensions/workflow-tool-guard.ts" 'export const MISSION_MILESTONE_RESULT_TOOL = "mission_milestone_result";'
|
|
117
|
+
require_text "extensions/workflow-tool-guard.ts" 'export const STANDARD_HANDOFF_RESULT_TOOL = "standard_handoff_result";'
|
|
118
|
+
require_text "extensions/workflow-modes.ts" 'workflow_repair_result({ status, changedFiles, movedFiles, preservedFiles, deletedFiles, rootArtifacts, possiblyUserOwnedFiles, needsUserApproval, safetyFlags, summary })'
|
|
77
119
|
|
|
78
120
|
require_file "agents/codebase-research.md"
|
|
79
121
|
require_file "agents/general-worker.md"
|
|
@@ -94,11 +136,15 @@ require_file "config/prompts/validate-approved-plan.md"
|
|
|
94
136
|
require_file "config/prompts/workflow-plan-prompt.md"
|
|
95
137
|
require_file "config/prompts/workflow-summary.md"
|
|
96
138
|
require_file "config/prompts/workflow-repair.md"
|
|
139
|
+
require_file "config/prompts/workflow-reviewer-prompt.md"
|
|
97
140
|
require_file "config/prompts/mission-plan.md"
|
|
98
141
|
require_file "config/prompts/mission-run.md"
|
|
142
|
+
require_file "config/prompts/mission-review-prompt.md"
|
|
99
143
|
require_file "config/prompts/mission-repair.md"
|
|
100
144
|
require_file "config/prompts/mission-checkpoint.md"
|
|
101
145
|
require_file "config/prompts/mission-final-validation.md"
|
|
146
|
+
require_text "config/prompts/workflow-repair.md" "possibly user-owned"
|
|
147
|
+
require_text "config/prompts/mission-repair.md" "possibly user-owned"
|
|
102
148
|
|
|
103
149
|
require_file "config/workflow-settings.example.json"
|
|
104
150
|
|