openclacky 1.1.2 → 1.1.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 +4 -4
- data/.clacky/skills/gem-release/SKILL.md +27 -31
- data/CHANGELOG.md +14 -0
- data/Dockerfile +28 -0
- data/docs/engineering-article.md +343 -0
- data/lib/clacky/agent/llm_caller.rb +1 -5
- data/lib/clacky/cli.rb +1 -1
- data/lib/clacky/message_format/anthropic.rb +17 -1
- data/lib/clacky/providers.rb +34 -0
- data/lib/clacky/server/channel/adapters/dingtalk/adapter.rb +142 -5
- data/lib/clacky/server/channel/adapters/dingtalk/api_client.rb +309 -0
- data/lib/clacky/ui2/ui_controller.rb +14 -0
- data/lib/clacky/ui_interface.rb +14 -0
- data/lib/clacky/utils/model_pricing.rb +96 -25
- data/lib/clacky/version.rb +1 -1
- data/lib/clacky/web/app.css +8 -0
- data/lib/clacky/web/index.html +1 -1
- data/lib/clacky/web/onboard.js +6 -0
- data/lib/clacky/web/settings.js +17 -5
- data/scripts/build/lib/apt.sh +30 -10
- data/scripts/build/lib/network.sh +3 -2
- data/scripts/install.sh +30 -9
- metadata +3 -16
- data/docs/HOW-TO-USE-CN.md +0 -96
- data/docs/HOW-TO-USE.md +0 -94
- data/docs/browser-cdp-native-design.md +0 -195
- data/docs/c-end-user-positioning.md +0 -64
- data/docs/config.example.yml +0 -27
- data/docs/deploy-architecture.md +0 -619
- data/docs/deploy_subagent_design.md +0 -540
- data/docs/install-script-simplification.md +0 -89
- data/docs/memory-architecture.md +0 -343
- data/docs/openclacky_cloud_api_reference.md +0 -584
- data/docs/security-design.md +0 -109
- data/docs/session-management-redesign.md +0 -202
- data/docs/system-skill-authoring-guide.md +0 -47
- data/docs/why-developer.md +0 -371
- data/docs/why-openclacky.md +0 -266
|
@@ -22,7 +22,7 @@ module Clacky
|
|
|
22
22
|
read: 0.50 # $0.50/MTok cache read
|
|
23
23
|
}
|
|
24
24
|
},
|
|
25
|
-
|
|
25
|
+
|
|
26
26
|
"claude-sonnet-4.5" => {
|
|
27
27
|
input: {
|
|
28
28
|
default: 3.00, # $3/MTok for prompts ≤ 200K tokens
|
|
@@ -39,7 +39,7 @@ module Clacky
|
|
|
39
39
|
read_over_200k: 0.60 # $0.60/MTok cache read (> 200K)
|
|
40
40
|
}
|
|
41
41
|
},
|
|
42
|
-
|
|
42
|
+
|
|
43
43
|
"claude-haiku-4.5" => {
|
|
44
44
|
input: {
|
|
45
45
|
default: 1.00, # $1/MTok
|
|
@@ -122,7 +122,7 @@ module Clacky
|
|
|
122
122
|
},
|
|
123
123
|
cache: {
|
|
124
124
|
write: 0.14, # DeepSeek doesn't charge extra for writes; bill at miss rate
|
|
125
|
-
read: 0.
|
|
125
|
+
read: 0.0028 # $0.0028/MTok cache hit
|
|
126
126
|
}
|
|
127
127
|
},
|
|
128
128
|
|
|
@@ -137,7 +137,7 @@ module Clacky
|
|
|
137
137
|
},
|
|
138
138
|
cache: {
|
|
139
139
|
write: 1.74, # no separate write charge; bill at miss rate
|
|
140
|
-
read: 0.
|
|
140
|
+
read: 0.0145 # $0.0145/MTok cache hit
|
|
141
141
|
}
|
|
142
142
|
},
|
|
143
143
|
|
|
@@ -352,6 +352,58 @@ module Clacky
|
|
|
352
352
|
cache: { write: 0.30, read: 0.06 }
|
|
353
353
|
},
|
|
354
354
|
|
|
355
|
+
# Qwen (Alibaba DashScope) — USD per 1M tokens, Singapore region list price.
|
|
356
|
+
# Source: Alibaba Cloud Model Studio international pricing.
|
|
357
|
+
# Cache convention (mirrors DeepSeek/Kimi/GLM "displayed ≤ actual"):
|
|
358
|
+
# - DashScope has two cache modes; implicit is auto-on, explicit is opt-in.
|
|
359
|
+
# Implicit: write @ 100% input, read @ 20% input (no setup, no guarantee)
|
|
360
|
+
# Explicit: write @ 125% input, read @ 10% input (cache_control marker)
|
|
361
|
+
# - We bill writes at the regular input rate (matches implicit, and avoids
|
|
362
|
+
# surprising users with the explicit 25% surcharge).
|
|
363
|
+
# - We bill reads at 20% (implicit rate) — the conservative side; users on
|
|
364
|
+
# explicit caching will see real bills slightly *lower* than displayed.
|
|
365
|
+
"qwen3.6-plus" => {
|
|
366
|
+
input: { default: 0.40, over_200k: 0.40 },
|
|
367
|
+
output: { default: 2.40, over_200k: 2.40 },
|
|
368
|
+
cache: { write: 0.40, read: 0.08 }
|
|
369
|
+
},
|
|
370
|
+
|
|
371
|
+
"qwen3.6-max" => {
|
|
372
|
+
input: { default: 1.20, over_200k: 1.20 },
|
|
373
|
+
output: { default: 6.00, over_200k: 6.00 },
|
|
374
|
+
cache: { write: 1.20, read: 0.24 }
|
|
375
|
+
},
|
|
376
|
+
|
|
377
|
+
"qwen3.6-27b" => {
|
|
378
|
+
input: { default: 0.20, over_200k: 0.20 },
|
|
379
|
+
output: { default: 0.80, over_200k: 0.80 },
|
|
380
|
+
cache: { write: 0.20, read: 0.04 }
|
|
381
|
+
},
|
|
382
|
+
|
|
383
|
+
"qwen3.6-flash" => {
|
|
384
|
+
input: { default: 0.15, over_200k: 0.15 },
|
|
385
|
+
output: { default: 0.90, over_200k: 0.90 },
|
|
386
|
+
cache: { write: 0.15, read: 0.03 }
|
|
387
|
+
},
|
|
388
|
+
|
|
389
|
+
"qwen-plus-latest" => {
|
|
390
|
+
input: { default: 0.40, over_200k: 0.40 },
|
|
391
|
+
output: { default: 1.20, over_200k: 1.20 },
|
|
392
|
+
cache: { write: 0.40, read: 0.08 }
|
|
393
|
+
},
|
|
394
|
+
|
|
395
|
+
"qwen-vl-plus" => {
|
|
396
|
+
input: { default: 0.14, over_200k: 0.14 },
|
|
397
|
+
output: { default: 0.41, over_200k: 0.41 },
|
|
398
|
+
cache: { write: 0.14, read: 0.028 }
|
|
399
|
+
},
|
|
400
|
+
|
|
401
|
+
"qwen-vl-max" => {
|
|
402
|
+
input: { default: 0.52, over_200k: 0.52 },
|
|
403
|
+
output: { default: 2.08, over_200k: 2.08 },
|
|
404
|
+
cache: { write: 0.52, read: 0.104 }
|
|
405
|
+
},
|
|
406
|
+
|
|
355
407
|
}.freeze
|
|
356
408
|
|
|
357
409
|
# Threshold for tiered pricing (200K tokens)
|
|
@@ -361,7 +413,7 @@ module Clacky
|
|
|
361
413
|
|
|
362
414
|
class << self
|
|
363
415
|
# Calculate cost for the given model and usage
|
|
364
|
-
#
|
|
416
|
+
#
|
|
365
417
|
# @param model [String] Model identifier
|
|
366
418
|
# @param usage [Hash] Usage statistics containing:
|
|
367
419
|
# - prompt_tokens: number of input tokens
|
|
@@ -384,24 +436,24 @@ module Clacky
|
|
|
384
436
|
completion_tokens = usage[:completion_tokens] || 0
|
|
385
437
|
cache_write_tokens = usage[:cache_creation_input_tokens] || 0
|
|
386
438
|
cache_read_tokens = usage[:cache_read_input_tokens] || 0
|
|
387
|
-
|
|
439
|
+
|
|
388
440
|
# Determine if we're in the over_200k tier
|
|
389
441
|
# Note: prompt_tokens includes cache_read_tokens but NOT cache_write_tokens
|
|
390
442
|
# cache_write_tokens are additional tokens that were written to cache
|
|
391
443
|
total_input_tokens = prompt_tokens + cache_write_tokens
|
|
392
444
|
over_threshold = total_input_tokens > TIERED_PRICING_THRESHOLD
|
|
393
|
-
|
|
445
|
+
|
|
394
446
|
# Calculate regular input cost (non-cached tokens)
|
|
395
447
|
# prompt_tokens already includes cache_read_tokens, so we need to subtract them
|
|
396
448
|
# cache_write_tokens are not part of prompt_tokens, so they're handled separately in cache_cost
|
|
397
449
|
regular_input_tokens = prompt_tokens - cache_read_tokens
|
|
398
450
|
input_rate = over_threshold ? pricing[:input][:over_200k] : pricing[:input][:default]
|
|
399
451
|
input_cost = (regular_input_tokens / 1_000_000.0) * input_rate
|
|
400
|
-
|
|
452
|
+
|
|
401
453
|
# Calculate output cost
|
|
402
454
|
output_rate = over_threshold ? pricing[:output][:over_200k] : pricing[:output][:default]
|
|
403
455
|
output_cost = (completion_tokens / 1_000_000.0) * output_rate
|
|
404
|
-
|
|
456
|
+
|
|
405
457
|
# Calculate cache costs
|
|
406
458
|
cache_cost = calculate_cache_cost(
|
|
407
459
|
pricing: pricing,
|
|
@@ -409,24 +461,24 @@ module Clacky
|
|
|
409
461
|
cache_read_tokens: cache_read_tokens,
|
|
410
462
|
over_threshold: over_threshold
|
|
411
463
|
)
|
|
412
|
-
|
|
464
|
+
|
|
413
465
|
{
|
|
414
466
|
cost: input_cost + output_cost + cache_cost,
|
|
415
467
|
source: source
|
|
416
468
|
}
|
|
417
469
|
end
|
|
418
|
-
|
|
470
|
+
|
|
419
471
|
# Get pricing for a specific model
|
|
420
472
|
# Falls back to default pricing if model not found
|
|
421
|
-
#
|
|
473
|
+
#
|
|
422
474
|
# @param model [String] Model identifier
|
|
423
475
|
# @return [Hash] Pricing structure for the model
|
|
424
476
|
def get_pricing(model)
|
|
425
477
|
get_pricing_with_source(model)[:pricing]
|
|
426
478
|
end
|
|
427
|
-
|
|
479
|
+
|
|
428
480
|
# Get pricing with source information
|
|
429
|
-
#
|
|
481
|
+
#
|
|
430
482
|
# @param model [String] Model identifier
|
|
431
483
|
# @return [Hash] Hash containing:
|
|
432
484
|
# - pricing: Pricing structure or nil if model is unknown
|
|
@@ -446,18 +498,18 @@ module Clacky
|
|
|
446
498
|
{ pricing: nil, source: nil }
|
|
447
499
|
end
|
|
448
500
|
end
|
|
449
|
-
|
|
450
|
-
|
|
501
|
+
|
|
502
|
+
|
|
451
503
|
# Normalize model name to match pricing table keys.
|
|
452
504
|
# Returns the canonical key on match, or nil when no pricing is available.
|
|
453
505
|
def normalize_model_name(model)
|
|
454
506
|
return nil if model.nil? || model.empty?
|
|
455
|
-
|
|
507
|
+
|
|
456
508
|
model = model.downcase.strip
|
|
457
|
-
|
|
509
|
+
|
|
458
510
|
# Direct match
|
|
459
511
|
return model if PRICING_TABLE.key?(model)
|
|
460
|
-
|
|
512
|
+
|
|
461
513
|
# Check for Claude model variations
|
|
462
514
|
# Support both dot and dash separators (e.g., "4.5", "4-5", "4-6")
|
|
463
515
|
# Also handles Bedrock cross-region prefixes (e.g. "jp.anthropic.claude-sonnet-4-6")
|
|
@@ -514,6 +566,25 @@ module Clacky
|
|
|
514
566
|
when /^minimax-m2\.7$/i
|
|
515
567
|
"minimax-m2.7"
|
|
516
568
|
|
|
569
|
+
# Qwen (Alibaba DashScope) — strict anchored match per registered
|
|
570
|
+
# model id in providers.rb. qwen3.6-* are the new flagship line;
|
|
571
|
+
# qwen-plus-latest is the rolling alias for the latest Qwen-Plus
|
|
572
|
+
# release; qwen-vl-* are the multimodal SKUs.
|
|
573
|
+
when /^qwen3\.6-plus$/i
|
|
574
|
+
"qwen3.6-plus"
|
|
575
|
+
when /^qwen3\.6-max$/i
|
|
576
|
+
"qwen3.6-max"
|
|
577
|
+
when /^qwen3\.6-27b$/i
|
|
578
|
+
"qwen3.6-27b"
|
|
579
|
+
when /^qwen3\.6-flash$/i
|
|
580
|
+
"qwen3.6-flash"
|
|
581
|
+
when /^qwen-plus-latest$/i
|
|
582
|
+
"qwen-plus-latest"
|
|
583
|
+
when /^qwen-vl-plus$/i
|
|
584
|
+
"qwen-vl-plus"
|
|
585
|
+
when /^qwen-vl-max$/i
|
|
586
|
+
"qwen-vl-max"
|
|
587
|
+
|
|
517
588
|
# OpenAI GPT-5.x models — match various dashed/dotted/compact forms
|
|
518
589
|
# (e.g. "gpt-5.5", "gpt-5-5", "gpt5.5", "gpt55")
|
|
519
590
|
when /^gpt-?5\.?5$/i, /^gpt-?5[\.-]?5$/i
|
|
@@ -533,11 +604,11 @@ module Clacky
|
|
|
533
604
|
nil # No pricing available for this model — cost will show as N/A
|
|
534
605
|
end
|
|
535
606
|
end
|
|
536
|
-
|
|
607
|
+
|
|
537
608
|
# Calculate cache-related costs
|
|
538
609
|
def calculate_cache_cost(pricing:, cache_write_tokens:, cache_read_tokens:, over_threshold:)
|
|
539
610
|
cache_cost = 0.0
|
|
540
|
-
|
|
611
|
+
|
|
541
612
|
# Cache write cost
|
|
542
613
|
if cache_write_tokens > 0
|
|
543
614
|
write_rate = if pricing[:cache].key?(:write)
|
|
@@ -549,10 +620,10 @@ module Clacky
|
|
|
549
620
|
else
|
|
550
621
|
pricing[:cache][:write_default]
|
|
551
622
|
end
|
|
552
|
-
|
|
623
|
+
|
|
553
624
|
cache_cost += (cache_write_tokens / 1_000_000.0) * write_rate
|
|
554
625
|
end
|
|
555
|
-
|
|
626
|
+
|
|
556
627
|
# Cache read cost
|
|
557
628
|
if cache_read_tokens > 0
|
|
558
629
|
read_rate = if pricing[:cache].key?(:read)
|
|
@@ -564,10 +635,10 @@ module Clacky
|
|
|
564
635
|
else
|
|
565
636
|
pricing[:cache][:read_default]
|
|
566
637
|
end
|
|
567
|
-
|
|
638
|
+
|
|
568
639
|
cache_cost += (cache_read_tokens / 1_000_000.0) * read_rate
|
|
569
640
|
end
|
|
570
|
-
|
|
641
|
+
|
|
571
642
|
cache_cost
|
|
572
643
|
end
|
|
573
644
|
end
|
data/lib/clacky/version.rb
CHANGED
data/lib/clacky/web/app.css
CHANGED
|
@@ -3289,6 +3289,14 @@ body {
|
|
|
3289
3289
|
.custom-select-trigger:hover {
|
|
3290
3290
|
border-color: var(--color-text-muted);
|
|
3291
3291
|
}
|
|
3292
|
+
/* Focus: same accent border as `.open` so users see "this is where to start"
|
|
3293
|
+
without the dropdown auto-expanding. Used by onboard step 2 and the
|
|
3294
|
+
settings "add model" flow to nudge users to pick a provider first. */
|
|
3295
|
+
.custom-select-trigger:focus,
|
|
3296
|
+
.custom-select-trigger:focus-visible {
|
|
3297
|
+
outline: none;
|
|
3298
|
+
border-color: var(--color-accent-primary);
|
|
3299
|
+
}
|
|
3292
3300
|
.custom-select-trigger.open {
|
|
3293
3301
|
border-color: var(--color-accent-primary);
|
|
3294
3302
|
}
|
data/lib/clacky/web/index.html
CHANGED
|
@@ -834,7 +834,7 @@
|
|
|
834
834
|
<div class="setup-field">
|
|
835
835
|
<label class="setup-label" data-i18n="onboard.key.provider">Provider</label>
|
|
836
836
|
<div class="custom-select-wrapper" id="setup-provider-wrapper">
|
|
837
|
-
<div class="custom-select-trigger">
|
|
837
|
+
<div class="custom-select-trigger" tabindex="0">
|
|
838
838
|
<span class="custom-select-value placeholder" data-i18n="onboard.key.provider.placeholder">— Choose provider —</span>
|
|
839
839
|
<svg class="custom-select-arrow" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
840
840
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path>
|
data/lib/clacky/web/onboard.js
CHANGED
|
@@ -86,6 +86,12 @@ const Onboard = (() => {
|
|
|
86
86
|
_showSetupStep("key");
|
|
87
87
|
await _loadProviders();
|
|
88
88
|
_bindKeyStep();
|
|
89
|
+
// Nudge: focus the provider trigger so the user knows step 1 is "pick
|
|
90
|
+
// a provider". `tabindex="0"` on the trigger makes it focusable; the
|
|
91
|
+
// .open class is NOT toggled, so the dropdown stays closed — we just
|
|
92
|
+
// get the accent-color border via `.custom-select-trigger:focus`.
|
|
93
|
+
const trigger = $("setup-provider-wrapper")?.querySelector(".custom-select-trigger");
|
|
94
|
+
if (trigger) trigger.focus({ preventScroll: true });
|
|
89
95
|
});
|
|
90
96
|
}
|
|
91
97
|
|
data/lib/clacky/web/settings.js
CHANGED
|
@@ -81,7 +81,7 @@ const Settings = (() => {
|
|
|
81
81
|
<label class="model-field quick-setup-field" ${(model.model || model.base_url) ? 'style="display:none"' : ''}>
|
|
82
82
|
<span class="field-label">${I18n.t("settings.models.field.quicksetup")}</span>
|
|
83
83
|
<div class="custom-select-wrapper" data-index="${index}">
|
|
84
|
-
<div class="custom-select-trigger">
|
|
84
|
+
<div class="custom-select-trigger" tabindex="0">
|
|
85
85
|
<span class="custom-select-value placeholder">${I18n.t("settings.models.placeholder.provider")}</span>
|
|
86
86
|
<svg class="custom-select-arrow" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
87
87
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path>
|
|
@@ -709,10 +709,22 @@ const Settings = (() => {
|
|
|
709
709
|
behavior: "smooth"
|
|
710
710
|
});
|
|
711
711
|
|
|
712
|
-
// Put focus on the new card
|
|
713
|
-
//
|
|
714
|
-
|
|
715
|
-
|
|
712
|
+
// Put focus on the new card so the user can start configuring.
|
|
713
|
+
// Priority order:
|
|
714
|
+
// 1. The provider `.custom-select-trigger` — nudges the user to
|
|
715
|
+
// pick a provider first (step 1 of the 3-field form). It's a
|
|
716
|
+
// div with tabindex="0", so it gets the accent border via
|
|
717
|
+
// `:focus` without expanding the dropdown.
|
|
718
|
+
// 2. Fall back to the first form input (used when the quick-setup
|
|
719
|
+
// field is hidden, e.g. on a model card that already has values).
|
|
720
|
+
const providerTrigger = last.querySelector(".custom-select-wrapper .custom-select-trigger");
|
|
721
|
+
const isVisible = el => el && el.offsetParent !== null;
|
|
722
|
+
if (isVisible(providerTrigger)) {
|
|
723
|
+
providerTrigger.focus({ preventScroll: true });
|
|
724
|
+
} else {
|
|
725
|
+
const firstInput = last.querySelector("input, select, textarea");
|
|
726
|
+
if (firstInput) firstInput.focus({ preventScroll: true });
|
|
727
|
+
}
|
|
716
728
|
});
|
|
717
729
|
});
|
|
718
730
|
}
|
data/scripts/build/lib/apt.sh
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# apt.sh — apt package manager helpers (Ubuntu/Debian)
|
|
2
|
-
# Depends-On: colors.sh
|
|
3
|
-
# Requires-Vars: $DISTRO $USE_CN_MIRRORS
|
|
2
|
+
# Depends-On: colors.sh network.sh
|
|
3
|
+
# Requires-Vars: $DISTRO $USE_CN_MIRRORS $CN_ALIYUN_MIRROR
|
|
4
4
|
# Sets-Vars: (none)
|
|
5
5
|
# Include via: @include lib/apt.sh
|
|
6
6
|
|
|
@@ -12,20 +12,40 @@ setup_apt_mirror() {
|
|
|
12
12
|
|
|
13
13
|
if [ "$USE_CN_MIRRORS" = true ]; then
|
|
14
14
|
print_info "Region: China — configuring Aliyun apt mirror"
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
local mirror="https://mirrors.aliyun.com/ubuntu-ports/"
|
|
20
|
-
else
|
|
21
|
-
local mirror="https://mirrors.aliyun.com/ubuntu/"
|
|
15
|
+
|
|
16
|
+
if [ -f /etc/apt/sources.list ]; then
|
|
17
|
+
sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak
|
|
18
|
+
print_info "Backed up /etc/apt/sources.list to sources.list.bak"
|
|
22
19
|
fi
|
|
23
|
-
|
|
20
|
+
|
|
21
|
+
if [ "$DISTRO" = "debian" ]; then
|
|
22
|
+
local codename="${VERSION_CODENAME:-bookworm}"
|
|
23
|
+
local components="main contrib non-free non-free-firmware"
|
|
24
|
+
local mirror="${CN_ALIYUN_MIRROR}/debian/"
|
|
25
|
+
local security_mirror="${CN_ALIYUN_MIRROR}/debian-security/"
|
|
26
|
+
sudo tee /etc/apt/sources.list > /dev/null <<EOF
|
|
27
|
+
deb ${mirror} ${codename} ${components}
|
|
28
|
+
deb ${mirror} ${codename}-updates ${components}
|
|
29
|
+
deb ${mirror} ${codename}-backports ${components}
|
|
30
|
+
deb ${security_mirror} ${codename}-security ${components}
|
|
31
|
+
EOF
|
|
32
|
+
else
|
|
33
|
+
local codename="${VERSION_CODENAME:-jammy}"
|
|
34
|
+
local components="main restricted universe multiverse"
|
|
35
|
+
local arch; arch=$(dpkg --print-architecture 2>/dev/null || uname -m)
|
|
36
|
+
if [ "$arch" = "arm64" ] || [ "$arch" = "aarch64" ]; then
|
|
37
|
+
local mirror="${CN_ALIYUN_MIRROR}/ubuntu-ports/"
|
|
38
|
+
else
|
|
39
|
+
local mirror="${CN_ALIYUN_MIRROR}/ubuntu/"
|
|
40
|
+
fi
|
|
41
|
+
sudo tee /etc/apt/sources.list > /dev/null <<EOF
|
|
24
42
|
deb ${mirror} ${codename} ${components}
|
|
25
43
|
deb ${mirror} ${codename}-updates ${components}
|
|
26
44
|
deb ${mirror} ${codename}-backports ${components}
|
|
27
45
|
deb ${mirror} ${codename}-security ${components}
|
|
28
46
|
EOF
|
|
47
|
+
fi
|
|
48
|
+
|
|
29
49
|
print_success "apt mirror set to Aliyun"
|
|
30
50
|
else
|
|
31
51
|
print_info "Region: global — using default apt sources"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# network.sh — network region detection, mirror variables, URL probing
|
|
2
2
|
# Depends-On: colors.sh
|
|
3
3
|
# Requires-Vars: (none)
|
|
4
|
-
# Sets-Vars: $USE_CN_MIRRORS $NETWORK_REGION $CN_CDN_BASE_URL $CN_RUBYGEMS_URL $CN_NODE_MIRROR_URL $CN_NPM_REGISTRY $CN_MISE_INSTALL_URL $CN_RUBY_PRECOMPILED_URL $MISE_INSTALL_URL $NODE_MIRROR_URL $NPM_REGISTRY_URL $RUBY_VERSION_SPEC $DEFAULT_RUBYGEMS_URL $DEFAULT_MISE_INSTALL_URL $DEFAULT_NPM_REGISTRY
|
|
4
|
+
# Sets-Vars: $USE_CN_MIRRORS $NETWORK_REGION $CN_CDN_BASE_URL $CN_ALIYUN_MIRROR $CN_RUBYGEMS_URL $CN_NODE_MIRROR_URL $CN_NPM_REGISTRY $CN_MISE_INSTALL_URL $CN_RUBY_PRECOMPILED_URL $MISE_INSTALL_URL $NODE_MIRROR_URL $NPM_REGISTRY_URL $RUBY_VERSION_SPEC $DEFAULT_RUBYGEMS_URL $DEFAULT_MISE_INSTALL_URL $DEFAULT_NPM_REGISTRY
|
|
5
5
|
# Include via: @include lib/network.sh
|
|
6
6
|
|
|
7
7
|
# --------------------------------------------------------------------------
|
|
@@ -17,9 +17,10 @@ DEFAULT_NPM_REGISTRY="https://registry.npmjs.org"
|
|
|
17
17
|
DEFAULT_MISE_INSTALL_URL="https://mise.run"
|
|
18
18
|
|
|
19
19
|
CN_CDN_BASE_URL="https://oss.1024code.com"
|
|
20
|
+
CN_ALIYUN_MIRROR="https://mirrors.aliyun.com"
|
|
20
21
|
CN_MISE_INSTALL_URL="${CN_CDN_BASE_URL}/mise.sh"
|
|
21
22
|
CN_RUBY_PRECOMPILED_URL="${CN_CDN_BASE_URL}/ruby/ruby-{version}.{platform}.tar.gz"
|
|
22
|
-
CN_RUBYGEMS_URL="
|
|
23
|
+
CN_RUBYGEMS_URL="${CN_ALIYUN_MIRROR}/rubygems/"
|
|
23
24
|
CN_NPM_REGISTRY="https://registry.npmmirror.com"
|
|
24
25
|
CN_NODE_MIRROR_URL="https://cdn.npmmirror.com/binaries/node/"
|
|
25
26
|
CN_GEM_BASE_URL="${CN_CDN_BASE_URL}/openclacky"
|
data/scripts/install.sh
CHANGED
|
@@ -129,9 +129,10 @@ DEFAULT_NPM_REGISTRY="https://registry.npmjs.org"
|
|
|
129
129
|
DEFAULT_MISE_INSTALL_URL="https://mise.run"
|
|
130
130
|
|
|
131
131
|
CN_CDN_BASE_URL="https://oss.1024code.com"
|
|
132
|
+
CN_ALIYUN_MIRROR="https://mirrors.aliyun.com"
|
|
132
133
|
CN_MISE_INSTALL_URL="${CN_CDN_BASE_URL}/mise.sh"
|
|
133
134
|
CN_RUBY_PRECOMPILED_URL="${CN_CDN_BASE_URL}/ruby/ruby-{version}.{platform}.tar.gz"
|
|
134
|
-
CN_RUBYGEMS_URL="
|
|
135
|
+
CN_RUBYGEMS_URL="${CN_ALIYUN_MIRROR}/rubygems/"
|
|
135
136
|
CN_NPM_REGISTRY="https://registry.npmmirror.com"
|
|
136
137
|
CN_NODE_MIRROR_URL="https://cdn.npmmirror.com/binaries/node/"
|
|
137
138
|
CN_GEM_BASE_URL="${CN_CDN_BASE_URL}/openclacky"
|
|
@@ -278,20 +279,40 @@ setup_apt_mirror() {
|
|
|
278
279
|
|
|
279
280
|
if [ "$USE_CN_MIRRORS" = true ]; then
|
|
280
281
|
print_info "Region: China — configuring Aliyun apt mirror"
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
local mirror="https://mirrors.aliyun.com/ubuntu-ports/"
|
|
286
|
-
else
|
|
287
|
-
local mirror="https://mirrors.aliyun.com/ubuntu/"
|
|
282
|
+
|
|
283
|
+
if [ -f /etc/apt/sources.list ]; then
|
|
284
|
+
sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak
|
|
285
|
+
print_info "Backed up /etc/apt/sources.list to sources.list.bak"
|
|
288
286
|
fi
|
|
289
|
-
|
|
287
|
+
|
|
288
|
+
if [ "$DISTRO" = "debian" ]; then
|
|
289
|
+
local codename="${VERSION_CODENAME:-bookworm}"
|
|
290
|
+
local components="main contrib non-free non-free-firmware"
|
|
291
|
+
local mirror="${CN_ALIYUN_MIRROR}/debian/"
|
|
292
|
+
local security_mirror="${CN_ALIYUN_MIRROR}/debian-security/"
|
|
293
|
+
sudo tee /etc/apt/sources.list > /dev/null <<EOF
|
|
294
|
+
deb ${mirror} ${codename} ${components}
|
|
295
|
+
deb ${mirror} ${codename}-updates ${components}
|
|
296
|
+
deb ${mirror} ${codename}-backports ${components}
|
|
297
|
+
deb ${security_mirror} ${codename}-security ${components}
|
|
298
|
+
EOF
|
|
299
|
+
else
|
|
300
|
+
local codename="${VERSION_CODENAME:-jammy}"
|
|
301
|
+
local components="main restricted universe multiverse"
|
|
302
|
+
local arch; arch=$(dpkg --print-architecture 2>/dev/null || uname -m)
|
|
303
|
+
if [ "$arch" = "arm64" ] || [ "$arch" = "aarch64" ]; then
|
|
304
|
+
local mirror="${CN_ALIYUN_MIRROR}/ubuntu-ports/"
|
|
305
|
+
else
|
|
306
|
+
local mirror="${CN_ALIYUN_MIRROR}/ubuntu/"
|
|
307
|
+
fi
|
|
308
|
+
sudo tee /etc/apt/sources.list > /dev/null <<EOF
|
|
290
309
|
deb ${mirror} ${codename} ${components}
|
|
291
310
|
deb ${mirror} ${codename}-updates ${components}
|
|
292
311
|
deb ${mirror} ${codename}-backports ${components}
|
|
293
312
|
deb ${mirror} ${codename}-security ${components}
|
|
294
313
|
EOF
|
|
314
|
+
fi
|
|
315
|
+
|
|
295
316
|
print_success "apt mirror set to Aliyun"
|
|
296
317
|
else
|
|
297
318
|
print_info "Region: global — using default apt sources"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: openclacky
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.1.
|
|
4
|
+
version: 1.1.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- windy
|
|
@@ -281,6 +281,7 @@ files:
|
|
|
281
281
|
- ".rubocop.yml"
|
|
282
282
|
- CHANGELOG.md
|
|
283
283
|
- CODE_OF_CONDUCT.md
|
|
284
|
+
- Dockerfile
|
|
284
285
|
- LICENSE.txt
|
|
285
286
|
- README.md
|
|
286
287
|
- Rakefile
|
|
@@ -300,26 +301,12 @@ files:
|
|
|
300
301
|
- bin/openclacky
|
|
301
302
|
- clacky-legacy/clacky.gemspec
|
|
302
303
|
- clacky-legacy/clarky.gemspec
|
|
303
|
-
- docs/HOW-TO-USE-CN.md
|
|
304
|
-
- docs/HOW-TO-USE.md
|
|
305
304
|
- docs/agent-first-ui-design.md
|
|
306
|
-
- docs/browser-cdp-native-design.md
|
|
307
|
-
- docs/c-end-user-positioning.md
|
|
308
305
|
- docs/channel-architecture.md
|
|
309
|
-
- docs/
|
|
310
|
-
- docs/deploy-architecture.md
|
|
311
|
-
- docs/deploy_subagent_design.md
|
|
312
|
-
- docs/install-script-simplification.md
|
|
313
|
-
- docs/memory-architecture.md
|
|
314
|
-
- docs/openclacky_cloud_api_reference.md
|
|
315
|
-
- docs/security-design.md
|
|
316
|
-
- docs/session-management-redesign.md
|
|
306
|
+
- docs/engineering-article.md
|
|
317
307
|
- docs/session-skill-invocation.md
|
|
318
|
-
- docs/system-skill-authoring-guide.md
|
|
319
308
|
- docs/time_machine_design.md
|
|
320
309
|
- docs/ui2-architecture.md
|
|
321
|
-
- docs/why-developer.md
|
|
322
|
-
- docs/why-openclacky.md
|
|
323
310
|
- homebrew/README.md
|
|
324
311
|
- homebrew/openclacky.rb
|
|
325
312
|
- lib/clacky.rb
|
data/docs/HOW-TO-USE-CN.md
DELETED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
# OpenClacky 使用指南
|
|
2
|
-
|
|
3
|
-
## 安装
|
|
4
|
-
|
|
5
|
-
```bash
|
|
6
|
-
gem install openclacky
|
|
7
|
-
```
|
|
8
|
-
|
|
9
|
-
**系统要求:** Ruby >= 3.1
|
|
10
|
-
|
|
11
|
-
## 快速开始
|
|
12
|
-
|
|
13
|
-
### 1. 启动 Clacky
|
|
14
|
-
|
|
15
|
-
```bash
|
|
16
|
-
clacky
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
### 2. 配置 API Key(首次使用)
|
|
20
|
-
|
|
21
|
-
在聊天界面中输入:
|
|
22
|
-
|
|
23
|
-
```
|
|
24
|
-
/config
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
然后按提示设置你的 API key:
|
|
28
|
-
- **OpenAI**:从 https://platform.openai.com/api-keys 获取
|
|
29
|
-
- **Anthropic**:从 https://console.anthropic.com/ 获取
|
|
30
|
-
- **MiniMax**:国内推荐,https://platform.minimaxi.com/
|
|
31
|
-
- **OpenRouter**:聚合多个 AI 模型,https://openrouter.ai/
|
|
32
|
-
|
|
33
|
-
### 3. 开始对话
|
|
34
|
-
|
|
35
|
-
直接在聊天框输入你的问题或需求:
|
|
36
|
-
|
|
37
|
-
```
|
|
38
|
-
帮我写一个解析 CSV 文件的 Ruby 脚本
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
```
|
|
42
|
-
创建一个网页爬虫提取文章标题
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
## 核心功能
|
|
46
|
-
|
|
47
|
-
### 🎯 自主代理模式
|
|
48
|
-
Clacky 可以自动执行复杂任务,内置多种工具:
|
|
49
|
-
- **文件操作**:读取、写入、编辑、搜索文件
|
|
50
|
-
- **网页访问**:浏览网页、搜索信息
|
|
51
|
-
- **代码执行**:运行 shell 命令、测试代码
|
|
52
|
-
- **项目管理**:Git 操作、测试、部署
|
|
53
|
-
|
|
54
|
-
### 🔌 技能系统
|
|
55
|
-
使用简写命令调用强大的技能:
|
|
56
|
-
|
|
57
|
-
```
|
|
58
|
-
/commit # 智能 Git 提交助手
|
|
59
|
-
/gem-release # 自动化 gem 发布流程
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
你还可以在 `.clacky/skills/` 目录创建自己的技能!
|
|
63
|
-
|
|
64
|
-
### 💬 智能记忆管理
|
|
65
|
-
- **自动压缩**长对话内容
|
|
66
|
-
- **保留上下文**同时降低 token 成本
|
|
67
|
-
- **智能总结**对话历史
|
|
68
|
-
|
|
69
|
-
### ⚙️ 简单配置
|
|
70
|
-
- 交互式设置向导
|
|
71
|
-
- 支持多个 API 提供商
|
|
72
|
-
- 成本追踪和使用限制
|
|
73
|
-
- 常用场景的智能默认值
|
|
74
|
-
|
|
75
|
-
## 聊天中的常用命令
|
|
76
|
-
|
|
77
|
-
```
|
|
78
|
-
/config # 配置 API 设置
|
|
79
|
-
/help # 显示可用命令
|
|
80
|
-
/skills # 列出可用技能
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
## 为什么选择 OpenClacky?
|
|
84
|
-
|
|
85
|
-
✅ **安装简单** - 一条命令安装,立即开始对话
|
|
86
|
-
✅ **功能强大** - 自主执行复杂任务
|
|
87
|
-
✅ **可扩展** - 为你的工作流创建自定义技能
|
|
88
|
-
✅ **省钱高效** - 智能记忆压缩节省 token 费用
|
|
89
|
-
✅ **多平台** - 支持 OpenAI、Anthropic、MiniMax、OpenRouter 等
|
|
90
|
-
✅ **质量保证** - 367+ 测试用例确保可靠性
|
|
91
|
-
|
|
92
|
-
## 了解更多
|
|
93
|
-
|
|
94
|
-
- GitHub:https://github.com/clacky-ai/openclacky
|
|
95
|
-
- 问题反馈:https://github.com/clacky-ai/openclacky/issues
|
|
96
|
-
- 当前版本:0.7.0
|