kairos-chain 3.28.1 → 3.28.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 603eca51c926a1987575ae63a1266a34840fc59e7a3603685e03c37676ba23ba
4
- data.tar.gz: c4da91a87396d878a62465219d80fa4e26219766f4ca8389ea132a0c7828d873
3
+ metadata.gz: 7f3b4857e18283e4c80b9197c54e83a962ce2ee4b465b85de7969dc78244fb58
4
+ data.tar.gz: 512356715a6db9e5110162b61a81017c99f00179dd8bbe9250fb23ba0f631981
5
5
  SHA512:
6
- metadata.gz: ea9230f6dbe43986f6a2f81c0c77a549567110dda38205d769f0802c4ccb8418db4c5dee8e3ac037ae91082eab5cb5b5d890feb823119f0182980abf92e217c9
7
- data.tar.gz: 906f320cc565a68ac28d644978c35a8234d1aecc0cb50f828260d407d425f90f3f514c968c0f391e46b69f2db2842ecd33ae31ed85760d4d2b4410723f7ca509
6
+ metadata.gz: 65b002260019464cc20531ab9c7c7d8d5ebecf293a21414e9af5ead16c00490b29495dc53bb8bbddc3d32d572697e91984644350149f93f587022c94b96bbf4c
7
+ data.tar.gz: e673f6f2233ebc56ea8fb7247ed6e91bd05e61f5efd624ca8d48e814dbda70007f808ebd5db2199920f312ef0b978a576b1e3a5d910a2eb094a45f63c986097f
@@ -215,6 +215,7 @@ module KairosMcp
215
215
  # Resource tools (unified access to L0/L1/L2 resources)
216
216
  register_if_defined('KairosMcp::Tools::ResourceList')
217
217
  register_if_defined('KairosMcp::Tools::ResourceRead')
218
+ register_if_defined('KairosMcp::Tools::ResourceRender')
218
219
 
219
220
  # L1: knowledge/ (Anthropic skills format with hash-only blockchain record)
220
221
  register_if_defined('KairosMcp::Tools::KnowledgeList')
