openclacky 0.7.6 → 0.7.7
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.
- checksums.yaml +4 -4
- data/.clackyrules +13 -1
- data/CHANGELOG.md +27 -0
- data/lib/clacky/agent.rb +8 -3
- data/lib/clacky/cli.rb +36 -0
- data/lib/clacky/default_skills/create-task/SKILL.md +102 -0
- data/lib/clacky/json_ui_controller.rb +1 -5
- data/lib/clacky/plain_ui_controller.rb +1 -1
- data/lib/clacky/server/http_server.rb +731 -0
- data/lib/clacky/server/scheduler.rb +246 -0
- data/lib/clacky/server/session_registry.rb +122 -0
- data/lib/clacky/server/web_ui_controller.rb +211 -0
- data/lib/clacky/skill.rb +5 -2
- data/lib/clacky/ui2/components/message_component.rb +22 -1
- data/lib/clacky/ui2/ui_controller.rb +35 -14
- data/lib/clacky/ui2/view_renderer.rb +4 -2
- data/lib/clacky/ui_interface.rb +1 -2
- data/lib/clacky/version.rb +1 -1
- data/lib/clacky/web/app.css +785 -0
- data/lib/clacky/web/app.js +351 -0
- data/lib/clacky/web/index.html +127 -0
- data/lib/clacky/web/sessions.js +237 -0
- data/lib/clacky/web/settings.js +283 -0
- data/lib/clacky/web/tasks.js +290 -0
- data/lib/clacky/web/ws.js +119 -0
- data/lib/clacky.rb +2 -0
- metadata +41 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5c3815310a11bea9ccad7ab6891b4ad85e248635af6919606e8963096699a1d7
|
|
4
|
+
data.tar.gz: 17f8059179701394a6951966ec0284ee6321750e2651c4de0ecbf37a4542c7fc
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b7b32ce62e12f9aa12db59b1f6640e4a6234c34c485d9b679df80654dc8722a369687e1fc0b5165a78a12f6210fcd02959133d6d3753c5c22873d071251b07fb
|
|
7
|
+
data.tar.gz: 20f4498c976579333b7e261490d287a33cec89b888c5ae1a640205c25f48c70c3863a551e1bef6173804b7670970ead88ed9a67702987da97963c0a981cd1e2a
|
data/.clackyrules
CHANGED
|
@@ -49,7 +49,11 @@ It provides chat functionality and autonomous AI agent capabilities with tool us
|
|
|
49
49
|
- **IMPORTANT**: When testing clacky commands or debugging, always use `bundle exec ruby bin/clacky` instead of the global `clacky` command. The global command loads the system-installed gem version (e.g., `openclacky-0.7.0`), not your local development code
|
|
50
50
|
|
|
51
51
|
### Tool Development
|
|
52
|
-
|
|
52
|
+
**IMPORTANT**: Do NOT add new Ruby Tool classes without careful consideration. Tools are low-level primitives (file I/O, shell, web search, etc.). Before creating a new Tool, always ask: can this capability be achieved with an existing Tool + a Skill (SKILL.md) instead? If yes, use a Skill.
|
|
53
|
+
|
|
54
|
+
Only add a new Tool when it requires capabilities that no existing tool can provide (e.g., a new API integration, a new system-level operation).
|
|
55
|
+
|
|
56
|
+
When a new Tool is truly necessary:
|
|
53
57
|
1. Create class in `lib/clacky/tools/`
|
|
54
58
|
2. Inherit from `Clacky::Tools::Base`
|
|
55
59
|
3. Define required class attributes
|
|
@@ -57,6 +61,14 @@ When adding new tools:
|
|
|
57
61
|
5. Add optional `format_call` and `format_result` methods
|
|
58
62
|
6. Require in `lib/clacky.rb`
|
|
59
63
|
|
|
64
|
+
### Skill Development
|
|
65
|
+
Skills are the preferred way to add new high-level capabilities. A skill is a Markdown instruction file (SKILL.md) that guides the Agent to accomplish a goal using existing Tools.
|
|
66
|
+
|
|
67
|
+
- Built-in default skills live in `lib/clacky/default_skills/<skill-name>/SKILL.md` (shipped with the gem)
|
|
68
|
+
- Project-level skills live in `.clacky/skills/<skill-name>/SKILL.md`
|
|
69
|
+
- User-level skills live in `~/.clacky/skills/<skill-name>/SKILL.md`
|
|
70
|
+
- **Prefer Skills over new Tools** whenever the task can be composed from existing primitives (write, shell, read, etc.)
|
|
71
|
+
|
|
60
72
|
### Agent Behavior
|
|
61
73
|
- TODO manager is for planning only - must execute tasks after planning
|
|
62
74
|
- Always use tools to create/modify files, don't just return code
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,33 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.7.7] - 2026-03-04
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- Web UI server with WebSocket support for real-time agent interaction in the browser (`clacky serve`)
|
|
14
|
+
- Task scheduler with cron-based automation, REST API, and scheduled task execution
|
|
15
|
+
- Settings panel in web UI for viewing and editing AI model configurations (API keys, base URL, provider presets)
|
|
16
|
+
- Image upload support in web UI with attach button for multimodal prompts
|
|
17
|
+
- Create Task button in the task list panel for quick task creation from the web UI
|
|
18
|
+
- `create-task` default skill for guided automated task creation
|
|
19
|
+
|
|
20
|
+
### Improved
|
|
21
|
+
- Web UI frontend split into modular files (`ws.js`, `sessions.js`, `tasks.js`, `settings.js`) for maintainability
|
|
22
|
+
- Web session agents now run in `auto_approve` mode for unattended execution
|
|
23
|
+
- Session management moved to client-side for faster, round-trip-free navigation
|
|
24
|
+
- User message rendering moved to the UI layer for cleaner architecture
|
|
25
|
+
- No-cache headers for static file serving to ensure fresh asset delivery
|
|
26
|
+
|
|
27
|
+
### Fixed
|
|
28
|
+
- `DELETE`/`PUT`/`PATCH` HTTP methods now supported via custom WEBrick servlet
|
|
29
|
+
- Task run broadcasts correctly after WebSocket subscription; table button visibility fixed
|
|
30
|
+
- Mutex deadlock in scheduler `stop` method when called from a signal trap context
|
|
31
|
+
- `split` used instead of `shellsplit` for skill arguments to avoid parsing errors
|
|
32
|
+
|
|
33
|
+
### More
|
|
34
|
+
- Add HTTP server spec and scheduler spec with full test coverage
|
|
35
|
+
- Minor web UI style improvements and reduced mouse dependency
|
|
36
|
+
|
|
10
37
|
## [0.7.6] - 2026-03-02
|
|
11
38
|
|
|
12
39
|
### Added
|
data/lib/clacky/agent.rb
CHANGED
|
@@ -774,7 +774,7 @@ module Clacky
|
|
|
774
774
|
|
|
775
775
|
# Format user content with optional images
|
|
776
776
|
# @param text [String] User's text input
|
|
777
|
-
# @param images [Array<String>] Array of image file paths
|
|
777
|
+
# @param images [Array<String>] Array of image file paths or data: URLs
|
|
778
778
|
# @return [String|Array] String if no images, Array with text and image_url objects if images present
|
|
779
779
|
private def format_user_content(text, images)
|
|
780
780
|
return text if images.nil? || images.empty?
|
|
@@ -782,8 +782,13 @@ module Clacky
|
|
|
782
782
|
content = []
|
|
783
783
|
content << { type: "text", text: text } unless text.nil? || text.empty?
|
|
784
784
|
|
|
785
|
-
images.each do |
|
|
786
|
-
|
|
785
|
+
images.each do |image|
|
|
786
|
+
# Accept both file paths and pre-encoded data: URLs (e.g. from Web UI)
|
|
787
|
+
image_url = if image.start_with?("data:")
|
|
788
|
+
image
|
|
789
|
+
else
|
|
790
|
+
Utils::FileProcessor.image_path_to_data_url(image)
|
|
791
|
+
end
|
|
787
792
|
content << { type: "image_url", image_url: { url: image_url } }
|
|
788
793
|
end
|
|
789
794
|
|
data/lib/clacky/cli.rb
CHANGED
|
@@ -690,5 +690,41 @@ module Clacky
|
|
|
690
690
|
|
|
691
691
|
|
|
692
692
|
end
|
|
693
|
+
|
|
694
|
+
# ── server command ─────────────────────────────────────────────────────────
|
|
695
|
+
desc "server", "Start the Clacky web UI server"
|
|
696
|
+
long_desc <<-LONGDESC
|
|
697
|
+
Start a long-running HTTP + WebSocket server that serves the Clacky web UI.
|
|
698
|
+
|
|
699
|
+
Open http://localhost:7070 in your browser to access the multi-session interface.
|
|
700
|
+
Multiple sessions (e.g. "coding", "copywriting") can run simultaneously.
|
|
701
|
+
|
|
702
|
+
Examples:
|
|
703
|
+
$ clacky server
|
|
704
|
+
$ clacky server --port 8080
|
|
705
|
+
LONGDESC
|
|
706
|
+
option :host, type: :string, default: "127.0.0.1", desc: "Bind host (default: 127.0.0.1)"
|
|
707
|
+
option :port, type: :numeric, default: 7070, desc: "Listen port (default: 7070)"
|
|
708
|
+
def server
|
|
709
|
+
require_relative "server/http_server"
|
|
710
|
+
|
|
711
|
+
agent_config = Clacky::AgentConfig.load
|
|
712
|
+
|
|
713
|
+
# Factory so each new session gets a fresh Client instance
|
|
714
|
+
client_factory = lambda do
|
|
715
|
+
Clacky::Client.new(
|
|
716
|
+
agent_config.api_key,
|
|
717
|
+
base_url: agent_config.base_url,
|
|
718
|
+
anthropic_format: agent_config.anthropic_format?
|
|
719
|
+
)
|
|
720
|
+
end
|
|
721
|
+
|
|
722
|
+
Clacky::Server::HttpServer.new(
|
|
723
|
+
host: options[:host],
|
|
724
|
+
port: options[:port],
|
|
725
|
+
agent_config: agent_config,
|
|
726
|
+
client_factory: client_factory
|
|
727
|
+
).start
|
|
728
|
+
end
|
|
693
729
|
end
|
|
694
730
|
end
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: create-task
|
|
3
|
+
description: Create a scheduled automated task. User describes what they want to automate, agent creates the task prompt file and optional cron schedule.
|
|
4
|
+
disable-model-invocation: false
|
|
5
|
+
user-invocable: true
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Create Task Skill
|
|
9
|
+
|
|
10
|
+
## When to Use
|
|
11
|
+
Invoke this skill when a user wants to:
|
|
12
|
+
- Automate something on a schedule (e.g. "send a daily report", "remind me every Monday", "check prices every hour")
|
|
13
|
+
- Create a task that runs automatically ("set up a scheduled task for me")
|
|
14
|
+
- Use the command `/create-task`
|
|
15
|
+
|
|
16
|
+
## Task & Schedule Storage Format
|
|
17
|
+
|
|
18
|
+
### Task file: `~/.clacky/tasks/<name>.md`
|
|
19
|
+
Plain text prompt file. When the task fires, the Agent reads this file as its input prompt and executes it autonomously.
|
|
20
|
+
|
|
21
|
+
Example content of `~/.clacky/tasks/daily_report.md`:
|
|
22
|
+
```
|
|
23
|
+
Check today's GitHub PR list, summarize the status of each PR, and save a daily report to ~/reports/daily_<date>.md
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Schedule file: `~/.clacky/schedules.yml`
|
|
27
|
+
YAML list. Each entry has:
|
|
28
|
+
```yaml
|
|
29
|
+
- name: daily_report # unique name, matches task name
|
|
30
|
+
task: daily_report # references ~/.clacky/tasks/daily_report.md
|
|
31
|
+
cron: "0 9 * * 1-5" # 5-field cron: minute hour day month weekday
|
|
32
|
+
enabled: true
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Cron field order: `minute hour day-of-month month day-of-week`
|
|
36
|
+
- `0 9 * * 1-5` → 09:00 every weekday
|
|
37
|
+
- `0 9 * * *` → 09:00 every day
|
|
38
|
+
- `0 */2 * * *` → every 2 hours
|
|
39
|
+
- `*/30 * * * *` → every 30 minutes
|
|
40
|
+
|
|
41
|
+
## Process
|
|
42
|
+
|
|
43
|
+
### Step 1: Understand the user's intent
|
|
44
|
+
Ask clarifying questions if needed:
|
|
45
|
+
- What should the task DO? (what action, what goal)
|
|
46
|
+
- How often / when should it run? (if scheduling is needed)
|
|
47
|
+
- Any specific working directory or context?
|
|
48
|
+
|
|
49
|
+
### Step 2: Generate a task name
|
|
50
|
+
- Lowercase, alphanumeric + underscores only
|
|
51
|
+
- Short and descriptive, e.g. `daily_standup`, `price_monitor`, `weekly_report`
|
|
52
|
+
|
|
53
|
+
### Step 3: Write the task prompt file
|
|
54
|
+
Use the `write` tool to create `~/.clacky/tasks/<name>.md`.
|
|
55
|
+
|
|
56
|
+
The prompt content should be:
|
|
57
|
+
- Clear and self-contained (the agent running it has no prior context)
|
|
58
|
+
- Written as a direct instruction to an AI agent
|
|
59
|
+
- Include any relevant details the user provided (URLs, file paths, output format, etc.)
|
|
60
|
+
|
|
61
|
+
Example:
|
|
62
|
+
```
|
|
63
|
+
write(
|
|
64
|
+
path: "~/.clacky/tasks/daily_standup.md",
|
|
65
|
+
content: "Check today's work progress:\n1. Review recent git commits\n2. List open TODOs\n3. Generate a standup summary and print it to the terminal"
|
|
66
|
+
)
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Step 4: Write the schedule (if user wants it automated)
|
|
70
|
+
Read the existing `~/.clacky/schedules.yml` first (if it exists), then append the new entry and write the whole file back.
|
|
71
|
+
|
|
72
|
+
Use the `write` tool. Example full file:
|
|
73
|
+
```yaml
|
|
74
|
+
- name: daily_standup
|
|
75
|
+
task: daily_standup
|
|
76
|
+
cron: "0 9 * * 1-5"
|
|
77
|
+
enabled: true
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
If `schedules.yml` already has entries, preserve them and append the new one.
|
|
81
|
+
|
|
82
|
+
### Step 5: Confirm to the user
|
|
83
|
+
Reply with a clear summary:
|
|
84
|
+
```
|
|
85
|
+
✅ Task created successfully!
|
|
86
|
+
|
|
87
|
+
📋 Name: daily_standup
|
|
88
|
+
📄 File: ~/.clacky/tasks/daily_standup.md
|
|
89
|
+
⏰ Schedule: Every weekday at 09:00 (cron: 0 9 * * 1-5)
|
|
90
|
+
|
|
91
|
+
Task prompt:
|
|
92
|
+
> Check today's work progress...
|
|
93
|
+
|
|
94
|
+
The task will run automatically at the next scheduled time.
|
|
95
|
+
You can also click ▶ in the sidebar to run it immediately.
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Notes
|
|
99
|
+
- If the user only wants a task without a schedule (run manually), skip Step 4
|
|
100
|
+
- Always expand `~` to the actual home path when writing files
|
|
101
|
+
- Task name must be sanitized: only `[a-z0-9_-]`, no spaces
|
|
102
|
+
- The cron scheduler checks every minute; `clacky server` must be running for auto-execution
|
|
@@ -28,10 +28,6 @@ module Clacky
|
|
|
28
28
|
|
|
29
29
|
# === Output display ===
|
|
30
30
|
|
|
31
|
-
def show_user_message(content, images: [])
|
|
32
|
-
emit("user_message", content: content, images: images)
|
|
33
|
-
end
|
|
34
|
-
|
|
35
31
|
def show_assistant_message(content)
|
|
36
32
|
return if content.nil? || content.strip.empty?
|
|
37
33
|
|
|
@@ -117,7 +113,7 @@ module Clacky
|
|
|
117
113
|
|
|
118
114
|
# === Progress ===
|
|
119
115
|
|
|
120
|
-
def show_progress(message = nil, prefix_newline: true)
|
|
116
|
+
def show_progress(message = nil, prefix_newline: true, output_buffer: nil)
|
|
121
117
|
@progress_start_time = Time.now
|
|
122
118
|
emit("progress", message: message, status: "start")
|
|
123
119
|
end
|
|
@@ -107,7 +107,7 @@ module Clacky
|
|
|
107
107
|
|
|
108
108
|
# === Progress (no-ops — no spinner in plain mode) ===
|
|
109
109
|
|
|
110
|
-
def show_progress(message = nil, prefix_newline: true); end
|
|
110
|
+
def show_progress(message = nil, prefix_newline: true, output_buffer: nil); end
|
|
111
111
|
def clear_progress; end
|
|
112
112
|
|
|
113
113
|
# === State updates (no-ops) ===
|