tina4ruby 3.13.7 → 3.13.11
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/lib/tina4/ai.rb +114 -3
- data/lib/tina4/orm.rb +25 -3
- data/lib/tina4/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a23c9445f57fd1c84a7bed4e5325a26f94f2234d703f889ffea769faefa5622e
|
|
4
|
+
data.tar.gz: 7082c808b1d72968997c69167b734cea292e2616c086b46b05831254f30f0353
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f9896ecf33201656f977ceb7bdf4739f2585b14ec32e2c969f61b5ae3c24d69b007ce02d79b053dd96be680af7a5eed8bac8f262fab43e0fc1c51720ff3b2cae
|
|
7
|
+
data.tar.gz: 9722548ba9dcc819407c20d426154eab388f092424e2d1a9bcd253a877bf79579e5937ee98d319adf2f736aceee0ce57e24c939755a38db070109df9bca76819
|
data/lib/tina4/ai.rb
CHANGED
|
@@ -135,6 +135,118 @@ module Tina4
|
|
|
135
135
|
# @param tool [Hash] tool entry from AI_TOOLS
|
|
136
136
|
# @param context [String] generated context content
|
|
137
137
|
# @return [Array<String>] list of created/updated relative file paths
|
|
138
|
+
# ── v3.13.9: non-destructive context-file writer ─────────────────
|
|
139
|
+
#
|
|
140
|
+
# Pre-v3.13.9 the installer wrote a full developer guide to
|
|
141
|
+
# CLAUDE.md (and the other context files) on every run, clobbering
|
|
142
|
+
# whatever the user had put there. Now it writes only a marker-
|
|
143
|
+
# bracketed Tina4 skill block -- pointing the assistant at
|
|
144
|
+
# .claude/skills/tina4-*/SKILL.md -- and leaves the rest alone.
|
|
145
|
+
|
|
146
|
+
# Return [start, end] markers for the given context file.
|
|
147
|
+
def markers_for(context_file)
|
|
148
|
+
if context_file.downcase.end_with?(".md")
|
|
149
|
+
["<!-- tina4-skills:start -->", "<!-- tina4-skills:end -->"]
|
|
150
|
+
else
|
|
151
|
+
["# tina4-skills:start", "# tina4-skills:end"]
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# Return the marker-bracketed Tina4 skill registration block.
|
|
156
|
+
def skill_block(context_file)
|
|
157
|
+
start, finish = markers_for(context_file)
|
|
158
|
+
body = if context_file.downcase.end_with?(".md")
|
|
159
|
+
"## Tina4 Skills\n\n" \
|
|
160
|
+
"When working on this Tina4 project, these skills give the assistant project-aware behaviour:\n\n" \
|
|
161
|
+
"- **tina4-developer** -- Read `.claude/skills/tina4-developer/SKILL.md` before building features.\n" \
|
|
162
|
+
"- **tina4-js** -- Read `.claude/skills/tina4-js/SKILL.md` for frontend work.\n" \
|
|
163
|
+
"- **tina4-maintainer** -- Read `.claude/skills/tina4-maintainer/SKILL.md` for framework-level changes.\n\n" \
|
|
164
|
+
"See https://tina4.com for full docs."
|
|
165
|
+
else
|
|
166
|
+
"Tina4 Skills -- read these files before working on this project:\n" \
|
|
167
|
+
" .claude/skills/tina4-developer/SKILL.md (feature development)\n" \
|
|
168
|
+
" .claude/skills/tina4-js/SKILL.md (frontend / tina4-js)\n" \
|
|
169
|
+
" .claude/skills/tina4-maintainer/SKILL.md (framework-level changes)\n" \
|
|
170
|
+
"Docs: https://tina4.com"
|
|
171
|
+
end
|
|
172
|
+
"#{start}\n#{body}\n#{finish}"
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# True iff both start and end markers appear in order.
|
|
176
|
+
def has_markers?(existing, start, finish)
|
|
177
|
+
s_idx = existing.index(start)
|
|
178
|
+
return false unless s_idx
|
|
179
|
+
!existing.index(finish, s_idx + start.length).nil?
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
# Replace the bracketed block in `existing` with `block`.
|
|
183
|
+
def replace_marker_block(existing, block, start, finish)
|
|
184
|
+
s_idx = existing.index(start)
|
|
185
|
+
return existing.rstrip + "\n\n" + block + "\n" unless s_idx
|
|
186
|
+
e_idx = existing.index(finish, s_idx + start.length)
|
|
187
|
+
return existing.rstrip + "\n\n" + block + "\n" unless e_idx
|
|
188
|
+
before = existing[0...s_idx].rstrip
|
|
189
|
+
after = existing[(e_idx + finish.length)..].sub(/\A\n+/, "")
|
|
190
|
+
glue_before = before.empty? ? "" : "\n\n"
|
|
191
|
+
glue_after = after.empty? ? "\n" : "\n" + after
|
|
192
|
+
"#{before}#{glue_before}#{block}#{glue_after}"
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
# Headers the pre-v3.13.9 installer wrote at the top of CLAUDE.md.
|
|
196
|
+
OLD_FRAMEWORK_HEADERS = [
|
|
197
|
+
"# Tina4 Python",
|
|
198
|
+
"# Tina4 PHP",
|
|
199
|
+
"# Tina4 Ruby",
|
|
200
|
+
"# CLAUDE.md -- AI Developer Guide for tina4-nodejs",
|
|
201
|
+
"# CLAUDE.md — AI Developer Guide for tina4-nodejs",
|
|
202
|
+
].freeze
|
|
203
|
+
|
|
204
|
+
def looks_like_old_framework_install?(existing)
|
|
205
|
+
head = existing.lstrip[0, 400] || ""
|
|
206
|
+
OLD_FRAMEWORK_HEADERS.any? { |h| head.start_with?(h) }
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
# Write the context file non-destructively. Returns a human-readable
|
|
210
|
+
# action verb for the caller's log line.
|
|
211
|
+
#
|
|
212
|
+
# Four branches:
|
|
213
|
+
# 1. Doesn't exist -> write framework guide + skill block
|
|
214
|
+
# 2. Has markers -> refresh just the skill block (idempotent)
|
|
215
|
+
# 3. Old header -> migrate: replace old dump with new guide + block
|
|
216
|
+
# 4. User content -> append the skill block, preserve everything else
|
|
217
|
+
def write_or_merge(context_path, context_file, framework_guide)
|
|
218
|
+
# Force UTF-8 — CLAUDE.md and the framework guide both contain
|
|
219
|
+
# non-ASCII (em-dashes, ✓, etc.). Without this, File.read may
|
|
220
|
+
# return ASCII-8BIT and string concat raises CompatibilityError.
|
|
221
|
+
block = skill_block(context_file).dup.force_encoding("UTF-8")
|
|
222
|
+
guide = framework_guide.dup.force_encoding("UTF-8")
|
|
223
|
+
start, finish = markers_for(context_file)
|
|
224
|
+
|
|
225
|
+
unless File.exist?(context_path)
|
|
226
|
+
File.write(context_path, guide.rstrip + "\n\n" + block + "\n", encoding: "UTF-8")
|
|
227
|
+
return "Installed"
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
existing = File.read(context_path, encoding: "UTF-8")
|
|
231
|
+
|
|
232
|
+
if has_markers?(existing, start, finish)
|
|
233
|
+
File.write(context_path, replace_marker_block(existing, block, start, finish), encoding: "UTF-8")
|
|
234
|
+
return "Refreshed skill block in"
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
if looks_like_old_framework_install?(existing)
|
|
238
|
+
head = existing.lstrip
|
|
239
|
+
preamble = existing[0, existing.length - head.length] || ""
|
|
240
|
+
new_content = (preamble.strip.empty? ? "" : preamble.rstrip + "\n\n") +
|
|
241
|
+
guide.rstrip + "\n\n" + block + "\n"
|
|
242
|
+
File.write(context_path, new_content, encoding: "UTF-8")
|
|
243
|
+
return "Migrated (replaced old framework dump in)"
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
File.write(context_path, existing.rstrip + "\n\n" + block + "\n", encoding: "UTF-8")
|
|
247
|
+
"Appended skill block to"
|
|
248
|
+
end
|
|
249
|
+
|
|
138
250
|
def install_for_tool(root, tool, context)
|
|
139
251
|
created = []
|
|
140
252
|
context_path = File.join(root, tool[:context_file])
|
|
@@ -145,9 +257,8 @@ module Tina4
|
|
|
145
257
|
end
|
|
146
258
|
FileUtils.mkdir_p(File.dirname(context_path))
|
|
147
259
|
|
|
148
|
-
#
|
|
149
|
-
action =
|
|
150
|
-
File.write(context_path, context)
|
|
260
|
+
# v3.13.9: non-destructive write -- see write_or_merge below.
|
|
261
|
+
action = write_or_merge(context_path, tool[:context_file], context)
|
|
151
262
|
rel = context_path.sub("#{root}/", "")
|
|
152
263
|
created << rel
|
|
153
264
|
puts " \e[32m✓\e[0m #{action} #{rel}"
|
data/lib/tina4/orm.rb
CHANGED
|
@@ -302,13 +302,27 @@ module Tina4
|
|
|
302
302
|
def create_table
|
|
303
303
|
return true if db.table_exists?(table_name)
|
|
304
304
|
|
|
305
|
+
# v3.13.11 (BooleanField parity): pick each engine's native
|
|
306
|
+
# bool type where it's reliable. SQLite has no native bool;
|
|
307
|
+
# Firebird's driver round-trip for native BOOLEAN is uneven —
|
|
308
|
+
# both stay on INTEGER. PG/MySQL/MSSQL use their native types
|
|
309
|
+
# so Python ``True``/Ruby ``true`` bind cleanly without
|
|
310
|
+
# ``operator does not exist: boolean = integer`` errors.
|
|
311
|
+
engine = (db.respond_to?(:get_database_type) ? db.get_database_type : "").to_s.downcase
|
|
312
|
+
bool_sql = case engine
|
|
313
|
+
when "postgres", "postgresql" then "BOOLEAN"
|
|
314
|
+
when "mysql" then "BOOLEAN" # alias for TINYINT(1)
|
|
315
|
+
when "mssql", "sqlserver" then "BIT"
|
|
316
|
+
else "INTEGER" # sqlite, firebird, odbc, anything else
|
|
317
|
+
end
|
|
318
|
+
|
|
305
319
|
type_map = {
|
|
306
320
|
integer: "INTEGER",
|
|
307
321
|
string: "VARCHAR(255)",
|
|
308
322
|
text: "TEXT",
|
|
309
323
|
float: "REAL",
|
|
310
324
|
decimal: "REAL",
|
|
311
|
-
boolean:
|
|
325
|
+
boolean: bool_sql,
|
|
312
326
|
date: "DATE",
|
|
313
327
|
datetime: "DATETIME",
|
|
314
328
|
timestamp: "TIMESTAMP",
|
|
@@ -419,10 +433,18 @@ module Tina4
|
|
|
419
433
|
setter = "#{key}="
|
|
420
434
|
__send__(setter, value) if respond_to?(setter)
|
|
421
435
|
end
|
|
422
|
-
# Set defaults
|
|
436
|
+
# Set defaults.
|
|
437
|
+
# v3.13.11 (issue #50.1): when the default is a Proc/lambda
|
|
438
|
+
# (``default: -> { Time.now }``), call it per-instance so
|
|
439
|
+
# per-row timestamps actually differ. Class objects are
|
|
440
|
+
# excluded — ``default: Integer`` is almost never intended
|
|
441
|
+
# to mean ``Integer.new`` (and Integer has no zero-arg
|
|
442
|
+
# constructor anyway).
|
|
423
443
|
self.class.field_definitions.each do |name, opts|
|
|
424
444
|
if __send__(name).nil? && opts[:default]
|
|
425
|
-
|
|
445
|
+
d = opts[:default]
|
|
446
|
+
d = d.call if d.respond_to?(:call) && !d.is_a?(Class)
|
|
447
|
+
__send__("#{name}=", d)
|
|
426
448
|
end
|
|
427
449
|
end
|
|
428
450
|
end
|
data/lib/tina4/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: tina4ruby
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.13.
|
|
4
|
+
version: 3.13.11
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Tina4 Team
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-06-
|
|
11
|
+
date: 2026-06-11 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rack
|