@mediadatafusion/pi-workflow-suite 0.0.17 → 0.0.19
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 +14 -0
- package/README.md +85 -54
- package/VERSION +1 -1
- package/config/workflow-settings.example.json +1 -0
- package/extensions/workflow-model-router.ts +5 -8
- package/extensions/workflow-modes.ts +612 -290
- package/package.json +2 -2
|
@@ -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, 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";
|
|
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 WorkflowEditorHintContrast, 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";
|
|
@@ -206,6 +206,15 @@ type PiSessionEntry = SessionEntry;
|
|
|
206
206
|
const DEFAULT_PI_COMPACTION_RESERVE_TOKENS = 16_384;
|
|
207
207
|
const DEFAULT_PI_COMPACTION_KEEP_RECENT_TOKENS = 20_000;
|
|
208
208
|
const CUSTOM_COMPACTION_PROMPT_OVERHEAD_TOKENS = 8_192;
|
|
209
|
+
const PI_SETTINGS_FILE = join(AGENT_DIR, "settings.json");
|
|
210
|
+
|
|
211
|
+
type PiNativeCompactionSettings = {
|
|
212
|
+
enabled: boolean;
|
|
213
|
+
reserveTokens: number;
|
|
214
|
+
keepRecentTokens: number;
|
|
215
|
+
source: "default" | "global" | "project";
|
|
216
|
+
file?: string;
|
|
217
|
+
};
|
|
209
218
|
|
|
210
219
|
function loadPiCompactionApi(): PiCompactionApi {
|
|
211
220
|
return {
|
|
@@ -215,6 +224,85 @@ function loadPiCompactionApi(): PiCompactionApi {
|
|
|
215
224
|
};
|
|
216
225
|
}
|
|
217
226
|
|
|
227
|
+
function readJsonObject(path: string): Record<string, unknown> | undefined {
|
|
228
|
+
try {
|
|
229
|
+
const parsed = JSON.parse(readFileSync(path, "utf8")) as unknown;
|
|
230
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed as Record<string, unknown> : undefined;
|
|
231
|
+
} catch {
|
|
232
|
+
return undefined;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function findProjectPiSettings(cwd: string): string | undefined {
|
|
237
|
+
let dir = cwd;
|
|
238
|
+
for (let i = 0; i < 40; i += 1) {
|
|
239
|
+
const candidate = join(dir, ".pi", "settings.json");
|
|
240
|
+
if (existsSync(candidate)) return candidate;
|
|
241
|
+
const parent = dirname(dir);
|
|
242
|
+
if (parent === dir) break;
|
|
243
|
+
dir = parent;
|
|
244
|
+
}
|
|
245
|
+
return undefined;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function coercePiCompactionSettings(raw: unknown): Partial<PiNativeCompactionSettings> | undefined {
|
|
249
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return undefined;
|
|
250
|
+
const compaction = raw as Record<string, unknown>;
|
|
251
|
+
const settings: Partial<PiNativeCompactionSettings> = {};
|
|
252
|
+
if (typeof compaction.enabled === "boolean") settings.enabled = compaction.enabled;
|
|
253
|
+
const reserveTokens = Number(compaction.reserveTokens);
|
|
254
|
+
if (Number.isFinite(reserveTokens) && reserveTokens > 0) settings.reserveTokens = Math.round(reserveTokens);
|
|
255
|
+
const keepRecentTokens = Number(compaction.keepRecentTokens);
|
|
256
|
+
if (Number.isFinite(keepRecentTokens) && keepRecentTokens > 0) settings.keepRecentTokens = Math.round(keepRecentTokens);
|
|
257
|
+
return settings;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function loadPiNativeCompactionSettings(cwd?: string): PiNativeCompactionSettings {
|
|
261
|
+
let settings: PiNativeCompactionSettings = {
|
|
262
|
+
enabled: true,
|
|
263
|
+
reserveTokens: DEFAULT_PI_COMPACTION_RESERVE_TOKENS,
|
|
264
|
+
keepRecentTokens: DEFAULT_PI_COMPACTION_KEEP_RECENT_TOKENS,
|
|
265
|
+
source: "default",
|
|
266
|
+
};
|
|
267
|
+
const globalSettings = existsSync(PI_SETTINGS_FILE) ? coercePiCompactionSettings(readJsonObject(PI_SETTINGS_FILE)?.compaction) : undefined;
|
|
268
|
+
if (globalSettings) settings = { ...settings, ...globalSettings, source: "global", file: PI_SETTINGS_FILE };
|
|
269
|
+
|
|
270
|
+
const projectFile = cwd ? findProjectPiSettings(cwd) : undefined;
|
|
271
|
+
const projectSettings = projectFile ? coercePiCompactionSettings(readJsonObject(projectFile)?.compaction) : undefined;
|
|
272
|
+
if (projectSettings) settings = { ...settings, ...projectSettings, source: "project", file: projectFile };
|
|
273
|
+
return settings;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
function contextWindowFrom(ctx?: ExtensionContext, usage?: { contextWindow?: number }): number | undefined {
|
|
277
|
+
const contextWindow = Number(usage?.contextWindow ?? ctx?.getContextUsage?.()?.contextWindow ?? ctx?.model?.contextWindow);
|
|
278
|
+
return Number.isFinite(contextWindow) && contextWindow > 0 ? contextWindow : undefined;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
function piNativeCompactionThreshold(cwd: string | undefined, contextWindow: number | undefined): { settings: PiNativeCompactionSettings; triggerTokens?: number; triggerPercent?: number } {
|
|
282
|
+
const settings = loadPiNativeCompactionSettings(cwd);
|
|
283
|
+
if (!settings.enabled || !contextWindow) return { settings };
|
|
284
|
+
const threshold = compactionThresholdForReserve(contextWindow, settings.reserveTokens);
|
|
285
|
+
return { settings, ...threshold };
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function compactionThresholdForReserve(contextWindow: number, reserveTokens: number): { triggerTokens: number; triggerPercent: number } {
|
|
289
|
+
const triggerTokens = Math.max(0, contextWindow - reserveTokens);
|
|
290
|
+
return { triggerTokens, triggerPercent: (triggerTokens / contextWindow) * 100 };
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
function formatPiNativeCompactionThreshold(cwd: string | undefined, contextWindow: number | undefined): string {
|
|
294
|
+
const threshold = piNativeCompactionThreshold(cwd, contextWindow);
|
|
295
|
+
if (!threshold.settings.enabled) return "disabled";
|
|
296
|
+
return "Pi default";
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
function formatSharedCompactionTrigger(settings: ReturnType<typeof loadWorkflowSettings>, ctx?: ExtensionContext): string {
|
|
300
|
+
if (settings.context.compactionMode === "disabled" || settings.context.autoCompactionEnabled === false) return "disabled";
|
|
301
|
+
const override = compactionTriggerPercentOverride(settings);
|
|
302
|
+
if (override != null) return `custom, ${override}%`;
|
|
303
|
+
return formatPiNativeCompactionThreshold(ctx?.cwd, contextWindowFrom(ctx));
|
|
304
|
+
}
|
|
305
|
+
|
|
218
306
|
function createWorkflowCompactionFileOps(): FileOperations {
|
|
219
307
|
return { read: new Set<string>(), written: new Set<string>(), edited: new Set<string>() };
|
|
220
308
|
}
|
|
@@ -2592,6 +2680,7 @@ UI Widgets:
|
|
|
2592
2680
|
- /workflow-settings set ui showActiveWorkflowSwitchHint true|false
|
|
2593
2681
|
- /workflow-settings set ui showWidgetShortcutHint true|false
|
|
2594
2682
|
- /workflow-settings set ui showPresetShortcutHint true|false
|
|
2683
|
+
- /workflow-settings set ui editorHintContrast subtle|normal|bright|high
|
|
2595
2684
|
|
|
2596
2685
|
Sub-agents and parallelism:
|
|
2597
2686
|
- /workflow-settings set subagents enabled true|false
|
|
@@ -2675,15 +2764,15 @@ Mission Mode settings:
|
|
|
2675
2764
|
|
|
2676
2765
|
Compaction:
|
|
2677
2766
|
- /workflow-settings configure compaction opens the selectable compaction menu
|
|
2678
|
-
- Compaction Provider and Compaction Model
|
|
2679
|
-
- /workflow-settings set context
|
|
2680
|
-
- /workflow-settings set context customCompactionEnabled true|false
|
|
2681
|
-
- /workflow-settings set context autoCompactionEnabled true|false
|
|
2767
|
+
- Compaction Provider and Compaction Model select the summary model preference
|
|
2768
|
+
- /workflow-settings set context autoCompactionEnabled true|false|default
|
|
2682
2769
|
- /workflow-settings set context compactionTriggerPercent 50-95|default|reset
|
|
2683
|
-
- /workflow-settings set context compactionCooldownMinutes 0-240
|
|
2770
|
+
- /workflow-settings set context compactionCooldownMinutes 0-240|default|reset
|
|
2684
2771
|
- /workflow-settings set context customCompactionReserveTokens 4096-65536|default|reset
|
|
2685
2772
|
- /workflow-settings set context customCompactionKeepRecentTokens 1000-200000|default|reset
|
|
2686
2773
|
- /workflow-settings set context workflowCompactionCheckMode boundary|in_session (legacy/backward-compatible; primary UI uses safe after-turn compaction)
|
|
2774
|
+
- /workflow-settings set context compactionMode pi_default|custom_model|disabled (legacy/backward-compatible; primary UI uses trigger/provider/model controls)
|
|
2775
|
+
- /workflow-settings set context customCompactionEnabled true|false (legacy/backward-compatible; no longer required for summary model routing)
|
|
2687
2776
|
- /workflow-settings set context compactionModelProvider <provider> (advanced/manual fallback)
|
|
2688
2777
|
- /workflow-settings set context compactionModel <model> (advanced/manual fallback)
|
|
2689
2778
|
- /workflow-settings set context compactionAgent <agent> (legacy/backward-compatible; custom agent is planned only)
|
|
@@ -3172,40 +3261,34 @@ function workflowCompactionCheckRuntimeStatus(): string {
|
|
|
3172
3261
|
return `Last Check: ${workflowLastCompactionCheckAt}\nLast Decision: ${workflowLastCompactionDecision}`;
|
|
3173
3262
|
}
|
|
3174
3263
|
|
|
3175
|
-
function
|
|
3176
|
-
return settings.context.
|
|
3177
|
-
&& settings.context.compactionMode === "custom_model"
|
|
3178
|
-
&& Boolean(settings.context.compactionModelProvider)
|
|
3264
|
+
function summaryModelConfigured(settings: ReturnType<typeof loadWorkflowSettings>): boolean {
|
|
3265
|
+
return Boolean(settings.context.compactionModelProvider)
|
|
3179
3266
|
&& Boolean(settings.context.compactionModel);
|
|
3180
3267
|
}
|
|
3181
3268
|
|
|
3269
|
+
function customModelCompactionConfigured(settings: ReturnType<typeof loadWorkflowSettings>): boolean {
|
|
3270
|
+
return settings.context.compactionMode !== "disabled" && summaryModelConfigured(settings);
|
|
3271
|
+
}
|
|
3272
|
+
|
|
3182
3273
|
function workflowProactiveCompactionEffective(settings: ReturnType<typeof loadWorkflowSettings>): boolean {
|
|
3183
3274
|
if (settings.context.compactionMode === "disabled") return false;
|
|
3184
3275
|
return settings.context.autoCompactionEnabled === true;
|
|
3185
3276
|
}
|
|
3186
3277
|
|
|
3187
3278
|
function compactionIntegrationStatus(settings: ReturnType<typeof loadWorkflowSettings>): string {
|
|
3188
|
-
if (
|
|
3189
|
-
if (settings.context.
|
|
3190
|
-
if (!settings.context.compactionModelProvider || !settings.context.compactionModel) return "Custom model selected but provider/model is missing. Fallback: Pi default compaction.";
|
|
3191
|
-
return `Custom model active through Pi's session_before_compact hook using ${settings.context.compactionModelProvider}/${settings.context.compactionModel}. Fallback: Pi default if custom compaction cannot run or fails.`;
|
|
3192
|
-
}
|
|
3279
|
+
if (settings.context.compactionMode === "disabled") return "Workflow compaction disabled";
|
|
3280
|
+
if (summaryModelConfigured(settings)) return `Custom summary model configured through Pi's session_before_compact hook using ${settings.context.compactionModelProvider}/${settings.context.compactionModel}. Fallback: Pi default if custom compaction cannot run or fails.`;
|
|
3193
3281
|
if (settings.context.compactionMode === "custom_agent") return "Custom agent compaction is planned only. Fallback: Pi default compaction.";
|
|
3194
|
-
return "
|
|
3282
|
+
return "Pi default summary model is active";
|
|
3195
3283
|
}
|
|
3196
3284
|
|
|
3197
|
-
function
|
|
3198
|
-
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
function compactionTriggerPercent(settings: ReturnType<typeof loadWorkflowSettings>): number {
|
|
3202
|
-
const fallback = defaultCompactionTriggerPercent();
|
|
3203
|
-
const value = Number(settings.context.compactionTriggerPercent ?? fallback);
|
|
3204
|
-
return Number.isFinite(value) && value >= 50 && value <= 95 ? Math.round(value) : fallback;
|
|
3285
|
+
function compactionTriggerPercentOverride(settings: ReturnType<typeof loadWorkflowSettings>): number | undefined {
|
|
3286
|
+
const value = Number(settings.context.compactionTriggerPercent);
|
|
3287
|
+
return Number.isFinite(value) && value >= 50 && value <= 95 ? Math.round(value) : undefined;
|
|
3205
3288
|
}
|
|
3206
3289
|
|
|
3207
3290
|
function compactionTriggerOverrideLabel(settings: ReturnType<typeof loadWorkflowSettings>): string {
|
|
3208
|
-
const value = settings
|
|
3291
|
+
const value = compactionTriggerPercentOverride(settings);
|
|
3209
3292
|
return typeof value === "number" ? `${value}%` : "none";
|
|
3210
3293
|
}
|
|
3211
3294
|
|
|
@@ -3220,18 +3303,9 @@ function resetCompactionContextToPiDefault(context: ReturnType<typeof loadWorkfl
|
|
|
3220
3303
|
}
|
|
3221
3304
|
|
|
3222
3305
|
function effectiveWorkflowCompactionTriggerPercent(settings: ReturnType<typeof loadWorkflowSettings>, ctx: ExtensionContext, usage: { contextWindow?: number }): number {
|
|
3223
|
-
const
|
|
3224
|
-
|
|
3225
|
-
|
|
3226
|
-
if (!Number.isFinite(contextWindow) || contextWindow <= 0) return configured;
|
|
3227
|
-
const model = ctx.modelRegistry.find(settings.context.compactionModelProvider, settings.context.compactionModel);
|
|
3228
|
-
if (!model) return configured;
|
|
3229
|
-
const safeInputTokens = customCompactionSafeInputTokens(model);
|
|
3230
|
-
if (!safeInputTokens) return configured;
|
|
3231
|
-
const safeTotalBeforeCompaction = safeInputTokens + DEFAULT_PI_COMPACTION_KEEP_RECENT_TOKENS;
|
|
3232
|
-
const modelSafePercent = Math.floor((safeTotalBeforeCompaction / contextWindow) * 100);
|
|
3233
|
-
if (!Number.isFinite(modelSafePercent) || modelSafePercent <= 0) return configured;
|
|
3234
|
-
return Math.max(10, Math.min(configured, modelSafePercent));
|
|
3306
|
+
const contextWindow = contextWindowFrom(ctx, usage);
|
|
3307
|
+
const nativeThreshold = piNativeCompactionThreshold(ctx.cwd, contextWindow);
|
|
3308
|
+
return compactionTriggerPercentOverride(settings) ?? nativeThreshold.triggerPercent ?? NaN;
|
|
3235
3309
|
}
|
|
3236
3310
|
|
|
3237
3311
|
function compactionCooldownMinutes(settings: ReturnType<typeof loadWorkflowSettings>): number {
|
|
@@ -3239,6 +3313,16 @@ function compactionCooldownMinutes(settings: ReturnType<typeof loadWorkflowSetti
|
|
|
3239
3313
|
return Number.isFinite(value) && value >= 0 && value <= 240 ? Math.round(value) : 5;
|
|
3240
3314
|
}
|
|
3241
3315
|
|
|
3316
|
+
function compactionCooldownLabel(settings: ReturnType<typeof loadWorkflowSettings>): string {
|
|
3317
|
+
const value = compactionCooldownMinutes(settings);
|
|
3318
|
+
return value === 5 ? "Pi default" : `${value} min`;
|
|
3319
|
+
}
|
|
3320
|
+
|
|
3321
|
+
function workflowAutoTriggerLabel(settings: ReturnType<typeof loadWorkflowSettings>): string {
|
|
3322
|
+
if (settings.context.compactionMode === "disabled" || settings.context.autoCompactionEnabled === false) return "disabled";
|
|
3323
|
+
return settings.context.autoCompactionEnabled === true ? "enabled" : "Pi default";
|
|
3324
|
+
}
|
|
3325
|
+
|
|
3242
3326
|
function customCompactionReserveTokens(settings: ReturnType<typeof loadWorkflowSettings>): number {
|
|
3243
3327
|
const value = Number(settings.context.customCompactionReserveTokens ?? DEFAULT_PI_COMPACTION_RESERVE_TOKENS);
|
|
3244
3328
|
return Number.isFinite(value) && value >= 4096 && value <= 65536 ? Math.round(value) : DEFAULT_PI_COMPACTION_RESERVE_TOKENS;
|
|
@@ -3249,6 +3333,16 @@ function customCompactionKeepRecentTokens(settings: ReturnType<typeof loadWorkfl
|
|
|
3249
3333
|
return Number.isFinite(value) && value >= 1000 && value <= 200000 ? Math.round(value) : DEFAULT_PI_COMPACTION_KEEP_RECENT_TOKENS;
|
|
3250
3334
|
}
|
|
3251
3335
|
|
|
3336
|
+
function compactionReserveTokensLabel(settings: ReturnType<typeof loadWorkflowSettings>): string {
|
|
3337
|
+
const value = customCompactionReserveTokens(settings);
|
|
3338
|
+
return value === DEFAULT_PI_COMPACTION_RESERVE_TOKENS ? "Pi default" : value.toLocaleString();
|
|
3339
|
+
}
|
|
3340
|
+
|
|
3341
|
+
function compactionKeepRecentTokensLabel(settings: ReturnType<typeof loadWorkflowSettings>): string {
|
|
3342
|
+
const value = customCompactionKeepRecentTokens(settings);
|
|
3343
|
+
return value === DEFAULT_PI_COMPACTION_KEEP_RECENT_TOKENS ? "Pi default" : value.toLocaleString();
|
|
3344
|
+
}
|
|
3345
|
+
|
|
3252
3346
|
function customCompactionPreparationSettings(settings: ReturnType<typeof loadWorkflowSettings>, fallback: PiCompactionPreparation["settings"]): PiCompactionPreparation["settings"] {
|
|
3253
3347
|
return {
|
|
3254
3348
|
...fallback,
|
|
@@ -3261,14 +3355,15 @@ function compactionTriggerStatus(settings: ReturnType<typeof loadWorkflowSetting
|
|
|
3261
3355
|
if (settings.context.compactionMode === "disabled") return "Workflow compaction disabled";
|
|
3262
3356
|
const cooldown = `${compactionCooldownMinutes(settings)} minute cooldown`;
|
|
3263
3357
|
const safeBoundary = "safe after-turn idle boundary only";
|
|
3264
|
-
|
|
3265
|
-
if (
|
|
3358
|
+
const override = compactionTriggerPercentOverride(settings);
|
|
3359
|
+
if (workflowProactiveCompactionEffective(settings)) return `Armed at ${override == null ? "Pi default formula" : `${override}%`}; ${cooldown}; Compaction runs at ${safeBoundary}`;
|
|
3360
|
+
if (summaryModelConfigured(settings)) return `Custom summary model configured for Pi session_before_compact: ${settings.context.compactionModelProvider}/${settings.context.compactionModel}. Workflow proactive trigger is not enabled.`;
|
|
3266
3361
|
if (settings.context.autoCompactionEnabled !== true) return "Workflow proactive compaction disabled; Pi default auto-compaction still applies";
|
|
3267
|
-
return
|
|
3362
|
+
return "Pi default auto-compaction applies";
|
|
3268
3363
|
}
|
|
3269
3364
|
|
|
3270
3365
|
function missionCheckpointModelLabel(settings: ReturnType<typeof loadWorkflowSettings>): string {
|
|
3271
|
-
if (settings
|
|
3366
|
+
if (customModelCompactionConfigured(settings)) {
|
|
3272
3367
|
return `concise checkpoint summaries; Pi session compaction uses configured compaction model when active (currently ${settings.context.compactionModelProvider}/${settings.context.compactionModel})`;
|
|
3273
3368
|
}
|
|
3274
3369
|
return "concise checkpoint summaries; Pi session compaction uses configured compaction model when active";
|
|
@@ -3294,7 +3389,7 @@ Mission Checkpoint Model: ${missionCheckpointModelLabel(settings)}`;
|
|
|
3294
3389
|
function renderPlanModelSettings(settings: ReturnType<typeof loadWorkflowSettings>): string {
|
|
3295
3390
|
return `Plan Model Source: shared workflow role models
|
|
3296
3391
|
${renderWorkflowModels(settings)}
|
|
3297
|
-
Compaction Model: ${settings.context.
|
|
3392
|
+
Compaction Model: ${settings.context.compactionModelProvider && settings.context.compactionModel ? `${settings.context.compactionModelProvider}/${settings.context.compactionModel}` : "Pi default"}`;
|
|
3298
3393
|
}
|
|
3299
3394
|
|
|
3300
3395
|
function renderPlanSubagentWorkerSettings(settings: ReturnType<typeof loadWorkflowSettings>): string {
|
|
@@ -3393,8 +3488,10 @@ function renderWorkflowSettingsHealth(settings: ReturnType<typeof loadWorkflowSe
|
|
|
3393
3488
|
`Validator: ${configuredLabel(settings.models.validator)}`,
|
|
3394
3489
|
"",
|
|
3395
3490
|
"## Compaction",
|
|
3396
|
-
`
|
|
3397
|
-
`
|
|
3491
|
+
`Provider: ${settings.context.compactionModelProvider || "Pi default"}`,
|
|
3492
|
+
`Model: ${settings.context.compactionModel || "Pi default"}`,
|
|
3493
|
+
`Workflow Auto Trigger: ${workflowAutoTriggerLabel(settings)}`,
|
|
3494
|
+
`Trigger: ${formatSharedCompactionTrigger(settings)}`,
|
|
3398
3495
|
"Runtime: safe after-turn compaction",
|
|
3399
3496
|
"",
|
|
3400
3497
|
"## Capability Matrix Summary",
|
|
@@ -3588,7 +3685,7 @@ ${renderPlanModelSettings(settings)}
|
|
|
3588
3685
|
|
|
3589
3686
|
${renderMissionModelStrategy(settings)}
|
|
3590
3687
|
|
|
3591
|
-
## UI /
|
|
3688
|
+
## UI / Widgets
|
|
3592
3689
|
Plan Top Widget: ${widgetVisibilityLabel(settings, "planTop")}
|
|
3593
3690
|
Plan Bottom Widget: ${widgetVisibilityLabel(settings, "planBottom")}
|
|
3594
3691
|
Mission Top Widget: ${widgetVisibilityLabel(settings, "missionTop")}
|
|
@@ -3599,6 +3696,7 @@ Idle Entry Hint: ${workflowWidgetUi(settings).showIdleWorkflowEntryHint !== fals
|
|
|
3599
3696
|
Active Switch Hint: ${workflowWidgetUi(settings).showActiveWorkflowSwitchHint !== false ? "visible" : "hidden"}
|
|
3600
3697
|
Widget Shortcut Hint: ${workflowWidgetUi(settings).showWidgetShortcutHint !== false ? "visible" : "hidden"}
|
|
3601
3698
|
Preset Shortcut Hint: ${workflowWidgetUi(settings).showPresetShortcutHint !== false ? "visible" : "hidden"}
|
|
3699
|
+
Editor Hint Contrast: ${workflowEditorHintContrastLabel(workflowEditorHintContrast(settings))}
|
|
3602
3700
|
Workflow Theme: ${workflowThemeDisplayName(workflowThemeName(settings))}
|
|
3603
3701
|
Startup Visual: ${startupVisualOrDefault(settings)}
|
|
3604
3702
|
Startup Logo: ${startupLogoOrDefault(settings)}
|
|
@@ -3652,18 +3750,16 @@ Note: Parallel File Edits controls simultaneous file writes only. It must not di
|
|
|
3652
3750
|
${renderSafetySettings(settings)}
|
|
3653
3751
|
|
|
3654
3752
|
## Compaction
|
|
3655
|
-
Compaction
|
|
3656
|
-
|
|
3657
|
-
Compaction
|
|
3658
|
-
Compaction Model: ${settings.context.compactionModel || "(not set)"}
|
|
3659
|
-
${compactionAgentLine(settings)}${compactionAgentLine(settings) ? "\n" : ""}Workflow Auto Compaction Trigger Setting: ${settings.context.autoCompactionEnabled === true ? "enabled" : "disabled"}
|
|
3753
|
+
Compaction Provider: ${settings.context.compactionModelProvider || "Pi default"}
|
|
3754
|
+
Compaction Model: ${settings.context.compactionModel || "Pi default"}
|
|
3755
|
+
${compactionAgentLine(settings)}${compactionAgentLine(settings) ? "\n" : ""}Workflow Auto Compaction Trigger Setting: ${workflowAutoTriggerLabel(settings)}
|
|
3660
3756
|
Effective Workflow Compaction Trigger: ${workflowProactiveCompactionEffective(settings) ? "armed" : "inactive"}
|
|
3661
3757
|
Compaction Runtime: safe after-turn idle boundary only
|
|
3662
3758
|
Workflow Compaction Trigger Override: ${compactionTriggerOverrideLabel(settings)}
|
|
3663
|
-
|
|
3759
|
+
Trigger: ${formatSharedCompactionTrigger(settings)}
|
|
3664
3760
|
Workflow Compaction Cooldown: ${compactionCooldownMinutes(settings)} minute(s)
|
|
3665
|
-
|
|
3666
|
-
|
|
3761
|
+
Compaction Reserve Tokens: ${compactionReserveTokensLabel(settings)}
|
|
3762
|
+
Compaction Keep Recent Tokens: ${compactionKeepRecentTokensLabel(settings)}
|
|
3667
3763
|
Compaction Integration Status: ${compactionIntegrationStatus(settings)}
|
|
3668
3764
|
Compaction Trigger Status: ${compactionTriggerStatus(settings)}
|
|
3669
3765
|
${workflowCompactionCheckRuntimeStatus()}
|
|
@@ -5433,8 +5529,8 @@ class WorkflowSuiteEditor extends CustomEditor {
|
|
|
5433
5529
|
try {
|
|
5434
5530
|
const settings = loadWorkflowSettings(this.workflowCwd);
|
|
5435
5531
|
const decorate = workflowRoleTextDecoration(settings, "muted");
|
|
5436
|
-
let hintStyled =
|
|
5437
|
-
if (decorate) hintStyled = decorate(hintStyled);
|
|
5532
|
+
let hintStyled = workflowEditorHintStyledText(settings, workflowEditorHintText);
|
|
5533
|
+
if (workflowEditorHintContrast(settings) === "subtle" && decorate) hintStyled = decorate(hintStyled);
|
|
5438
5534
|
const innerWidth = width - 2;
|
|
5439
5535
|
const hintLen = visibleTextWidth(hintStyled);
|
|
5440
5536
|
const displayHint = hintLen > innerWidth ? truncateVisibleText(hintStyled, innerWidth) : hintStyled;
|
|
@@ -6431,6 +6527,13 @@ function isMissionWorkflowMode(state: WorkflowState): boolean {
|
|
|
6431
6527
|
}
|
|
6432
6528
|
|
|
6433
6529
|
type WorkflowWidgetSlot = "planTop" | "planBottom" | "missionTop" | "missionBottom" | "standardTop" | "standardBottom";
|
|
6530
|
+
const WORKFLOW_EDITOR_HINT_CONTRASTS: WorkflowEditorHintContrast[] = ["subtle", "normal", "bright", "high"];
|
|
6531
|
+
const WORKFLOW_EDITOR_HINT_CONTRAST_LABELS: Record<WorkflowEditorHintContrast, string> = {
|
|
6532
|
+
subtle: "Subtle",
|
|
6533
|
+
normal: "Normal",
|
|
6534
|
+
bright: "Bright",
|
|
6535
|
+
high: "High Contrast",
|
|
6536
|
+
};
|
|
6434
6537
|
type WorkflowWidgetUiSettings = ReturnType<typeof loadWorkflowSettings>["ui"] & {
|
|
6435
6538
|
showPlanModeIndicator?: boolean;
|
|
6436
6539
|
planModeIndicatorText?: string;
|
|
@@ -6444,6 +6547,7 @@ type WorkflowWidgetUiSettings = ReturnType<typeof loadWorkflowSettings>["ui"] &
|
|
|
6444
6547
|
showActiveWorkflowSwitchHint?: boolean;
|
|
6445
6548
|
showWidgetShortcutHint?: boolean;
|
|
6446
6549
|
showPresetShortcutHint?: boolean;
|
|
6550
|
+
editorHintContrast?: WorkflowEditorHintContrast;
|
|
6447
6551
|
};
|
|
6448
6552
|
|
|
6449
6553
|
const widgetVisibilityOverrides: Partial<Record<WorkflowWidgetSlot, boolean>> = {};
|
|
@@ -6460,6 +6564,38 @@ function workflowWidgetUi(settings: ReturnType<typeof loadWorkflowSettings>): Wo
|
|
|
6460
6564
|
return settings.ui as WorkflowWidgetUiSettings;
|
|
6461
6565
|
}
|
|
6462
6566
|
|
|
6567
|
+
function parseEditorHintContrast(value?: string): WorkflowEditorHintContrast | undefined {
|
|
6568
|
+
const input = value?.trim().toLowerCase().replace(/[\s_-]+/g, "");
|
|
6569
|
+
if (!input) return undefined;
|
|
6570
|
+
if (input === "subtle" || input === "muted" || input === "dim") return "subtle";
|
|
6571
|
+
if (input === "normal" || input === "default") return "normal";
|
|
6572
|
+
if (input === "bright") return "bright";
|
|
6573
|
+
if (input === "high" || input === "highcontrast" || input === "maximum") return "high";
|
|
6574
|
+
return undefined;
|
|
6575
|
+
}
|
|
6576
|
+
|
|
6577
|
+
function workflowEditorHintContrast(settings: ReturnType<typeof loadWorkflowSettings>): WorkflowEditorHintContrast {
|
|
6578
|
+
return parseEditorHintContrast(workflowWidgetUi(settings).editorHintContrast) ?? "normal";
|
|
6579
|
+
}
|
|
6580
|
+
|
|
6581
|
+
function workflowEditorHintContrastLabel(contrast: WorkflowEditorHintContrast): string {
|
|
6582
|
+
return WORKFLOW_EDITOR_HINT_CONTRAST_LABELS[contrast];
|
|
6583
|
+
}
|
|
6584
|
+
|
|
6585
|
+
function workflowEditorHintStyledText(settings: ReturnType<typeof loadWorkflowSettings>, text: string): string {
|
|
6586
|
+
switch (workflowEditorHintContrast(settings)) {
|
|
6587
|
+
case "subtle":
|
|
6588
|
+
return `\x1b[2m\x1b[38;5;240m${text}\x1b[0m`;
|
|
6589
|
+
case "bright":
|
|
6590
|
+
return `\x1b[38;5;250m${text}\x1b[0m`;
|
|
6591
|
+
case "high":
|
|
6592
|
+
return `\x1b[1m\x1b[38;5;255m${text}\x1b[0m`;
|
|
6593
|
+
case "normal":
|
|
6594
|
+
default:
|
|
6595
|
+
return `\x1b[38;5;245m${text}\x1b[0m`;
|
|
6596
|
+
}
|
|
6597
|
+
}
|
|
6598
|
+
|
|
6463
6599
|
function workflowWidgetVisible(settings: ReturnType<typeof loadWorkflowSettings>, slot: WorkflowWidgetSlot): boolean {
|
|
6464
6600
|
const override = widgetVisibilityOverrides[slot];
|
|
6465
6601
|
if (override !== undefined) return override;
|
|
@@ -9624,7 +9760,7 @@ export default function workflowModes(pi: ExtensionAPI): void {
|
|
|
9624
9760
|
const route = await applyModelForRole(pi, ctx, "planner", { cwd: ctx.cwd });
|
|
9625
9761
|
if (!route) return false;
|
|
9626
9762
|
updateState({ modelsUsed: { ...(state.modelsUsed ?? {}), planner: modelLabel(route) } }, ctx);
|
|
9627
|
-
if (showNotice) ctx
|
|
9763
|
+
if (showNotice) workflowUiNotify(ctx, `Active Plan Mode planner route reapplied: ${modelLabel(route)}\n${activeModelDiagnostic(ctx)}`, "info");
|
|
9628
9764
|
return true;
|
|
9629
9765
|
};
|
|
9630
9766
|
|
|
@@ -9633,13 +9769,13 @@ export default function workflowModes(pi: ExtensionAPI): void {
|
|
|
9633
9769
|
const settings = loadWorkflowSettings(ctx.cwd);
|
|
9634
9770
|
const standardRole = effectiveStandardModelRole(settings);
|
|
9635
9771
|
if (standardRole === "current") {
|
|
9636
|
-
if (showNotice) ctx
|
|
9772
|
+
if (showNotice) workflowUiNotify(ctx, `Standard Mode keeps the current Pi model.\n${activeModelDiagnostic(ctx)}`, "info");
|
|
9637
9773
|
return false;
|
|
9638
9774
|
}
|
|
9639
9775
|
const route = await applyStandardModelForRole(pi, ctx, standardRole, { cwd: ctx.cwd });
|
|
9640
9776
|
if (!route) return false;
|
|
9641
9777
|
updateState({ modelsUsed: { ...(state.modelsUsed ?? {}), [standardRole]: modelLabel(route) } }, ctx);
|
|
9642
|
-
if (showNotice) ctx
|
|
9778
|
+
if (showNotice) workflowUiNotify(ctx, `Active Standard Mode ${standardRole} route applied: ${modelLabel(route)}\n${activeModelDiagnostic(ctx)}`, "info");
|
|
9643
9779
|
return true;
|
|
9644
9780
|
};
|
|
9645
9781
|
|
|
@@ -9654,7 +9790,7 @@ export default function workflowModes(pi: ExtensionAPI): void {
|
|
|
9654
9790
|
const settings = loadWorkflowSettings(ctx.cwd);
|
|
9655
9791
|
const globalUi = workflowWidgetUi(loadGlobalSettings());
|
|
9656
9792
|
const ui = workflowWidgetUi(settings);
|
|
9657
|
-
const common = `Active Mode: ${state.mode}\nShortcuts: ${globalUi.enableWidgetShortcuts !== false ? "enabled" : "disabled"}\nRemember Visibility: ${globalUi.rememberWidgetVisibility !== false ? "enabled" : "disabled"}\nStorage: ${globalUi.rememberWidgetVisibility !== false ? "global settings" : "current Pi session"}\
|
|
9793
|
+
const common = `Active Mode: ${state.mode}\nShortcuts: ${globalUi.enableWidgetShortcuts !== false ? "enabled" : "disabled"}\nRemember Visibility: ${globalUi.rememberWidgetVisibility !== false ? "enabled" : "disabled"}\nStorage: ${globalUi.rememberWidgetVisibility !== false ? "global settings" : "current Pi session"}\nEditor Hints: idle entry ${ui.showIdleWorkflowEntryHint !== false ? "visible" : "hidden"}, active switch ${ui.showActiveWorkflowSwitchHint !== false ? "visible" : "hidden"}, widgets ${ui.showWidgetShortcutHint !== false ? "visible" : "hidden"}, preset ${ui.showPresetShortcutHint !== false ? "visible" : "hidden"}, contrast ${workflowEditorHintContrastLabel(workflowEditorHintContrast(settings))}`;
|
|
9658
9794
|
if (isPlanWorkflowUiMode(state)) {
|
|
9659
9795
|
const bottom = planBottomRelevant(state) ? widgetVisibilityLabel(settings, "planBottom") : "not applicable";
|
|
9660
9796
|
return `# Workflow Widgets\n\nPlan Top Widget: ${widgetVisibilityLabel(settings, "planTop")}\nPlan Bottom Widget: ${bottom}\nStatus Line: ${widgetVisibilityStatus(state, settings) ?? "none"}\n${common}`;
|
|
@@ -9667,7 +9803,13 @@ export default function workflowModes(pi: ExtensionAPI): void {
|
|
|
9667
9803
|
if (isStandardWorkflowMode(state)) {
|
|
9668
9804
|
return `# Workflow Widgets\n\nStandard Top Widget: ${widgetVisibilityLabel(settings, "standardTop")}\nStandard To Do Widget: ${widgetVisibilityLabel(settings, "standardBottom")}\nStatus Line: ${widgetVisibilityStatus(state, settings) ?? "none"}\n${common}`;
|
|
9669
9805
|
}
|
|
9670
|
-
return `# Workflow Widgets\n\nNo active Plan/Mission/Standard widget is currently visible.\nStatus Line: ${widgetVisibilityStatus(state, settings) ?? "none"}\n\nEntry Shortcuts:\n- ${workflowEntryShortcutLabel("standard")}\n- ${workflowEntryShortcutLabel("plan")}\n- ${workflowEntryShortcutLabel("mission")}\n\nActive-mode
|
|
9806
|
+
return `# Workflow Widgets\n\nNo active Plan/Mission/Standard widget is currently visible.\nStatus Line: ${widgetVisibilityStatus(state, settings) ?? "none"}\n\nEntry Shortcuts:\n- ${workflowEntryShortcutLabel("standard")}\n- ${workflowEntryShortcutLabel("plan")}\n- ${workflowEntryShortcutLabel("mission")}\n\nActive-mode editor hints use compact text such as: Widgets:Ctrl+Shift+T/B Preset:${activeWorkflowPresetLabel(settings)} Ctrl+Shift+U Standard:Ctrl+Shift+S Mission:Ctrl+Shift+M\nWidget toggles and preset cycling are visible only while Plan/Mission/Standard Mode is active.\n\n${common}`;
|
|
9807
|
+
};
|
|
9808
|
+
|
|
9809
|
+
const renderEditorHintsSettings = (ctx: ExtensionContext): string => {
|
|
9810
|
+
const settings = loadWorkflowSettings(ctx.cwd);
|
|
9811
|
+
const ui = workflowWidgetUi(settings);
|
|
9812
|
+
return `# Editor Hints\n\nThese hints render inline in the editor/input box.\n\nIdle Entry Hint: ${ui.showIdleWorkflowEntryHint !== false ? "visible" : "hidden"}\nActive Switch Hint: ${ui.showActiveWorkflowSwitchHint !== false ? "visible" : "hidden"}\nWidget Shortcut Hint: ${ui.showWidgetShortcutHint !== false ? "visible" : "hidden"}\nPreset Shortcut Hint: ${ui.showPresetShortcutHint !== false ? "visible" : "hidden"}\nHint Contrast: ${workflowEditorHintContrastLabel(workflowEditorHintContrast(settings))}`;
|
|
9671
9813
|
};
|
|
9672
9814
|
|
|
9673
9815
|
const setWorkflowWidgetVisibility = (ctx: ExtensionContext, slot: WorkflowWidgetSlot, visible: boolean): string => {
|
|
@@ -9720,7 +9862,7 @@ export default function workflowModes(pi: ExtensionAPI): void {
|
|
|
9720
9862
|
const messages = (["planTop", "planBottom", "missionTop", "missionBottom", "standardTop", "standardBottom"] as WorkflowWidgetSlot[]).map((slot) => setWorkflowWidgetVisibility(ctx, slot, visible));
|
|
9721
9863
|
return show(pi, `# Workflow Widgets\n\n${messages.join("\n")}\n\n${renderWorkflowWidgetsStatus(ctx)}`);
|
|
9722
9864
|
}
|
|
9723
|
-
return show(pi, "# Workflow Widgets\n\nUsage:\n- /workflow widgets status\n- /workflow widgets list\n- /workflow widgets configure\n- /workflow widgets toggle top\n- /workflow widgets toggle bottom\n- /workflow widgets on\n- /workflow widgets off\n\
|
|
9865
|
+
return show(pi, "# Workflow Widgets\n\nUsage:\n- /workflow widgets status\n- /workflow widgets list\n- /workflow widgets configure\n- /workflow widgets toggle top\n- /workflow widgets toggle bottom\n- /workflow widgets on\n- /workflow widgets off\n\nEditor hint behavior:\n- Idle: Plan/Mission entry shortcuts only\n- Active modes: compact widget/preset hints plus Plan/Mission switch hints by default\n- Active switch hints can be configured in /workflow-settings configure widgets -> Editor Hints");
|
|
9724
9866
|
};
|
|
9725
9867
|
|
|
9726
9868
|
const persistCurrentPlan = (ctx: ExtensionContext, approvalStatus: "draft" | "approved" | "revised" | "completed" | "archived", saveReason: string, handoff: { executionSummary?: string; reviewerReport?: string; validationReport?: string; repairAttempt?: string; finalReport?: string } = {}): string | undefined => {
|
|
@@ -14301,7 +14443,7 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
14301
14443
|
const plannerReapplied = role === "planner" ? await reapplyPlannerRouteIfPlanMode(ctx, true) : false;
|
|
14302
14444
|
const standardSettings = loadWorkflowSettings(ctx.cwd);
|
|
14303
14445
|
const standardReapplied = effectiveStandardModelRole(standardSettings) === role ? await reapplyStandardRouteIfStandardMode(ctx, true) : false;
|
|
14304
|
-
ctx
|
|
14446
|
+
workflowUiNotify(ctx, `${role} model set to ${provider}/${model} in ${result.file}${plannerReapplied || standardReapplied ? `\n${activeModelDiagnostic(ctx)}` : ""}`, "info");
|
|
14305
14447
|
}
|
|
14306
14448
|
|
|
14307
14449
|
async function configureStandardRoleModel(ctx: ExtensionContext, role: WorkflowRole) {
|
|
@@ -14309,14 +14451,14 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
14309
14451
|
if (!selected) return;
|
|
14310
14452
|
const result = setStandardModelForRole(role, selected.provider, selected.model, ctx.cwd);
|
|
14311
14453
|
await reapplyStandardRouteIfStandardMode(ctx, true);
|
|
14312
|
-
ctx
|
|
14454
|
+
workflowUiNotify(ctx, `standard ${role} model set to ${selected.provider}/${selected.model} in ${result.file}`, "info");
|
|
14313
14455
|
}
|
|
14314
14456
|
|
|
14315
14457
|
async function configureMissionRoleModel(ctx: ExtensionContext, role: MissionModelRole) {
|
|
14316
14458
|
const selected = await selectProviderAndModel(ctx, `Mission ${role} model`);
|
|
14317
14459
|
if (!selected) return;
|
|
14318
14460
|
const result = setMissionModelForRole(role, selected.provider, selected.model, ctx.cwd);
|
|
14319
|
-
ctx
|
|
14461
|
+
workflowUiNotify(ctx, `mission ${role} model set to ${selected.provider}/${selected.model} in ${result.file}`, "info");
|
|
14320
14462
|
}
|
|
14321
14463
|
|
|
14322
14464
|
async function configureStandardThinking(ctx: ExtensionContext) {
|
|
@@ -14326,7 +14468,7 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
14326
14468
|
if (!level) return;
|
|
14327
14469
|
const result = setStandardThinkingForRole(role, level, ctx.cwd);
|
|
14328
14470
|
await reapplyStandardRouteIfStandardMode(ctx, true);
|
|
14329
|
-
ctx
|
|
14471
|
+
workflowUiNotify(ctx, `standard ${role} thinking set to ${level} in ${result.file}`, "info");
|
|
14330
14472
|
}
|
|
14331
14473
|
|
|
14332
14474
|
async function configureMissionThinking(ctx: ExtensionContext) {
|
|
@@ -14335,7 +14477,7 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
14335
14477
|
const level = parseThinkingLevel((await ctx.ui.select("Select mission thinking level:", ["off", "minimal", "low", "medium", "high", "xhigh"])) ?? "");
|
|
14336
14478
|
if (!level) return;
|
|
14337
14479
|
const result = setMissionThinkingForRole(role, level, ctx.cwd);
|
|
14338
|
-
ctx
|
|
14480
|
+
workflowUiNotify(ctx, `mission ${role} thinking set to ${level} in ${result.file}`, "info");
|
|
14339
14481
|
}
|
|
14340
14482
|
|
|
14341
14483
|
async function configureThinking(ctx: ExtensionContext) {
|
|
@@ -14347,7 +14489,7 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
14347
14489
|
const plannerReapplied = role === "planner" ? await reapplyPlannerRouteIfPlanMode(ctx, true) : false;
|
|
14348
14490
|
const standardSettings = loadWorkflowSettings(ctx.cwd);
|
|
14349
14491
|
const standardReapplied = effectiveStandardModelRole(standardSettings) === role ? await reapplyStandardRouteIfStandardMode(ctx, true) : false;
|
|
14350
|
-
ctx
|
|
14492
|
+
workflowUiNotify(ctx, `${role} thinking set to ${level} in ${result.file}${plannerReapplied || standardReapplied ? `\n${activeModelDiagnostic(ctx)}` : ""}`, "info");
|
|
14351
14493
|
}
|
|
14352
14494
|
|
|
14353
14495
|
async function chooseBool(ctx: ExtensionContext, title: string): Promise<boolean | undefined> {
|
|
@@ -14355,6 +14497,128 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
14355
14497
|
return parseBool(choice ?? undefined);
|
|
14356
14498
|
}
|
|
14357
14499
|
|
|
14500
|
+
function humanizeWorkflowSettingSegment(segment: string): string {
|
|
14501
|
+
return segment
|
|
14502
|
+
.replace(/([a-z0-9])([A-Z])/g, "$1 $2")
|
|
14503
|
+
.replace(/[_-]+/g, " ")
|
|
14504
|
+
.replace(/\bui\b/gi, "UI")
|
|
14505
|
+
.replace(/\bapi\b/gi, "API")
|
|
14506
|
+
.replace(/\bto do\b/gi, "To Do")
|
|
14507
|
+
.trim()
|
|
14508
|
+
.replace(/\s+/g, " ")
|
|
14509
|
+
.replace(/\w\S*/g, (word) => word === "UI" || word === "API" ? word : word.charAt(0).toUpperCase() + word.slice(1).toLowerCase());
|
|
14510
|
+
}
|
|
14511
|
+
|
|
14512
|
+
function workflowSettingDisplayLabel(setting: string): string {
|
|
14513
|
+
const labels: Record<string, string> = {
|
|
14514
|
+
"ui.editorHintContrast": "Editor hint contrast",
|
|
14515
|
+
"ui.showIdleWorkflowEntryHint": "Idle entry hint",
|
|
14516
|
+
"ui.showActiveWorkflowSwitchHint": "Active switch hint",
|
|
14517
|
+
"ui.showWidgetShortcutHint": "Widget shortcut hint",
|
|
14518
|
+
"ui.showPresetShortcutHint": "Preset shortcut hint",
|
|
14519
|
+
"ui.enableWidgetShortcuts": "Widget shortcuts",
|
|
14520
|
+
"ui.rememberWidgetVisibility": "Remember widget visibility",
|
|
14521
|
+
"ui.workflowTheme": "Workflow theme",
|
|
14522
|
+
"ui.widgetTextStyle": "Widget text style",
|
|
14523
|
+
"ui.startupTextStyle": "Startup text style",
|
|
14524
|
+
"ui.startupVisual": "Startup visual",
|
|
14525
|
+
"ui.startupLogo": "Startup logo",
|
|
14526
|
+
"ui.startupLogoText": "Startup logo text",
|
|
14527
|
+
"ui.startupLogoFont": "Startup logo font",
|
|
14528
|
+
"ui.startupLogoShadowDirection": "Startup logo shadow direction",
|
|
14529
|
+
"ui.startupLogoColorStyle": "Startup logo color style",
|
|
14530
|
+
"ui.startupVisualOnSessionStart": "Startup on session start",
|
|
14531
|
+
"ui.customBrandEnabled": "Custom brand",
|
|
14532
|
+
"ui.customBrandText": "Custom brand text",
|
|
14533
|
+
"ui.customBrandBaseVisual": "Custom brand base visual",
|
|
14534
|
+
"interactiveClarificationEnabled": "Interactive clarification",
|
|
14535
|
+
"maxClarificationQuestions": "Max clarification questions",
|
|
14536
|
+
"planning.depth": "Planning depth",
|
|
14537
|
+
"planning.clarificationMode": "Planning clarification mode",
|
|
14538
|
+
"planning.interactiveClarificationEnabled": "Interactive clarification",
|
|
14539
|
+
"planning.maxClarificationQuestions": "Max clarification questions",
|
|
14540
|
+
"planning.clarificationTiming": "Planning clarification timing",
|
|
14541
|
+
"planning.maxTokens": "Planning token budget",
|
|
14542
|
+
"planning.maxRuntimeHours": "Planning runtime budget",
|
|
14543
|
+
"standard.allowSubagents": "Standard sub-agents",
|
|
14544
|
+
"standard.subagentScope": "Standard sub-agent scope",
|
|
14545
|
+
"standard.todoTriggerMode": "To Do trigger mode",
|
|
14546
|
+
"standard.clarificationMode": "Standard clarification mode",
|
|
14547
|
+
"standard.interactiveClarificationEnabled": "Standard interactive clarification",
|
|
14548
|
+
"standard.maxClarificationQuestions": "Standard max clarification questions",
|
|
14549
|
+
"standard.clarificationTiming": "Standard clarification timing",
|
|
14550
|
+
"standard.maxTokens": "Standard token budget",
|
|
14551
|
+
"standard.enabled": "Standard Mode",
|
|
14552
|
+
"subagents.enabled": "Sub-agents",
|
|
14553
|
+
"subagents.activityIndicatorEnabled": "Sub-agent activity indicator",
|
|
14554
|
+
"subagents.allowBackgroundSubagents": "Background sub-agents",
|
|
14555
|
+
"subagents.editConcurrencyMode": "Sub-agent edit concurrency mode",
|
|
14556
|
+
"subagents.planningOrchestrationPolicy": "Planning orchestration policy",
|
|
14557
|
+
"missions.enabled": "Mission Mode",
|
|
14558
|
+
"missions.defaultAutonomy": "Mission default autonomy",
|
|
14559
|
+
"missions.subagentPolicy": "Mission sub-agent policy",
|
|
14560
|
+
"missions.planningDepth": "Mission planning depth",
|
|
14561
|
+
"missions.clarificationMode": "Mission clarification mode",
|
|
14562
|
+
"missions.interactiveClarificationEnabled": "Mission interactive clarification",
|
|
14563
|
+
"missions.maxClarificationQuestions": "Mission max clarification questions",
|
|
14564
|
+
"missions.clarificationTiming": "Mission clarification timing",
|
|
14565
|
+
"missions.maxTokens": "Mission token budget",
|
|
14566
|
+
"missions.maxRuntimeHours": "Mission runtime budget",
|
|
14567
|
+
"missions.checkpointIntervalMinutes": "Mission checkpoint interval",
|
|
14568
|
+
"missions.heartbeatEnabled": "Mission heartbeat",
|
|
14569
|
+
"missions.watchdogEnabled": "Mission watchdog",
|
|
14570
|
+
"missions.watchdogStaleMinutes": "Mission watchdog stale minutes",
|
|
14571
|
+
"missions.missionHistoryLimit": "Mission history limit",
|
|
14572
|
+
"context.autoCompactionEnabled": "Workflow auto trigger",
|
|
14573
|
+
"context.compactionTriggerPercent": "Workflow trigger percent",
|
|
14574
|
+
"context.compactionCooldownMinutes": "Compaction cooldown",
|
|
14575
|
+
"context.customCompactionReserveTokens": "Custom compaction reserve tokens",
|
|
14576
|
+
"context.customCompactionKeepRecentTokens": "Custom compaction keep-recent tokens",
|
|
14577
|
+
"workflow.validationRetryMode": "Validation retry mode",
|
|
14578
|
+
"workflow.planHistoryLimit": "Plan history limit",
|
|
14579
|
+
"workflow.planShowProgressBar": "Plan progress bar",
|
|
14580
|
+
"safety.repoLockEnabled": "Project Repo Lock",
|
|
14581
|
+
};
|
|
14582
|
+
if (labels[setting]) return labels[setting];
|
|
14583
|
+
const parts = setting.split(".");
|
|
14584
|
+
return humanizeWorkflowSettingSegment(parts[parts.length - 1] || setting);
|
|
14585
|
+
}
|
|
14586
|
+
|
|
14587
|
+
function workflowSettingDisplayValue(setting: string, value: string): string {
|
|
14588
|
+
const clean = value.trim().replace(/\s+/g, " ");
|
|
14589
|
+
if (setting === "ui.editorHintContrast") {
|
|
14590
|
+
return workflowEditorHintContrastLabel(parseEditorHintContrast(clean) ?? "normal");
|
|
14591
|
+
}
|
|
14592
|
+
if (clean === "true") {
|
|
14593
|
+
return /^ui\.show.*Hint$/.test(setting) ? "shown" : "enabled";
|
|
14594
|
+
}
|
|
14595
|
+
if (clean === "false") {
|
|
14596
|
+
return /^ui\.show.*Hint$/.test(setting) ? "hidden" : "disabled";
|
|
14597
|
+
}
|
|
14598
|
+
return clean
|
|
14599
|
+
.replace(/_/g, " ")
|
|
14600
|
+
.replace(/\bpi\b/gi, "Pi")
|
|
14601
|
+
.replace(/\w\S*/g, (word) => word === "Pi" || word.toUpperCase() === "API" ? word : word.charAt(0).toUpperCase() + word.slice(1).toLowerCase());
|
|
14602
|
+
}
|
|
14603
|
+
|
|
14604
|
+
function workflowFriendlyNotification(message: string, level?: "info" | "warning" | "error"): string {
|
|
14605
|
+
if (level !== "info") return message;
|
|
14606
|
+
let text = message.replace(/\s+in\s+\/\S+/g, "").replace(/\s+/g, " ").trim();
|
|
14607
|
+
const settingMatch = text.match(/^([A-Za-z][A-Za-z0-9_]*(?:\.[A-Za-z0-9_]+)*)\s+set to\s+([^.;]+)([.;]?.*)$/);
|
|
14608
|
+
if (settingMatch) {
|
|
14609
|
+
const [, setting, value, tail = ""] = settingMatch;
|
|
14610
|
+
const label = workflowSettingDisplayLabel(setting);
|
|
14611
|
+
const displayValue = workflowSettingDisplayValue(setting, value);
|
|
14612
|
+
const suffix = tail.replace(/^[.;]\s*/, "").trim();
|
|
14613
|
+
return `${label} set to ${displayValue}.${suffix ? ` ${suffix}` : ""}`;
|
|
14614
|
+
}
|
|
14615
|
+
return text.charAt(0).toUpperCase() + text.slice(1);
|
|
14616
|
+
}
|
|
14617
|
+
|
|
14618
|
+
function workflowUiNotify(ctx: ExtensionContext, message: string, level?: "info" | "warning" | "error"): void {
|
|
14619
|
+
ctx.ui.notify(workflowFriendlyNotification(message, level), level);
|
|
14620
|
+
}
|
|
14621
|
+
|
|
14358
14622
|
async function showPlanningSettingsMenu(ctx: ExtensionContext) {
|
|
14359
14623
|
if (!ctx.hasUI) return show(pi, renderFullWorkflowSettings(loadWorkflowSettings(ctx.cwd)));
|
|
14360
14624
|
while (ctx.hasUI) {
|
|
@@ -14362,7 +14626,7 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
14362
14626
|
if (!choice || choice === "Back") return;
|
|
14363
14627
|
if (choice === "Set planning.depth") {
|
|
14364
14628
|
const depth = parsePlanningDepth((await ctx.ui.select("Planning depth", ["fast", "standard", "deep", "maximum"])) ?? "");
|
|
14365
|
-
if (depth) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.planning.depth = depth; }); ctx
|
|
14629
|
+
if (depth) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.planning.depth = depth; }); workflowUiNotify(ctx, `planning.depth set to ${depth} in ${r.file}`, "info"); }
|
|
14366
14630
|
} else if (choice === "List Current Settings") {
|
|
14367
14631
|
const s = loadWorkflowSettings(ctx.cwd);
|
|
14368
14632
|
show(pi, `# Planning Settings\n\nplanning.depth: ${s.planning.depth}`);
|
|
@@ -14377,13 +14641,13 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
14377
14641
|
if (!choice || choice === "Back") return;
|
|
14378
14642
|
if (choice === "Set clarificationMode") {
|
|
14379
14643
|
const mode = parseClarificationMode((await ctx.ui.select("Clarification mode", ["auto", "always_for_nontrivial", "never"])) ?? "");
|
|
14380
|
-
if (mode) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.planning.clarificationMode = mode; }); ctx
|
|
14644
|
+
if (mode) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.planning.clarificationMode = mode; }); workflowUiNotify(ctx, `planning.clarificationMode set to ${mode} in ${r.file}`, "info"); }
|
|
14381
14645
|
} else if (choice === "Set interactiveClarificationEnabled") {
|
|
14382
14646
|
const enabled = await chooseBool(ctx, "Interactive clarification enabled?");
|
|
14383
|
-
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.planning.interactiveClarificationEnabled = enabled; }); ctx
|
|
14647
|
+
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.planning.interactiveClarificationEnabled = enabled; }); workflowUiNotify(ctx, `interactiveClarificationEnabled set to ${enabled} in ${r.file}`, "info"); }
|
|
14384
14648
|
} else if (choice === "Set maxClarificationQuestions") {
|
|
14385
14649
|
const count = parsePositiveInt((await ctx.ui.select("Max clarification questions", ["1", "2", "3", "4", "5"])) ?? "");
|
|
14386
|
-
if (count) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.planning.maxClarificationQuestions = count; }); ctx
|
|
14650
|
+
if (count) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.planning.maxClarificationQuestions = count; }); workflowUiNotify(ctx, `maxClarificationQuestions set to ${count} in ${r.file}`, "info"); }
|
|
14387
14651
|
} else if (choice === "List Current Settings") {
|
|
14388
14652
|
const s = loadWorkflowSettings(ctx.cwd);
|
|
14389
14653
|
show(pi, `# Clarification Settings\n\nClarification Mode: ${s.planning.clarificationMode}\nInteractive Clarification: ${s.planning.interactiveClarificationEnabled !== false ? "enabled" : "disabled"}\nMax Clarification Questions: ${s.planning.maxClarificationQuestions}`);
|
|
@@ -14399,11 +14663,11 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
14399
14663
|
if (!choice || choice === "Back") return;
|
|
14400
14664
|
if (choice.endsWith("Policy")) {
|
|
14401
14665
|
const policy = parseSubagentPolicy((await ctx.ui.select(`${label} policy`, ["off", "auto", "deep", "maximum", "forced"])) ?? "");
|
|
14402
|
-
if (policy) { const r = updateSettings(ctx.cwd, undefined, (s) => { (s.subagents as typeof s.subagents & Record<string, string>)[keys.policyKey] = policy; }); ctx
|
|
14666
|
+
if (policy) { const r = updateSettings(ctx.cwd, undefined, (s) => { (s.subagents as typeof s.subagents & Record<string, string>)[keys.policyKey] = policy; }); workflowUiNotify(ctx, `subagents.${keys.policyKey} set to ${policy} in ${r.file}`, "info"); }
|
|
14403
14667
|
} else {
|
|
14404
14668
|
const key = choice.includes("Deep") ? keys.deepKey : keys.maximumKey;
|
|
14405
14669
|
const count = parsePositiveInt((await ctx.ui.select(`${label} ${choice.includes("Deep") ? "deep" : "maximum / forced"} workers`, ["0", "1", "2", "3", "4", "5", "6", "7", "8"])) ?? "");
|
|
14406
|
-
if (count !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { (s.subagents as typeof s.subagents & Record<string, number>)[key] = count; }); ctx
|
|
14670
|
+
if (count !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { (s.subagents as typeof s.subagents & Record<string, number>)[key] = count; }); workflowUiNotify(ctx, `subagents.${key} set to ${count} in ${r.file}. Forced policy uses this phase's Maximum / Forced worker count.`, "info"); }
|
|
14407
14671
|
}
|
|
14408
14672
|
}
|
|
14409
14673
|
}
|
|
@@ -14421,7 +14685,7 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
14421
14685
|
const standard = s.standard as typeof s.standard & { subagents?: Record<string, boolean | number | string | undefined> };
|
|
14422
14686
|
standard.subagents = { ...(standard.subagents ?? {}), [keys.policyKey]: policy };
|
|
14423
14687
|
});
|
|
14424
|
-
ctx
|
|
14688
|
+
workflowUiNotify(ctx, `standard.subagents.${keys.policyKey} set to ${policy} in ${r.file}`, "info");
|
|
14425
14689
|
}
|
|
14426
14690
|
} else {
|
|
14427
14691
|
const key = choice.includes("Deep") ? keys.deepKey : keys.maximumKey;
|
|
@@ -14431,7 +14695,7 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
14431
14695
|
const standard = s.standard as typeof s.standard & { subagents?: Record<string, boolean | number | string | undefined> };
|
|
14432
14696
|
standard.subagents = { ...(standard.subagents ?? {}), [key]: count };
|
|
14433
14697
|
});
|
|
14434
|
-
ctx
|
|
14698
|
+
workflowUiNotify(ctx, `standard.subagents.${key} set to ${count} in ${r.file}. Forced policy uses this Standard phase's Maximum / Forced worker count.`, "info");
|
|
14435
14699
|
}
|
|
14436
14700
|
}
|
|
14437
14701
|
}
|
|
@@ -14450,7 +14714,7 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
14450
14714
|
const standard = s.standard as typeof s.standard & { subagents?: Record<string, boolean | number | string | undefined> };
|
|
14451
14715
|
standard.subagents = { ...(standard.subagents ?? {}), [key]: enabled };
|
|
14452
14716
|
});
|
|
14453
|
-
ctx
|
|
14717
|
+
workflowUiNotify(ctx, `standard.subagents.${key} set to ${enabled} in ${r.file}`, "info");
|
|
14454
14718
|
}
|
|
14455
14719
|
}
|
|
14456
14720
|
}
|
|
@@ -14467,7 +14731,7 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
14467
14731
|
const standard = s.standard as typeof s.standard & { subagents?: Record<string, boolean | number | string | undefined> };
|
|
14468
14732
|
standard.subagents = { ...(standard.subagents ?? {}), [key]: enabled };
|
|
14469
14733
|
});
|
|
14470
|
-
ctx
|
|
14734
|
+
workflowUiNotify(ctx, `standard.subagents.${key} set to ${enabled} in ${r.file}`, "info");
|
|
14471
14735
|
}
|
|
14472
14736
|
}
|
|
14473
14737
|
}
|
|
@@ -14479,7 +14743,7 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
14479
14743
|
if (!choice || choice === "Back") return;
|
|
14480
14744
|
if (choice === "Enable / Disable Standard Sub-agents") {
|
|
14481
14745
|
const enabled = await chooseBool(ctx, "standard.allowSubagents?");
|
|
14482
|
-
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.standard.allowSubagents = enabled; }); ctx
|
|
14746
|
+
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.standard.allowSubagents = enabled; }); workflowUiNotify(ctx, `standard.allowSubagents set to ${enabled} in ${r.file}`, "info"); }
|
|
14483
14747
|
} else if (choice === "Standard Planning / Research Policy / Workers") await showStandardSubagentPhaseSettingsMenu(ctx, "Planning", "Standard Planning / Research");
|
|
14484
14748
|
else if (choice === "Standard Execution Policy / Workers") await showStandardSubagentPhaseSettingsMenu(ctx, "Execution", "Standard Execution");
|
|
14485
14749
|
else if (choice === "Standard Repair Policy / Workers") await showStandardSubagentPhaseSettingsMenu(ctx, "Repair", "Standard Repair");
|
|
@@ -14487,15 +14751,15 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
14487
14751
|
else if (choice === "Standard Validation Policy / Workers") await showStandardSubagentPhaseSettingsMenu(ctx, "Validation", "Standard Validation");
|
|
14488
14752
|
else if (choice === "Agent Scope") {
|
|
14489
14753
|
const scope = parseWorkflowAgentScope((await ctx.ui.select("Standard agent scope", ["user", "project", "both"])) ?? "");
|
|
14490
|
-
if (scope) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.standard.subagentScope = scope; }); ctx
|
|
14754
|
+
if (scope) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.standard.subagentScope = scope; }); workflowUiNotify(ctx, `standard.subagentScope set to ${scope} in ${r.file}`, "info"); }
|
|
14491
14755
|
} else if (choice === "Auto-use Toggles") await showStandardSubagentAutoUseMenu(ctx);
|
|
14492
14756
|
else if (choice === "Parallel Agent Settings") await showStandardParallelismSettingsMenu(ctx);
|
|
14493
14757
|
else if (choice === "Activity Indicator") {
|
|
14494
14758
|
const enabled = await chooseBool(ctx, "subagents.activityIndicatorEnabled?");
|
|
14495
|
-
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.subagents.activityIndicatorEnabled = enabled; }); ctx
|
|
14759
|
+
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.subagents.activityIndicatorEnabled = enabled; }); workflowUiNotify(ctx, `subagents.activityIndicatorEnabled set to ${enabled} in ${r.file}`, "info"); renderWorkflowSubagentActivity(ctx); }
|
|
14496
14760
|
} else if (choice === "List Current Settings") {
|
|
14497
14761
|
const s = loadWorkflowSettings(ctx.cwd);
|
|
14498
|
-
show(pi, `#
|
|
14762
|
+
show(pi, `# Standard Sub-agents / Workers\n\nSub-agents: ${s.standard.allowSubagents !== false ? "enabled" : "disabled"}\nAgent Scope: ${s.standard.subagentScope ?? "user"}\nActivity Indicator: ${s.subagents.activityIndicatorEnabled !== false ? "enabled" : "disabled"}\nAuto-use Planning: ${s.standard.subagents?.autoUseDuringPlanning !== false ? "on" : "off"}\nAuto-use Execution: ${s.standard.subagents?.autoUseDuringExecution !== false ? "on" : "off"}\nAuto-use Repair: ${s.standard.subagents?.autoUseDuringRepair !== false ? "on" : "off"}\nAuto-use Review: ${s.standard.subagents?.autoUseDuringReview !== false ? "on" : "off"}\nAuto-use Validation: ${s.standard.subagents?.autoUseDuringValidation !== false ? "on" : "off"}`);
|
|
14499
14763
|
}
|
|
14500
14764
|
}
|
|
14501
14765
|
}
|
|
@@ -14507,11 +14771,11 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
14507
14771
|
if (!choice || choice === "Back") return;
|
|
14508
14772
|
if (choice === "Mission Planning Policy") {
|
|
14509
14773
|
const policy = parseSubagentPolicy((await ctx.ui.select("Mission planning policy", ["off", "auto", "deep", "maximum", "forced"])) ?? "");
|
|
14510
|
-
if (policy) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.missions.subagentPolicy = policy; }); ctx
|
|
14774
|
+
if (policy) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.missions.subagentPolicy = policy; }); workflowUiNotify(ctx, `missions.subagentPolicy set to ${policy} in ${r.file}`, "info"); }
|
|
14511
14775
|
} else {
|
|
14512
14776
|
const key = choice.includes("Deep") ? "minWorkersForDeep" : "minWorkersForMaximum";
|
|
14513
14777
|
const count = parsePositiveInt((await ctx.ui.select(choice, ["0", "1", "2", "3", "4", "5", "6", "7", "8"])) ?? "");
|
|
14514
|
-
if (count !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { (s.missions as typeof s.missions & Record<string, number>)[key] = count; }); ctx
|
|
14778
|
+
if (count !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { (s.missions as typeof s.missions & Record<string, number>)[key] = count; }); workflowUiNotify(ctx, `missions.${key} set to ${count} in ${r.file}. Forced mission planning uses Mission Planning Maximum / Forced Workers.`, "info"); }
|
|
14515
14779
|
}
|
|
14516
14780
|
}
|
|
14517
14781
|
}
|
|
@@ -14524,7 +14788,7 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
14524
14788
|
const keyMap: Record<string, string> = { "Planning Auto-use": "autoUseDuringPlanning", "Execution Auto-use": "autoUseDuringExecution", "Repair Auto-use": "autoUseDuringRepair", "Review Auto-use": "autoUseDuringReview", "Validation Auto-use": "autoUseDuringValidation" };
|
|
14525
14789
|
const key = keyMap[choice];
|
|
14526
14790
|
const enabled = await chooseBool(ctx, `${key}?`);
|
|
14527
|
-
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { (s.subagents as typeof s.subagents & Record<string, boolean>)[key] = enabled; }); ctx
|
|
14791
|
+
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { (s.subagents as typeof s.subagents & Record<string, boolean>)[key] = enabled; }); workflowUiNotify(ctx, `subagents.${key} set to ${enabled} in ${r.file}`, "info"); }
|
|
14528
14792
|
}
|
|
14529
14793
|
}
|
|
14530
14794
|
|
|
@@ -14535,7 +14799,7 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
14535
14799
|
if (!choice || choice === "Back") return;
|
|
14536
14800
|
if (choice === "Enable / Disable Sub-agents") {
|
|
14537
14801
|
const enabled = await chooseBool(ctx, "subagents.enabled?");
|
|
14538
|
-
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.subagents.enabled = enabled; }); ctx
|
|
14802
|
+
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.subagents.enabled = enabled; }); workflowUiNotify(ctx, `subagents.enabled set to ${enabled} in ${r.file}`, "info"); }
|
|
14539
14803
|
} else if (choice === "Planning Policy / Workers") await showSubagentPhaseSettingsMenu(ctx, "Planning", "Shared Planning");
|
|
14540
14804
|
else if (choice === "Execution Policy / Workers") await showSubagentPhaseSettingsMenu(ctx, "Execution", "Shared Execution");
|
|
14541
14805
|
else if (choice === "Repair Policy / Workers") await showSubagentPhaseSettingsMenu(ctx, "Repair", "Shared Repair");
|
|
@@ -14545,10 +14809,10 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
14545
14809
|
else if (choice === "Parallel Agent Settings") await showParallelismSettingsMenu(ctx);
|
|
14546
14810
|
else if (choice === "Background Sub-agents") {
|
|
14547
14811
|
const enabled = await chooseBool(ctx, "subagents.allowBackgroundSubagents?");
|
|
14548
|
-
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.subagents.allowBackgroundSubagents = enabled; }); ctx
|
|
14812
|
+
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.subagents.allowBackgroundSubagents = enabled; }); workflowUiNotify(ctx, `subagents.allowBackgroundSubagents set to ${enabled} in ${r.file}. Background sub-agents run in Planning/Review/Validation phases without blocking the parent.`, "info"); }
|
|
14549
14813
|
} else if (choice === "Activity Indicator") {
|
|
14550
14814
|
const enabled = await chooseBool(ctx, "subagents.activityIndicatorEnabled?");
|
|
14551
|
-
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.subagents.activityIndicatorEnabled = enabled; }); ctx
|
|
14815
|
+
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.subagents.activityIndicatorEnabled = enabled; }); workflowUiNotify(ctx, `subagents.activityIndicatorEnabled set to ${enabled} in ${r.file}`, "info"); renderWorkflowSubagentActivity(ctx); }
|
|
14552
14816
|
} else if (choice === "List Current Settings") {
|
|
14553
14817
|
const s = loadWorkflowSettings(ctx.cwd);
|
|
14554
14818
|
show(pi, `# Shared Sub-agents / Workers\n\nSub-agents: ${s.subagents.enabled !== false ? "enabled" : "disabled"}\nBackground Sub-agents: ${s.subagents.allowBackgroundSubagents === true ? "enabled" : "disabled"}\nActivity Indicator: ${s.subagents.activityIndicatorEnabled !== false ? "enabled" : "disabled"}\nAuto-use Planning: ${s.subagents.autoUseDuringPlanning !== false ? "on" : "off"}\nAuto-use Execution: ${s.subagents.autoUseDuringExecution !== false ? "on" : "off"}\nAuto-use Repair: ${s.subagents.autoUseDuringRepair !== false ? "on" : "off"}\nAuto-use Review: ${s.subagents.autoUseDuringReview !== false ? "on" : "off"}\nAuto-use Validation: ${s.subagents.autoUseDuringValidation !== false ? "on" : "off"}`);
|
|
@@ -14563,7 +14827,7 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
14563
14827
|
if (!choice || choice === "Back") return;
|
|
14564
14828
|
if (choice === "Enable / Disable Sub-agents") {
|
|
14565
14829
|
const enabled = await chooseBool(ctx, "subagents.enabled?");
|
|
14566
|
-
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.subagents.enabled = enabled; }); ctx
|
|
14830
|
+
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.subagents.enabled = enabled; }); workflowUiNotify(ctx, `subagents.enabled set to ${enabled} in ${r.file}`, "info"); }
|
|
14567
14831
|
} else if (choice === "Plan Planning Policy / Workers") await showSubagentPhaseSettingsMenu(ctx, "Planning", "Plan Planning");
|
|
14568
14832
|
else if (choice === "Plan Execution Policy / Workers") await showSubagentPhaseSettingsMenu(ctx, "Execution", "Plan Execution");
|
|
14569
14833
|
else if (choice === "Plan Repair Policy / Workers") await showSubagentPhaseSettingsMenu(ctx, "Repair", "Plan Repair");
|
|
@@ -14573,10 +14837,10 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
14573
14837
|
else if (choice === "Parallel Agent Settings") await showParallelismSettingsMenu(ctx);
|
|
14574
14838
|
else if (choice === "Activity Indicator") {
|
|
14575
14839
|
const enabled = await chooseBool(ctx, "subagents.activityIndicatorEnabled?");
|
|
14576
|
-
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.subagents.activityIndicatorEnabled = enabled; }); ctx
|
|
14840
|
+
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.subagents.activityIndicatorEnabled = enabled; }); workflowUiNotify(ctx, `subagents.activityIndicatorEnabled set to ${enabled} in ${r.file}`, "info"); renderWorkflowSubagentActivity(ctx); }
|
|
14577
14841
|
} else if (choice === "List Current Settings") {
|
|
14578
14842
|
const s = loadWorkflowSettings(ctx.cwd);
|
|
14579
|
-
show(pi, `#
|
|
14843
|
+
show(pi, `# Plan Sub-agents / Workers\n\n${renderPlanSubagentWorkerSettings(s)}`);
|
|
14580
14844
|
}
|
|
14581
14845
|
}
|
|
14582
14846
|
}
|
|
@@ -14588,7 +14852,7 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
14588
14852
|
if (!choice || choice === "Back") return;
|
|
14589
14853
|
if (choice === "Enable / Disable Sub-agents") {
|
|
14590
14854
|
const enabled = await chooseBool(ctx, "subagents.enabled?");
|
|
14591
|
-
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.subagents.enabled = enabled; }); ctx
|
|
14855
|
+
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.subagents.enabled = enabled; }); workflowUiNotify(ctx, `subagents.enabled set to ${enabled} in ${r.file}`, "info"); }
|
|
14592
14856
|
} else if (choice === "Mission Planning Policy / Workers") await showMissionPlanningSubagentSettingsMenu(ctx);
|
|
14593
14857
|
else if (choice === "Mission Execution Policy / Workers") await showSubagentPhaseSettingsMenu(ctx, "Execution", "Mission Execution");
|
|
14594
14858
|
else if (choice === "Mission Repair Policy / Workers") await showSubagentPhaseSettingsMenu(ctx, "Repair", "Mission Repair");
|
|
@@ -14598,7 +14862,7 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
14598
14862
|
else if (choice === "Parallel Agent Settings") await showParallelismSettingsMenu(ctx);
|
|
14599
14863
|
else if (choice === "Activity Indicator") {
|
|
14600
14864
|
const enabled = await chooseBool(ctx, "subagents.activityIndicatorEnabled?");
|
|
14601
|
-
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.subagents.activityIndicatorEnabled = enabled; }); ctx
|
|
14865
|
+
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.subagents.activityIndicatorEnabled = enabled; }); workflowUiNotify(ctx, `subagents.activityIndicatorEnabled set to ${enabled} in ${r.file}`, "info"); renderWorkflowSubagentActivity(ctx); }
|
|
14602
14866
|
} else if (choice === "List Current Settings") {
|
|
14603
14867
|
const s = loadWorkflowSettings(ctx.cwd);
|
|
14604
14868
|
show(pi, `# Mission Sub-agents / Workers\n\n${renderMissionSubagentWorkerSettings(s)}`);
|
|
@@ -14614,10 +14878,10 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
14614
14878
|
if (choice?.startsWith("Set allow") || choice === "Set requireParallelEditConflictProtection") {
|
|
14615
14879
|
const key = choice.replace("Set ", "");
|
|
14616
14880
|
const enabled = await chooseBool(ctx, `${key}?`);
|
|
14617
|
-
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { (s.subagents as typeof s.subagents & Record<string, boolean>)[key] = enabled; }); ctx
|
|
14881
|
+
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { (s.subagents as typeof s.subagents & Record<string, boolean>)[key] = enabled; }); workflowUiNotify(ctx, `subagents.${key} set to ${enabled} in ${r.file}`, "info"); }
|
|
14618
14882
|
} else if (choice === "Set editConcurrencyMode") {
|
|
14619
14883
|
const mode = parseEditConcurrencyMode((await ctx.ui.select("Edit concurrency mode", ["sequential", "scoped", "blocked"])) ?? "");
|
|
14620
|
-
if (mode) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.subagents.editConcurrencyMode = mode; }); ctx
|
|
14884
|
+
if (mode) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.subagents.editConcurrencyMode = mode; }); workflowUiNotify(ctx, `subagents.editConcurrencyMode set to ${mode} in ${r.file}`, "info"); }
|
|
14621
14885
|
} else if (choice === "List Current Settings") {
|
|
14622
14886
|
const s = loadWorkflowSettings(ctx.cwd);
|
|
14623
14887
|
show(pi, `# Parallelism Settings\n\nParallel Read-Only: ${s.subagents.allowParallelReadOnly !== false ? "enabled" : "disabled"}\nParallel Planning: ${s.subagents.allowParallelPlanning !== false ? "enabled" : "disabled"}\nParallel Execution: ${s.subagents.allowParallelExecution !== false ? "enabled" : "disabled"}\nParallel Repair: ${s.subagents.allowParallelRepair !== false ? "enabled" : "disabled"}\nParallel Review: ${s.subagents.allowParallelReview !== false ? "enabled" : "disabled"}\nParallel Validation: ${s.subagents.allowParallelValidation !== false ? "enabled" : "disabled"}\nParallel File Edits: ${s.subagents.allowParallelEdits !== false ? "enabled" : "disabled"}\nEdit Concurrency Mode: ${s.subagents.editConcurrencyMode ?? "sequential"}\nConflict Protection: ${s.subagents.requireParallelEditConflictProtection !== false ? "enabled" : "disabled"}`);
|
|
@@ -14629,7 +14893,7 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
14629
14893
|
const models = ctx.modelRegistry.getAll();
|
|
14630
14894
|
const providers = [...new Set(models.map((m) => m.provider))].sort();
|
|
14631
14895
|
if (providers.length === 0) {
|
|
14632
|
-
ctx
|
|
14896
|
+
workflowUiNotify(ctx, "No models are available in the model registry.", "error");
|
|
14633
14897
|
return undefined;
|
|
14634
14898
|
}
|
|
14635
14899
|
const providerChoice = await ctx.ui.select(`${title}: select provider`, [...providers, "Custom provider name"]);
|
|
@@ -14643,7 +14907,7 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
14643
14907
|
}
|
|
14644
14908
|
const providerModels = models.filter((m) => m.provider === providerChoice).map((m) => m.id).sort();
|
|
14645
14909
|
if (providerModels.length === 0) {
|
|
14646
|
-
ctx
|
|
14910
|
+
workflowUiNotify(ctx, `No models found for provider ${providerChoice}.`, "error");
|
|
14647
14911
|
return undefined;
|
|
14648
14912
|
}
|
|
14649
14913
|
const modelChoice = await ctx.ui.select(`${title}: select model`, providerModels.map((model) => `${providerChoice}/${model}`));
|
|
@@ -14651,33 +14915,62 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
14651
14915
|
return { provider: providerChoice, model: modelChoice.replace(`${providerChoice}/`, "") };
|
|
14652
14916
|
}
|
|
14653
14917
|
|
|
14654
|
-
async function
|
|
14655
|
-
const
|
|
14656
|
-
|
|
14918
|
+
async function chooseCompactionProvider(ctx: ExtensionContext): Promise<string | undefined> {
|
|
14919
|
+
const models = ctx.modelRegistry.getAll();
|
|
14920
|
+
const providers = [...new Set(models.map((m) => m.provider))].sort();
|
|
14921
|
+
const providerChoice = await ctx.ui.select("Compaction Provider", ["Pi default", "Custom provider", "Back"]);
|
|
14922
|
+
if (!providerChoice || providerChoice === "Back") return undefined;
|
|
14923
|
+
if (providerChoice === "Pi default") return "";
|
|
14924
|
+
const choice = await ctx.ui.select("Custom provider", [...providers, "Custom provider name", "Back"]);
|
|
14925
|
+
if (!choice || choice === "Back") return undefined;
|
|
14926
|
+
if (choice === "Custom provider name") return (await ctx.ui.input("Custom compaction provider:", "provider-name"))?.trim();
|
|
14927
|
+
return choice;
|
|
14928
|
+
}
|
|
14929
|
+
|
|
14930
|
+
async function selectCompactionProvider(ctx: ExtensionContext) {
|
|
14931
|
+
const provider = await chooseCompactionProvider(ctx);
|
|
14932
|
+
if (provider === undefined) return;
|
|
14657
14933
|
const result = updateSettings(ctx.cwd, undefined, (s) => {
|
|
14658
|
-
s.context.
|
|
14659
|
-
s.context.
|
|
14660
|
-
s.context.compactionModel = selected.model;
|
|
14661
|
-
s.context.customCompactionEnabled = true;
|
|
14934
|
+
s.context.compactionModelProvider = provider;
|
|
14935
|
+
s.context.compactionModel = "";
|
|
14662
14936
|
});
|
|
14663
|
-
ctx
|
|
14937
|
+
workflowUiNotify(ctx, provider ? `Compaction provider preference stored as ${provider} in ${result.file}. Trigger behavior was not changed.` : `Compaction provider reset to Pi default in ${result.file}. Trigger behavior was not changed.`, "info");
|
|
14664
14938
|
}
|
|
14665
14939
|
|
|
14666
|
-
async function
|
|
14940
|
+
async function selectCompactionModel(ctx: ExtensionContext) {
|
|
14667
14941
|
const settings = loadWorkflowSettings(ctx.cwd);
|
|
14668
14942
|
const provider = settings.context.compactionModelProvider;
|
|
14669
|
-
|
|
14670
|
-
|
|
14671
|
-
if (
|
|
14672
|
-
|
|
14673
|
-
|
|
14674
|
-
|
|
14943
|
+
const mode = await ctx.ui.select("Compaction Model", ["Pi default", "Custom model", "Back"]);
|
|
14944
|
+
if (!mode || mode === "Back") return;
|
|
14945
|
+
if (mode === "Pi default") {
|
|
14946
|
+
const result = updateSettings(ctx.cwd, undefined, (s) => {
|
|
14947
|
+
s.context.compactionModelProvider = "";
|
|
14948
|
+
s.context.compactionModel = "";
|
|
14949
|
+
});
|
|
14950
|
+
workflowUiNotify(ctx, `Compaction summary model reset to Pi default in ${result.file}. Trigger behavior was not changed.`, "info");
|
|
14951
|
+
return;
|
|
14952
|
+
}
|
|
14953
|
+
|
|
14954
|
+
let selectedProvider = provider;
|
|
14955
|
+
if (!selectedProvider) {
|
|
14956
|
+
const chosen = await chooseCompactionProvider(ctx);
|
|
14957
|
+
if (chosen === undefined) return;
|
|
14958
|
+
selectedProvider = chosen;
|
|
14959
|
+
}
|
|
14960
|
+
if (!selectedProvider) {
|
|
14961
|
+
workflowUiNotify(ctx, "Select a custom compaction provider before selecting a custom model.", "warning");
|
|
14962
|
+
return;
|
|
14963
|
+
}
|
|
14964
|
+
const providerModels = ctx.modelRegistry.getAll().filter((m) => m.provider === selectedProvider).map((m) => m.id).sort();
|
|
14965
|
+
const modelChoice = await ctx.ui.select(`Custom model for ${selectedProvider}:`, [...providerModels.map((model) => `${selectedProvider}/${model}`), "Custom model name", "Back"]);
|
|
14966
|
+
if (!modelChoice || modelChoice === "Back") return;
|
|
14967
|
+
const model = modelChoice === "Custom model name" ? (await ctx.ui.input("Custom compaction model:", "model-name"))?.trim() : modelChoice.replace(`${selectedProvider}/`, "");
|
|
14968
|
+
if (!model) return;
|
|
14675
14969
|
const result = updateSettings(ctx.cwd, undefined, (s) => {
|
|
14676
|
-
s.context.
|
|
14970
|
+
s.context.compactionModelProvider = selectedProvider;
|
|
14677
14971
|
s.context.compactionModel = model;
|
|
14678
|
-
s.context.customCompactionEnabled = true;
|
|
14679
14972
|
});
|
|
14680
|
-
ctx
|
|
14973
|
+
workflowUiNotify(ctx, `Compaction model preference stored as ${selectedProvider}/${model} in ${result.file}. Trigger behavior was not changed.`, "info");
|
|
14681
14974
|
}
|
|
14682
14975
|
|
|
14683
14976
|
async function selectCompactionAgent(ctx: ExtensionContext) {
|
|
@@ -14691,66 +14984,76 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
14691
14984
|
s.context.compactionAgent = agent;
|
|
14692
14985
|
s.context.customCompactionEnabled = true;
|
|
14693
14986
|
});
|
|
14694
|
-
ctx
|
|
14987
|
+
workflowUiNotify(ctx, `Compaction agent stored as ${agent} in ${result.file}. Current releases keep Pi default fallback behavior for agent-routed compaction.`, "info");
|
|
14695
14988
|
}
|
|
14696
14989
|
|
|
14697
14990
|
async function showCompactionSettingsMenu(ctx: ExtensionContext) {
|
|
14698
14991
|
if (!ctx.hasUI) return show(pi, renderFullWorkflowSettings(loadWorkflowSettings(ctx.cwd)));
|
|
14699
14992
|
while (ctx.hasUI) {
|
|
14700
|
-
const choice = await ctx.ui.select("Shared Compaction Settings", ["Compaction
|
|
14993
|
+
const choice = await ctx.ui.select("Shared Compaction Settings", ["Compaction Provider", "Compaction Model", "Workflow Auto Trigger Enabled", "Workflow Trigger Percent", "Workflow Trigger Cooldown", "Custom Reserve Tokens", "Custom Keep Recent Tokens", "List Current Settings", "Back"]);
|
|
14701
14994
|
if (!choice || choice === "Back") return;
|
|
14702
|
-
if (choice === "Compaction
|
|
14703
|
-
|
|
14704
|
-
if (!mode) continue;
|
|
14705
|
-
if (mode === "custom_model") { await selectCompactionModel(ctx); continue; }
|
|
14706
|
-
const r = updateSettings(ctx.cwd, undefined, (s) => {
|
|
14707
|
-
if (mode === "pi_default") resetCompactionContextToPiDefault(s.context);
|
|
14708
|
-
else {
|
|
14709
|
-
s.context.compactionMode = mode;
|
|
14710
|
-
s.context.customCompactionEnabled = false;
|
|
14711
|
-
}
|
|
14712
|
-
});
|
|
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");
|
|
14714
|
-
} else if (choice === "Compaction Provider") {
|
|
14715
|
-
await selectCompactionModel(ctx);
|
|
14995
|
+
if (choice === "Compaction Provider") {
|
|
14996
|
+
await selectCompactionProvider(ctx);
|
|
14716
14997
|
} else if (choice === "Compaction Model") {
|
|
14717
|
-
await
|
|
14718
|
-
} else if (choice === "Custom Compaction Enabled") {
|
|
14719
|
-
const enabled = await chooseBool(ctx, "Custom compaction enabled?");
|
|
14720
|
-
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.context.customCompactionEnabled = enabled; }); ctx.ui.notify(`Custom compaction set to ${enabled ? "enabled" : "disabled"} in ${r.file}. Custom model routing uses the session compaction hook when configured; Pi default fallback remains enabled.`, "info"); }
|
|
14998
|
+
await selectCompactionModel(ctx);
|
|
14721
14999
|
} else if (choice === "Workflow Auto Trigger Enabled") {
|
|
14722
|
-
const
|
|
14723
|
-
if (
|
|
15000
|
+
const trigger = await ctx.ui.select("Workflow Auto Trigger Enabled", ["Pi default", "Enabled", "Disabled", "Back"]);
|
|
15001
|
+
if (!trigger || trigger === "Back") continue;
|
|
15002
|
+
const r = updateSettings(ctx.cwd, undefined, (s) => {
|
|
15003
|
+
if (trigger === "Pi default") delete s.context.autoCompactionEnabled;
|
|
15004
|
+
else s.context.autoCompactionEnabled = trigger === "Enabled";
|
|
15005
|
+
});
|
|
15006
|
+
workflowUiNotify(ctx, `Workflow auto trigger set to ${trigger.toLowerCase()} in ${r.file}.`, "info");
|
|
14724
15007
|
} else if (choice === "Workflow Trigger Percent") {
|
|
14725
|
-
const
|
|
14726
|
-
|
|
14727
|
-
if (
|
|
15008
|
+
const mode = await ctx.ui.select("Workflow Trigger Percent", ["Pi default", "Custom percent", "Back"]);
|
|
15009
|
+
if (!mode || mode === "Back") continue;
|
|
15010
|
+
if (mode === "Pi default") {
|
|
14728
15011
|
const r = updateSettings(ctx.cwd, undefined, (s) => { delete s.context.compactionTriggerPercent; });
|
|
14729
|
-
ctx
|
|
15012
|
+
workflowUiNotify(ctx, `Workflow compaction trigger percent override removed in ${r.file}; Pi native trigger formula remains in control.`, "info");
|
|
14730
15013
|
} else {
|
|
15014
|
+
const raw = String((await ctx.ui.input("Workflow compaction trigger percent (50-95)", String(compactionTriggerPercentOverride(loadWorkflowSettings(ctx.cwd)) ?? 85))) ?? "").trim();
|
|
14731
15015
|
const count = Number(raw);
|
|
14732
|
-
if (Number.isInteger(count) && count >= 50 && count <= 95) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.context.compactionTriggerPercent = count; }); ctx
|
|
14733
|
-
else ctx
|
|
15016
|
+
if (Number.isInteger(count) && count >= 50 && count <= 95) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.context.compactionTriggerPercent = count; }); workflowUiNotify(ctx, `Workflow compaction trigger percent set to ${count}% in ${r.file}`, "info"); }
|
|
15017
|
+
else workflowUiNotify(ctx, "Trigger percent must be an integer from 50 to 95.", "error");
|
|
14734
15018
|
}
|
|
14735
15019
|
} else if (choice === "Workflow Trigger Cooldown") {
|
|
14736
|
-
const
|
|
14737
|
-
if (
|
|
14738
|
-
|
|
15020
|
+
const mode = await ctx.ui.select("Workflow Trigger Cooldown", ["Pi default", "Custom cooldown", "Back"]);
|
|
15021
|
+
if (!mode || mode === "Back") continue;
|
|
15022
|
+
if (mode === "Pi default") {
|
|
15023
|
+
const r = updateSettings(ctx.cwd, undefined, (s) => { s.context.compactionCooldownMinutes = 5; });
|
|
15024
|
+
workflowUiNotify(ctx, `Compaction cooldown reset to Pi default (5 minutes) in ${r.file}.`, "info");
|
|
15025
|
+
} else {
|
|
15026
|
+
const count = Number((await ctx.ui.input("Minimum minutes between Workflow Suite proactive compaction attempts", String(compactionCooldownMinutes(loadWorkflowSettings(ctx.cwd)))) ?? ""));
|
|
15027
|
+
if (Number.isInteger(count) && count >= 0 && count <= 240) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.context.compactionCooldownMinutes = count; }); workflowUiNotify(ctx, `Compaction cooldown set to ${count} minute(s) in ${r.file}. This is the minimum wait between proactive compaction attempts, not a delay before compaction starts.`, "info"); }
|
|
15028
|
+
else workflowUiNotify(ctx, "Cooldown must be an integer from 0 to 240 minutes.", "error");
|
|
15029
|
+
}
|
|
14739
15030
|
} else if (choice === "Custom Reserve Tokens") {
|
|
14740
|
-
const
|
|
14741
|
-
|
|
14742
|
-
if (
|
|
14743
|
-
|
|
14744
|
-
|
|
15031
|
+
const mode = await ctx.ui.select("Custom Reserve Tokens", ["Pi default", "Custom reserve tokens", "Back"]);
|
|
15032
|
+
if (!mode || mode === "Back") continue;
|
|
15033
|
+
if (mode === "Pi default") {
|
|
15034
|
+
const r = updateSettings(ctx.cwd, undefined, (s) => { s.context.customCompactionReserveTokens = DEFAULT_PI_COMPACTION_RESERVE_TOKENS; });
|
|
15035
|
+
workflowUiNotify(ctx, `Custom compaction reserve tokens reset to Pi default (${DEFAULT_PI_COMPACTION_RESERVE_TOKENS.toLocaleString()}) in ${r.file}`, "info");
|
|
15036
|
+
} else {
|
|
15037
|
+
const raw = String((await ctx.ui.input("Custom compaction reserve tokens (4096-65536)", String(customCompactionReserveTokens(loadWorkflowSettings(ctx.cwd)))) ?? "")).trim();
|
|
15038
|
+
const count = Number(raw);
|
|
15039
|
+
if (Number.isInteger(count) && count >= 4096 && count <= 65536) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.context.customCompactionReserveTokens = count; }); workflowUiNotify(ctx, `Custom compaction reserve tokens set to ${count.toLocaleString()} in ${r.file}`, "info"); }
|
|
15040
|
+
else workflowUiNotify(ctx, "Reserve tokens must be an integer from 4096 to 65536.", "error");
|
|
15041
|
+
}
|
|
14745
15042
|
} else if (choice === "Custom Keep Recent Tokens") {
|
|
14746
|
-
const
|
|
14747
|
-
|
|
14748
|
-
if (
|
|
14749
|
-
|
|
14750
|
-
|
|
15043
|
+
const mode = await ctx.ui.select("Custom Keep Recent Tokens", ["Pi default", "Custom keep-recent tokens", "Back"]);
|
|
15044
|
+
if (!mode || mode === "Back") continue;
|
|
15045
|
+
if (mode === "Pi default") {
|
|
15046
|
+
const r = updateSettings(ctx.cwd, undefined, (s) => { s.context.customCompactionKeepRecentTokens = DEFAULT_PI_COMPACTION_KEEP_RECENT_TOKENS; });
|
|
15047
|
+
workflowUiNotify(ctx, `Custom compaction keep-recent tokens reset to Pi default (${DEFAULT_PI_COMPACTION_KEEP_RECENT_TOKENS.toLocaleString()}) in ${r.file}`, "info");
|
|
15048
|
+
} else {
|
|
15049
|
+
const raw = String((await ctx.ui.input("Custom compaction keep-recent tokens (1000-200000)", String(customCompactionKeepRecentTokens(loadWorkflowSettings(ctx.cwd)))) ?? "")).trim();
|
|
15050
|
+
const count = Number(raw);
|
|
15051
|
+
if (Number.isInteger(count) && count >= 1000 && count <= 200000) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.context.customCompactionKeepRecentTokens = count; }); workflowUiNotify(ctx, `Custom compaction keep-recent tokens set to ${count.toLocaleString()} in ${r.file}`, "info"); }
|
|
15052
|
+
else workflowUiNotify(ctx, "Keep-recent tokens must be an integer from 1000 to 200000.", "error");
|
|
15053
|
+
}
|
|
14751
15054
|
} else if (choice === "List Current Settings") {
|
|
14752
15055
|
const s = loadWorkflowSettings(ctx.cwd);
|
|
14753
|
-
show(pi, `# Shared Compaction\n\
|
|
15056
|
+
show(pi, `# Shared Compaction\n\nProvider: ${s.context.compactionModelProvider || "Pi default"}\nModel: ${s.context.compactionModel || "Pi default"}\nWorkflow Auto Trigger: ${workflowAutoTriggerLabel(s)}\nTrigger: ${formatSharedCompactionTrigger(s, ctx)}\nCooldown: ${compactionCooldownLabel(s)}\nReserve Tokens: ${compactionReserveTokensLabel(s)}\nKeep Recent Tokens: ${compactionKeepRecentTokensLabel(s)}`);
|
|
14754
15057
|
}
|
|
14755
15058
|
}
|
|
14756
15059
|
}
|
|
@@ -14797,7 +15100,7 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
14797
15100
|
}
|
|
14798
15101
|
});
|
|
14799
15102
|
await reapplyStandardRouteIfStandardMode(ctx, true);
|
|
14800
|
-
ctx
|
|
15103
|
+
workflowUiNotify(ctx, `Standard model source set to ${source} in ${result.file}`, "info");
|
|
14801
15104
|
} else if (choice === "Standard Model Role") {
|
|
14802
15105
|
const role = parseStandardModelRole((await ctx.ui.select("Standard model role", ["Current Pi model", "Planner", "Executor", "Reviewer", "Validator"])) ?? "");
|
|
14803
15106
|
if (!role) continue;
|
|
@@ -14811,7 +15114,7 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
14811
15114
|
}
|
|
14812
15115
|
});
|
|
14813
15116
|
await reapplyStandardRouteIfStandardMode(ctx, true);
|
|
14814
|
-
ctx
|
|
15117
|
+
workflowUiNotify(ctx, `Standard model role set to ${workflowRoleLabel(role)} in ${result.file}`, "info");
|
|
14815
15118
|
} else if (choice === "Configure Standard Planner") await configureStandardRoleModel(ctx, "planner");
|
|
14816
15119
|
else if (choice === "Configure Standard Executor") await configureStandardRoleModel(ctx, "executor");
|
|
14817
15120
|
else if (choice === "Configure Standard Reviewer") await configureStandardRoleModel(ctx, "reviewer");
|
|
@@ -14832,10 +15135,10 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
14832
15135
|
const options = key === "maxValidationRetriesPerPlan" ? ["0", "1", "2", "3", "4", "5", "10"] : ["0", "1", "2", "4", "8", "12", "20", "50", "100"];
|
|
14833
15136
|
const raw = await ctx.ui.select(setting, options);
|
|
14834
15137
|
const count = raw === undefined ? undefined : Number(raw);
|
|
14835
|
-
if (Number.isInteger(count) && count >= 0 && count <= max) { const r = updateSettings(ctx.cwd, undefined, (s) => { (s.workflow as typeof s.workflow & Record<string, number>)[key] = count; }); ctx
|
|
15138
|
+
if (Number.isInteger(count) && count >= 0 && count <= max) { const r = updateSettings(ctx.cwd, undefined, (s) => { (s.workflow as typeof s.workflow & Record<string, number>)[key] = count; }); workflowUiNotify(ctx, `workflow.${key} set to ${count} in ${r.file}`, "info"); }
|
|
14836
15139
|
} else if (setting === "Validation Retry Mode") {
|
|
14837
15140
|
const mode = parseValidationRetryMode((await ctx.ui.select("Validation retry mode", ["off", "safe_only", "aggressive_within_scope"])) ?? "");
|
|
14838
|
-
if (mode) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.workflow.validationRetryMode = mode; }); ctx
|
|
15141
|
+
if (mode) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.workflow.validationRetryMode = mode; }); workflowUiNotify(ctx, `workflow.validationRetryMode set to ${mode} in ${r.file}`, "info"); }
|
|
14839
15142
|
} else {
|
|
14840
15143
|
const keyMap: Record<string, keyof ReturnType<typeof loadWorkflowSettings>["workflow"]> = {
|
|
14841
15144
|
"Auto Repair Validation Failures": "autoRepairValidationFailures",
|
|
@@ -14845,7 +15148,7 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
14845
15148
|
};
|
|
14846
15149
|
const key = keyMap[setting];
|
|
14847
15150
|
const enabled = await chooseBool(ctx, `${String(key)}?`);
|
|
14848
|
-
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { (s.workflow as Record<string, unknown>)[String(key)] = enabled; }); ctx
|
|
15151
|
+
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { (s.workflow as Record<string, unknown>)[String(key)] = enabled; }); workflowUiNotify(ctx, `workflow.${String(key)} set to ${enabled} in ${r.file}`, "info"); }
|
|
14849
15152
|
}
|
|
14850
15153
|
}
|
|
14851
15154
|
}
|
|
@@ -14859,26 +15162,26 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
14859
15162
|
await showModelSettingsMenu(ctx);
|
|
14860
15163
|
} else if (choice === "Planning Depth") {
|
|
14861
15164
|
const depth = parsePlanningDepth((await ctx.ui.select("Planning depth", ["fast", "standard", "deep", "maximum"])) ?? "");
|
|
14862
|
-
if (depth) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.planning.depth = depth; }); ctx
|
|
15165
|
+
if (depth) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.planning.depth = depth; }); workflowUiNotify(ctx, `planning.depth set to ${depth} in ${r.file}`, "info"); }
|
|
14863
15166
|
} else if (choice === "Plan Clarification") {
|
|
14864
15167
|
const setting = await ctx.ui.select("Plan Clarification", ["Clarification Mode", "Interactive Clarification", "Max Clarification Questions", "Timing", "Quality Gate", "Allow Without Analysis", "Use Sub-agents Before Clarification", "Back"]);
|
|
14865
15168
|
if (!setting || setting === "Back") continue;
|
|
14866
15169
|
if (setting === "Clarification Mode") {
|
|
14867
15170
|
const mode = parseClarificationMode((await ctx.ui.select("Plan clarification mode", ["auto", "always_for_nontrivial", "never"])) ?? "");
|
|
14868
|
-
if (mode) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.planning.clarificationMode = mode; }); ctx
|
|
15171
|
+
if (mode) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.planning.clarificationMode = mode; }); workflowUiNotify(ctx, `planning.clarificationMode set to ${mode} in ${r.file}`, "info"); }
|
|
14869
15172
|
} else if (setting === "Interactive Clarification") {
|
|
14870
15173
|
const enabled = await chooseBool(ctx, "Interactive clarification enabled?");
|
|
14871
|
-
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.planning.interactiveClarificationEnabled = enabled; }); ctx
|
|
15174
|
+
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.planning.interactiveClarificationEnabled = enabled; }); workflowUiNotify(ctx, `planning.interactiveClarificationEnabled set to ${enabled} in ${r.file}`, "info"); }
|
|
14872
15175
|
} else if (setting === "Max Clarification Questions") {
|
|
14873
15176
|
const count = parsePositiveInt((await ctx.ui.select("Max clarification questions", ["1", "2", "3", "4", "5"])) ?? "");
|
|
14874
|
-
if (count) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.planning.maxClarificationQuestions = count; }); ctx
|
|
15177
|
+
if (count) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.planning.maxClarificationQuestions = count; }); workflowUiNotify(ctx, `planning.maxClarificationQuestions set to ${count} in ${r.file}`, "info"); }
|
|
14875
15178
|
} else if (setting === "Timing") {
|
|
14876
15179
|
const timing = parseClarificationTiming((await ctx.ui.select("Plan clarification timing", ["after_initial_analysis", "immediate"])) ?? "");
|
|
14877
|
-
if (timing) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.planning.clarificationTiming = timing; }); ctx
|
|
15180
|
+
if (timing) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.planning.clarificationTiming = timing; }); workflowUiNotify(ctx, `planning.clarificationTiming set to ${timing} in ${r.file}`, "info"); }
|
|
14878
15181
|
} else {
|
|
14879
15182
|
const key = setting === "Quality Gate" ? "clarificationQualityGate" : setting === "Allow Without Analysis" ? "allowClarificationWithoutAnalysis" : "useSubagentsBeforeClarification";
|
|
14880
15183
|
const enabled = await chooseBool(ctx, `planning.${key}?`);
|
|
14881
|
-
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { (s.planning as typeof s.planning & Record<string, boolean | string | number | undefined>)[key] = enabled; }); ctx
|
|
15184
|
+
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { (s.planning as typeof s.planning & Record<string, boolean | string | number | undefined>)[key] = enabled; }); workflowUiNotify(ctx, `planning.${key} set to ${enabled} in ${r.file}`, "info"); }
|
|
14882
15185
|
}
|
|
14883
15186
|
} else if (choice === "Plan Sub-agents / Workers") {
|
|
14884
15187
|
await showPlanSubagentWorkerSettingsMenu(ctx);
|
|
@@ -14887,16 +15190,16 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
14887
15190
|
if (!setting || setting === "Back") continue;
|
|
14888
15191
|
const enabled = await chooseBool(ctx, `${setting}?`);
|
|
14889
15192
|
if (enabled === undefined) continue;
|
|
14890
|
-
if (setting === "Reviewer Enabled") { const r = setRoleEnabled("reviewer", enabled, ctx.cwd); ctx
|
|
14891
|
-
else if (setting === "Validator Enabled") { const r = setRoleEnabled("validator", enabled, ctx.cwd); ctx
|
|
14892
|
-
else if (setting === "Auto Run Reviewer") { const r = updateSettings(ctx.cwd, undefined, (s) => { s.workflow.autoRunReviewerBeforeExecute = enabled; }); ctx
|
|
14893
|
-
else if (setting === "Auto Run Validation") { const r = updateSettings(ctx.cwd, undefined, (s) => { s.workflow.autoRunValidationAfterExecute = enabled; }); ctx
|
|
14894
|
-
else if (setting === "Auto Repair Review Failures") { const r = updateSettings(ctx.cwd, undefined, (s) => { s.workflow.autoRepairReviewFailures = enabled; }); ctx
|
|
14895
|
-
else if (setting === "Pause After Review Failure") { const r = updateSettings(ctx.cwd, undefined, (s) => { s.workflow.pauseAfterReviewFailure = enabled; }); ctx
|
|
14896
|
-
else if (setting === "Approval Before Execution") { const r = updateSettings(ctx.cwd, undefined, (s) => { s.workflow.requireApprovalBeforeExecution = enabled; s.workflow.requirePlanApprovalBeforeExecute = enabled; }); ctx
|
|
14897
|
-
else if (setting === "Approval Per Step") { const r = updateSettings(ctx.cwd, undefined, (s) => { s.workflow.requireApprovalPerStep = enabled; }); ctx
|
|
14898
|
-
else if (setting === "Validate After Each Step") { const r = updateSettings(ctx.cwd, undefined, (s) => { s.workflow.validateAfterEachStep = enabled; }); ctx
|
|
14899
|
-
else if (setting === "Validate After Full Execution") { const r = updateSettings(ctx.cwd, undefined, (s) => { s.workflow.validateAfterExecution = enabled; s.workflow.autoRunValidationAfterExecute = enabled; }); ctx
|
|
15193
|
+
if (setting === "Reviewer Enabled") { const r = setRoleEnabled("reviewer", enabled, ctx.cwd); workflowUiNotify(ctx, `reviewer.enabled set to ${enabled} in ${r.file}`, "info"); }
|
|
15194
|
+
else if (setting === "Validator Enabled") { const r = setRoleEnabled("validator", enabled, ctx.cwd); workflowUiNotify(ctx, `validator.enabled set to ${enabled} in ${r.file}`, "info"); }
|
|
15195
|
+
else if (setting === "Auto Run Reviewer") { const r = updateSettings(ctx.cwd, undefined, (s) => { s.workflow.autoRunReviewerBeforeExecute = enabled; }); workflowUiNotify(ctx, `workflow.autoRunReviewerBeforeExecute set to ${enabled} in ${r.file}`, "info"); }
|
|
15196
|
+
else if (setting === "Auto Run Validation") { const r = updateSettings(ctx.cwd, undefined, (s) => { s.workflow.autoRunValidationAfterExecute = enabled; }); workflowUiNotify(ctx, `workflow.autoRunValidationAfterExecute set to ${enabled} in ${r.file}`, "info"); }
|
|
15197
|
+
else if (setting === "Auto Repair Review Failures") { const r = updateSettings(ctx.cwd, undefined, (s) => { s.workflow.autoRepairReviewFailures = enabled; }); workflowUiNotify(ctx, `workflow.autoRepairReviewFailures set to ${enabled} in ${r.file}`, "info"); }
|
|
15198
|
+
else if (setting === "Pause After Review Failure") { const r = updateSettings(ctx.cwd, undefined, (s) => { s.workflow.pauseAfterReviewFailure = enabled; }); workflowUiNotify(ctx, `workflow.pauseAfterReviewFailure set to ${enabled} in ${r.file}`, "info"); }
|
|
15199
|
+
else if (setting === "Approval Before Execution") { const r = updateSettings(ctx.cwd, undefined, (s) => { s.workflow.requireApprovalBeforeExecution = enabled; s.workflow.requirePlanApprovalBeforeExecute = enabled; }); workflowUiNotify(ctx, `workflow.requireApprovalBeforeExecution set to ${enabled} in ${r.file}`, "info"); }
|
|
15200
|
+
else if (setting === "Approval Per Step") { const r = updateSettings(ctx.cwd, undefined, (s) => { s.workflow.requireApprovalPerStep = enabled; }); workflowUiNotify(ctx, `workflow.requireApprovalPerStep set to ${enabled} in ${r.file}`, "info"); }
|
|
15201
|
+
else if (setting === "Validate After Each Step") { const r = updateSettings(ctx.cwd, undefined, (s) => { s.workflow.validateAfterEachStep = enabled; }); workflowUiNotify(ctx, `workflow.validateAfterEachStep set to ${enabled} in ${r.file}`, "info"); }
|
|
15202
|
+
else if (setting === "Validate After Full Execution") { const r = updateSettings(ctx.cwd, undefined, (s) => { s.workflow.validateAfterExecution = enabled; s.workflow.autoRunValidationAfterExecute = enabled; }); workflowUiNotify(ctx, `workflow.validateAfterExecution set to ${enabled} in ${r.file}`, "info"); }
|
|
14900
15203
|
} else if (choice === "Repair / Validation Retry") {
|
|
14901
15204
|
await showWorkflowRepairRetrySettingsMenu(ctx);
|
|
14902
15205
|
} else if (choice === "Plan Progress / Runtime") {
|
|
@@ -14912,28 +15215,28 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
14912
15215
|
const choice = await ctx.ui.select("Plan Token Budget", ["Default (unlimited)", "Custom..."]);
|
|
14913
15216
|
if (choice === "Default (unlimited)") {
|
|
14914
15217
|
const r = updateSettings(ctx.cwd, undefined, (s) => { s.planning.maxTokens = 0; });
|
|
14915
|
-
ctx
|
|
15218
|
+
workflowUiNotify(ctx, `planning.maxTokens set to default (unlimited) in ${r.file}`, "info");
|
|
14916
15219
|
} else if (choice === "Custom...") {
|
|
14917
15220
|
const count = parsePositiveInt((await ctx.ui.input("Enter custom plan token budget", String(current > 0 ? current : ""))) ?? "");
|
|
14918
|
-
if (count !== undefined && count >= 0) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.planning.maxTokens = count; }); ctx
|
|
15221
|
+
if (count !== undefined && count >= 0) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.planning.maxTokens = count; }); workflowUiNotify(ctx, `planning.maxTokens set to ${count === 0 ? "unlimited" : count.toLocaleString()} in ${r.file}`, "info"); }
|
|
14919
15222
|
}
|
|
14920
15223
|
} else if (setting === "Runtime Budget") {
|
|
14921
15224
|
const current = loadWorkflowSettings(ctx.cwd).planning.maxRuntimeHours ?? 0;
|
|
14922
15225
|
const choice = await ctx.ui.select("Plan Runtime Budget", ["Default (unlimited)", "Custom..."]);
|
|
14923
15226
|
if (choice === "Default (unlimited)") {
|
|
14924
15227
|
const r = updateSettings(ctx.cwd, undefined, (s) => { s.planning.maxRuntimeHours = 0; });
|
|
14925
|
-
ctx
|
|
15228
|
+
workflowUiNotify(ctx, `planning.maxRuntimeHours set to default (unlimited) in ${r.file}`, "info");
|
|
14926
15229
|
} else if (choice === "Custom...") {
|
|
14927
15230
|
const count = parsePositiveInt((await ctx.ui.input("Enter custom plan runtime budget (hours)", String(current > 0 ? current : ""))) ?? "");
|
|
14928
|
-
if (count !== undefined && count > 0) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.planning.maxRuntimeHours = count; }); ctx
|
|
15231
|
+
if (count !== undefined && count > 0) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.planning.maxRuntimeHours = count; }); workflowUiNotify(ctx, `planning.maxRuntimeHours set to ${count} hours in ${r.file}`, "info"); }
|
|
14929
15232
|
}
|
|
14930
15233
|
} else if (setting === "Progress Bar Display") {
|
|
14931
15234
|
const enabled = await chooseBool(ctx, "workflow.planShowProgressBar?");
|
|
14932
|
-
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.workflow.planShowProgressBar = enabled; }); ctx
|
|
15235
|
+
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.workflow.planShowProgressBar = enabled; }); workflowUiNotify(ctx, `workflow.planShowProgressBar set to ${enabled} in ${r.file}`, "info"); }
|
|
14933
15236
|
} else {
|
|
14934
15237
|
const key = setting === "Progress Tracking" ? "planProgressEnabled" : "planRuntimeEnabled";
|
|
14935
15238
|
const enabled = await chooseBool(ctx, `workflow.${key}?`);
|
|
14936
|
-
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { (s.workflow as typeof s.workflow & Record<string, boolean>)[key] = enabled; }); ctx
|
|
15239
|
+
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { (s.workflow as typeof s.workflow & Record<string, boolean>)[key] = enabled; }); workflowUiNotify(ctx, `workflow.${key} set to ${enabled} in ${r.file}`, "info"); }
|
|
14937
15240
|
}
|
|
14938
15241
|
} else if (choice === "Plan History") {
|
|
14939
15242
|
const setting = await ctx.ui.select("Plan History", ["Save Plans", "Save Plan History", "Plan History Limit", "Back"]);
|
|
@@ -14941,11 +15244,11 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
14941
15244
|
if (!setting || setting === "Back") continue;
|
|
14942
15245
|
if (setting === "Plan History Limit") {
|
|
14943
15246
|
const count = parsePositiveInt((await ctx.ui.input("Plan history limit", String(workflow.planHistoryLimit ?? 50))) ?? "");
|
|
14944
|
-
if (count !== undefined && count > 0) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.workflow.planHistoryLimit = count; }); ctx
|
|
15247
|
+
if (count !== undefined && count > 0) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.workflow.planHistoryLimit = count; }); workflowUiNotify(ctx, `workflow.planHistoryLimit set to ${count} in ${r.file}`, "info"); }
|
|
14945
15248
|
} else {
|
|
14946
15249
|
const key = setting === "Save Plans" ? "savePlans" : "savePlanHistory";
|
|
14947
15250
|
const enabled = await chooseBool(ctx, `${key}?`);
|
|
14948
|
-
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { (s.workflow as typeof s.workflow & Record<string, boolean>)[key] = enabled; }); ctx
|
|
15251
|
+
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { (s.workflow as typeof s.workflow & Record<string, boolean>)[key] = enabled; }); workflowUiNotify(ctx, `workflow.${key} set to ${enabled} in ${r.file}`, "info"); }
|
|
14949
15252
|
}
|
|
14950
15253
|
} else if (choice === "List Current Settings") {
|
|
14951
15254
|
const s = loadWorkflowSettings(ctx.cwd);
|
|
@@ -14961,11 +15264,11 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
14961
15264
|
if (!setting || setting === "Back") return;
|
|
14962
15265
|
if (setting === "To Do Trigger Mode") {
|
|
14963
15266
|
const mode = parseStandardTodoTriggerMode((await ctx.ui.select("To Do Trigger Mode", ["Disabled", "On request", "Automatic when useful", "Required"])) ?? "");
|
|
14964
|
-
if (mode) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.standard.todoTriggerMode = mode; s.standard.autoTodoEnabled = mode !== "off"; }); ctx
|
|
15267
|
+
if (mode) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.standard.todoTriggerMode = mode; s.standard.autoTodoEnabled = mode !== "off"; }); workflowUiNotify(ctx, `To Do Trigger Mode set to ${standardTodoTriggerModeLabel(mode)} in ${r.file}`, "info"); }
|
|
14965
15268
|
} else {
|
|
14966
15269
|
const key = setting === "Automatic To Do Enabled" ? "autoTodoEnabled" : "todoProgressVisible";
|
|
14967
15270
|
const enabled = await chooseBool(ctx, `standard.${key}?`);
|
|
14968
|
-
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { (s.standard as typeof s.standard & Record<string, boolean>)[key] = enabled; }); ctx
|
|
15271
|
+
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { (s.standard as typeof s.standard & Record<string, boolean>)[key] = enabled; }); workflowUiNotify(ctx, `standard.${key} set to ${enabled} in ${r.file}`, "info"); }
|
|
14969
15272
|
}
|
|
14970
15273
|
}
|
|
14971
15274
|
}
|
|
@@ -14977,20 +15280,20 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
14977
15280
|
if (!setting || setting === "Back") return;
|
|
14978
15281
|
if (setting === "Clarification Mode") {
|
|
14979
15282
|
const mode = parseStandardClarificationMode((await ctx.ui.select("Standard clarification mode", ["auto", "always_for_nontrivial", "never"])) ?? "");
|
|
14980
|
-
if (mode) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.standard.clarificationMode = mode; s.standard.clarificationEnabled = mode !== "never"; }); ctx
|
|
15283
|
+
if (mode) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.standard.clarificationMode = mode; s.standard.clarificationEnabled = mode !== "never"; }); workflowUiNotify(ctx, `standard.clarificationMode set to ${mode} in ${r.file}`, "info"); }
|
|
14981
15284
|
} else if (setting === "Interactive Clarification") {
|
|
14982
15285
|
const enabled = await chooseBool(ctx, "Standard interactive clarification enabled?");
|
|
14983
|
-
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.standard.interactiveClarificationEnabled = enabled; }); ctx
|
|
15286
|
+
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.standard.interactiveClarificationEnabled = enabled; }); workflowUiNotify(ctx, `standard.interactiveClarificationEnabled set to ${enabled} in ${r.file}`, "info"); }
|
|
14984
15287
|
} else if (setting === "Max Clarification Questions") {
|
|
14985
15288
|
const count = parsePositiveInt((await ctx.ui.select("Max Standard clarification questions", ["0", "1", "2"])) ?? "");
|
|
14986
|
-
if (count !== undefined && count >= 0) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.standard.maxClarificationQuestions = count; }); ctx
|
|
15289
|
+
if (count !== undefined && count >= 0) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.standard.maxClarificationQuestions = count; }); workflowUiNotify(ctx, `standard.maxClarificationQuestions set to ${count} in ${r.file}`, "info"); }
|
|
14987
15290
|
} else if (setting === "Timing") {
|
|
14988
15291
|
const timing = parseClarificationTiming((await ctx.ui.select("Standard clarification timing", ["after_initial_analysis", "immediate"])) ?? "");
|
|
14989
|
-
if (timing) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.standard.clarificationTiming = timing; }); ctx
|
|
15292
|
+
if (timing) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.standard.clarificationTiming = timing; }); workflowUiNotify(ctx, `standard.clarificationTiming set to ${timing} in ${r.file}`, "info"); }
|
|
14990
15293
|
} else {
|
|
14991
15294
|
const key = setting === "Quality Gate" ? "clarificationQualityGate" : setting === "Allow Without Analysis" ? "allowClarificationWithoutAnalysis" : "useSubagentsBeforeClarification";
|
|
14992
15295
|
const enabled = await chooseBool(ctx, `standard.${key}?`);
|
|
14993
|
-
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { (s.standard as typeof s.standard & Record<string, boolean | string | number | undefined>)[key] = enabled; }); ctx
|
|
15296
|
+
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { (s.standard as typeof s.standard & Record<string, boolean | string | number | undefined>)[key] = enabled; }); workflowUiNotify(ctx, `standard.${key} set to ${enabled} in ${r.file}`, "info"); }
|
|
14994
15297
|
}
|
|
14995
15298
|
}
|
|
14996
15299
|
}
|
|
@@ -15010,15 +15313,15 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
15010
15313
|
const choice = await ctx.ui.select("Standard Token Budget", ["Default (unlimited)", "Custom..."]);
|
|
15011
15314
|
if (choice === "Default (unlimited)") {
|
|
15012
15315
|
const r = updateSettings(ctx.cwd, undefined, (s) => { s.standard.maxTokens = 0; });
|
|
15013
|
-
ctx
|
|
15316
|
+
workflowUiNotify(ctx, `standard.maxTokens set to default (unlimited) in ${r.file}`, "info");
|
|
15014
15317
|
} else if (choice === "Custom...") {
|
|
15015
15318
|
const count = parsePositiveInt((await ctx.ui.input("Enter custom standard token budget", String(current > 0 ? current : ""))) ?? "");
|
|
15016
|
-
if (count !== undefined && count >= 0) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.standard.maxTokens = count; }); ctx
|
|
15319
|
+
if (count !== undefined && count >= 0) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.standard.maxTokens = count; }); workflowUiNotify(ctx, `standard.maxTokens set to ${count === 0 ? "unlimited" : count.toLocaleString()} in ${r.file}`, "info"); }
|
|
15017
15320
|
}
|
|
15018
15321
|
} else {
|
|
15019
15322
|
const key = setting === "Status Widget Visible" ? "statusWidgetVisible" : "todoProgressVisible";
|
|
15020
15323
|
const enabled = await chooseBool(ctx, `standard.${key}?`);
|
|
15021
|
-
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { (s.standard as typeof s.standard & Record<string, boolean>)[key] = enabled; }); ctx
|
|
15324
|
+
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { (s.standard as typeof s.standard & Record<string, boolean>)[key] = enabled; }); workflowUiNotify(ctx, `standard.${key} set to ${enabled} in ${r.file}`, "info"); }
|
|
15022
15325
|
}
|
|
15023
15326
|
}
|
|
15024
15327
|
}
|
|
@@ -15035,7 +15338,7 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
15035
15338
|
}
|
|
15036
15339
|
if (choice === "Enable / Disable Standard Mode") {
|
|
15037
15340
|
const enabled = await chooseBool(ctx, "standard.enabled?");
|
|
15038
|
-
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.standard.enabled = enabled; }); ctx
|
|
15341
|
+
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.standard.enabled = enabled; }); workflowUiNotify(ctx, `standard.enabled set to ${enabled} in ${r.file}`, "info"); }
|
|
15039
15342
|
} else if (choice === "Standard To Do" || choice === "To Do Behavior") {
|
|
15040
15343
|
await showStandardTodoSettingsMenu(ctx);
|
|
15041
15344
|
} else if (choice === "Standard Clarification" || choice === "Clarification") {
|
|
@@ -15064,7 +15367,7 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
15064
15367
|
if (!source) continue;
|
|
15065
15368
|
const enabled = source === "Mission-Specific Models";
|
|
15066
15369
|
const r = updateSettings(ctx.cwd, undefined, (s) => { s.missions.useMissionSpecificModels = enabled; });
|
|
15067
|
-
ctx
|
|
15370
|
+
workflowUiNotify(ctx, `missions.useMissionSpecificModels set to ${enabled} in ${r.file}`, "info");
|
|
15068
15371
|
} else if (choice === "Configure Mission Planner") await configureMissionRoleModel(ctx, "planner");
|
|
15069
15372
|
else if (choice === "Configure Mission Executor") await configureMissionRoleModel(ctx, "executor");
|
|
15070
15373
|
else if (choice === "Configure Mission Reviewer") await configureMissionRoleModel(ctx, "reviewer");
|
|
@@ -15085,13 +15388,13 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
15085
15388
|
show(pi, renderHeartbeatWatchdogStatus(loadWorkflowSettings(ctx.cwd), activeMission ?? loadMissionState()));
|
|
15086
15389
|
} else if (choice === "Enable / Disable Heartbeat") {
|
|
15087
15390
|
const enabled = await chooseBool(ctx, "missions.heartbeatEnabled?");
|
|
15088
|
-
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.missions.heartbeatEnabled = enabled; }); ctx
|
|
15391
|
+
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.missions.heartbeatEnabled = enabled; }); workflowUiNotify(ctx, `missions.heartbeatEnabled set to ${enabled} in ${r.file}`, "info"); }
|
|
15089
15392
|
} else if (choice === "Enable / Disable Watchdog") {
|
|
15090
15393
|
const enabled = await chooseBool(ctx, "missions.watchdogEnabled? (warning only; no auto-recovery)");
|
|
15091
|
-
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.missions.watchdogEnabled = enabled; }); ctx
|
|
15394
|
+
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.missions.watchdogEnabled = enabled; }); workflowUiNotify(ctx, `missions.watchdogEnabled set to ${enabled} in ${r.file}`, "info"); }
|
|
15092
15395
|
} else if (choice === "Set Watchdog Stale Minutes") {
|
|
15093
15396
|
const count = parsePositiveInt((await ctx.ui.input("watchdogStaleMinutes", String(loadWorkflowSettings(ctx.cwd).missions.watchdogStaleMinutes ?? 30))) ?? "");
|
|
15094
|
-
if (count !== undefined && count > 0) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.missions.watchdogStaleMinutes = count; }); ctx
|
|
15397
|
+
if (count !== undefined && count > 0) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.missions.watchdogStaleMinutes = count; }); workflowUiNotify(ctx, `missions.watchdogStaleMinutes set to ${count} in ${r.file}`, "info"); }
|
|
15095
15398
|
}
|
|
15096
15399
|
}
|
|
15097
15400
|
}
|
|
@@ -15104,11 +15407,11 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
15104
15407
|
const enabled = await chooseBool(ctx, `${setting}?`);
|
|
15105
15408
|
if (enabled === undefined) continue;
|
|
15106
15409
|
if (setting === "Mission Reviewer Enabled") {
|
|
15107
|
-
if (loadWorkflowSettings(ctx.cwd).missions.useMissionSpecificModels) { const r = updateSettings(ctx.cwd, undefined, (s) => { setMissionRoleEnabled(s, "reviewer", enabled); }); ctx
|
|
15108
|
-
else { const r = setRoleEnabled("reviewer", enabled, ctx.cwd); ctx
|
|
15410
|
+
if (loadWorkflowSettings(ctx.cwd).missions.useMissionSpecificModels) { const r = updateSettings(ctx.cwd, undefined, (s) => { setMissionRoleEnabled(s, "reviewer", enabled); }); workflowUiNotify(ctx, `missions.models.reviewer.enabled set to ${enabled} in ${r.file}`, "info"); }
|
|
15411
|
+
else { const r = setRoleEnabled("reviewer", enabled, ctx.cwd); workflowUiNotify(ctx, `reviewer.enabled set to ${enabled} in ${r.file}`, "info"); }
|
|
15109
15412
|
} else if (setting === "Mission Validator Enabled") {
|
|
15110
|
-
if (loadWorkflowSettings(ctx.cwd).missions.useMissionSpecificModels) { const r = updateSettings(ctx.cwd, undefined, (s) => { setMissionRoleEnabled(s, "validator", enabled); }); ctx
|
|
15111
|
-
else { const r = setRoleEnabled("validator", enabled, ctx.cwd); ctx
|
|
15413
|
+
if (loadWorkflowSettings(ctx.cwd).missions.useMissionSpecificModels) { const r = updateSettings(ctx.cwd, undefined, (s) => { setMissionRoleEnabled(s, "validator", enabled); }); workflowUiNotify(ctx, `missions.models.validator.enabled set to ${enabled} in ${r.file}`, "info"); }
|
|
15414
|
+
else { const r = setRoleEnabled("validator", enabled, ctx.cwd); workflowUiNotify(ctx, `validator.enabled set to ${enabled} in ${r.file}`, "info"); }
|
|
15112
15415
|
} else {
|
|
15113
15416
|
const keyMap: Record<string, string> = {
|
|
15114
15417
|
"Offer Reviewer Before Approval": "offerReviewerBeforeApprove",
|
|
@@ -15126,7 +15429,7 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
15126
15429
|
s.missions.reviewRetryMode = "safe_only";
|
|
15127
15430
|
}
|
|
15128
15431
|
});
|
|
15129
|
-
ctx
|
|
15432
|
+
workflowUiNotify(ctx, `missions.${key} set to ${enabled} in ${r.file}`, "info");
|
|
15130
15433
|
}
|
|
15131
15434
|
}
|
|
15132
15435
|
}
|
|
@@ -15139,18 +15442,18 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
15139
15442
|
if (setting === "Max Review Retries Per Mission") {
|
|
15140
15443
|
const raw = await ctx.ui.select(setting, ["0", "1", "2", "3", "4", "5", "10"]);
|
|
15141
15444
|
const count = raw === undefined ? undefined : Number(raw);
|
|
15142
|
-
if (Number.isInteger(count) && count >= 0 && count <= 10) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.missions.maxReviewRetriesPerMission = count; }); ctx
|
|
15445
|
+
if (Number.isInteger(count) && count >= 0 && count <= 10) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.missions.maxReviewRetriesPerMission = count; }); workflowUiNotify(ctx, `missions.maxReviewRetriesPerMission set to ${count} in ${r.file}`, "info"); }
|
|
15143
15446
|
} else if (setting === "Max Retries Per Milestone" || setting === "Max Retries Per Mission" || setting === "Max Final Validation Retries") {
|
|
15144
15447
|
const key = setting === "Max Retries Per Milestone" ? "maxValidationRetriesPerMilestone" : setting === "Max Retries Per Mission" ? "maxValidationRetriesPerMission" : "maxFinalValidationRetries";
|
|
15145
15448
|
const max = key === "maxValidationRetriesPerMission" ? 100 : 10;
|
|
15146
15449
|
const options = key === "maxValidationRetriesPerMission" ? ["0", "1", "2", "4", "8", "12", "20", "50", "100"] : ["0", "1", "2", "3", "4", "5", "10"];
|
|
15147
15450
|
const raw = await ctx.ui.select(setting, options);
|
|
15148
15451
|
const count = raw === undefined ? undefined : Number(raw);
|
|
15149
|
-
if (Number.isInteger(count) && count >= 0 && count <= max) { const r = updateSettings(ctx.cwd, undefined, (s) => { (s.missions as typeof s.missions & Record<string, number>)[key] = count; }); ctx
|
|
15452
|
+
if (Number.isInteger(count) && count >= 0 && count <= max) { const r = updateSettings(ctx.cwd, undefined, (s) => { (s.missions as typeof s.missions & Record<string, number>)[key] = count; }); workflowUiNotify(ctx, `missions.${key} set to ${count} in ${r.file}`, "info"); }
|
|
15150
15453
|
} else if (setting === "Validation Retry Mode" || setting === "Review Retry Mode") {
|
|
15151
15454
|
const key = setting === "Validation Retry Mode" ? "validationRetryMode" : "reviewRetryMode";
|
|
15152
15455
|
const mode = parseValidationRetryMode((await ctx.ui.select(`${key}`, ["off", "safe_only", "aggressive_within_scope"])) ?? "");
|
|
15153
|
-
if (mode) { const r = updateSettings(ctx.cwd, undefined, (s) => { (s.missions as typeof s.missions & Record<string, string | undefined>)[key] = mode; }); ctx
|
|
15456
|
+
if (mode) { const r = updateSettings(ctx.cwd, undefined, (s) => { (s.missions as typeof s.missions & Record<string, string | undefined>)[key] = mode; }); workflowUiNotify(ctx, `missions.${key} set to ${mode} in ${r.file}`, "info"); }
|
|
15154
15457
|
} else {
|
|
15155
15458
|
const keyMap: Record<string, string> = {
|
|
15156
15459
|
"Auto Repair Review Failures": "autoRepairReviewFailures",
|
|
@@ -15163,7 +15466,7 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
15163
15466
|
};
|
|
15164
15467
|
const key = keyMap[setting];
|
|
15165
15468
|
const enabled = await chooseBool(ctx, `${String(key)}?`);
|
|
15166
|
-
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { (s.missions as Record<string, unknown>)[String(key)] = enabled; if (key === "autoRepairReviewFailures" && enabled && s.missions.reviewRetryMode === "off") { s.missions.reviewRetryMode = "safe_only"; } }); ctx
|
|
15469
|
+
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { (s.missions as Record<string, unknown>)[String(key)] = enabled; if (key === "autoRepairReviewFailures" && enabled && s.missions.reviewRetryMode === "off") { s.missions.reviewRetryMode = "safe_only"; } }); workflowUiNotify(ctx, `missions.${String(key)} set to ${enabled} in ${r.file}`, "info"); }
|
|
15167
15470
|
}
|
|
15168
15471
|
}
|
|
15169
15472
|
}
|
|
@@ -15176,12 +15479,12 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
15176
15479
|
if (setting === "Max Final Validation Retries") {
|
|
15177
15480
|
const raw = await ctx.ui.select(setting, ["0", "1", "2", "3", "4", "5", "10"]);
|
|
15178
15481
|
const count = raw === undefined ? undefined : Number(raw);
|
|
15179
|
-
if (Number.isInteger(count) && count >= 0 && count <= 10) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.missions.maxFinalValidationRetries = count; }); ctx
|
|
15482
|
+
if (Number.isInteger(count) && count >= 0 && count <= 10) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.missions.maxFinalValidationRetries = count; }); workflowUiNotify(ctx, `missions.maxFinalValidationRetries set to ${count} in ${r.file}`, "info"); }
|
|
15180
15483
|
} else {
|
|
15181
15484
|
const keyMap: Record<string, string> = { "Final Comprehensive Validation": "finalValidationEnabled", "Final Validation Requires Pass": "finalValidationRequiresPass", "Auto Repair Final Validation Failures": "autoRepairFinalValidationFailures" };
|
|
15182
15485
|
const key = keyMap[setting];
|
|
15183
15486
|
const enabled = await chooseBool(ctx, `${String(key)}?`);
|
|
15184
|
-
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { (s.missions as Record<string, unknown>)[String(key)] = enabled; }); ctx
|
|
15487
|
+
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { (s.missions as Record<string, unknown>)[String(key)] = enabled; }); workflowUiNotify(ctx, `missions.${String(key)} set to ${enabled} in ${r.file}`, "info"); }
|
|
15185
15488
|
}
|
|
15186
15489
|
}
|
|
15187
15490
|
}
|
|
@@ -15196,12 +15499,12 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
15196
15499
|
const count = parsePositiveInt((await ctx.ui.input("Mission history limit", String(current))) ?? "");
|
|
15197
15500
|
if (count !== undefined && count >= 1 && count <= 500) {
|
|
15198
15501
|
const r = updateSettings(ctx.cwd, undefined, (s) => { s.missions.missionHistoryLimit = count; });
|
|
15199
|
-
ctx
|
|
15502
|
+
workflowUiNotify(ctx, `missions.missionHistoryLimit set to ${count} in ${r.file}`, "info");
|
|
15200
15503
|
}
|
|
15201
15504
|
} else if (setting === "Cleanup Saved Missions") {
|
|
15202
15505
|
const settings = loadWorkflowSettings(ctx.cwd);
|
|
15203
15506
|
const removed = clearOldMissionStates(settings.missions.missionHistoryLimit ?? 50);
|
|
15204
|
-
ctx
|
|
15507
|
+
workflowUiNotify(ctx, `Removed ${removed} old mission file${removed === 1 ? "" : "s"}.`, "info");
|
|
15205
15508
|
} else if (setting === "List Current Settings") {
|
|
15206
15509
|
const settings = loadWorkflowSettings(ctx.cwd);
|
|
15207
15510
|
show(pi, `# Mission History\n\nMission History Limit: ${settings.missions.missionHistoryLimit ?? 50}\nMissions Directory: ${MISSION_HISTORY_DIR}`);
|
|
@@ -15218,48 +15521,48 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
15218
15521
|
await showMissionModelBehaviorMenu(ctx);
|
|
15219
15522
|
} else if (choice === "Enable / Disable Mission Mode") {
|
|
15220
15523
|
const enabled = await chooseBool(ctx, "Missions enabled?");
|
|
15221
|
-
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.missions.enabled = enabled; }); ctx
|
|
15524
|
+
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.missions.enabled = enabled; }); workflowUiNotify(ctx, `missions.enabled set to ${enabled} in ${r.file}`, "info"); }
|
|
15222
15525
|
} else if (choice === "Mission Autonomy") {
|
|
15223
15526
|
const setting = await ctx.ui.select("Mission Autonomy", ["Default Autonomy", "Allow Full Auto", "Auto Run After Approval", "Continue Across Milestones", "Pause Between Milestones", "Auto Resume", "Back"]);
|
|
15224
15527
|
if (!setting || setting === "Back") continue;
|
|
15225
15528
|
if (setting === "Default Autonomy") {
|
|
15226
15529
|
const autonomy = parseMissionAutonomy((await ctx.ui.select("Mission default autonomy", ["manual", "approval_gated", "supervised_auto", "full_auto"])) ?? "");
|
|
15227
|
-
if (autonomy) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.missions.defaultAutonomy = autonomy; }); ctx
|
|
15530
|
+
if (autonomy) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.missions.defaultAutonomy = autonomy; }); workflowUiNotify(ctx, `missions.defaultAutonomy set to ${autonomy} in ${r.file}${autonomy === "full_auto" && !r.settings.missions.allowFullAuto ? "; full_auto will be blocked until allowFullAuto=true" : ""}`, "info"); }
|
|
15228
15531
|
} else {
|
|
15229
15532
|
const keyMap: Record<string, keyof ReturnType<typeof loadWorkflowSettings>["missions"]> = { "Allow Full Auto": "allowFullAuto", "Auto Run After Approval": "autoRunAfterApproval", "Continue Across Milestones": "continueAcrossMilestones", "Pause Between Milestones": "pauseBetweenMilestones", "Auto Resume": "autoResume" };
|
|
15230
15533
|
const key = keyMap[setting];
|
|
15231
15534
|
const enabled = await chooseBool(ctx, `${String(key)}?`);
|
|
15232
|
-
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { (s.missions as Record<string, unknown>)[String(key)] = enabled; }); ctx
|
|
15535
|
+
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { (s.missions as Record<string, unknown>)[String(key)] = enabled; }); workflowUiNotify(ctx, `missions.${String(key)} set to ${enabled} in ${r.file}${key === "allowFullAuto" && enabled === false && r.settings.missions.defaultAutonomy === "full_auto" ? "; full_auto default is retained but blocked" : ""}`, "info"); }
|
|
15233
15536
|
}
|
|
15234
15537
|
} else if (choice === "Default Autonomy") {
|
|
15235
15538
|
const autonomy = parseMissionAutonomy((await ctx.ui.select("Mission default autonomy", ["manual", "approval_gated", "supervised_auto", "full_auto"])) ?? "");
|
|
15236
|
-
if (autonomy) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.missions.defaultAutonomy = autonomy; }); ctx
|
|
15539
|
+
if (autonomy) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.missions.defaultAutonomy = autonomy; }); workflowUiNotify(ctx, `missions.defaultAutonomy set to ${autonomy} in ${r.file}${autonomy === "full_auto" && !r.settings.missions.allowFullAuto ? "; full_auto will be blocked until allowFullAuto=true" : ""}`, "info"); }
|
|
15237
15540
|
} else if (choice === "Mission Clarification") {
|
|
15238
15541
|
const setting = await ctx.ui.select("Mission Clarification", ["Clarification Mode", "Interactive Clarification", "Max Clarification Questions", "Timing", "Quality Gate", "Allow Without Analysis", "Use Sub-agents Before Clarification", "Back"]);
|
|
15239
15542
|
if (!setting || setting === "Back") continue;
|
|
15240
15543
|
if (setting === "Clarification Mode") {
|
|
15241
15544
|
const mode = parseClarificationMode((await ctx.ui.select("Mission clarification mode", ["auto", "always_for_nontrivial", "never"])) ?? "");
|
|
15242
|
-
if (mode) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.missions.clarificationMode = mode; }); ctx
|
|
15545
|
+
if (mode) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.missions.clarificationMode = mode; }); workflowUiNotify(ctx, `missions.clarificationMode set to ${mode} in ${r.file}`, "info"); }
|
|
15243
15546
|
} else if (setting === "Interactive Clarification") {
|
|
15244
15547
|
const enabled = await chooseBool(ctx, "Mission interactive clarification enabled?");
|
|
15245
|
-
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.missions.interactiveClarificationEnabled = enabled; }); ctx
|
|
15548
|
+
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.missions.interactiveClarificationEnabled = enabled; }); workflowUiNotify(ctx, `missions.interactiveClarificationEnabled set to ${enabled} in ${r.file}`, "info"); }
|
|
15246
15549
|
} else if (setting === "Max Clarification Questions") {
|
|
15247
15550
|
const count = parsePositiveInt((await ctx.ui.select("Mission max clarification questions", ["1", "2", "3", "4", "5", "6"])) ?? "");
|
|
15248
|
-
if (count) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.missions.maxClarificationQuestions = count; }); ctx
|
|
15551
|
+
if (count) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.missions.maxClarificationQuestions = count; }); workflowUiNotify(ctx, `missions.maxClarificationQuestions set to ${count} in ${r.file}`, "info"); }
|
|
15249
15552
|
} else if (setting === "Timing") {
|
|
15250
15553
|
const timing = parseClarificationTiming((await ctx.ui.select("Mission clarification timing", ["after_initial_analysis", "immediate"])) ?? "");
|
|
15251
|
-
if (timing) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.missions.clarificationTiming = timing; }); ctx
|
|
15554
|
+
if (timing) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.missions.clarificationTiming = timing; }); workflowUiNotify(ctx, `missions.clarificationTiming set to ${timing} in ${r.file}`, "info"); }
|
|
15252
15555
|
} else {
|
|
15253
15556
|
const key = setting === "Quality Gate" ? "clarificationQualityGate" : setting === "Allow Without Analysis" ? "allowClarificationWithoutAnalysis" : "useSubagentsBeforeClarification";
|
|
15254
15557
|
const enabled = await chooseBool(ctx, `missions.${key}?`);
|
|
15255
|
-
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { (s.missions as typeof s.missions & Record<string, boolean | string | number | undefined>)[key] = enabled; }); ctx
|
|
15558
|
+
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { (s.missions as typeof s.missions & Record<string, boolean | string | number | undefined>)[key] = enabled; }); workflowUiNotify(ctx, `missions.${key} set to ${enabled} in ${r.file}`, "info"); }
|
|
15256
15559
|
}
|
|
15257
15560
|
} else if (choice === "Mission Planning Depth") {
|
|
15258
15561
|
const depth = parsePlanningDepth((await ctx.ui.select("Mission planning depth", ["fast", "standard", "deep", "maximum"])) ?? "");
|
|
15259
|
-
if (depth) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.missions.planningDepth = depth; }); ctx
|
|
15562
|
+
if (depth) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.missions.planningDepth = depth; }); workflowUiNotify(ctx, `missions.planningDepth set to ${depth} in ${r.file}`, "info"); }
|
|
15260
15563
|
} else if (choice === "Mission Sub-Agent Policy") {
|
|
15261
15564
|
const policy = parseSubagentPolicy((await ctx.ui.select("Mission sub-agent policy", ["off", "auto", "deep", "maximum", "forced"])) ?? "");
|
|
15262
|
-
if (policy) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.missions.subagentPolicy = policy; }); ctx
|
|
15565
|
+
if (policy) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.missions.subagentPolicy = policy; }); workflowUiNotify(ctx, `missions.subagentPolicy set to ${policy} in ${r.file}`, "info"); }
|
|
15263
15566
|
} else if (choice === "Mission Sub-agents / Workers" || choice === "Mission Worker Targets") {
|
|
15264
15567
|
await showMissionSubagentWorkerSettingsMenu(ctx);
|
|
15265
15568
|
} else if (choice === "Mission History") {
|
|
@@ -15275,50 +15578,50 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
15275
15578
|
if (setting === "Progress Widget" || setting === "Progress Bar Display") {
|
|
15276
15579
|
const key = setting === "Progress Widget" ? "progressWidgetEnabled" : "showProgressBar";
|
|
15277
15580
|
const enabled = await chooseBool(ctx, `missions.${key}?`);
|
|
15278
|
-
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { (s.missions as typeof s.missions & Record<string, boolean>)[key] = enabled; }); ctx
|
|
15581
|
+
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { (s.missions as typeof s.missions & Record<string, boolean>)[key] = enabled; }); workflowUiNotify(ctx, `missions.${key} set to ${enabled} in ${r.file}`, "info"); }
|
|
15279
15582
|
} else if (setting === "Heartbeat / Watchdog") await showHeartbeatWatchdogMenu(ctx);
|
|
15280
15583
|
else if (setting === "Token Budget") {
|
|
15281
15584
|
const current = loadWorkflowSettings(ctx.cwd).missions.maxTokens ?? 0;
|
|
15282
15585
|
const choice = await ctx.ui.select("Mission Token Budget", ["Default (unlimited)", "Custom..."]);
|
|
15283
15586
|
if (choice === "Default (unlimited)") {
|
|
15284
15587
|
const r = updateSettings(ctx.cwd, undefined, (s) => { s.missions.maxTokens = 0; });
|
|
15285
|
-
ctx
|
|
15588
|
+
workflowUiNotify(ctx, `missions.maxTokens set to default (unlimited) in ${r.file}`, "info");
|
|
15286
15589
|
} else if (choice === "Custom...") {
|
|
15287
15590
|
const count = parsePositiveInt((await ctx.ui.input("Enter custom mission token budget", String(current > 0 ? current : ""))) ?? "");
|
|
15288
|
-
if (count !== undefined && count >= 0) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.missions.maxTokens = count; }); ctx
|
|
15591
|
+
if (count !== undefined && count >= 0) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.missions.maxTokens = count; }); workflowUiNotify(ctx, `missions.maxTokens set to ${count === 0 ? "unlimited" : count.toLocaleString()} in ${r.file}`, "info"); }
|
|
15289
15592
|
}
|
|
15290
15593
|
} else if (setting === "Runtime Budget") {
|
|
15291
15594
|
const current = loadWorkflowSettings(ctx.cwd).missions.maxRuntimeHours;
|
|
15292
15595
|
const choice = await ctx.ui.select("Mission Runtime Budget", ["Default (13 hours)", "Custom..."]);
|
|
15293
15596
|
if (choice === "Default (13 hours)") {
|
|
15294
15597
|
const r = updateSettings(ctx.cwd, undefined, (s) => { s.missions.maxRuntimeHours = 13; });
|
|
15295
|
-
ctx
|
|
15598
|
+
workflowUiNotify(ctx, `missions.maxRuntimeHours set to default (13 hours) in ${r.file}`, "info");
|
|
15296
15599
|
} else if (choice === "Custom...") {
|
|
15297
15600
|
const count = parsePositiveInt((await ctx.ui.input("Enter custom runtime budget (hours)", String(current !== 13 ? current : ""))) ?? "");
|
|
15298
|
-
if (count !== undefined && count > 0) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.missions.maxRuntimeHours = count; }); ctx
|
|
15601
|
+
if (count !== undefined && count > 0) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.missions.maxRuntimeHours = count; }); workflowUiNotify(ctx, `missions.maxRuntimeHours set to ${count} hours in ${r.file}`, "info"); }
|
|
15299
15602
|
}
|
|
15300
15603
|
} else {
|
|
15301
15604
|
const count = parsePositiveInt((await ctx.ui.input("checkpointIntervalMinutes", "30")) ?? "");
|
|
15302
|
-
if (count !== undefined && count > 0) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.missions.checkpointIntervalMinutes = count; }); ctx
|
|
15605
|
+
if (count !== undefined && count > 0) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.missions.checkpointIntervalMinutes = count; }); workflowUiNotify(ctx, `missions.checkpointIntervalMinutes set to ${count} in ${r.file}`, "info"); }
|
|
15303
15606
|
}
|
|
15304
15607
|
} else if (choice === "Runtime Budget") {
|
|
15305
15608
|
const current = loadWorkflowSettings(ctx.cwd).missions.maxRuntimeHours;
|
|
15306
15609
|
const choice2 = await ctx.ui.select("Mission Runtime Budget", ["Default (13 hours)", "Custom..."]);
|
|
15307
15610
|
if (choice2 === "Default (13 hours)") {
|
|
15308
15611
|
const r = updateSettings(ctx.cwd, undefined, (s) => { s.missions.maxRuntimeHours = 13; });
|
|
15309
|
-
ctx
|
|
15612
|
+
workflowUiNotify(ctx, `missions.maxRuntimeHours set to default (13 hours) in ${r.file}`, "info");
|
|
15310
15613
|
} else if (choice2 === "Custom...") {
|
|
15311
15614
|
const count = parsePositiveInt((await ctx.ui.input("Enter custom runtime budget (hours)", String(current !== 13 ? current : ""))) ?? "");
|
|
15312
|
-
if (count !== undefined && count > 0) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.missions.maxRuntimeHours = count; }); ctx
|
|
15615
|
+
if (count !== undefined && count > 0) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.missions.maxRuntimeHours = count; }); workflowUiNotify(ctx, `missions.maxRuntimeHours set to ${count} hours in ${r.file}`, "info"); }
|
|
15313
15616
|
}
|
|
15314
15617
|
} else if (choice === "Checkpoint Interval") {
|
|
15315
15618
|
const count = parsePositiveInt((await ctx.ui.input("checkpointIntervalMinutes", "30")) ?? "");
|
|
15316
|
-
if (count !== undefined && count > 0) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.missions.checkpointIntervalMinutes = count; }); ctx
|
|
15619
|
+
if (count !== undefined && count > 0) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.missions.checkpointIntervalMinutes = count; }); workflowUiNotify(ctx, `missions.checkpointIntervalMinutes set to ${count} in ${r.file}`, "info"); }
|
|
15317
15620
|
} else if (choice === "Approval Safety" || choice === "Validation Per Milestone" || choice === "Full Auto Safety" || choice === "Auto Resume") {
|
|
15318
15621
|
const keyMap: Record<string, keyof ReturnType<typeof loadWorkflowSettings>["missions"]> = { "Validation Per Milestone": "requireValidationPerMilestone", "Approval Safety": "requireApprovalForDestructiveActions", "Full Auto Safety": "allowFullAuto", "Auto Resume": "autoResume" };
|
|
15319
15622
|
const key = keyMap[choice];
|
|
15320
15623
|
const enabled = await chooseBool(ctx, `${String(key)}?`);
|
|
15321
|
-
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { (s.missions as Record<string, unknown>)[String(key)] = enabled; }); ctx
|
|
15624
|
+
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { (s.missions as Record<string, unknown>)[String(key)] = enabled; }); workflowUiNotify(ctx, `missions.${String(key)} set to ${enabled} in ${r.file}${key === "allowFullAuto" && enabled === false && r.settings.missions.defaultAutonomy === "full_auto" ? "; full_auto default is retained but blocked" : ""}`, "info"); }
|
|
15322
15625
|
} else if (choice === "Review / Validation Behavior") {
|
|
15323
15626
|
await showMissionReviewValidationBehaviorMenu(ctx);
|
|
15324
15627
|
} else if (choice === "Repair / Validation Retry" || choice === "Mission Repair / Validation" || choice === "Repair / Validation Retry Settings") {
|
|
@@ -15351,18 +15654,18 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
15351
15654
|
const enabled = await chooseBool(ctx, "safety.repoLockEnabled for this project only?");
|
|
15352
15655
|
if (enabled !== undefined) {
|
|
15353
15656
|
const r = updateSettings(ctx.cwd, "project", (s) => { s.safety.repoLockEnabled = enabled; });
|
|
15354
|
-
ctx
|
|
15657
|
+
workflowUiNotify(ctx, `Project Repo Lock set to ${enabled} in ${r.file}. This project override wins over global settings and does not apply to other repos.`, "info");
|
|
15355
15658
|
}
|
|
15356
15659
|
} else {
|
|
15357
15660
|
const key = keyMap[choice];
|
|
15358
15661
|
const enabled = await chooseBool(ctx, `${String(key)}?`);
|
|
15359
|
-
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.safety[key] = enabled; }); ctx
|
|
15662
|
+
if (enabled !== undefined) { const r = updateSettings(ctx.cwd, undefined, (s) => { s.safety[key] = enabled; }); workflowUiNotify(ctx, `safety.${String(key)} set to ${enabled} in ${r.file}`, "info"); }
|
|
15360
15663
|
}
|
|
15361
15664
|
}
|
|
15362
15665
|
}
|
|
15363
15666
|
|
|
15364
|
-
async function
|
|
15365
|
-
if (!ctx.hasUI) return show(pi,
|
|
15667
|
+
async function showEditorHintsSettingsMenu(ctx: ExtensionContext) {
|
|
15668
|
+
if (!ctx.hasUI) return show(pi, renderEditorHintsSettings(ctx));
|
|
15366
15669
|
const options = [
|
|
15367
15670
|
{ label: "Idle Entry Hint", key: "showIdleWorkflowEntryHint" as const },
|
|
15368
15671
|
{ label: "Active Switch Hint", key: "showActiveWorkflowSwitchHint" as const },
|
|
@@ -15373,17 +15676,31 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
15373
15676
|
const settings = loadWorkflowSettings(ctx.cwd);
|
|
15374
15677
|
const ui = workflowWidgetUi(settings);
|
|
15375
15678
|
const labels = options.map((option) => `${option.label}: ${ui[option.key] !== false ? "visible" : "hidden"}`);
|
|
15376
|
-
const
|
|
15679
|
+
const contrastLabel = `Hint Contrast: ${workflowEditorHintContrastLabel(workflowEditorHintContrast(settings))}`;
|
|
15680
|
+
const choice = await ctx.ui.select("Editor Hints", [...labels, contrastLabel, "List Current Settings", "Back"]);
|
|
15377
15681
|
if (!choice || choice === "Back") return;
|
|
15378
|
-
if (choice === "List Current Settings") { show(pi,
|
|
15682
|
+
if (choice === "List Current Settings") { show(pi, renderEditorHintsSettings(ctx)); continue; }
|
|
15683
|
+
if (choice === contrastLabel) {
|
|
15684
|
+
const current = workflowEditorHintContrast(settings);
|
|
15685
|
+
const contrastChoice = await ctx.ui.select("Editor Hint Contrast", WORKFLOW_EDITOR_HINT_CONTRASTS.map((contrast) => `${workflowEditorHintContrastLabel(contrast)}${contrast === current ? " (current)" : ""}`).concat("Back"));
|
|
15686
|
+
if (!contrastChoice || contrastChoice === "Back") continue;
|
|
15687
|
+
const contrast = parseEditorHintContrast(contrastChoice.replace(/\s+\(current\)$/, ""));
|
|
15688
|
+
if (contrast) {
|
|
15689
|
+
updateSettings(ctx.cwd, "global", (s) => { workflowWidgetUi(s).editorHintContrast = contrast; });
|
|
15690
|
+
setWorkflowUi(ctx, state, activeSubagents);
|
|
15691
|
+
workflowEditorHintText = workflowEditorHintTextFor(state, loadWorkflowSettings(ctx.cwd));
|
|
15692
|
+
workflowUiNotify(ctx, `Editor hint contrast set to ${workflowEditorHintContrastLabel(contrast)}.`, "info");
|
|
15693
|
+
}
|
|
15694
|
+
continue;
|
|
15695
|
+
}
|
|
15379
15696
|
const index = labels.indexOf(choice);
|
|
15380
15697
|
const option = options[index];
|
|
15381
15698
|
if (!option) continue;
|
|
15382
15699
|
const enabled = await chooseBool(ctx, `ui.${option.key}?`);
|
|
15383
15700
|
if (enabled !== undefined) {
|
|
15384
|
-
|
|
15701
|
+
updateSettings(ctx.cwd, "global", (s) => { workflowWidgetUi(s)[option.key] = enabled; });
|
|
15385
15702
|
setWorkflowUi(ctx, state, activeSubagents);
|
|
15386
|
-
ctx
|
|
15703
|
+
workflowUiNotify(ctx, `${option.label} ${enabled ? "shown" : "hidden"}.`, "info");
|
|
15387
15704
|
}
|
|
15388
15705
|
}
|
|
15389
15706
|
}
|
|
@@ -15391,22 +15708,22 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
15391
15708
|
async function showUiWidgetsSettingsMenu(ctx: ExtensionContext) {
|
|
15392
15709
|
if (!ctx.hasUI) return show(pi, renderWorkflowWidgetsStatus(ctx));
|
|
15393
15710
|
while (ctx.hasUI) {
|
|
15394
|
-
const choice = await ctx.ui.select("UI Widgets", ["Plan Top Widget", "Plan Bottom Widget", "Mission Top Widget", "Mission Bottom Widget", "Enable Widget Shortcuts", "Remember Widget Visibility", "
|
|
15711
|
+
const choice = await ctx.ui.select("UI Widgets", ["Plan Top Widget", "Plan Bottom Widget", "Mission Top Widget", "Mission Bottom Widget", "Enable Widget Shortcuts", "Remember Widget Visibility", "Editor Hints", "List Current Settings", "Back"]);
|
|
15395
15712
|
if (!choice || choice === "Back") return;
|
|
15396
15713
|
if (choice === "List Current Settings") show(pi, renderWorkflowWidgetsStatus(ctx));
|
|
15397
|
-
else if (choice === "
|
|
15714
|
+
else if (choice === "Editor Hints") await showEditorHintsSettingsMenu(ctx);
|
|
15398
15715
|
else if (choice === "Enable Widget Shortcuts" || choice === "Remember Widget Visibility") {
|
|
15399
15716
|
const key = choice === "Enable Widget Shortcuts" ? "enableWidgetShortcuts" : "rememberWidgetVisibility";
|
|
15400
15717
|
const enabled = await chooseBool(ctx, `ui.${key}?`);
|
|
15401
15718
|
if (enabled !== undefined) {
|
|
15402
|
-
|
|
15719
|
+
updateSettings(ctx.cwd, "global", (s) => { workflowWidgetUi(s)[key] = enabled; });
|
|
15403
15720
|
setWorkflowUi(ctx, state, activeSubagents);
|
|
15404
|
-
ctx
|
|
15721
|
+
workflowUiNotify(ctx, `${choice} ${enabled ? "enabled" : "disabled"}.`, "info");
|
|
15405
15722
|
}
|
|
15406
15723
|
} else {
|
|
15407
15724
|
const slot: WorkflowWidgetSlot = choice === "Plan Top Widget" ? "planTop" : choice === "Plan Bottom Widget" ? "planBottom" : choice === "Mission Top Widget" ? "missionTop" : "missionBottom";
|
|
15408
15725
|
const visible = await chooseBool(ctx, `${widgetSlotLabel(slot)} visible?`);
|
|
15409
|
-
if (visible !== undefined) ctx
|
|
15726
|
+
if (visible !== undefined) workflowUiNotify(ctx, setWorkflowWidgetVisibility(ctx, slot, visible), "info");
|
|
15410
15727
|
}
|
|
15411
15728
|
}
|
|
15412
15729
|
}
|
|
@@ -15458,14 +15775,14 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
15458
15775
|
const result = applyWorkflowPreset(ctx.cwd, undefined, resolved);
|
|
15459
15776
|
setWorkflowUi(ctx, state, activeSubagents);
|
|
15460
15777
|
const label = workflowPresetLabel(resolved, workflowPresetCatalog(result.settings)[resolved]);
|
|
15461
|
-
if (notifyOnly) ctx
|
|
15778
|
+
if (notifyOnly) workflowUiNotify(ctx, `Workflow preset active: ${label}`, "info");
|
|
15462
15779
|
else show(pi, presetActionMessage("Workflow Preset Applied", label, result.file, result.scope));
|
|
15463
15780
|
}
|
|
15464
15781
|
|
|
15465
15782
|
async function markWorkflowPresetCustom(ctx: ExtensionContext): Promise<void> {
|
|
15466
15783
|
const result = updateSettings(ctx.cwd, undefined, (s) => { s.presets = { ...(s.presets ?? {}), activePreset: WORKFLOW_CUSTOM_PRESET_MARKER, items: { ...(s.presets?.items ?? {}) } }; });
|
|
15467
15784
|
setWorkflowUi(ctx, state, activeSubagents);
|
|
15468
|
-
ctx
|
|
15785
|
+
workflowUiNotify(ctx, `Workflow preset marker cleared in ${result.file}; workflow settings unchanged.`, "info");
|
|
15469
15786
|
}
|
|
15470
15787
|
|
|
15471
15788
|
async function cycleWorkflowPreset(ctx: ExtensionContext, direction: 1 | -1): Promise<void> {
|
|
@@ -15533,7 +15850,7 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
15533
15850
|
if (policy) updateSettings(ctx.cwd, undefined, (s) => { const item = (s.presets!.items![name] ??= { planning: {}, workflow: {}, missions: {}, subagents: {} }); item.subagents = { ...(item.subagents ?? {}), planningPolicy: policy, executionPolicy: policy, repairPolicy: policy, reviewPolicy: policy, validationPolicy: policy }; });
|
|
15534
15851
|
}
|
|
15535
15852
|
setWorkflowUi(ctx, state, activeSubagents);
|
|
15536
|
-
ctx
|
|
15853
|
+
workflowUiNotify(ctx, `Preset ${name} updated in ${r.file}`, "info");
|
|
15537
15854
|
} catch (e) { show(pi, `# Workflow Preset Error\n\n${e instanceof Error ? e.message : String(e)}`); }
|
|
15538
15855
|
}
|
|
15539
15856
|
}
|
|
@@ -15628,7 +15945,7 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
15628
15945
|
async function showCustomBrandStartupVisualMenu(ctx: ExtensionContext): Promise<boolean | undefined> {
|
|
15629
15946
|
if (!ctx.hasUI) return undefined;
|
|
15630
15947
|
const saved = updateSettings(ctx.cwd, undefined, (s) => { s.ui.startupVisual = "custom_brand"; });
|
|
15631
|
-
ctx
|
|
15948
|
+
workflowUiNotify(ctx, `ui.startupVisual set to custom_brand in ${saved.file}`, "info");
|
|
15632
15949
|
while (ctx.hasUI) {
|
|
15633
15950
|
const choice = await ctx.ui.select("Custom Brand Startup Visual", ["Set Text", "Choose Base Template", "Preview", "List Theme Settings", "Back"]);
|
|
15634
15951
|
if (!choice || choice === "Back") return undefined;
|
|
@@ -15637,13 +15954,13 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
15637
15954
|
} else if (choice === "Set Text") {
|
|
15638
15955
|
const text = sanitizeCustomBrandText(await ctx.ui.input("Custom brand text", sanitizeCustomBrandText(loadWorkflowSettings(ctx.cwd).ui.customBrandText) || "WORKFLOW SUITE"));
|
|
15639
15956
|
const r = updateSettings(ctx.cwd, undefined, (s) => { s.ui.customBrandEnabled = true; s.ui.customBrandText = text; s.ui.startupVisual = "custom_brand"; });
|
|
15640
|
-
ctx
|
|
15957
|
+
workflowUiNotify(ctx, `ui.customBrandText set in ${r.file}`, "info");
|
|
15641
15958
|
void showStartupVisual(ctx, { intent: "manual" });
|
|
15642
15959
|
} else if (choice === "Choose Base Template") {
|
|
15643
15960
|
const base = parseCustomBrandBaseVisual((await ctx.ui.select("Custom brand base template", WORKFLOW_CUSTOM_BRAND_BASE_VISUALS)) ?? "");
|
|
15644
15961
|
if (base) {
|
|
15645
15962
|
const r = updateSettings(ctx.cwd, undefined, (s) => { s.ui.customBrandBaseVisual = base; s.ui.startupVisual = "custom_brand"; });
|
|
15646
|
-
ctx
|
|
15963
|
+
workflowUiNotify(ctx, `ui.customBrandBaseVisual set to ${base} in ${r.file}`, "info");
|
|
15647
15964
|
void showStartupVisual(ctx, { intent: "manual" });
|
|
15648
15965
|
}
|
|
15649
15966
|
} else if (choice === "Preview") {
|
|
@@ -15665,27 +15982,27 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
15665
15982
|
const text = startupLogoText(loadWorkflowSettings(ctx.cwd)) || "WFS";
|
|
15666
15983
|
const value = sanitizeCustomBrandText(await ctx.ui.input("Custom logo letters (max 6 A-Z/0-9)", text)).toUpperCase().replace(/[^A-Z0-9]/g, "").slice(0, 6);
|
|
15667
15984
|
const r = updateSettings(ctx.cwd, undefined, (s) => { s.ui.startupLogo = "custom"; s.ui.startupLogoText = value; });
|
|
15668
|
-
ctx
|
|
15985
|
+
workflowUiNotify(ctx, `ui.startupLogoText set to ${value || "(empty)"} in ${r.file}`, "info");
|
|
15669
15986
|
void showStartupVisual(ctx, { intent: "manual" });
|
|
15670
15987
|
} else if (choice === "Choose Font") {
|
|
15671
15988
|
const font = parseStartupLogoFont((await ctx.ui.select("Custom logo font", WORKFLOW_STARTUP_LOGO_FONTS)) ?? "");
|
|
15672
15989
|
if (font) {
|
|
15673
15990
|
const r = updateSettings(ctx.cwd, undefined, (s) => { s.ui.startupLogo = "custom"; s.ui.startupLogoFont = font; });
|
|
15674
|
-
ctx
|
|
15991
|
+
workflowUiNotify(ctx, `ui.startupLogoFont set to ${font} in ${r.file}`, "info");
|
|
15675
15992
|
void showStartupVisual(ctx, { intent: "manual" });
|
|
15676
15993
|
}
|
|
15677
15994
|
} else if (choice === "Choose Shadow Direction") {
|
|
15678
15995
|
const direction = parseStartupLogoShadowDirection((await ctx.ui.select("Custom logo shadow direction", WORKFLOW_STARTUP_LOGO_SHADOW_DIRECTIONS)) ?? "");
|
|
15679
15996
|
if (direction) {
|
|
15680
15997
|
const r = updateSettings(ctx.cwd, undefined, (s) => { s.ui.startupLogo = "custom"; s.ui.startupLogoShadowDirection = direction; });
|
|
15681
|
-
ctx
|
|
15998
|
+
workflowUiNotify(ctx, `ui.startupLogoShadowDirection set to ${direction} in ${r.file}`, "info");
|
|
15682
15999
|
void showStartupVisual(ctx, { intent: "manual" });
|
|
15683
16000
|
}
|
|
15684
16001
|
} else if (choice === "Choose Color Style") {
|
|
15685
16002
|
const colorStyle = parseStartupLogoColorStyle((await ctx.ui.select("Custom logo color style", WORKFLOW_STARTUP_LOGO_COLOR_STYLES)) ?? "");
|
|
15686
16003
|
if (colorStyle) {
|
|
15687
16004
|
const r = updateSettings(ctx.cwd, undefined, (s) => { s.ui.startupLogo = "custom"; s.ui.startupLogoColorStyle = colorStyle; });
|
|
15688
|
-
ctx
|
|
16005
|
+
workflowUiNotify(ctx, `ui.startupLogoColorStyle set to ${colorStyle} in ${r.file}`, "info");
|
|
15689
16006
|
void showStartupVisual(ctx, { intent: "manual" });
|
|
15690
16007
|
}
|
|
15691
16008
|
} else if (choice === "Preview") {
|
|
@@ -15710,7 +16027,7 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
15710
16027
|
} else {
|
|
15711
16028
|
const r = updateSettings(ctx.cwd, undefined, (s) => { s.ui.startupVisual = visual; });
|
|
15712
16029
|
const canPreview = startupVisualOrDefault(r.settings) !== "none";
|
|
15713
|
-
ctx
|
|
16030
|
+
workflowUiNotify(ctx, canPreview ? `Startup visual set to ${visual} in ${r.file}` : `Startup visual set to ${visual} (disabled) in ${r.file}`, "info");
|
|
15714
16031
|
if (canPreview) void showStartupVisual(ctx, { intent: "manual" });
|
|
15715
16032
|
}
|
|
15716
16033
|
}
|
|
@@ -15718,14 +16035,14 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
15718
16035
|
const name = parseWidgetTextPreset((await ctx.ui.select("Startup text style", (WORKFLOW_WIDGET_TEXT_PRESETS as readonly string[]).map((p) => WORKFLOW_WIDGET_TEXT_PRESET_LABELS[p]))) ?? "");
|
|
15719
16036
|
if (name) {
|
|
15720
16037
|
const r = updateSettings(ctx.cwd, undefined, (s) => { s.ui.startupTextStyle = name; });
|
|
15721
|
-
ctx
|
|
16038
|
+
workflowUiNotify(ctx, `Startup text style set to ${WORKFLOW_WIDGET_TEXT_PRESET_LABELS[name]} in ${r.file}.`, "info");
|
|
15722
16039
|
void showStartupVisual(ctx, { intent: "manual" });
|
|
15723
16040
|
}
|
|
15724
16041
|
} else if (choice === "Turn On" || choice === "Turn Off") {
|
|
15725
16042
|
const visual: WorkflowStartupVisual = choice === "Turn On" ? "mission_control" : "none";
|
|
15726
16043
|
const r = updateSettings(ctx.cwd, undefined, (s) => { s.ui.startupVisual = visual; });
|
|
15727
16044
|
const canPreview = startupVisualOrDefault(r.settings) !== "none";
|
|
15728
|
-
ctx
|
|
16045
|
+
workflowUiNotify(ctx, canPreview ? `Startup visual turned on (${visual}) in ${r.file}` : `Startup visual turned off in ${r.file}`, "info");
|
|
15729
16046
|
if (canPreview) void showStartupVisual(ctx, { intent: "manual" });
|
|
15730
16047
|
} else if (choice === "On Session Start") {
|
|
15731
16048
|
const enabled = await chooseBool(ctx, "Show startup visual on session start?");
|
|
@@ -15734,12 +16051,12 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
15734
16051
|
s.ui.startupVisualOnSessionStart = enabled;
|
|
15735
16052
|
if (enabled === true && (parseStartupVisual(s.ui.startupVisual) ?? "none") === "none") s.ui.startupVisual = "minimal";
|
|
15736
16053
|
});
|
|
15737
|
-
ctx
|
|
16054
|
+
workflowUiNotify(ctx, `Startup on session start ${enabled ? "enabled" : "disabled"} in ${r.file}`, "info");
|
|
15738
16055
|
void showStartupVisual(ctx, { intent: "manual" });
|
|
15739
16056
|
}
|
|
15740
16057
|
} else if (choice === "Preview") {
|
|
15741
16058
|
const previewed = await showStartupVisual(ctx, { intent: "manual" });
|
|
15742
|
-
if (!previewed) ctx
|
|
16059
|
+
if (!previewed) workflowUiNotify(ctx, "Startup visual is disabled. Choose a visual or turn it on to preview.", "info");
|
|
15743
16060
|
}
|
|
15744
16061
|
}
|
|
15745
16062
|
return undefined;
|
|
@@ -15768,7 +16085,7 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
15768
16085
|
const r = updateSettings(ctx.cwd, undefined, (s) => { s.ui.workflowTheme = name; });
|
|
15769
16086
|
applyWorkflowEditorTheme(ctx);
|
|
15770
16087
|
setWorkflowUi(ctx, state, activeSubagents);
|
|
15771
|
-
ctx
|
|
16088
|
+
workflowUiNotify(ctx, `ui.workflowTheme set to ${workflowThemeDisplayName(name)} in ${r.file}`, "info");
|
|
15772
16089
|
void showStartupVisual(ctx, { intent: "manual" });
|
|
15773
16090
|
}
|
|
15774
16091
|
} else if (choice === "Startup Visual") {
|
|
@@ -15777,7 +16094,7 @@ ${renderMissionStatus(activeMission ?? paused)}`);
|
|
|
15777
16094
|
const logo = parseStartupLogo((await ctx.ui.select("Startup logo", WORKFLOW_STARTUP_LOGOS)) ?? "");
|
|
15778
16095
|
if (logo) {
|
|
15779
16096
|
const r = updateSettings(ctx.cwd, undefined, (s) => { s.ui.startupLogo = logo; });
|
|
15780
|
-
ctx
|
|
16097
|
+
workflowUiNotify(ctx, `ui.startupLogo set to ${logo} in ${r.file}`, "info");
|
|
15781
16098
|
if (logo === "custom") await showCustomStartupLogoMenu(ctx);
|
|
15782
16099
|
else void showStartupVisual(ctx, { intent: "manual" });
|
|
15783
16100
|
}
|
|
@@ -15868,10 +16185,9 @@ Pi Version: v${VERSION}
|
|
|
15868
16185
|
|
|
15869
16186
|
function workflowAutoCompactionDecision(ctx: ExtensionContext, options: { allowPendingMessages?: boolean } = {}): { ok: true; percent: number; trigger: number; cooldownMinutes: number } | { ok: false; reason: string } {
|
|
15870
16187
|
const settings = loadWorkflowSettings(ctx.cwd);
|
|
15871
|
-
const customModelTrigger = customModelCompactionConfigured(settings);
|
|
15872
16188
|
if (!workflowProactiveCompactionEffective(settings)) return { ok: false, reason: "workflow proactive compaction disabled" };
|
|
15873
16189
|
if (settings.context.compactionMode === "disabled") return { ok: false, reason: "workflow compaction mode disabled" };
|
|
15874
|
-
if (!
|
|
16190
|
+
if (!workflowAutoCompactionModeEligible(state.mode)) return { ok: false, reason: `workflow mode ${state.mode} is active` };
|
|
15875
16191
|
if (!options.allowPendingMessages) {
|
|
15876
16192
|
if (workflowScheduledAgentTurns > 0) return { ok: false, reason: "pending workflow handoff queued" };
|
|
15877
16193
|
try { if (ctx.hasPendingMessages()) return { ok: false, reason: "pending messages queued" }; } catch { /* pending state unavailable */ }
|
|
@@ -15880,6 +16196,7 @@ Pi Version: v${VERSION}
|
|
|
15880
16196
|
const percent = Number(usage?.percent);
|
|
15881
16197
|
if (!Number.isFinite(percent)) return { ok: false, reason: "context usage unavailable" };
|
|
15882
16198
|
const trigger = effectiveWorkflowCompactionTriggerPercent(settings, ctx, usage ?? {});
|
|
16199
|
+
if (!Number.isFinite(trigger)) return { ok: false, reason: "compaction trigger unavailable" };
|
|
15883
16200
|
if (percent < trigger) return { ok: false, reason: `context ${percent.toFixed(1)}% below trigger ${trigger}%` };
|
|
15884
16201
|
const cooldownMinutes = compactionCooldownMinutes(settings);
|
|
15885
16202
|
const cooldownMs = cooldownMinutes * 60 * 1000;
|
|
@@ -15937,20 +16254,20 @@ Pi Version: v${VERSION}
|
|
|
15937
16254
|
workflowLastAutoCompactionAt = Date.now();
|
|
15938
16255
|
clearDeferredWorkflowCompaction();
|
|
15939
16256
|
rememberWorkflowCompactionCheck(`${checkpoint} boundary triggered at ${percent.toFixed(1)}% context`);
|
|
15940
|
-
try { ctx
|
|
16257
|
+
try { workflowUiNotify(ctx, `Workflow auto-compaction triggered at ${percent.toFixed(1)}% context usage.`, "info"); } catch { /* UI may be unavailable */ }
|
|
15941
16258
|
ctx.compact({
|
|
15942
16259
|
customInstructions,
|
|
15943
16260
|
onComplete: () => {
|
|
15944
16261
|
workflowAutoCompactionRunning = false;
|
|
15945
16262
|
workflowLastAutoCompactionAt = Date.now();
|
|
15946
16263
|
rememberWorkflowCompactionCheck(`${checkpoint} boundary compaction completed`);
|
|
15947
|
-
try { ctx
|
|
16264
|
+
try { workflowUiNotify(ctx, "Workflow auto-compaction complete.", "info"); } catch { /* UI may be unavailable */ }
|
|
15948
16265
|
},
|
|
15949
16266
|
onError: (error: Error) => {
|
|
15950
16267
|
workflowAutoCompactionRunning = false;
|
|
15951
16268
|
rememberWorkflowCompactionCheck(`${checkpoint} boundary compaction failed — ${error.message}`);
|
|
15952
16269
|
rememberCustomCompactionStatus(`proactive compaction request failed: ${error.message}`);
|
|
15953
|
-
try { ctx
|
|
16270
|
+
try { workflowUiNotify(ctx, `Workflow auto-compaction skipped: ${error.message}`, "warning"); } catch { /* UI may be unavailable */ }
|
|
15954
16271
|
},
|
|
15955
16272
|
});
|
|
15956
16273
|
}
|
|
@@ -15992,26 +16309,18 @@ Pi Version: v${VERSION}
|
|
|
15992
16309
|
|
|
15993
16310
|
pi.on("session_before_compact", async (event, ctx) => {
|
|
15994
16311
|
const settings = loadWorkflowSettings(ctx.cwd);
|
|
15995
|
-
if (
|
|
15996
|
-
if (settings.context.compactionMode === "pi_default" || settings.context.compactionMode === "disabled") return;
|
|
15997
|
-
if (settings.context.compactionMode !== "custom_model") {
|
|
15998
|
-
rememberCustomCompactionStatus(`fallback to Pi default: ${compactionModeLabel(settings.context.compactionMode)} uses Pi fallback behavior in current releases`);
|
|
15999
|
-
ctx.ui.notify("Agent-routed custom compaction uses Pi default fallback behavior in current releases.", "warning");
|
|
16000
|
-
return;
|
|
16001
|
-
}
|
|
16312
|
+
if (settings.context.compactionMode === "disabled") return;
|
|
16002
16313
|
|
|
16003
16314
|
const provider = settings.context.compactionModelProvider;
|
|
16004
16315
|
const modelId = settings.context.compactionModel;
|
|
16005
16316
|
if (!provider || !modelId) {
|
|
16006
|
-
rememberCustomCompactionStatus("fallback to Pi default: custom compaction model is missing provider/model");
|
|
16007
|
-
ctx.ui.notify("Custom compaction model is missing provider/model; using Pi default compaction.", "warning");
|
|
16008
16317
|
return;
|
|
16009
16318
|
}
|
|
16010
16319
|
|
|
16011
16320
|
const model = ctx.modelRegistry.find(provider, modelId);
|
|
16012
16321
|
if (!model) {
|
|
16013
16322
|
rememberCustomCompactionStatus(`fallback to Pi default: model not found ${provider}/${modelId}`);
|
|
16014
|
-
ctx
|
|
16323
|
+
workflowUiNotify(ctx, `Custom compaction model not found: ${provider}/${modelId}; using Pi default compaction.`, "warning");
|
|
16015
16324
|
return;
|
|
16016
16325
|
}
|
|
16017
16326
|
|
|
@@ -16019,12 +16328,12 @@ Pi Version: v${VERSION}
|
|
|
16019
16328
|
if (auth.ok === false) {
|
|
16020
16329
|
const authError = auth.error;
|
|
16021
16330
|
rememberCustomCompactionStatus(`fallback to Pi default: auth failed for ${provider}/${modelId}: ${authError}`);
|
|
16022
|
-
ctx
|
|
16331
|
+
workflowUiNotify(ctx, `Custom compaction auth failed for ${provider}/${modelId}: ${authError}; using Pi default compaction.`, "warning");
|
|
16023
16332
|
return;
|
|
16024
16333
|
}
|
|
16025
16334
|
if (!auth.apiKey) {
|
|
16026
16335
|
rememberCustomCompactionStatus(`fallback to Pi default: no API key for ${provider}/${modelId}`);
|
|
16027
|
-
ctx
|
|
16336
|
+
workflowUiNotify(ctx, `No API key for custom compaction model ${provider}/${modelId}; using Pi default compaction.`, "warning");
|
|
16028
16337
|
return;
|
|
16029
16338
|
}
|
|
16030
16339
|
|
|
@@ -16036,14 +16345,14 @@ Pi Version: v${VERSION}
|
|
|
16036
16345
|
const fitNote = fitted.adjusted && fitted.safeInputTokens
|
|
16037
16346
|
? ` Adaptive fit: summarizing about ${Math.round(fitted.inputTokens).toLocaleString()} tokens within ${Math.round(fitted.safeInputTokens).toLocaleString()} safe input tokens for the compaction model.`
|
|
16038
16347
|
: "";
|
|
16039
|
-
ctx
|
|
16348
|
+
workflowUiNotify(ctx, `Custom compaction using ${provider}/${modelId}. Keep recent: ${customCompactionKeepRecentTokens(settings).toLocaleString()} tokens; reserve: ${customCompactionReserveTokens(settings).toLocaleString()} tokens.${fitNote}`, "info");
|
|
16040
16349
|
const result = await compactionApi.compact(fitted.preparation, model, auth.apiKey, auth.headers, event.customInstructions, event.signal);
|
|
16041
16350
|
rememberCustomCompactionStatus(`custom compaction succeeded using ${provider}/${modelId}${fitted.adjusted ? " with adaptive context fit" : ""}`);
|
|
16042
16351
|
return { compaction: result };
|
|
16043
16352
|
} catch (error) {
|
|
16044
16353
|
const message = error instanceof Error ? error.message : String(error);
|
|
16045
16354
|
rememberCustomCompactionStatus(`fallback to Pi default: custom compaction failed for ${provider}/${modelId}: ${message}`);
|
|
16046
|
-
if (!event.signal.aborted) ctx
|
|
16355
|
+
if (!event.signal.aborted) workflowUiNotify(ctx, `Custom compaction failed: ${message}; using Pi default compaction.`, "warning");
|
|
16047
16356
|
return;
|
|
16048
16357
|
}
|
|
16049
16358
|
});
|
|
@@ -16715,7 +17024,7 @@ Pi Version: v${VERSION}
|
|
|
16715
17024
|
if (action === "scope" || action === "write-target") {
|
|
16716
17025
|
const effective = loadEffectiveSettings(ctx.cwd);
|
|
16717
17026
|
const target = getDefaultWriteTarget(ctx.cwd);
|
|
16718
|
-
show(pi, `# Workflow Settings Scope\n\nCurrent Directory: ${ctx.cwd}\nProject Override: ${effective.projectOverridePath ?? "none"}\nWrite Target: ${target.scope}\nWrite Target File: ${target.file}\nGlobal Settings File: ${WORKFLOW_SETTINGS_FILE}\nSettings Priority: project workflow settings > global workflow-settings.json > example config defaults > built-in emergency fallback\nCompaction Effective Source: ${effective.projectOverridePath ? "project override may override global compaction settings" : "global workflow-settings.json"}\
|
|
17027
|
+
show(pi, `# Workflow Settings Scope\n\nCurrent Directory: ${ctx.cwd}\nProject Override: ${effective.projectOverridePath ?? "none"}\nWrite Target: ${target.scope}\nWrite Target File: ${target.file}\nGlobal Settings File: ${WORKFLOW_SETTINGS_FILE}\nSettings Priority: project workflow settings > global workflow-settings.json > example config defaults > built-in emergency fallback\nCompaction Effective Source: ${effective.projectOverridePath ? "project override may override global compaction settings" : "global workflow-settings.json"}\nCompaction Summary Model: ${effective.settings.context.compactionModelProvider && effective.settings.context.compactionModel ? `${effective.settings.context.compactionModelProvider}/${effective.settings.context.compactionModel}` : "Pi default"}`);
|
|
16719
17028
|
return;
|
|
16720
17029
|
}
|
|
16721
17030
|
if (action === "create-project-override") {
|
|
@@ -16900,6 +17209,14 @@ Pi Version: v${VERSION}
|
|
|
16900
17209
|
setWorkflowUi(ctx, state, activeSubagents);
|
|
16901
17210
|
return show(pi, updatedMessage(result.scope, result.file, `ui.${key}`, String(bool)));
|
|
16902
17211
|
}
|
|
17212
|
+
if (subject === "ui" && key === "editorHintContrast") {
|
|
17213
|
+
const contrast = parseEditorHintContrast(value);
|
|
17214
|
+
if (!contrast) return show(pi, "# Error\n\nUsage: `/workflow-settings set ui editorHintContrast <subtle|normal|bright|high>`");
|
|
17215
|
+
const result = updateSettings(ctx.cwd, scope ?? "global", (s) => { workflowWidgetUi(s).editorHintContrast = contrast; });
|
|
17216
|
+
setWorkflowUi(ctx, state, activeSubagents);
|
|
17217
|
+
workflowEditorHintText = workflowEditorHintTextFor(state, loadWorkflowSettings(ctx.cwd));
|
|
17218
|
+
return show(pi, updatedMessage(result.scope, result.file, "ui.editorHintContrast", contrast));
|
|
17219
|
+
}
|
|
16903
17220
|
if (subject === "subagents" && (key === "enabled" || key === "activityIndicatorEnabled" || key === "autoUseDuringPlanning" || key === "autoUseDuringExecution" || key === "autoUseDuringRepair" || key === "autoUseDuringReview" || key === "autoUseDuringValidation" || key === "allowParallelReadOnly" || key === "allowParallelPlanning" || key === "allowParallelExecution" || key === "allowParallelRepair" || key === "allowParallelReview" || key === "allowParallelValidation" || key === "allowParallelEdits" || key === "requireParallelEditConflictProtection" || key === "allowBackgroundSubagents")) {
|
|
16904
17221
|
if (bool === undefined) return show(pi, "# Error\n\nUsage: `/workflow-settings set subagents <enabled|activityIndicatorEnabled|autoUseDuringPlanning|autoUseDuringExecution|autoUseDuringRepair|autoUseDuringReview|autoUseDuringValidation|allowParallelReadOnly|allowParallelPlanning|allowParallelExecution|allowParallelRepair|allowParallelReview|allowParallelValidation|allowParallelEdits|requireParallelEditConflictProtection> <true|false>`");
|
|
16905
17222
|
const result = updateSettings(ctx.cwd, scope, (s) => {
|
|
@@ -17022,7 +17339,12 @@ Pi Version: v${VERSION}
|
|
|
17022
17339
|
return show(pi, updatedMessage(result.scope, result.file, "context.customCompactionEnabled", String(bool)));
|
|
17023
17340
|
}
|
|
17024
17341
|
if (subject === "context" && key === "autoCompactionEnabled") {
|
|
17025
|
-
|
|
17342
|
+
const normalizedValue = String(value ?? "").trim().toLowerCase();
|
|
17343
|
+
if (normalizedValue === "default" || normalizedValue === "reset") {
|
|
17344
|
+
const result = updateSettings(ctx.cwd, scope, (s) => { delete s.context.autoCompactionEnabled; });
|
|
17345
|
+
return show(pi, updatedMessage(result.scope, result.file, "context.autoCompactionEnabled", "Pi default") + `\n\n${compactionTriggerStatus(result.settings)}`);
|
|
17346
|
+
}
|
|
17347
|
+
if (bool === undefined) return show(pi, "# Error\n\nUsage: `/workflow-settings set context autoCompactionEnabled <true|false|default>`");
|
|
17026
17348
|
const result = updateSettings(ctx.cwd, scope, (s) => { s.context.autoCompactionEnabled = bool; });
|
|
17027
17349
|
return show(pi, updatedMessage(result.scope, result.file, "context.autoCompactionEnabled", String(bool)) + `\n\n${compactionTriggerStatus(result.settings)}`);
|
|
17028
17350
|
}
|
|
@@ -17036,18 +17358,18 @@ Pi Version: v${VERSION}
|
|
|
17036
17358
|
const normalizedValue = String(value ?? "").trim().toLowerCase();
|
|
17037
17359
|
if (key === "compactionTriggerPercent" && (normalizedValue === "default" || normalizedValue === "reset")) {
|
|
17038
17360
|
const result = updateSettings(ctx.cwd, scope, (s) => { delete s.context.compactionTriggerPercent; });
|
|
17039
|
-
return show(pi, updatedMessage(result.scope, result.file, "context.compactionTriggerPercent", "removed override; Pi
|
|
17361
|
+
return show(pi, updatedMessage(result.scope, result.file, "context.compactionTriggerPercent", "removed override; Pi native formula applies") + `\n\n${compactionTriggerStatus(result.settings)}`);
|
|
17040
17362
|
}
|
|
17041
|
-
if ((key === "customCompactionReserveTokens" || key === "customCompactionKeepRecentTokens") && (normalizedValue === "default" || normalizedValue === "reset")) {
|
|
17042
|
-
const fallback = key === "customCompactionReserveTokens" ? DEFAULT_PI_COMPACTION_RESERVE_TOKENS : DEFAULT_PI_COMPACTION_KEEP_RECENT_TOKENS;
|
|
17363
|
+
if ((key === "compactionCooldownMinutes" || key === "customCompactionReserveTokens" || key === "customCompactionKeepRecentTokens") && (normalizedValue === "default" || normalizedValue === "reset")) {
|
|
17364
|
+
const fallback = key === "compactionCooldownMinutes" ? 5 : key === "customCompactionReserveTokens" ? DEFAULT_PI_COMPACTION_RESERVE_TOKENS : DEFAULT_PI_COMPACTION_KEEP_RECENT_TOKENS;
|
|
17043
17365
|
const result = updateSettings(ctx.cwd, scope, (s) => { (s.context as typeof s.context & Record<string, number>)[key] = fallback; });
|
|
17044
|
-
return show(pi, updatedMessage(result.scope, result.file, `context.${key}`, `default ${fallback}`) + `\n\n${compactionTriggerStatus(result.settings)}`);
|
|
17366
|
+
return show(pi, updatedMessage(result.scope, result.file, `context.${key}`, `Pi default ${fallback}`) + `\n\n${compactionTriggerStatus(result.settings)}`);
|
|
17045
17367
|
}
|
|
17046
17368
|
const rawCount = value === undefined ? NaN : Number(value);
|
|
17047
17369
|
const count = Number.isInteger(rawCount) ? rawCount : undefined;
|
|
17048
17370
|
const min = key === "compactionTriggerPercent" ? 50 : key === "compactionCooldownMinutes" ? 0 : key === "customCompactionReserveTokens" ? 4096 : 1000;
|
|
17049
17371
|
const max = key === "compactionTriggerPercent" ? 95 : key === "compactionCooldownMinutes" ? 240 : key === "customCompactionReserveTokens" ? 65536 : 200000;
|
|
17050
|
-
const usage =
|
|
17372
|
+
const usage = `<${min}-${max}|default|reset>`;
|
|
17051
17373
|
if (count === undefined || count < min || count > max) return show(pi, `# Error\n\nUsage: \`/workflow-settings set context ${key} ${usage}\``);
|
|
17052
17374
|
const result = updateSettings(ctx.cwd, scope, (s) => { (s.context as typeof s.context & Record<string, number>)[key] = count; });
|
|
17053
17375
|
return show(pi, updatedMessage(result.scope, result.file, `context.${key}`, String(count)) + `\n\n${compactionTriggerStatus(result.settings)}`);
|