@@ -0,0 +1,187 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'open3'
4
+ require 'timeout'
5
+ require_relative 'base_tool'
6
+ require_relative '../anthropic_skill_parser'
7
+
8
+ module KairosMcp
9
+ module Tools
10
+ class ResourceRender < BaseTool
11
+ RENDER_TIMEOUT = 30
12
+
13
+ def name
14
+ 'resource_render'
15
+ end
16
+
17
+ def description
18
+ 'Execute a render script from a knowledge entry to generate an HTML asset. ' \
19
+ 'Scripts live in knowledge/{name}/scripts/ and output HTML to assets/. ' \
20
+ 'Data is passed via stdin as JSON. Convention: scripts named render_*.rb.'
21
+ end
22
+
23
+ def category
24
+ :resource
25
+ end
26
+
27
+ def usecase_tags
28
+ %w[render html visualize dashboard asset generate]
29
+ end
30
+
31
+ def examples
32
+ [
33
+ {
34
+ title: 'Generate review dashboard',
35
+ code: 'resource_render(knowledge: "multi_llm_review_workflow", ' \
36
+ 'script: "render_dashboard.rb", data: "{...}", open: true)'
37
+ },
38
+ {
39
+ title: 'Generate with custom output name',
40
+ code: 'resource_render(knowledge: "multi_llm_review_workflow", ' \
41
+ 'script: "render_dashboard.rb", data: "{...}", output: "round2.html")'
42
+ }
43
+ ]
44
+ end
45
+
46
+ def related_tools
47
+ %w[resource_list resource_read knowledge_get]
48
+ end
49
+
50
+ def input_schema
51
+ {
52
+ type: 'object',
53
+ properties: {
54
+ knowledge: {
55
+ type: 'string',
56
+ description: 'L1 knowledge entry name (e.g., "multi_llm_review_workflow")'
57
+ },
58
+ script: {
59
+ type: 'string',
60
+ description: 'Script filename in the knowledge scripts/ directory (e.g., "render_dashboard.rb")'
61
+ },
62
+ data: {
63
+ type: 'string',
64
+ description: 'JSON data to pass to the script via stdin'
65
+ },
66
+ output: {
67
+ type: 'string',
68
+ description: 'Output filename in assets/ (default: derived from script name, e.g., render_dashboard.rb -> dashboard.html)'
69
+ },
70
+ open: {
71
+ type: 'boolean',
72
+ description: 'Open the generated HTML in the default browser (default: false)'
73
+ }
74
+ },
75
+ required: %w[knowledge script data]
76
+ }
77
+ end
78
+
79
+ def call(arguments)
80
+ knowledge_name = arguments['knowledge']
81
+ script_name = arguments['script']
82
+ data = arguments['data']
83
+ output_name = arguments['output']
84
+ open_after = arguments['open'] || false
85
+
86
+ return text_content("Error: knowledge is required") unless knowledge_name && !knowledge_name.empty?
87
+ return text_content("Error: script is required") unless script_name && !script_name.empty?
88
+ return text_content("Error: data is required") unless data && !data.empty?
89
+
90
+ # Validate JSON
91
+ begin
92
+ JSON.parse(data)
93
+ rescue JSON::ParserError => e
94
+ return text_content("Error: invalid JSON data — #{e.message}")
95
+ end
96
+
97
+ # Resolve knowledge directory
98
+ knowledge_dir = File.join(KairosMcp.knowledge_dir(user_context: @safety&.current_user), knowledge_name)
99
+ unless File.directory?(knowledge_dir)
100
+ return text_content("Error: knowledge '#{knowledge_name}' not found")
101
+ end
102
+
103
+ # Security: normalize script name to prevent path traversal
104
+ safe_script = File.basename(script_name)
105
+ script_path = File.join(knowledge_dir, 'scripts', safe_script)
106
+ unless File.exist?(script_path)
107
+ return text_content("Error: script '#{safe_script}' not found in #{knowledge_name}/scripts/")
108
+ end
109
+
110
+ # Derive output filename
111
+ if output_name
112
+ safe_output = File.basename(output_name)
113
+ else
114
+ safe_output = safe_script
115
+ .sub(/\Arender_/, '')
116
+ .sub(/\.rb\z/, '.html')
117
+ end
118
+
119
+ # Ensure assets/ directory exists
120
+ assets_dir = File.join(knowledge_dir, 'assets')
121
+ FileUtils.mkdir_p(assets_dir)
122
+
123
+ # Execute script with data on stdin
124
+ stdout, stderr, status = execute_script(script_path, data, knowledge_dir)
125
+
126
+ unless status.success?
127
+ error_msg = "Error: script exited with code #{status.exitstatus}"
128
+ error_msg += "\n\nstderr:\n```\n#{stderr}\n```" unless stderr.empty?
129
+ return text_content(error_msg)
130
+ end
131
+
132
+ if stdout.nil? || stdout.empty?
133
+ return text_content("Error: script produced no output")
134
+ end
135
+
136
+ # Write output to assets/
137
+ output_path = File.join(assets_dir, safe_output)
138
+ AnthropicSkillParser.atomic_write(output_path, stdout)
139
+
140
+ # Open in browser if requested
141
+ if open_after
142
+ system('open', output_path)
143
+ end
144
+
145
+ uri = "knowledge://#{knowledge_name}/assets/#{safe_output}"
146
+ build_success_response(uri, output_path, stdout.bytesize, open_after)
147
+ end
148
+
149
+ private
150
+
151
+ def execute_script(script_path, data, working_dir)
152
+ Timeout.timeout(RENDER_TIMEOUT) do
153
+ Open3.capture3(
154
+ 'ruby', script_path,
155
+ stdin_data: data,
156
+ chdir: working_dir
157
+ )
158
+ end
159
+ rescue Timeout::Error
160
+ ["", "Script execution timed out after #{RENDER_TIMEOUT}s", OpenStruct.new(success?: false, exitstatus: 124)]
161
+ end
162
+
163
+ def build_success_response(uri, path, size, opened)
164
+ output = "## Resource Rendered\n\n"
165
+ output += "| Property | Value |\n"
166
+ output += "|----------|-------|\n"
167
+ output += "| **URI** | `#{uri}` |\n"
168
+ output += "| **Path** | `#{path}` |\n"
169
+ output += "| **Size** | #{format_size(size)} |\n"
170
+ output += "| **Opened** | #{opened ? 'Yes' : 'No'} |\n\n"
171
+ output += "Use `resource_read(uri: \"#{uri}\")` to read the generated content.\n"
172
+ output += "Use `open #{path}` to view in browser." unless opened
173
+ text_content(output)
174
+ end
175
+
176
+ def format_size(bytes)
177
+ if bytes < 1024
178
+ "#{bytes} B"
179
+ elsif bytes < 1024 * 1024
180
+ "#{(bytes / 1024.0).round(1)} KB"
181
+ else
182
+ "#{(bytes / (1024.0 * 1024)).round(1)} MB"
183
+ end
184
+ end
185
+ end
186
+ end
187
+ end
@@ -1,4 +1,4 @@
1
1
  module KairosMcp
2
- VERSION = "3.28.1"
2
+ VERSION = "3.28.3"
3
3
  CHANGELOG_URL = "https://github.com/masaomi/KairosChain_2026/blob/main/CHANGELOG.md"
4
4
  end
@@ -193,7 +193,7 @@ starting** and verify each against `config/multi_llm_review.yml`:
193
193
  - [ ] Your model (orchestrator): ___
