Add configurable automation tool access with live manual-run streaming for schedules and routines. - Add an automation tool allowlist model and dashboard selectors for AI prompt steps. - Stream manual automation and routine run progress, output, step updates, and tool events over SSE. - Surface live run transcripts in automation/routine cards and document the operator workflow. - Cover validation, runner callbacks, API streaming, and UI behavior with targeted tests. Files changed: .changeset/fn-7038-automation-tools-live-output.md | 7 + docs/dashboard-guide.md | 9 + packages/core/src/__tests__/automation.test.ts | 27 +- packages/core/src/automation.ts | 18 + packages/core/src/index.ts | 4 +- packages/core/src/types.ts | 6 + packages/dashboard/app/api/legacy.ts | 48 +++ packages/dashboard/app/components/RoutineCard.tsx | 16 +- packages/dashboard/app/components/ScheduleForm.tsx | 53 ++- .../app/components/ScheduleStepsEditor.tsx | 49 ++- .../app/components/ScheduledTasksModal.tsx | 72 +++- packages/dashboard/app/components/ScriptsModal.css | 79 ++++ .../app/components/__tests__/RoutineCard.test.tsx | 45 +++ .../app/components/__tests__/ScheduleForm.test.tsx | 100 +++++- .../__tests__/ScheduleStepsEditor.test.tsx | 67 +++- .../__tests__/ScheduledTasksModal.test.tsx | 36 +- .../src/__tests__/routes-automation.test.ts | 151 +++++++- packages/dashboard/src/routes.ts | 400 ++++++++++++++++++++- packages/dashboard/src/server.ts | 7 +- packages/engine/src/__tests__/cron-runner.test.ts | 56 ++- .../src/__tests__/pi-create-fn-agent.test.ts | 44 +++ .../engine/src/__tests__/routine-runner.test.ts | 28 ++ packages/engine/src/cron-runner.ts | 20 +- packages/engine/src/pi.ts | 32 +- packages/engine/src/routine-runner.ts | 39 +- packages/i18n/locales/en/app.json | 9 + packages/i18n/src/resources.d.ts | 21 ++ 27 files changed, 1374 insertions(+), 69 deletions(-) Fusion-Task-Id: FN-7038 Fusion-Task-Lineage: 7f5871d0-1de0-4d22-a9c9-ee9418658677
174 lines
6.6 KiB
TypeScript
174 lines
6.6 KiB
TypeScript
/** Schedule type presets plus a custom cron option. */
|
|
export type ScheduleType = "hourly" | "daily" | "weekly" | "monthly" | "custom" | "every15Minutes" | "every30Minutes" | "every2Hours" | "every6Hours" | "every12Hours" | "weekdays";
|
|
|
|
/** Mapping from preset schedule types to their cron expressions. */
|
|
export const AUTOMATION_PRESETS: Record<Exclude<ScheduleType, "custom">, string> = {
|
|
hourly: "0 * * * *",
|
|
daily: "0 0 * * *",
|
|
weekly: "0 0 * * 1",
|
|
monthly: "0 0 1 * *",
|
|
every15Minutes: "*/15 * * * *",
|
|
every30Minutes: "*/30 * * * *",
|
|
every2Hours: "0 */2 * * *",
|
|
every6Hours: "0 */6 * * *",
|
|
every12Hours: "0 */12 * * *",
|
|
weekdays: "0 9 * * 1-5",
|
|
};
|
|
|
|
// ── Automation Step Types ────────────────────────────────────────────
|
|
|
|
/**
|
|
* Builtin tool names that automation AI-prompt steps can expose in the dashboard selector.
|
|
*
|
|
* FNXC:AutomationTools 2026-06-26-00:00:
|
|
* Automation AI steps default to every selectable coding tool for backward-compatible legacy schedules. Persist an explicit allowlist only when the operator narrows the set; an empty allowlist intentionally means no tools.
|
|
*/
|
|
export const AUTOMATION_SELECTABLE_TOOLS = ["Read", "Bash", "Edit", "Write", "Grep", "Find", "Ls"] as const;
|
|
|
|
/** Selectable automation AI tool name. */
|
|
export type AutomationSelectableTool = (typeof AUTOMATION_SELECTABLE_TOOLS)[number];
|
|
|
|
/** The type of an automation step. */
|
|
export type AutomationStepType = "command" | "ai-prompt" | "create-task";
|
|
|
|
/** A single step within a multi-step scheduled task. */
|
|
export interface AutomationStep {
|
|
/** Unique step identifier (UUID). */
|
|
id: string;
|
|
/** The type of this step. */
|
|
type: AutomationStepType;
|
|
/** Human-readable step name. */
|
|
name: string;
|
|
/** Shell command to execute (for command steps). */
|
|
command?: string;
|
|
/** AI prompt to run (for ai-prompt steps). */
|
|
prompt?: string;
|
|
/** AI model provider (for ai-prompt steps). */
|
|
modelProvider?: string;
|
|
/** AI model ID (for ai-prompt steps). */
|
|
modelId?: string;
|
|
/**
|
|
* Optional tool allowlist for ai-prompt steps.
|
|
*
|
|
* FNXC:Automations 2026-06-26-00:00:
|
|
* Undefined means the agent receives all automation coding tools by default. A provided array restricts the agent to those tool names, and an empty array deliberately runs the prompt with no tools.
|
|
*/
|
|
allowedTools?: string[];
|
|
/** Task title for the created task (for create-task steps). */
|
|
taskTitle?: string;
|
|
/** Task description for the created task (for create-task steps). */
|
|
taskDescription?: string;
|
|
/** Target column for the created task (for create-task steps). Defaults to "triage". */
|
|
taskColumn?: string;
|
|
/** Per-step timeout override in milliseconds. */
|
|
timeoutMs?: number;
|
|
/** Whether to continue to the next step if this one fails. Default: false. */
|
|
continueOnFailure?: boolean;
|
|
}
|
|
|
|
/** Result of executing a single automation step. */
|
|
export interface AutomationStepResult {
|
|
/** Step ID that produced this result. */
|
|
stepId: string;
|
|
/** Step name (for display). */
|
|
stepName: string;
|
|
/** Zero-based index of the step. */
|
|
stepIndex: number;
|
|
/** Whether the step completed successfully. */
|
|
success: boolean;
|
|
/** Output from the step. */
|
|
output: string;
|
|
/** Error message if the step failed. */
|
|
error?: string;
|
|
/** ISO-8601 timestamp of when this step started. */
|
|
startedAt: string;
|
|
/** ISO-8601 timestamp of when this step completed. */
|
|
completedAt: string;
|
|
}
|
|
|
|
/** Result of a single automation run. */
|
|
export interface AutomationRunResult {
|
|
success: boolean;
|
|
output: string;
|
|
error?: string;
|
|
startedAt: string;
|
|
completedAt: string;
|
|
/** Per-step results (present only for multi-step schedules). */
|
|
stepResults?: AutomationStepResult[];
|
|
}
|
|
|
|
/** A scheduled automation task. */
|
|
export interface ScheduledTask {
|
|
/** Unique identifier for this schedule (UUID). */
|
|
id: string;
|
|
/** Human-readable name for this schedule. */
|
|
name: string;
|
|
/** Optional description of what this schedule does. */
|
|
description?: string;
|
|
/** The type of schedule — preset or custom. */
|
|
scheduleType: ScheduleType;
|
|
/** The cron expression (auto-derived from preset or user-supplied for custom). */
|
|
cronExpression: string;
|
|
/** The shell command to execute (legacy single-command mode). */
|
|
command: string;
|
|
/** Multi-step workflow. When present, steps execute sequentially instead of `command`. */
|
|
steps?: AutomationStep[];
|
|
/** Index of the step currently being executed (runtime only, not persisted as running state). */
|
|
currentStepIndex?: number;
|
|
/** Whether this schedule is currently active. */
|
|
enabled: boolean;
|
|
/** ISO-8601 timestamp of the last run start, if any. */
|
|
lastRunAt?: string;
|
|
/** Result of the most recent run, if any. */
|
|
lastRunResult?: AutomationRunResult;
|
|
/** ISO-8601 timestamp of the next scheduled run. */
|
|
nextRunAt?: string;
|
|
/** Total number of runs executed. */
|
|
runCount: number;
|
|
/** Per-schedule execution timeout in milliseconds. Default: 300000 (5 min). */
|
|
timeoutMs?: number;
|
|
/** History of recent run results (most recent first, capped at 50). */
|
|
runHistory: AutomationRunResult[];
|
|
/** Scope of this schedule: "global" (shared) or "project" (isolated). */
|
|
scope?: "global" | "project";
|
|
/** ISO-8601 timestamp of when this schedule was created. */
|
|
createdAt: string;
|
|
/** ISO-8601 timestamp of when this schedule was last updated. */
|
|
updatedAt: string;
|
|
}
|
|
|
|
/** Input for creating a new scheduled task. */
|
|
export interface ScheduledTaskCreateInput {
|
|
name: string;
|
|
description?: string;
|
|
scheduleType: ScheduleType;
|
|
/** Required for 'custom' type; ignored for presets (auto-derived). */
|
|
cronExpression?: string;
|
|
/** Shell command (legacy single-command mode). Required if `steps` is not provided. */
|
|
command: string;
|
|
enabled?: boolean;
|
|
timeoutMs?: number;
|
|
/** Multi-step workflow. When provided, `command` is ignored in favor of sequential step execution. */
|
|
steps?: AutomationStep[];
|
|
/** Scope of this schedule: "global" (shared) or "project" (isolated). Default: "project". */
|
|
scope?: "global" | "project";
|
|
}
|
|
|
|
/** Input for updating an existing scheduled task. */
|
|
export interface ScheduledTaskUpdateInput {
|
|
name?: string;
|
|
description?: string;
|
|
scheduleType?: ScheduleType;
|
|
cronExpression?: string;
|
|
command?: string;
|
|
enabled?: boolean;
|
|
timeoutMs?: number;
|
|
/** Multi-step workflow. When provided, `command` is ignored in favor of sequential step execution. */
|
|
steps?: AutomationStep[];
|
|
/** Scope of this schedule: "global" (shared) or "project" (isolated). */
|
|
scope?: "global" | "project";
|
|
}
|
|
|
|
/** Maximum number of run history entries to retain per schedule. */
|
|
export const MAX_RUN_HISTORY = 50;
|