praisonai-code 0.0.1__py3-none-any.whl
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.
- praisonai_code/__init__.py +17 -0
- praisonai_code/cli/__init__.py +12 -0
- praisonai_code/cli/_forward_shim.py +10 -0
- praisonai_code/cli/_paths.py +88 -0
- praisonai_code/cli/_warnings.py +58 -0
- praisonai_code/cli/app.py +757 -0
- praisonai_code/cli/approval_backend.py +272 -0
- praisonai_code/cli/branding.py +94 -0
- praisonai_code/cli/commands/__init__.py +114 -0
- praisonai_code/cli/commands/acp.py +80 -0
- praisonai_code/cli/commands/agent.py +116 -0
- praisonai_code/cli/commands/agents.py +80 -0
- praisonai_code/cli/commands/app.py +139 -0
- praisonai_code/cli/commands/attach.py +95 -0
- praisonai_code/cli/commands/audit.py +102 -0
- praisonai_code/cli/commands/auth.py +508 -0
- praisonai_code/cli/commands/batch.py +848 -0
- praisonai_code/cli/commands/benchmark.py +286 -0
- praisonai_code/cli/commands/browser.py +299 -0
- praisonai_code/cli/commands/call.py +45 -0
- praisonai_code/cli/commands/chat.py +332 -0
- praisonai_code/cli/commands/checkpoint.py +170 -0
- praisonai_code/cli/commands/code.py +276 -0
- praisonai_code/cli/commands/command.py +114 -0
- praisonai_code/cli/commands/commit.py +47 -0
- praisonai_code/cli/commands/completion.py +333 -0
- praisonai_code/cli/commands/config.py +681 -0
- praisonai_code/cli/commands/context.py +414 -0
- praisonai_code/cli/commands/daemon.py +203 -0
- praisonai_code/cli/commands/debug.py +142 -0
- praisonai_code/cli/commands/deploy.py +71 -0
- praisonai_code/cli/commands/diag.py +55 -0
- praisonai_code/cli/commands/docs.py +1575 -0
- praisonai_code/cli/commands/doctor.py +332 -0
- praisonai_code/cli/commands/endpoints.py +51 -0
- praisonai_code/cli/commands/environment.py +179 -0
- praisonai_code/cli/commands/eval.py +131 -0
- praisonai_code/cli/commands/examples.py +953 -0
- praisonai_code/cli/commands/flow.py +436 -0
- praisonai_code/cli/commands/github.py +752 -0
- praisonai_code/cli/commands/hooks.py +74 -0
- praisonai_code/cli/commands/init.py +174 -0
- praisonai_code/cli/commands/knowledge.py +440 -0
- praisonai_code/cli/commands/langextract.py +120 -0
- praisonai_code/cli/commands/langfuse.py +984 -0
- praisonai_code/cli/commands/loop.py +211 -0
- praisonai_code/cli/commands/lsp.py +112 -0
- praisonai_code/cli/commands/managed.py +659 -0
- praisonai_code/cli/commands/mcp.py +763 -0
- praisonai_code/cli/commands/memory.py +298 -0
- praisonai_code/cli/commands/models.py +264 -0
- praisonai_code/cli/commands/n8n.py +326 -0
- praisonai_code/cli/commands/obs.py +19 -0
- praisonai_code/cli/commands/package.py +76 -0
- praisonai_code/cli/commands/paths.py +106 -0
- praisonai_code/cli/commands/permissions.py +272 -0
- praisonai_code/cli/commands/plugins.py +609 -0
- praisonai_code/cli/commands/port.py +530 -0
- praisonai_code/cli/commands/profile.py +466 -0
- praisonai_code/cli/commands/publish.py +193 -0
- praisonai_code/cli/commands/rag.py +913 -0
- praisonai_code/cli/commands/realtime.py +52 -0
- praisonai_code/cli/commands/recipe.py +684 -0
- praisonai_code/cli/commands/registry.py +59 -0
- praisonai_code/cli/commands/replay.py +830 -0
- praisonai_code/cli/commands/research.py +49 -0
- praisonai_code/cli/commands/retrieval.py +377 -0
- praisonai_code/cli/commands/rules.py +71 -0
- praisonai_code/cli/commands/run.py +1573 -0
- praisonai_code/cli/commands/sandbox.py +371 -0
- praisonai_code/cli/commands/schedule.py +529 -0
- praisonai_code/cli/commands/serve.py +690 -0
- praisonai_code/cli/commands/session.py +450 -0
- praisonai_code/cli/commands/setup.py +174 -0
- praisonai_code/cli/commands/skills.py +545 -0
- praisonai_code/cli/commands/standardise.py +711 -0
- praisonai_code/cli/commands/templates.py +54 -0
- praisonai_code/cli/commands/test.py +558 -0
- praisonai_code/cli/commands/todo.py +74 -0
- praisonai_code/cli/commands/tools.py +205 -0
- praisonai_code/cli/commands/traces.py +145 -0
- praisonai_code/cli/commands/tracker.py +852 -0
- praisonai_code/cli/commands/train.py +613 -0
- praisonai_code/cli/commands/ui.py +172 -0
- praisonai_code/cli/commands/up.py +354 -0
- praisonai_code/cli/commands/validate.py +291 -0
- praisonai_code/cli/commands/version.py +101 -0
- praisonai_code/cli/commands/workflow.py +97 -0
- praisonai_code/cli/config_loader.py +437 -0
- praisonai_code/cli/configuration/__init__.py +27 -0
- praisonai_code/cli/configuration/config.schema.json +57 -0
- praisonai_code/cli/configuration/credentials.py +446 -0
- praisonai_code/cli/configuration/loader.py +364 -0
- praisonai_code/cli/configuration/model_resolver.py +161 -0
- praisonai_code/cli/configuration/oauth.py +389 -0
- praisonai_code/cli/configuration/paths.py +224 -0
- praisonai_code/cli/configuration/resolver.py +687 -0
- praisonai_code/cli/configuration/schema.py +317 -0
- praisonai_code/cli/execution/__init__.py +99 -0
- praisonai_code/cli/execution/core.py +208 -0
- praisonai_code/cli/execution/profiler.py +898 -0
- praisonai_code/cli/execution/request.py +85 -0
- praisonai_code/cli/execution/result.py +74 -0
- praisonai_code/cli/fallback_schema.py +416 -0
- praisonai_code/cli/features/__init__.py +278 -0
- praisonai_code/cli/features/_endpoint_registry.py +64 -0
- praisonai_code/cli/features/_search_registry.py +43 -0
- praisonai_code/cli/features/acp.py +236 -0
- praisonai_code/cli/features/action_orchestrator.py +576 -0
- praisonai_code/cli/features/agent_scheduler.py +773 -0
- praisonai_code/cli/features/agent_tools.py +603 -0
- praisonai_code/cli/features/agents.py +397 -0
- praisonai_code/cli/features/at_mentions.py +471 -0
- praisonai_code/cli/features/audit_cli.py +270 -0
- praisonai_code/cli/features/auto_memory.py +182 -0
- praisonai_code/cli/features/auto_mode.py +552 -0
- praisonai_code/cli/features/autonomy_mode.py +546 -0
- praisonai_code/cli/features/background.py +356 -0
- praisonai_code/cli/features/base.py +168 -0
- praisonai_code/cli/features/benchmark.py +1462 -0
- praisonai_code/cli/features/capabilities.py +1326 -0
- praisonai_code/cli/features/checkpoints.py +345 -0
- praisonai_code/cli/features/cli_profiler.py +335 -0
- praisonai_code/cli/features/code_intelligence.py +666 -0
- praisonai_code/cli/features/compaction.py +294 -0
- praisonai_code/cli/features/compare.py +534 -0
- praisonai_code/cli/features/config_hierarchy.py +366 -0
- praisonai_code/cli/features/context_manager.py +597 -0
- praisonai_code/cli/features/cost_tracker.py +514 -0
- praisonai_code/cli/features/csv_test_runner.py +736 -0
- praisonai_code/cli/features/custom_definitions.py +790 -0
- praisonai_code/cli/features/debug.py +810 -0
- praisonai_code/cli/features/deploy.py +605 -0
- praisonai_code/cli/features/diag.py +289 -0
- praisonai_code/cli/features/display_jsonl.py +173 -0
- praisonai_code/cli/features/doctor/__init__.py +63 -0
- praisonai_code/cli/features/doctor/checks/__init__.py +29 -0
- praisonai_code/cli/features/doctor/checks/acp_checks.py +220 -0
- praisonai_code/cli/features/doctor/checks/bot_checks.py +340 -0
- praisonai_code/cli/features/doctor/checks/config_checks.py +373 -0
- praisonai_code/cli/features/doctor/checks/db_checks.py +366 -0
- praisonai_code/cli/features/doctor/checks/env_checks.py +637 -0
- praisonai_code/cli/features/doctor/checks/gateway_checks.py +387 -0
- praisonai_code/cli/features/doctor/checks/lsp_checks.py +231 -0
- praisonai_code/cli/features/doctor/checks/mcp_checks.py +367 -0
- praisonai_code/cli/features/doctor/checks/memory_checks.py +268 -0
- praisonai_code/cli/features/doctor/checks/network_checks.py +251 -0
- praisonai_code/cli/features/doctor/checks/obs_checks.py +328 -0
- praisonai_code/cli/features/doctor/checks/packaging_checks.py +422 -0
- praisonai_code/cli/features/doctor/checks/performance_checks.py +235 -0
- praisonai_code/cli/features/doctor/checks/permissions_checks.py +259 -0
- praisonai_code/cli/features/doctor/checks/runtime_checks.py +650 -0
- praisonai_code/cli/features/doctor/checks/runtime_migration_checks.py +220 -0
- praisonai_code/cli/features/doctor/checks/selftest_checks.py +322 -0
- praisonai_code/cli/features/doctor/checks/serve_checks.py +426 -0
- praisonai_code/cli/features/doctor/checks/skills_checks.py +327 -0
- praisonai_code/cli/features/doctor/checks/tools_checks.py +371 -0
- praisonai_code/cli/features/doctor/engine.py +266 -0
- praisonai_code/cli/features/doctor/formatters.py +377 -0
- praisonai_code/cli/features/doctor/handler.py +564 -0
- praisonai_code/cli/features/doctor/models.py +276 -0
- praisonai_code/cli/features/doctor/registry.py +239 -0
- praisonai_code/cli/features/endpoints.py +1016 -0
- praisonai_code/cli/features/eval.py +559 -0
- praisonai_code/cli/features/examples.py +707 -0
- praisonai_code/cli/features/external_agents.py +231 -0
- praisonai_code/cli/features/fast_context.py +410 -0
- praisonai_code/cli/features/file_history.py +320 -0
- praisonai_code/cli/features/flow_display.py +566 -0
- praisonai_code/cli/features/git_attribution.py +159 -0
- praisonai_code/cli/features/git_integration.py +651 -0
- praisonai_code/cli/features/guardrail.py +171 -0
- praisonai_code/cli/features/handoff.py +252 -0
- praisonai_code/cli/features/hooks.py +583 -0
- praisonai_code/cli/features/hybrid_workflow.py +391 -0
- praisonai_code/cli/features/image.py +384 -0
- praisonai_code/cli/features/interactive_core_headless.py +450 -0
- praisonai_code/cli/features/interactive_runtime.py +600 -0
- praisonai_code/cli/features/interactive_test_harness.py +537 -0
- praisonai_code/cli/features/interactive_tools.py +428 -0
- praisonai_code/cli/features/interactive_tui.py +603 -0
- praisonai_code/cli/features/job_workflow.py +906 -0
- praisonai_code/cli/features/jobs.py +632 -0
- praisonai_code/cli/features/knowledge.py +531 -0
- praisonai_code/cli/features/knowledge_cli.py +438 -0
- praisonai_code/cli/features/lite.py +244 -0
- praisonai_code/cli/features/logs.py +200 -0
- praisonai_code/cli/features/lsp_cli.py +225 -0
- praisonai_code/cli/features/lsp_diagnostics.py +185 -0
- praisonai_code/cli/features/mcp.py +344 -0
- praisonai_code/cli/features/message_queue.py +587 -0
- praisonai_code/cli/features/metrics.py +210 -0
- praisonai_code/cli/features/migrate.py +1329 -0
- praisonai_code/cli/features/migration_flow.py +463 -0
- praisonai_code/cli/features/migration_spec.py +276 -0
- praisonai_code/cli/features/n8n.py +703 -0
- praisonai_code/cli/features/observability.py +293 -0
- praisonai_code/cli/features/ollama.py +361 -0
- praisonai_code/cli/features/output_modes.py +155 -0
- praisonai_code/cli/features/output_style.py +273 -0
- praisonai_code/cli/features/package.py +631 -0
- praisonai_code/cli/features/performance.py +308 -0
- praisonai_code/cli/features/persistence.py +636 -0
- praisonai_code/cli/features/profiler/__init__.py +81 -0
- praisonai_code/cli/features/profiler/core.py +558 -0
- praisonai_code/cli/features/profiler/optimizations.py +652 -0
- praisonai_code/cli/features/profiler/suite.py +386 -0
- praisonai_code/cli/features/queue/__init__.py +73 -0
- praisonai_code/cli/features/queue/manager.py +435 -0
- praisonai_code/cli/features/queue/models.py +289 -0
- praisonai_code/cli/features/queue/persistence.py +564 -0
- praisonai_code/cli/features/queue/scheduler.py +529 -0
- praisonai_code/cli/features/queue/worker.py +400 -0
- praisonai_code/cli/features/recipe.py +2187 -0
- praisonai_code/cli/features/recipe_creator.py +996 -0
- praisonai_code/cli/features/recipe_optimizer.py +1364 -0
- praisonai_code/cli/features/recipe_prompts.py +226 -0
- praisonai_code/cli/features/registry.py +229 -0
- praisonai_code/cli/features/repo_map.py +860 -0
- praisonai_code/cli/features/router.py +466 -0
- praisonai_code/cli/features/safe_shell.py +427 -0
- praisonai_code/cli/features/sandbox_cli.py +283 -0
- praisonai_code/cli/features/sandbox_executor.py +536 -0
- praisonai_code/cli/features/sdk_knowledge.py +500 -0
- praisonai_code/cli/features/session.py +222 -0
- praisonai_code/cli/features/session_checkpoints.py +208 -0
- praisonai_code/cli/features/setup/__init__.py +9 -0
- praisonai_code/cli/features/setup/handler.py +355 -0
- praisonai_code/cli/features/setup/templates.py +62 -0
- praisonai_code/cli/features/skills.py +940 -0
- praisonai_code/cli/features/slash_commands.py +692 -0
- praisonai_code/cli/features/telemetry.py +179 -0
- praisonai_code/cli/features/templates.py +1390 -0
- praisonai_code/cli/features/thinking.py +343 -0
- praisonai_code/cli/features/todo.py +334 -0
- praisonai_code/cli/features/tools.py +680 -0
- praisonai_code/cli/features/tui/__init__.py +83 -0
- praisonai_code/cli/features/tui/app.py +871 -0
- praisonai_code/cli/features/tui/cli.py +580 -0
- praisonai_code/cli/features/tui/config.py +150 -0
- praisonai_code/cli/features/tui/debug.py +526 -0
- praisonai_code/cli/features/tui/events.py +99 -0
- praisonai_code/cli/features/tui/mock_provider.py +328 -0
- praisonai_code/cli/features/tui/orchestrator.py +652 -0
- praisonai_code/cli/features/tui/screens/__init__.py +50 -0
- praisonai_code/cli/features/tui/screens/help.py +157 -0
- praisonai_code/cli/features/tui/screens/main.py +568 -0
- praisonai_code/cli/features/tui/screens/queue.py +174 -0
- praisonai_code/cli/features/tui/screens/session.py +124 -0
- praisonai_code/cli/features/tui/screens/settings.py +148 -0
- praisonai_code/cli/features/tui/session_store.py +198 -0
- praisonai_code/cli/features/tui/widgets/__init__.py +56 -0
- praisonai_code/cli/features/tui/widgets/chat.py +263 -0
- praisonai_code/cli/features/tui/widgets/command_popup.py +258 -0
- praisonai_code/cli/features/tui/widgets/composer.py +292 -0
- praisonai_code/cli/features/tui/widgets/file_popup.py +207 -0
- praisonai_code/cli/features/tui/widgets/queue_panel.py +223 -0
- praisonai_code/cli/features/tui/widgets/status.py +181 -0
- praisonai_code/cli/features/tui/widgets/tool_panel.py +307 -0
- praisonai_code/cli/features/wizard.py +289 -0
- praisonai_code/cli/features/workflow.py +802 -0
- praisonai_code/cli/features/yaml_utils.py +321 -0
- praisonai_code/cli/interactive/__init__.py +48 -0
- praisonai_code/cli/interactive/async_tui.py +1218 -0
- praisonai_code/cli/interactive/config.py +139 -0
- praisonai_code/cli/interactive/core.py +618 -0
- praisonai_code/cli/interactive/events.py +131 -0
- praisonai_code/cli/interactive/frontends/__init__.py +31 -0
- praisonai_code/cli/interactive/frontends/rich_frontend.py +462 -0
- praisonai_code/cli/interactive/frontends/textual_frontend.py +157 -0
- praisonai_code/cli/interactive/praison_io.py +502 -0
- praisonai_code/cli/interactive/repl.py +297 -0
- praisonai_code/cli/interactive/split_tui.py +456 -0
- praisonai_code/cli/interactive/tui_app.py +457 -0
- praisonai_code/cli/langfuse_client.py +360 -0
- praisonai_code/cli/main.py +7421 -0
- praisonai_code/cli/output/__init__.py +25 -0
- praisonai_code/cli/output/console.py +456 -0
- praisonai_code/cli/output/event_bridge.py +191 -0
- praisonai_code/cli/schedule_cli.py +54 -0
- praisonai_code/cli/schema_provider.py +23 -0
- praisonai_code/cli/session/__init__.py +16 -0
- praisonai_code/cli/session/resume.py +148 -0
- praisonai_code/cli/session/unified.py +548 -0
- praisonai_code/cli/state/__init__.py +31 -0
- praisonai_code/cli/state/identifiers.py +161 -0
- praisonai_code/cli/state/project_sessions.py +383 -0
- praisonai_code/cli/state/sessions.py +390 -0
- praisonai_code/cli/ui/__init__.py +160 -0
- praisonai_code/cli/ui/config.py +46 -0
- praisonai_code/cli/ui/events.py +61 -0
- praisonai_code/cli/ui/mg_backend.py +342 -0
- praisonai_code/cli/ui/plain.py +133 -0
- praisonai_code/cli/ui/rich_backend.py +162 -0
- praisonai_code/cli/unified_schema.py +655 -0
- praisonai_code/cli/utils/env_utils.py +126 -0
- praisonai_code/cli/utils/project.py +131 -0
- praisonai_code/cli_backends/__init__.py +73 -0
- praisonai_code/cli_backends/claude.py +373 -0
- praisonai_code/cli_backends/registry.py +113 -0
- praisonai_code/runtime/__init__.py +36 -0
- praisonai_code/runtime/__main__.py +81 -0
- praisonai_code/runtime/client.py +131 -0
- praisonai_code/runtime/descriptor.py +209 -0
- praisonai_code/runtime/server.py +356 -0
- praisonai_code-0.0.1.dist-info/METADATA +80 -0
- praisonai_code-0.0.1.dist-info/RECORD +309 -0
- praisonai_code-0.0.1.dist-info/WHEEL +5 -0
- praisonai_code-0.0.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,529 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Schedule command group for PraisonAI CLI.
|
|
3
|
+
|
|
4
|
+
Provides scheduler management.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import Optional
|
|
8
|
+
|
|
9
|
+
import typer
|
|
10
|
+
|
|
11
|
+
from ..output.console import get_output_controller
|
|
12
|
+
|
|
13
|
+
app = typer.Typer(help="Scheduler management")
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _run_schedule(args: list) -> int:
|
|
17
|
+
"""Run schedule command with args."""
|
|
18
|
+
try:
|
|
19
|
+
from praisonai.cli.features.agent_scheduler import AgentSchedulerHandler
|
|
20
|
+
|
|
21
|
+
# Parse subcommand
|
|
22
|
+
if args and args[0] in ['start', 'list', 'stop', 'logs', 'restart', 'delete', 'describe', 'save', 'stop-all', 'stats']:
|
|
23
|
+
subcommand = args[0]
|
|
24
|
+
remaining = args[1:] if len(args) > 1 else []
|
|
25
|
+
|
|
26
|
+
# Create minimal args namespace
|
|
27
|
+
class Args:
|
|
28
|
+
pass
|
|
29
|
+
|
|
30
|
+
fake_args = Args()
|
|
31
|
+
return AgentSchedulerHandler.handle_daemon_command(subcommand, fake_args, remaining)
|
|
32
|
+
|
|
33
|
+
return 0
|
|
34
|
+
except ImportError as e:
|
|
35
|
+
output = get_output_controller()
|
|
36
|
+
output.print_error(f"Scheduler module not available: {e}")
|
|
37
|
+
return 4
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@app.command("add")
|
|
41
|
+
def schedule_add_cmd(
|
|
42
|
+
name: str = typer.Argument(..., help="Schedule name (e.g. 'morning-hello')"),
|
|
43
|
+
schedule: str = typer.Option(..., "--schedule", "-s", help="When to run: 'hourly', 'daily', '*/30m', 'cron:0 9 * * *', 'at:2026-03-01T09:00', 'in 20 minutes'"),
|
|
44
|
+
message: str = typer.Option("", "--message", "-m", help="Prompt / reminder text"),
|
|
45
|
+
agent: str = typer.Option("", "--agent", "-a", help="Agent ID to execute this job (default: first registered agent)"),
|
|
46
|
+
deliver: str = typer.Option("", "--deliver", "-d", help="Delivery token: 'origin', 'telegram', 'all', or 'platform:chat_id[:thread_id]'"),
|
|
47
|
+
channel: str = typer.Option("", "--channel", help="[Legacy] Delivery platform: telegram, discord, slack, whatsapp"),
|
|
48
|
+
channel_id: str = typer.Option("", "--channel-id", help="[Legacy] Target chat/channel ID on the platform"),
|
|
49
|
+
session_id: str = typer.Option("", "--session-id", help="Session ID to preserve conversation context"),
|
|
50
|
+
pre_run: str = typer.Option("", "--pre-run", help="Cheap pre-run gate command: exit 0 + output => run (output seeds the prompt); non-zero => skip (no model tokens, no delivery)"),
|
|
51
|
+
condition: str = typer.Option("", "--condition", help="Natural-language / expression alias for the pre-run gate"),
|
|
52
|
+
json_output: bool = typer.Option(False, "--json", help="Output JSON"),
|
|
53
|
+
):
|
|
54
|
+
"""Add a job to the schedule store (with optional delivery target).
|
|
55
|
+
|
|
56
|
+
Examples:
|
|
57
|
+
praisonai schedule add "morning-hello" -s "cron:0 9 * * *" -m "say hello"
|
|
58
|
+
praisonai schedule add "news" -s daily -m "news summary" --deliver telegram
|
|
59
|
+
praisonai schedule add "report" -s hourly -m "status report" --deliver all
|
|
60
|
+
praisonai schedule add "tg-reminder" -s daily -m "check email" --agent support --channel telegram --channel-id 12345
|
|
61
|
+
praisonai schedule add "inbox-watch" -s "*/5m" -m "Summarise new emails" --pre-run "scripts/new_mail.sh" --deliver telegram
|
|
62
|
+
"""
|
|
63
|
+
output = get_output_controller()
|
|
64
|
+
try:
|
|
65
|
+
from praisonaiagents.tools.schedule_tools import schedule_add as _schedule_add
|
|
66
|
+
|
|
67
|
+
# Build delivery target based on new or legacy format
|
|
68
|
+
delivery_kwargs = {}
|
|
69
|
+
if deliver:
|
|
70
|
+
# New token-based delivery
|
|
71
|
+
delivery_kwargs["deliver"] = deliver
|
|
72
|
+
elif channel or channel_id:
|
|
73
|
+
# Legacy explicit channel/channel_id
|
|
74
|
+
delivery_kwargs["channel"] = channel
|
|
75
|
+
delivery_kwargs["channel_id"] = channel_id
|
|
76
|
+
|
|
77
|
+
if session_id:
|
|
78
|
+
delivery_kwargs["session_id"] = session_id
|
|
79
|
+
|
|
80
|
+
result = _schedule_add(
|
|
81
|
+
name=name,
|
|
82
|
+
schedule=schedule,
|
|
83
|
+
message=message,
|
|
84
|
+
agent_id=agent,
|
|
85
|
+
**delivery_kwargs
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
# ``pre_run``/``condition`` run an arbitrary host shell command, so they
|
|
89
|
+
# are NOT part of the LLM-callable schedule_add surface. The CLI is a
|
|
90
|
+
# trusted, human-driven surface, so set them on the stored job here.
|
|
91
|
+
if (pre_run or condition) and "Error" not in result:
|
|
92
|
+
try:
|
|
93
|
+
from praisonaiagents.tools.schedule_tools import _get_store
|
|
94
|
+
store = _get_store()
|
|
95
|
+
job = store.get_by_name(name)
|
|
96
|
+
if job is not None:
|
|
97
|
+
job.pre_run = pre_run or None
|
|
98
|
+
job.condition = condition or None
|
|
99
|
+
store.update(job)
|
|
100
|
+
except Exception as e:
|
|
101
|
+
output.print_error(f"Failed to set pre-run gate: {e}")
|
|
102
|
+
raise typer.Exit(1)
|
|
103
|
+
|
|
104
|
+
if json_output:
|
|
105
|
+
import json as _json
|
|
106
|
+
print(_json.dumps({"result": result}))
|
|
107
|
+
else:
|
|
108
|
+
if "Error" in result:
|
|
109
|
+
output.print_error(result)
|
|
110
|
+
raise typer.Exit(1)
|
|
111
|
+
else:
|
|
112
|
+
output.print_success(result)
|
|
113
|
+
except ImportError as e:
|
|
114
|
+
output.print_error(f"Schedule tools not available: {e}")
|
|
115
|
+
raise typer.Exit(4)
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
@app.command("start")
|
|
119
|
+
def schedule_start(
|
|
120
|
+
agents_file: str = typer.Argument("agents.yaml", help="Agents YAML file"),
|
|
121
|
+
interval: Optional[str] = typer.Option(None, "--interval", "-i", help="Schedule interval (e.g., 'hourly', '*/30m')"),
|
|
122
|
+
daemon: bool = typer.Option(True, "--daemon/--no-daemon", help="Run as daemon"),
|
|
123
|
+
name: Optional[str] = typer.Option(None, "--name", "-n", help="Job name"),
|
|
124
|
+
):
|
|
125
|
+
"""Start scheduled agent execution."""
|
|
126
|
+
args = ["start", agents_file]
|
|
127
|
+
if interval:
|
|
128
|
+
args.extend(["--interval", interval])
|
|
129
|
+
if not daemon:
|
|
130
|
+
args.append("--no-daemon")
|
|
131
|
+
if name:
|
|
132
|
+
args.extend(["--name", name])
|
|
133
|
+
|
|
134
|
+
raise typer.Exit(_run_schedule(args))
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
@app.command("stop")
|
|
138
|
+
def schedule_stop(
|
|
139
|
+
job_id: Optional[str] = typer.Argument(None, help="Job ID to stop (or 'all')"),
|
|
140
|
+
):
|
|
141
|
+
"""Stop scheduled job(s)."""
|
|
142
|
+
if job_id == "all":
|
|
143
|
+
raise typer.Exit(_run_schedule(["stop-all"]))
|
|
144
|
+
elif job_id:
|
|
145
|
+
raise typer.Exit(_run_schedule(["stop", job_id]))
|
|
146
|
+
else:
|
|
147
|
+
raise typer.Exit(_run_schedule(["stop"]))
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
@app.command("list")
|
|
151
|
+
def schedule_list(
|
|
152
|
+
json_output: bool = typer.Option(False, "--json", help="Output JSON"),
|
|
153
|
+
):
|
|
154
|
+
"""List scheduled jobs."""
|
|
155
|
+
args = ["list"]
|
|
156
|
+
if json_output:
|
|
157
|
+
args.append("--json")
|
|
158
|
+
raise typer.Exit(_run_schedule(args))
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
@app.command("logs")
|
|
162
|
+
def schedule_logs(
|
|
163
|
+
job_id: Optional[str] = typer.Argument(None, help="Job ID"),
|
|
164
|
+
tail: int = typer.Option(50, "--tail", "-n", help="Number of lines"),
|
|
165
|
+
follow: bool = typer.Option(False, "--follow", "-f", help="Follow log output"),
|
|
166
|
+
):
|
|
167
|
+
"""View scheduler logs."""
|
|
168
|
+
args = ["logs"]
|
|
169
|
+
if job_id:
|
|
170
|
+
args.append(job_id)
|
|
171
|
+
args.extend(["--tail", str(tail)])
|
|
172
|
+
if follow:
|
|
173
|
+
args.append("--follow")
|
|
174
|
+
raise typer.Exit(_run_schedule(args))
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
@app.command("restart")
|
|
178
|
+
def schedule_restart(
|
|
179
|
+
job_id: str = typer.Argument(..., help="Job ID to restart"),
|
|
180
|
+
):
|
|
181
|
+
"""Restart a scheduled job."""
|
|
182
|
+
raise typer.Exit(_run_schedule(["restart", job_id]))
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
@app.command("delete")
|
|
186
|
+
def schedule_delete(
|
|
187
|
+
job_id: str = typer.Argument(..., help="Job ID to delete"),
|
|
188
|
+
confirm: bool = typer.Option(False, "--yes", "-y", help="Skip confirmation"),
|
|
189
|
+
):
|
|
190
|
+
"""Delete a scheduled job."""
|
|
191
|
+
if not confirm:
|
|
192
|
+
confirmed = typer.confirm(f"Delete job {job_id}?")
|
|
193
|
+
if not confirmed:
|
|
194
|
+
output = get_output_controller()
|
|
195
|
+
output.print_info("Cancelled")
|
|
196
|
+
raise typer.Exit(0)
|
|
197
|
+
|
|
198
|
+
raise typer.Exit(_run_schedule(["delete", job_id]))
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
@app.command("describe")
|
|
202
|
+
def schedule_describe(
|
|
203
|
+
job_id: str = typer.Argument(..., help="Job ID"),
|
|
204
|
+
json_output: bool = typer.Option(False, "--json", help="Output JSON"),
|
|
205
|
+
):
|
|
206
|
+
"""Show job details."""
|
|
207
|
+
args = ["describe", job_id]
|
|
208
|
+
if json_output:
|
|
209
|
+
args.append("--json")
|
|
210
|
+
raise typer.Exit(_run_schedule(args))
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
@app.command("stats")
|
|
214
|
+
def schedule_stats(
|
|
215
|
+
json_output: bool = typer.Option(False, "--json", help="Output JSON"),
|
|
216
|
+
):
|
|
217
|
+
"""Show scheduler statistics."""
|
|
218
|
+
args = ["stats"]
|
|
219
|
+
if json_output:
|
|
220
|
+
args.append("--json")
|
|
221
|
+
raise typer.Exit(_run_schedule(args))
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
# ── Blueprint commands ─────────────────────────────────────────────────
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
@app.command("blueprint")
|
|
228
|
+
def schedule_blueprint(
|
|
229
|
+
blueprint_name: str = typer.Argument(..., help="Blueprint name (morning-brief, important-mail, weekly-review)"),
|
|
230
|
+
hour: Optional[int] = typer.Option(None, "--hour", help="Delivery hour (0-23)"),
|
|
231
|
+
minute: Optional[int] = typer.Option(None, "--minute", help="Delivery minute (0-59)"),
|
|
232
|
+
weekdays: Optional[str] = typer.Option(None, "--weekdays", help="Days: mon-fri, daily, weekends, or a single day"),
|
|
233
|
+
focus: Optional[str] = typer.Option(None, "--focus", help="Focus area"),
|
|
234
|
+
interval: Optional[int] = typer.Option(None, "--interval", help="Interval in minutes (for interval-based blueprints)"),
|
|
235
|
+
keywords: Optional[str] = typer.Option(None, "--keywords", help="Priority keywords (for important-mail)"),
|
|
236
|
+
deliver: str = typer.Option("", "--deliver", "-d", help="Delivery target"),
|
|
237
|
+
agent: str = typer.Option("", "--agent", "-a", help="Agent ID"),
|
|
238
|
+
json_output: bool = typer.Option(False, "--json", help="Output JSON"),
|
|
239
|
+
):
|
|
240
|
+
"""Create a schedule from a blueprint template.
|
|
241
|
+
|
|
242
|
+
Examples:
|
|
243
|
+
praisonai schedule blueprint morning-brief --hour 8 --weekdays mon-fri --deliver telegram
|
|
244
|
+
praisonai schedule blueprint important-mail --interval 30 --keywords urgent,deadline --deliver telegram
|
|
245
|
+
praisonai schedule blueprint weekly-review --hour 17 --weekdays fri --focus tech
|
|
246
|
+
"""
|
|
247
|
+
output = get_output_controller()
|
|
248
|
+
try:
|
|
249
|
+
from praisonai.scheduler.blueprint_catalogue import BlueprintCatalogue
|
|
250
|
+
from praisonaiagents.tools.schedule_tools import schedule_add as _schedule_add
|
|
251
|
+
|
|
252
|
+
catalogue = BlueprintCatalogue()
|
|
253
|
+
bp = catalogue.get_blueprint(blueprint_name)
|
|
254
|
+
if bp is None:
|
|
255
|
+
available = [b.name for b in catalogue.list_blueprints()]
|
|
256
|
+
output.print_error(
|
|
257
|
+
f"Blueprint '{blueprint_name}' not found. "
|
|
258
|
+
f"Available: {', '.join(available)}"
|
|
259
|
+
)
|
|
260
|
+
raise typer.Exit(1)
|
|
261
|
+
|
|
262
|
+
# Build slots dict from CLI args
|
|
263
|
+
cli_slot_map: dict = {
|
|
264
|
+
"hour": hour, "minute": minute, "weekdays": weekdays,
|
|
265
|
+
"focus": focus, "interval_minutes": interval, "keywords": keywords,
|
|
266
|
+
}
|
|
267
|
+
slots = {}
|
|
268
|
+
for slot in bp.slots:
|
|
269
|
+
cli_val = cli_slot_map.get(slot.name)
|
|
270
|
+
if cli_val is not None:
|
|
271
|
+
slots[slot.name] = cli_val
|
|
272
|
+
|
|
273
|
+
resolved = catalogue.resolve_slots(bp, slots)
|
|
274
|
+
prompt = catalogue.materialize_prompt(bp, resolved)
|
|
275
|
+
schedule_expr = catalogue.materialize_schedule(bp, resolved)
|
|
276
|
+
final_deliver = deliver or bp.default_deliver
|
|
277
|
+
|
|
278
|
+
result = _schedule_add(
|
|
279
|
+
name=blueprint_name,
|
|
280
|
+
schedule=schedule_expr,
|
|
281
|
+
message=prompt,
|
|
282
|
+
deliver=final_deliver,
|
|
283
|
+
agent_id=agent or bp.default_agent,
|
|
284
|
+
)
|
|
285
|
+
|
|
286
|
+
if json_output:
|
|
287
|
+
import json as _json
|
|
288
|
+
print(_json.dumps({"result": result, "blueprint": blueprint_name,
|
|
289
|
+
"schedule": schedule_expr}))
|
|
290
|
+
else:
|
|
291
|
+
output.print_success(result)
|
|
292
|
+
except typer.Exit:
|
|
293
|
+
raise
|
|
294
|
+
except Exception as e:
|
|
295
|
+
output.print_error(str(e))
|
|
296
|
+
raise typer.Exit(1)
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
@app.command("blueprint-list")
|
|
300
|
+
def schedule_blueprint_list(
|
|
301
|
+
category: Optional[str] = typer.Option(None, "--category", "-c", help="Filter by category"),
|
|
302
|
+
json_output: bool = typer.Option(False, "--json", help="Output JSON"),
|
|
303
|
+
):
|
|
304
|
+
"""List available blueprints."""
|
|
305
|
+
output = get_output_controller()
|
|
306
|
+
try:
|
|
307
|
+
from praisonai.scheduler.blueprint_catalogue import BlueprintCatalogue
|
|
308
|
+
|
|
309
|
+
catalogue = BlueprintCatalogue()
|
|
310
|
+
blueprints = catalogue.list_blueprints(category=category)
|
|
311
|
+
|
|
312
|
+
if json_output:
|
|
313
|
+
import json as _json
|
|
314
|
+
print(_json.dumps([{
|
|
315
|
+
"name": bp.name,
|
|
316
|
+
"description": bp.description,
|
|
317
|
+
"category": bp.category,
|
|
318
|
+
"tags": bp.tags,
|
|
319
|
+
"slots": [
|
|
320
|
+
{"name": s.name, "type": s.type, "label": s.label,
|
|
321
|
+
"default": s.default, "choices": s.choices}
|
|
322
|
+
for s in bp.slots
|
|
323
|
+
],
|
|
324
|
+
"default_deliver": bp.default_deliver,
|
|
325
|
+
"builtin": bp.builtin,
|
|
326
|
+
} for bp in blueprints]))
|
|
327
|
+
else:
|
|
328
|
+
if not blueprints:
|
|
329
|
+
output.print_info("No blueprints found.")
|
|
330
|
+
else:
|
|
331
|
+
output.print_header(f"Available blueprints ({len(blueprints)}):")
|
|
332
|
+
for bp in blueprints:
|
|
333
|
+
slot_desc = ", ".join(
|
|
334
|
+
f"{s.name}={s.default}" if s.default is not None else s.name
|
|
335
|
+
for s in bp.slots
|
|
336
|
+
)
|
|
337
|
+
tag = " [builtin]" if bp.builtin else " [custom]"
|
|
338
|
+
output.print_info(f" {bp.name} [{bp.category}]{tag} — {bp.description}")
|
|
339
|
+
output.print_info(f" Slots: {slot_desc}")
|
|
340
|
+
if bp.default_deliver:
|
|
341
|
+
output.print_info(f" Default delivery: {bp.default_deliver}")
|
|
342
|
+
except Exception as e:
|
|
343
|
+
output.print_error(str(e))
|
|
344
|
+
raise typer.Exit(1)
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
# ── Suggestion commands ─────────────────────────────────────────────────
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
@app.command("suggestions")
|
|
351
|
+
def schedule_suggestions(
|
|
352
|
+
json_output: bool = typer.Option(False, "--json", help="Output JSON"),
|
|
353
|
+
):
|
|
354
|
+
"""List pending automation suggestions."""
|
|
355
|
+
output = get_output_controller()
|
|
356
|
+
try:
|
|
357
|
+
from praisonai.scheduler.suggestion_engine import SuggestionEngine
|
|
358
|
+
|
|
359
|
+
engine = SuggestionEngine()
|
|
360
|
+
pending = engine.pending()
|
|
361
|
+
|
|
362
|
+
if json_output:
|
|
363
|
+
import json as _json
|
|
364
|
+
print(_json.dumps([{
|
|
365
|
+
"id": s.id,
|
|
366
|
+
"blueprint_name": s.blueprint_name,
|
|
367
|
+
"slots": s.slots,
|
|
368
|
+
"reason": s.reason,
|
|
369
|
+
"created_at": s.created_at,
|
|
370
|
+
"expires_at": s.expires_at,
|
|
371
|
+
} for s in pending]))
|
|
372
|
+
else:
|
|
373
|
+
if not pending:
|
|
374
|
+
output.print_info("No pending suggestions.")
|
|
375
|
+
else:
|
|
376
|
+
output.print_header(f"Suggestions ({len(pending)}):")
|
|
377
|
+
for s in pending:
|
|
378
|
+
slot_str = ", ".join(f"{k}={v}" for k, v in s.slots.items())
|
|
379
|
+
output.print_info(f" [{s.id}] Blueprint: {s.blueprint_name}")
|
|
380
|
+
output.print_info(f" Reason: {s.reason or 'N/A'}")
|
|
381
|
+
output.print_info(f" Slots: {slot_str or '(defaults)'}")
|
|
382
|
+
output.print_info(f" Accept: praisonai schedule suggestion-accept {s.id}")
|
|
383
|
+
output.print_info(f" Dismiss: praisonai schedule suggestion-dismiss {s.id}")
|
|
384
|
+
except Exception as e:
|
|
385
|
+
output.print_error(str(e))
|
|
386
|
+
raise typer.Exit(1)
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+
@app.command("suggestion-accept")
|
|
390
|
+
def schedule_suggestion_accept(
|
|
391
|
+
suggestion_id: str = typer.Argument(..., help="Suggestion ID to accept"),
|
|
392
|
+
deliver: str = typer.Option("", "--deliver", "-d", help="Override delivery target"),
|
|
393
|
+
):
|
|
394
|
+
"""Accept a suggestion and create the schedule job."""
|
|
395
|
+
output = get_output_controller()
|
|
396
|
+
try:
|
|
397
|
+
from praisonai.scheduler.suggestion_engine import SuggestionEngine
|
|
398
|
+
from praisonai.scheduler.blueprint_catalogue import BlueprintCatalogue
|
|
399
|
+
from praisonaiagents.tools.schedule_tools import schedule_add as _schedule_add
|
|
400
|
+
|
|
401
|
+
engine = SuggestionEngine()
|
|
402
|
+
sug = engine.get_suggestion(suggestion_id)
|
|
403
|
+
if sug is None or sug.dismissed or sug.accepted:
|
|
404
|
+
output.print_error(f"Suggestion '{suggestion_id}' not found or already handled.")
|
|
405
|
+
raise typer.Exit(1)
|
|
406
|
+
|
|
407
|
+
# Reject expired suggestions (expires_at == 0 means no expiry)
|
|
408
|
+
import time as _time
|
|
409
|
+
if sug.expires_at != 0 and sug.expires_at <= _time.time():
|
|
410
|
+
output.print_error(f"Suggestion '{suggestion_id}' has expired.")
|
|
411
|
+
raise typer.Exit(1)
|
|
412
|
+
|
|
413
|
+
catalogue = BlueprintCatalogue()
|
|
414
|
+
bp = catalogue.get_blueprint(sug.blueprint_name)
|
|
415
|
+
if bp is None:
|
|
416
|
+
output.print_error(f"Blueprint '{sug.blueprint_name}' for suggestion not found.")
|
|
417
|
+
raise typer.Exit(1)
|
|
418
|
+
|
|
419
|
+
resolved = catalogue.resolve_slots(bp, sug.slots)
|
|
420
|
+
prompt = catalogue.materialize_prompt(bp, resolved)
|
|
421
|
+
schedule_expr = catalogue.materialize_schedule(bp, resolved)
|
|
422
|
+
final_deliver = deliver or sug.deliver or bp.default_deliver
|
|
423
|
+
|
|
424
|
+
result = _schedule_add(
|
|
425
|
+
name=sug.blueprint_name,
|
|
426
|
+
schedule=schedule_expr,
|
|
427
|
+
message=prompt,
|
|
428
|
+
deliver=final_deliver,
|
|
429
|
+
accept_suggestion=suggestion_id,
|
|
430
|
+
)
|
|
431
|
+
|
|
432
|
+
if result.startswith("Error") or "already exists" in result:
|
|
433
|
+
output.print_error(result)
|
|
434
|
+
raise typer.Exit(1)
|
|
435
|
+
output.print_success(f"Suggestion accepted. {result}")
|
|
436
|
+
except typer.Exit:
|
|
437
|
+
raise
|
|
438
|
+
except Exception as e:
|
|
439
|
+
output.print_error(str(e))
|
|
440
|
+
raise typer.Exit(1)
|
|
441
|
+
|
|
442
|
+
|
|
443
|
+
@app.command("suggestion-dismiss")
|
|
444
|
+
def schedule_suggestion_dismiss(
|
|
445
|
+
suggestion_id: str = typer.Argument(..., help="Suggestion ID to dismiss"),
|
|
446
|
+
):
|
|
447
|
+
"""Dismiss a suggestion without creating a job."""
|
|
448
|
+
output = get_output_controller()
|
|
449
|
+
try:
|
|
450
|
+
from praisonai.scheduler.suggestion_engine import SuggestionEngine
|
|
451
|
+
engine = SuggestionEngine()
|
|
452
|
+
ok = engine.dismiss(suggestion_id)
|
|
453
|
+
if ok:
|
|
454
|
+
output.print_info(f"Suggestion '{suggestion_id}' dismissed.")
|
|
455
|
+
else:
|
|
456
|
+
output.print_error(f"Suggestion '{suggestion_id}' not found.")
|
|
457
|
+
raise typer.Exit(1)
|
|
458
|
+
except typer.Exit:
|
|
459
|
+
raise
|
|
460
|
+
except Exception as e:
|
|
461
|
+
output.print_error(str(e))
|
|
462
|
+
raise typer.Exit(1)
|
|
463
|
+
|
|
464
|
+
|
|
465
|
+
@app.command("suggestion-propose")
|
|
466
|
+
def schedule_suggestion_propose(
|
|
467
|
+
blueprint_name: str = typer.Argument(..., help="Blueprint to suggest"),
|
|
468
|
+
reason: str = typer.Option("", "--reason", "-r", help="Why this is being suggested"),
|
|
469
|
+
hour: Optional[int] = typer.Option(None, "--hour"),
|
|
470
|
+
minute: Optional[int] = typer.Option(None, "--minute"),
|
|
471
|
+
weekdays: Optional[str] = typer.Option(None, "--weekdays"),
|
|
472
|
+
focus: Optional[str] = typer.Option(None, "--focus"),
|
|
473
|
+
interval: Optional[int] = typer.Option(None, "--interval"),
|
|
474
|
+
keywords: Optional[str] = typer.Option(None, "--keywords", help="Priority keywords (for important-mail)"),
|
|
475
|
+
deliver: str = typer.Option("", "--deliver", "-d", help="Suggested delivery target"),
|
|
476
|
+
):
|
|
477
|
+
"""Propose a blueprint as a suggestion (manual/CLI trigger)."""
|
|
478
|
+
output = get_output_controller()
|
|
479
|
+
try:
|
|
480
|
+
from praisonai.scheduler.blueprint_catalogue import BlueprintCatalogue
|
|
481
|
+
from praisonai.scheduler.suggestion_engine import SuggestionEngine
|
|
482
|
+
|
|
483
|
+
catalogue = BlueprintCatalogue()
|
|
484
|
+
bp = catalogue.get_blueprint(blueprint_name)
|
|
485
|
+
if bp is None:
|
|
486
|
+
available = [b.name for b in catalogue.list_blueprints()]
|
|
487
|
+
output.print_error(
|
|
488
|
+
f"Blueprint '{blueprint_name}' not found. "
|
|
489
|
+
f"Available: {', '.join(available)}"
|
|
490
|
+
)
|
|
491
|
+
raise typer.Exit(1)
|
|
492
|
+
|
|
493
|
+
cli_slot_map: dict = {
|
|
494
|
+
"hour": hour, "minute": minute, "weekdays": weekdays,
|
|
495
|
+
"focus": focus, "interval_minutes": interval,
|
|
496
|
+
"keywords": keywords,
|
|
497
|
+
}
|
|
498
|
+
slots = {}
|
|
499
|
+
for slot in bp.slots:
|
|
500
|
+
val = cli_slot_map.get(slot.name)
|
|
501
|
+
if val is not None:
|
|
502
|
+
slots[slot.name] = val
|
|
503
|
+
|
|
504
|
+
engine = SuggestionEngine()
|
|
505
|
+
sug_id = engine.propose(
|
|
506
|
+
blueprint_name=blueprint_name,
|
|
507
|
+
slots=slots,
|
|
508
|
+
deliver=deliver,
|
|
509
|
+
reason=reason or f"Suggestion from CLI for {blueprint_name}",
|
|
510
|
+
)
|
|
511
|
+
|
|
512
|
+
if sug_id:
|
|
513
|
+
output.print_success(f"Suggestion created (id: {sug_id}).")
|
|
514
|
+
output.print_info(f" Accept: praisonai schedule suggestion-accept {sug_id}")
|
|
515
|
+
output.print_info(f" Dismiss: praisonai schedule suggestion-dismiss {sug_id}")
|
|
516
|
+
else:
|
|
517
|
+
output.print_warning("Suggestion not created (cap reached or duplicate).")
|
|
518
|
+
except typer.Exit:
|
|
519
|
+
raise
|
|
520
|
+
except Exception as e:
|
|
521
|
+
output.print_error(str(e))
|
|
522
|
+
raise typer.Exit(1)
|
|
523
|
+
|
|
524
|
+
|
|
525
|
+
@app.callback(invoke_without_command=True)
|
|
526
|
+
def schedule_callback(ctx: typer.Context):
|
|
527
|
+
"""Show schedule help or list jobs."""
|
|
528
|
+
if ctx.invoked_subcommand is None:
|
|
529
|
+
schedule_list(json_output=False)
|