194
194
  - [ ] Agent Team Personas model: = orchestrator model (NOT a different model)
195
195
  - [ ] Subprocess CLI model: opposite Opus (4.6 if you are 4.7, vice versa)
196
- - [ ] Codex models: gpt-5.4 AND gpt-5.5 (both, not either/or)
196
+ - [ ] Codex models: gpt-5.5 (default) AND gpt-5.4 (both, not either/or)
197
197
  - [ ] Cursor model: default (composer-2.5, no --model flag)
198
198
  - [ ] Total reviewer count: 5 (or 4 after orchestrator exclusion from subprocess)
199
199
  - [ ] Convergence rule: 3/5 APPROVE (full) or 3/4 APPROVE (after exclusion)
@@ -410,7 +410,7 @@ which claude 2>/dev/null && echo "claude: available" || echo "claude: NOT FOUND"
410
410
 
411
411
  | Tool | Command | Prompt Input | Output Collection | Model |
412
412
  |------|---------|-------------|-------------------|-------|
413
- | **Codex** | `codex exec` | stdin pipe: `cat prompt.md \| codex exec -` | `-o /path/output.md` | GPT-5.4 (default) |
413
+ | **Codex** | `codex exec` | stdin pipe: `cat prompt.md \| codex exec -` | `-o /path/output.md` | GPT-5.5 (default) |
414
414
  | **Cursor Agent** | `agent -p` | File reference (stdin NOT supported) | stdout redirect: `> output.md` | Composer-2.5 (default) |
415
415
  | **Claude Code** | Agent tool (internal) | Direct prompt string | Write to workspace file | Opus 4.6 (session) |
416
416
  | **Claude CLI (4.7)** | `claude -p --model claude-opus-4-7 --bare` | stdin pipe: `cat prompt.md \| claude -p --model claude-opus-4-7 --bare` | stdout redirect: `> output.md` | Opus 4.7 |
@@ -426,7 +426,7 @@ Based on cross-evaluation experiment (7 models × 4 tasks + Nomic, 518 CLI calls
426
426
  | **Reviewer: Claude CLI** | Opus 4.7 | `--effort low` | Evaluator quality is effort-independent (low≈high: 8.35 vs 8.16) |
427
427
  | **Coding sub-agent** | Opus 4.7 | `--effort medium` | Cost-effective default; use `high` for complex tasks |
428
428
  | **Design sub-agent** | Opus 4.7 | `--effort medium` | Cost-effective default; use `high` for complex tasks |
429
- | **Codex** | GPT-5.4 | (no flag) | Fixed effort |
429
+ | **Codex** | GPT-5.5 (default) | (no flag) | Fixed effort |
430
430
  | **Cursor Agent** | Composer-2.5 | (no flag) | Fixed effort |
431
431
 
432
432
  Key findings:
@@ -709,7 +709,7 @@ Step 1: Generate review prompt
709
709
  Step 2: Detect environment and models
710
710
  - Run: which codex && which agent && which claude
711
711
  - Detect default models
712
- - Report: "Auto mode: Codex (gpt-5.4), Agent (composer-2.5), Claude (opus-4.6), Claude CLI (opus-4.7)"
712
+ - Report: "Auto mode: Codex (gpt-5.5), Agent (composer-2.5), Claude (opus-4.6), Claude CLI (opus-4.7)"
713
713
 
714
714
  Step 3: Execute N reviews in parallel (default 4 reviewers)
715
715
  - Bash(background): cat prompt.md | codex exec -C workspace -o log/review_codex.md -
@@ -753,7 +753,7 @@ log/{artifact}_review{N}_consensus_{date}.md # Consensus analysis
753
753
  ```
754
754
 
755
755
  LLM identifiers: `claude_opus4.6`, `claude_team_opus4.6`,
756
- `claude_cli_opus4.7`, `codex_gpt5.4`, `cursor_composer2`, `cursor_gpt5.4`,
756
+ `claude_cli_opus4.7`, `codex_gpt5.5`, `codex_gpt5.4`, `cursor_composer2`, `cursor_gpt5.4`,
757
757
  `cursor_premium`
758
758
 
759
759
  ## Internal Agent Team Review
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kairos-chain
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.28.1
4
+ version: 3.28.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Masaomi Hatakeyama
@@ -194,6 +194,7 @@ files:
194
194
  - lib/kairos_mcp/tools/knowledge_update.rb
195
195
  - lib/kairos_mcp/tools/resource_list.rb
196
196
  - lib/kairos_mcp/tools/resource_read.rb
197
+ - lib/kairos_mcp/tools/resource_render.rb
197
198
  - lib/kairos_mcp/tools/skills_audit.rb
198
199
  - lib/kairos_mcp/tools/skills_dsl_get.rb
199
200
  - lib/kairos_mcp/tools/skills_dsl_list.rb