@qqbrowser/openclaw-qbot 0.0.106 → 0.0.108
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.
- package/package.json +13 -13
- package/preset-config.json +2 -2
- package/skills/srt-sandbox/SKILL.md +39 -0
- package/extensions/acpx/skills/acp-router/SKILL.md +0 -219
- package/extensions/diffs/skills/diffs/SKILL.md +0 -22
- package/extensions/lobster/SKILL.md +0 -97
- package/extensions/open-prose/skills/prose/LICENSE +0 -21
- package/extensions/open-prose/skills/prose/SKILL.md +0 -323
- package/extensions/open-prose/skills/prose/alt-borges.md +0 -141
- package/extensions/open-prose/skills/prose/alts/arabian-nights.md +0 -358
- package/extensions/open-prose/skills/prose/alts/borges.md +0 -360
- package/extensions/open-prose/skills/prose/alts/folk.md +0 -322
- package/extensions/open-prose/skills/prose/alts/homer.md +0 -346
- package/extensions/open-prose/skills/prose/alts/kafka.md +0 -373
- package/extensions/open-prose/skills/prose/compiler.md +0 -2971
- package/extensions/open-prose/skills/prose/examples/01-hello-world.prose +0 -4
- package/extensions/open-prose/skills/prose/examples/02-research-and-summarize.prose +0 -6
- package/extensions/open-prose/skills/prose/examples/03-code-review.prose +0 -17
- package/extensions/open-prose/skills/prose/examples/04-write-and-refine.prose +0 -14
- package/extensions/open-prose/skills/prose/examples/05-debug-issue.prose +0 -20
- package/extensions/open-prose/skills/prose/examples/06-explain-codebase.prose +0 -17
- package/extensions/open-prose/skills/prose/examples/07-refactor.prose +0 -20
- package/extensions/open-prose/skills/prose/examples/08-blog-post.prose +0 -20
- package/extensions/open-prose/skills/prose/examples/09-research-with-agents.prose +0 -25
- package/extensions/open-prose/skills/prose/examples/10-code-review-agents.prose +0 -32
- package/extensions/open-prose/skills/prose/examples/11-skills-and-imports.prose +0 -27
- package/extensions/open-prose/skills/prose/examples/12-secure-agent-permissions.prose +0 -43
- package/extensions/open-prose/skills/prose/examples/13-variables-and-context.prose +0 -51
- package/extensions/open-prose/skills/prose/examples/14-composition-blocks.prose +0 -48
- package/extensions/open-prose/skills/prose/examples/15-inline-sequences.prose +0 -23
- package/extensions/open-prose/skills/prose/examples/16-parallel-reviews.prose +0 -19
- package/extensions/open-prose/skills/prose/examples/17-parallel-research.prose +0 -19
- package/extensions/open-prose/skills/prose/examples/18-mixed-parallel-sequential.prose +0 -36
- package/extensions/open-prose/skills/prose/examples/19-advanced-parallel.prose +0 -71
- package/extensions/open-prose/skills/prose/examples/20-fixed-loops.prose +0 -20
- package/extensions/open-prose/skills/prose/examples/21-pipeline-operations.prose +0 -35
- package/extensions/open-prose/skills/prose/examples/22-error-handling.prose +0 -51
- package/extensions/open-prose/skills/prose/examples/23-retry-with-backoff.prose +0 -63
- package/extensions/open-prose/skills/prose/examples/24-choice-blocks.prose +0 -86
- package/extensions/open-prose/skills/prose/examples/25-conditionals.prose +0 -114
- package/extensions/open-prose/skills/prose/examples/26-parameterized-blocks.prose +0 -100
- package/extensions/open-prose/skills/prose/examples/27-string-interpolation.prose +0 -105
- package/extensions/open-prose/skills/prose/examples/28-automated-pr-review.prose +0 -37
- package/extensions/open-prose/skills/prose/examples/28-gas-town.prose +0 -1572
- package/extensions/open-prose/skills/prose/examples/29-captains-chair.prose +0 -218
- package/extensions/open-prose/skills/prose/examples/30-captains-chair-simple.prose +0 -42
- package/extensions/open-prose/skills/prose/examples/31-captains-chair-with-memory.prose +0 -145
- package/extensions/open-prose/skills/prose/examples/33-pr-review-autofix.prose +0 -168
- package/extensions/open-prose/skills/prose/examples/34-content-pipeline.prose +0 -204
- package/extensions/open-prose/skills/prose/examples/35-feature-factory.prose +0 -296
- package/extensions/open-prose/skills/prose/examples/36-bug-hunter.prose +0 -237
- package/extensions/open-prose/skills/prose/examples/37-the-forge.prose +0 -1474
- package/extensions/open-prose/skills/prose/examples/38-skill-scan.prose +0 -455
- package/extensions/open-prose/skills/prose/examples/39-architect-by-simulation.prose +0 -277
- package/extensions/open-prose/skills/prose/examples/40-rlm-self-refine.prose +0 -32
- package/extensions/open-prose/skills/prose/examples/41-rlm-divide-conquer.prose +0 -38
- package/extensions/open-prose/skills/prose/examples/42-rlm-filter-recurse.prose +0 -46
- package/extensions/open-prose/skills/prose/examples/43-rlm-pairwise.prose +0 -50
- package/extensions/open-prose/skills/prose/examples/44-run-endpoint-ux-test.prose +0 -261
- package/extensions/open-prose/skills/prose/examples/45-plugin-release.prose +0 -159
- package/extensions/open-prose/skills/prose/examples/45-run-endpoint-ux-test-with-remediation.prose +0 -637
- package/extensions/open-prose/skills/prose/examples/46-run-endpoint-ux-test-fast.prose +0 -148
- package/extensions/open-prose/skills/prose/examples/46-workflow-crystallizer.prose +0 -225
- package/extensions/open-prose/skills/prose/examples/47-language-self-improvement.prose +0 -356
- package/extensions/open-prose/skills/prose/examples/48-habit-miner.prose +0 -445
- package/extensions/open-prose/skills/prose/examples/49-prose-run-retrospective.prose +0 -210
- package/extensions/open-prose/skills/prose/examples/README.md +0 -391
- package/extensions/open-prose/skills/prose/examples/roadmap/README.md +0 -22
- package/extensions/open-prose/skills/prose/examples/roadmap/iterative-refinement.prose +0 -20
- package/extensions/open-prose/skills/prose/examples/roadmap/parallel-review.prose +0 -18
- package/extensions/open-prose/skills/prose/examples/roadmap/simple-pipeline.prose +0 -17
- package/extensions/open-prose/skills/prose/examples/roadmap/syntax/open-prose-syntax.prose +0 -223
- package/extensions/open-prose/skills/prose/guidance/antipatterns.md +0 -951
- package/extensions/open-prose/skills/prose/guidance/patterns.md +0 -700
- package/extensions/open-prose/skills/prose/guidance/system-prompt.md +0 -180
- package/extensions/open-prose/skills/prose/help.md +0 -144
- package/extensions/open-prose/skills/prose/lib/README.md +0 -108
- package/extensions/open-prose/skills/prose/lib/calibrator.prose +0 -215
- package/extensions/open-prose/skills/prose/lib/cost-analyzer.prose +0 -174
- package/extensions/open-prose/skills/prose/lib/error-forensics.prose +0 -250
- package/extensions/open-prose/skills/prose/lib/inspector.prose +0 -196
- package/extensions/open-prose/skills/prose/lib/profiler.prose +0 -460
- package/extensions/open-prose/skills/prose/lib/program-improver.prose +0 -275
- package/extensions/open-prose/skills/prose/lib/project-memory.prose +0 -118
- package/extensions/open-prose/skills/prose/lib/user-memory.prose +0 -93
- package/extensions/open-prose/skills/prose/lib/vm-improver.prose +0 -243
- package/extensions/open-prose/skills/prose/primitives/session.md +0 -593
- package/extensions/open-prose/skills/prose/prose.md +0 -1237
- package/extensions/open-prose/skills/prose/state/filesystem.md +0 -498
- package/extensions/open-prose/skills/prose/state/in-context.md +0 -384
- package/extensions/open-prose/skills/prose/state/postgres.md +0 -880
- package/extensions/open-prose/skills/prose/state/sqlite.md +0 -574
- package/skills/model-usage/SKILL.md +0 -69
- package/skills/model-usage/references/codexbar-cli.md +0 -33
- package/skills/model-usage/scripts/model_usage.py +0 -320
- package/skills/model-usage/scripts/test_model_usage.py +0 -40
- package/skills/study-habits/SKILL.md +0 -72
- package/skills/study-habits/_meta.json +0 -6
- package/skills/xiaohongshu-mcp/SKILL.md +0 -95
- package/skills/xiaohongshu-mcp/_meta.json +0 -6
- package/skills/xiaohongshu-mcp/scripts/xhs_client.py +0 -264
|
@@ -1,320 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""
|
|
3
|
-
Summarize CodexBar local cost usage by model.
|
|
4
|
-
|
|
5
|
-
Defaults to current model (most recent daily entry), or list all models.
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
from __future__ import annotations
|
|
9
|
-
|
|
10
|
-
import argparse
|
|
11
|
-
import json
|
|
12
|
-
import os
|
|
13
|
-
import subprocess
|
|
14
|
-
import sys
|
|
15
|
-
from dataclasses import dataclass
|
|
16
|
-
from datetime import date, datetime, timedelta
|
|
17
|
-
from typing import Any, Dict, Iterable, List, Optional, Tuple
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
def positive_int(value: str) -> int:
|
|
21
|
-
try:
|
|
22
|
-
parsed = int(value)
|
|
23
|
-
except ValueError as exc:
|
|
24
|
-
raise argparse.ArgumentTypeError("must be an integer") from exc
|
|
25
|
-
if parsed < 1:
|
|
26
|
-
raise argparse.ArgumentTypeError("must be >= 1")
|
|
27
|
-
return parsed
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
def eprint(msg: str) -> None:
|
|
31
|
-
print(msg, file=sys.stderr)
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
def run_codexbar_cost(provider: str) -> List[Dict[str, Any]]:
|
|
35
|
-
cmd = ["codexbar", "cost", "--format", "json", "--provider", provider]
|
|
36
|
-
try:
|
|
37
|
-
output = subprocess.check_output(cmd, text=True)
|
|
38
|
-
except FileNotFoundError:
|
|
39
|
-
raise RuntimeError("codexbar not found on PATH. Install CodexBar CLI first.")
|
|
40
|
-
except subprocess.CalledProcessError as exc:
|
|
41
|
-
raise RuntimeError(f"codexbar cost failed (exit {exc.returncode}).")
|
|
42
|
-
try:
|
|
43
|
-
payload = json.loads(output)
|
|
44
|
-
except json.JSONDecodeError as exc:
|
|
45
|
-
raise RuntimeError(f"Failed to parse codexbar JSON output: {exc}")
|
|
46
|
-
if not isinstance(payload, list):
|
|
47
|
-
raise RuntimeError("Expected codexbar cost JSON array.")
|
|
48
|
-
return payload
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
def load_payload(input_path: Optional[str], provider: str) -> Dict[str, Any]:
|
|
52
|
-
if input_path:
|
|
53
|
-
if input_path == "-":
|
|
54
|
-
raw = sys.stdin.read()
|
|
55
|
-
else:
|
|
56
|
-
with open(input_path, "r", encoding="utf-8") as handle:
|
|
57
|
-
raw = handle.read()
|
|
58
|
-
data = json.loads(raw)
|
|
59
|
-
else:
|
|
60
|
-
data = run_codexbar_cost(provider)
|
|
61
|
-
|
|
62
|
-
if isinstance(data, dict):
|
|
63
|
-
return data
|
|
64
|
-
|
|
65
|
-
if isinstance(data, list):
|
|
66
|
-
for entry in data:
|
|
67
|
-
if isinstance(entry, dict) and entry.get("provider") == provider:
|
|
68
|
-
return entry
|
|
69
|
-
raise RuntimeError(f"Provider '{provider}' not found in codexbar payload.")
|
|
70
|
-
|
|
71
|
-
raise RuntimeError("Unsupported JSON input format.")
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
@dataclass
|
|
75
|
-
class ModelCost:
|
|
76
|
-
model: str
|
|
77
|
-
cost: float
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
def parse_daily_entries(payload: Dict[str, Any]) -> List[Dict[str, Any]]:
|
|
81
|
-
daily = payload.get("daily")
|
|
82
|
-
if not daily:
|
|
83
|
-
return []
|
|
84
|
-
if not isinstance(daily, list):
|
|
85
|
-
return []
|
|
86
|
-
return [entry for entry in daily if isinstance(entry, dict)]
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
def parse_date(value: str) -> Optional[date]:
|
|
90
|
-
try:
|
|
91
|
-
return datetime.strptime(value, "%Y-%m-%d").date()
|
|
92
|
-
except Exception:
|
|
93
|
-
return None
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
def filter_by_days(entries: List[Dict[str, Any]], days: Optional[int]) -> List[Dict[str, Any]]:
|
|
97
|
-
if not days:
|
|
98
|
-
return entries
|
|
99
|
-
cutoff = date.today() - timedelta(days=days - 1)
|
|
100
|
-
filtered: List[Dict[str, Any]] = []
|
|
101
|
-
for entry in entries:
|
|
102
|
-
day = entry.get("date")
|
|
103
|
-
if not isinstance(day, str):
|
|
104
|
-
continue
|
|
105
|
-
parsed = parse_date(day)
|
|
106
|
-
if parsed and parsed >= cutoff:
|
|
107
|
-
filtered.append(entry)
|
|
108
|
-
return filtered
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
def aggregate_costs(entries: Iterable[Dict[str, Any]]) -> Dict[str, float]:
|
|
112
|
-
totals: Dict[str, float] = {}
|
|
113
|
-
for entry in entries:
|
|
114
|
-
breakdowns = entry.get("modelBreakdowns")
|
|
115
|
-
if not breakdowns:
|
|
116
|
-
continue
|
|
117
|
-
if not isinstance(breakdowns, list):
|
|
118
|
-
continue
|
|
119
|
-
for item in breakdowns:
|
|
120
|
-
if not isinstance(item, dict):
|
|
121
|
-
continue
|
|
122
|
-
model = item.get("modelName")
|
|
123
|
-
cost = item.get("cost")
|
|
124
|
-
if not isinstance(model, str):
|
|
125
|
-
continue
|
|
126
|
-
if not isinstance(cost, (int, float)):
|
|
127
|
-
continue
|
|
128
|
-
totals[model] = totals.get(model, 0.0) + float(cost)
|
|
129
|
-
return totals
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
def pick_current_model(entries: List[Dict[str, Any]]) -> Tuple[Optional[str], Optional[str]]:
|
|
133
|
-
if not entries:
|
|
134
|
-
return None, None
|
|
135
|
-
sorted_entries = sorted(
|
|
136
|
-
entries,
|
|
137
|
-
key=lambda entry: entry.get("date") or "",
|
|
138
|
-
)
|
|
139
|
-
for entry in reversed(sorted_entries):
|
|
140
|
-
breakdowns = entry.get("modelBreakdowns")
|
|
141
|
-
if isinstance(breakdowns, list) and breakdowns:
|
|
142
|
-
scored: List[ModelCost] = []
|
|
143
|
-
for item in breakdowns:
|
|
144
|
-
if not isinstance(item, dict):
|
|
145
|
-
continue
|
|
146
|
-
model = item.get("modelName")
|
|
147
|
-
cost = item.get("cost")
|
|
148
|
-
if isinstance(model, str) and isinstance(cost, (int, float)):
|
|
149
|
-
scored.append(ModelCost(model=model, cost=float(cost)))
|
|
150
|
-
if scored:
|
|
151
|
-
scored.sort(key=lambda item: item.cost, reverse=True)
|
|
152
|
-
return scored[0].model, entry.get("date") if isinstance(entry.get("date"), str) else None
|
|
153
|
-
models_used = entry.get("modelsUsed")
|
|
154
|
-
if isinstance(models_used, list) and models_used:
|
|
155
|
-
last = models_used[-1]
|
|
156
|
-
if isinstance(last, str):
|
|
157
|
-
return last, entry.get("date") if isinstance(entry.get("date"), str) else None
|
|
158
|
-
return None, None
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
def usd(value: Optional[float]) -> str:
|
|
162
|
-
if value is None:
|
|
163
|
-
return "—"
|
|
164
|
-
return f"${value:,.2f}"
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
def latest_day_cost(entries: List[Dict[str, Any]], model: str) -> Tuple[Optional[str], Optional[float]]:
|
|
168
|
-
if not entries:
|
|
169
|
-
return None, None
|
|
170
|
-
sorted_entries = sorted(
|
|
171
|
-
entries,
|
|
172
|
-
key=lambda entry: entry.get("date") or "",
|
|
173
|
-
)
|
|
174
|
-
for entry in reversed(sorted_entries):
|
|
175
|
-
breakdowns = entry.get("modelBreakdowns")
|
|
176
|
-
if not isinstance(breakdowns, list):
|
|
177
|
-
continue
|
|
178
|
-
for item in breakdowns:
|
|
179
|
-
if not isinstance(item, dict):
|
|
180
|
-
continue
|
|
181
|
-
if item.get("modelName") == model:
|
|
182
|
-
cost = item.get("cost") if isinstance(item.get("cost"), (int, float)) else None
|
|
183
|
-
day = entry.get("date") if isinstance(entry.get("date"), str) else None
|
|
184
|
-
return day, float(cost) if cost is not None else None
|
|
185
|
-
return None, None
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
def render_text_current(
|
|
189
|
-
provider: str,
|
|
190
|
-
model: str,
|
|
191
|
-
latest_date: Optional[str],
|
|
192
|
-
total_cost: Optional[float],
|
|
193
|
-
latest_cost: Optional[float],
|
|
194
|
-
latest_cost_date: Optional[str],
|
|
195
|
-
entry_count: int,
|
|
196
|
-
) -> str:
|
|
197
|
-
lines = [f"Provider: {provider}", f"Current model: {model}"]
|
|
198
|
-
if latest_date:
|
|
199
|
-
lines.append(f"Latest model date: {latest_date}")
|
|
200
|
-
lines.append(f"Total cost (rows): {usd(total_cost)}")
|
|
201
|
-
if latest_cost_date:
|
|
202
|
-
lines.append(f"Latest day cost: {usd(latest_cost)} ({latest_cost_date})")
|
|
203
|
-
lines.append(f"Daily rows: {entry_count}")
|
|
204
|
-
return "\n".join(lines)
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
def render_text_all(provider: str, totals: Dict[str, float]) -> str:
|
|
208
|
-
lines = [f"Provider: {provider}", "Models:"]
|
|
209
|
-
for model, cost in sorted(totals.items(), key=lambda item: item[1], reverse=True):
|
|
210
|
-
lines.append(f"- {model}: {usd(cost)}")
|
|
211
|
-
return "\n".join(lines)
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
def build_json_current(
|
|
215
|
-
provider: str,
|
|
216
|
-
model: str,
|
|
217
|
-
latest_date: Optional[str],
|
|
218
|
-
total_cost: Optional[float],
|
|
219
|
-
latest_cost: Optional[float],
|
|
220
|
-
latest_cost_date: Optional[str],
|
|
221
|
-
entry_count: int,
|
|
222
|
-
) -> Dict[str, Any]:
|
|
223
|
-
return {
|
|
224
|
-
"provider": provider,
|
|
225
|
-
"mode": "current",
|
|
226
|
-
"model": model,
|
|
227
|
-
"latestModelDate": latest_date,
|
|
228
|
-
"totalCostUSD": total_cost,
|
|
229
|
-
"latestDayCostUSD": latest_cost,
|
|
230
|
-
"latestDayCostDate": latest_cost_date,
|
|
231
|
-
"dailyRowCount": entry_count,
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
def build_json_all(provider: str, totals: Dict[str, float]) -> Dict[str, Any]:
|
|
236
|
-
return {
|
|
237
|
-
"provider": provider,
|
|
238
|
-
"mode": "all",
|
|
239
|
-
"models": [
|
|
240
|
-
{"model": model, "totalCostUSD": cost}
|
|
241
|
-
for model, cost in sorted(totals.items(), key=lambda item: item[1], reverse=True)
|
|
242
|
-
],
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
def main() -> int:
|
|
247
|
-
parser = argparse.ArgumentParser(description="Summarize CodexBar model usage from local cost logs.")
|
|
248
|
-
parser.add_argument("--provider", choices=["codex", "claude"], default="codex")
|
|
249
|
-
parser.add_argument("--mode", choices=["current", "all"], default="current")
|
|
250
|
-
parser.add_argument("--model", help="Explicit model name to report instead of auto-current.")
|
|
251
|
-
parser.add_argument("--input", help="Path to codexbar cost JSON (or '-' for stdin).")
|
|
252
|
-
parser.add_argument("--days", type=positive_int, help="Limit to last N days (based on daily rows).")
|
|
253
|
-
parser.add_argument("--format", choices=["text", "json"], default="text")
|
|
254
|
-
parser.add_argument("--pretty", action="store_true", help="Pretty-print JSON output.")
|
|
255
|
-
|
|
256
|
-
args = parser.parse_args()
|
|
257
|
-
|
|
258
|
-
try:
|
|
259
|
-
payload = load_payload(args.input, args.provider)
|
|
260
|
-
except Exception as exc:
|
|
261
|
-
eprint(str(exc))
|
|
262
|
-
return 1
|
|
263
|
-
|
|
264
|
-
entries = parse_daily_entries(payload)
|
|
265
|
-
entries = filter_by_days(entries, args.days)
|
|
266
|
-
|
|
267
|
-
if args.mode == "current":
|
|
268
|
-
model = args.model
|
|
269
|
-
latest_date = None
|
|
270
|
-
if not model:
|
|
271
|
-
model, latest_date = pick_current_model(entries)
|
|
272
|
-
if not model:
|
|
273
|
-
eprint("No model data found in codexbar cost payload.")
|
|
274
|
-
return 2
|
|
275
|
-
totals = aggregate_costs(entries)
|
|
276
|
-
total_cost = totals.get(model)
|
|
277
|
-
latest_cost_date, latest_cost = latest_day_cost(entries, model)
|
|
278
|
-
|
|
279
|
-
if args.format == "json":
|
|
280
|
-
payload_out = build_json_current(
|
|
281
|
-
provider=args.provider,
|
|
282
|
-
model=model,
|
|
283
|
-
latest_date=latest_date,
|
|
284
|
-
total_cost=total_cost,
|
|
285
|
-
latest_cost=latest_cost,
|
|
286
|
-
latest_cost_date=latest_cost_date,
|
|
287
|
-
entry_count=len(entries),
|
|
288
|
-
)
|
|
289
|
-
indent = 2 if args.pretty else None
|
|
290
|
-
print(json.dumps(payload_out, indent=indent, sort_keys=args.pretty))
|
|
291
|
-
else:
|
|
292
|
-
print(
|
|
293
|
-
render_text_current(
|
|
294
|
-
provider=args.provider,
|
|
295
|
-
model=model,
|
|
296
|
-
latest_date=latest_date,
|
|
297
|
-
total_cost=total_cost,
|
|
298
|
-
latest_cost=latest_cost,
|
|
299
|
-
latest_cost_date=latest_cost_date,
|
|
300
|
-
entry_count=len(entries),
|
|
301
|
-
)
|
|
302
|
-
)
|
|
303
|
-
return 0
|
|
304
|
-
|
|
305
|
-
totals = aggregate_costs(entries)
|
|
306
|
-
if not totals:
|
|
307
|
-
eprint("No model breakdowns found in codexbar cost payload.")
|
|
308
|
-
return 2
|
|
309
|
-
|
|
310
|
-
if args.format == "json":
|
|
311
|
-
payload_out = build_json_all(provider=args.provider, totals=totals)
|
|
312
|
-
indent = 2 if args.pretty else None
|
|
313
|
-
print(json.dumps(payload_out, indent=indent, sort_keys=args.pretty))
|
|
314
|
-
else:
|
|
315
|
-
print(render_text_all(provider=args.provider, totals=totals))
|
|
316
|
-
return 0
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
if __name__ == "__main__":
|
|
320
|
-
raise SystemExit(main())
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""
|
|
3
|
-
Tests for model_usage helpers.
|
|
4
|
-
"""
|
|
5
|
-
|
|
6
|
-
import argparse
|
|
7
|
-
from datetime import date, timedelta
|
|
8
|
-
from unittest import TestCase, main
|
|
9
|
-
|
|
10
|
-
from model_usage import filter_by_days, positive_int
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class TestModelUsage(TestCase):
|
|
14
|
-
def test_positive_int_accepts_valid_numbers(self):
|
|
15
|
-
self.assertEqual(positive_int("1"), 1)
|
|
16
|
-
self.assertEqual(positive_int("7"), 7)
|
|
17
|
-
|
|
18
|
-
def test_positive_int_rejects_zero_and_negative(self):
|
|
19
|
-
with self.assertRaises(argparse.ArgumentTypeError):
|
|
20
|
-
positive_int("0")
|
|
21
|
-
with self.assertRaises(argparse.ArgumentTypeError):
|
|
22
|
-
positive_int("-3")
|
|
23
|
-
|
|
24
|
-
def test_filter_by_days_keeps_recent_entries(self):
|
|
25
|
-
today = date.today()
|
|
26
|
-
entries = [
|
|
27
|
-
{"date": (today - timedelta(days=5)).strftime("%Y-%m-%d"), "modelBreakdowns": []},
|
|
28
|
-
{"date": (today - timedelta(days=1)).strftime("%Y-%m-%d"), "modelBreakdowns": []},
|
|
29
|
-
{"date": today.strftime("%Y-%m-%d"), "modelBreakdowns": []},
|
|
30
|
-
]
|
|
31
|
-
|
|
32
|
-
filtered = filter_by_days(entries, 2)
|
|
33
|
-
|
|
34
|
-
self.assertEqual(len(filtered), 2)
|
|
35
|
-
self.assertEqual(filtered[0]["date"], (today - timedelta(days=1)).strftime("%Y-%m-%d"))
|
|
36
|
-
self.assertEqual(filtered[1]["date"], today.strftime("%Y-%m-%d"))
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
if __name__ == "__main__":
|
|
40
|
-
main()
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: study-habits
|
|
3
|
-
description: Build effective study habits with spaced repetition, active recall, and session tracking
|
|
4
|
-
author: clawd-team
|
|
5
|
-
version: 1.0.0
|
|
6
|
-
triggers:
|
|
7
|
-
- "study session"
|
|
8
|
-
- "study habits"
|
|
9
|
-
- "learn effectively"
|
|
10
|
-
- "study timer"
|
|
11
|
-
- "exam prep"
|
|
12
|
-
---
|
|
13
|
-
|
|
14
|
-
# Study Habits
|
|
15
|
-
|
|
16
|
-
_Learning that sticks—through science, not stubbornness._
|
|
17
|
-
|
|
18
|
-
## What it does
|
|
19
|
-
|
|
20
|
-
This skill transforms how you absorb and retain information by combining proven cognitive techniques with persistent session tracking:
|
|
21
|
-
|
|
22
|
-
- **Study Session Tracking** - Logs when you study, what topic, duration, and effectiveness rating for accountability and pattern recognition
|
|
23
|
-
- **Technique Suggestions** - Recommends study methods based on your learning goal (memorization vs. deep understanding vs. skill practice)
|
|
24
|
-
- **Spaced Repetition Reminders** - Intelligently schedules review sessions to hit the sweet spot where forgetting begins
|
|
25
|
-
- **Progress Dashboard** - Shows your study velocity, topic mastery levels, and retention curves over time
|
|
26
|
-
- **Exam Countdown** - Builds personalized prep schedules that work backward from exam date to ensure full coverage
|
|
27
|
-
|
|
28
|
-
## Usage
|
|
29
|
-
|
|
30
|
-
**Start study**
|
|
31
|
-
: "Start a 50-minute study session on photosynthesis" → Creates a session timer, suggests an optimal study technique, and tracks your focus
|
|
32
|
-
|
|
33
|
-
**Log topic**
|
|
34
|
-
: "I just finished studying Chapter 3, felt confident" → Records the session, captures confidence level, determines next review interval
|
|
35
|
-
|
|
36
|
-
**Review schedule**
|
|
37
|
-
: "When should I review calculus next?" → Shows which topics need review based on spaced repetition algorithm, prioritizes by forgetting curve
|
|
38
|
-
|
|
39
|
-
**Check progress**
|
|
40
|
-
: "Show me my study stats" → Displays sessions completed, topics covered, retention trends, time invested per subject
|
|
41
|
-
|
|
42
|
-
**Exam countdown**
|
|
43
|
-
: "I have an exam in 21 days on biology" → Creates a study plan that distributes chapters across available time, accounts for review cycles, flags high-risk topics
|
|
44
|
-
|
|
45
|
-
## Study Techniques
|
|
46
|
-
|
|
47
|
-
**Active Recall**
|
|
48
|
-
: Test yourself without looking at notes. Forces your brain to retrieve information rather than passively reread. Far more effective than review.
|
|
49
|
-
|
|
50
|
-
**Spaced Repetition**
|
|
51
|
-
: Review material at increasing intervals (1 day, 3 days, 1 week, 2 weeks). This combats the forgetting curve and moves knowledge to long-term memory.
|
|
52
|
-
|
|
53
|
-
**Pomodoro Technique**
|
|
54
|
-
: Study in 25-minute focused bursts with 5-minute breaks. Prevents burnout and maintains attention during sessions.
|
|
55
|
-
|
|
56
|
-
**Feynman Technique**
|
|
57
|
-
: Explain a concept aloud as if teaching it to someone with no background. Exposes gaps in understanding immediately.
|
|
58
|
-
|
|
59
|
-
**Interleaving**
|
|
60
|
-
: Mix different topics or problem types in one session instead of blocking them. Builds flexible knowledge and stronger pattern recognition.
|
|
61
|
-
|
|
62
|
-
## Tips
|
|
63
|
-
|
|
64
|
-
1. **Track confidence, not just completion** — Rate how well you understood each topic (1-10) rather than just marking it done. This surfaces weak areas early.
|
|
65
|
-
|
|
66
|
-
2. **Use active recall over rereading** — Flashcards, practice problems, and explain-it-aloud beat passively reviewing notes by 10x.
|
|
67
|
-
|
|
68
|
-
3. **Study in shorter sprints, more often** — Three 45-minute sessions spread across a week beat one 2-hour cramming session. Your brain consolidates overnight.
|
|
69
|
-
|
|
70
|
-
4. **Review the day after, then space out** — First review should be 24 hours later, then 3 days, then a week. The algorithm handles this automatically.
|
|
71
|
-
|
|
72
|
-
5. **All data stays local on your machine** — Your study history, notes, and progress never leave your device. Full privacy, full control.
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: xiaohongshu-mcp
|
|
3
|
-
description: >
|
|
4
|
-
Automate Xiaohongshu (RedNote) content operations using a Python client for the xiaohongshu-mcp server.
|
|
5
|
-
Use for: (1) Publishing image, text, and video content, (2) Searching for notes and trends,
|
|
6
|
-
(3) Analyzing post details and comments, (4) Managing user profiles and content feeds.
|
|
7
|
-
Triggers: xiaohongshu automation, rednote content, publish to xiaohongshu, xiaohongshu search, social media management.
|
|
8
|
-
---
|
|
9
|
-
|
|
10
|
-
# Xiaohongshu MCP Skill (with Python Client)
|
|
11
|
-
|
|
12
|
-
Automate content operations on Xiaohongshu (小红书) using a bundled Python script that interacts with the `xpzouying/xiaohongshu-mcp` server (8.4k+ stars).
|
|
13
|
-
|
|
14
|
-
**Project:** [xpzouying/xiaohongshu-mcp](https://github.com/xpzouying/xiaohongshu-mcp)
|
|
15
|
-
|
|
16
|
-
## 1. Local Server Setup
|
|
17
|
-
|
|
18
|
-
This skill requires the `xiaohongshu-mcp` server to be running on your local machine.
|
|
19
|
-
|
|
20
|
-
### Step 1: Download Binaries
|
|
21
|
-
|
|
22
|
-
Download the appropriate binaries for your system from the [GitHub Releases](https://github.com/xpzouying/xiaohongshu-mcp/releases) page.
|
|
23
|
-
|
|
24
|
-
| Platform | MCP Server | Login Tool |
|
|
25
|
-
| --------------------- | ----------------------------------- | ------------------------------------- |
|
|
26
|
-
| macOS (Apple Silicon) | `xiaohongshu-mcp-darwin-arm64` | `xiaohongshu-login-darwin-arm64` |
|
|
27
|
-
| macOS (Intel) | `xiaohongshu-mcp-darwin-amd64` | `xiaohongshu-login-darwin-amd64` |
|
|
28
|
-
| Windows | `xiaohongshu-mcp-windows-amd64.exe` | `xiaohongshu-login-windows-amd64.exe` |
|
|
29
|
-
| Linux | `xiaohongshu-mcp-linux-amd64` | `xiaohongshu-login-linux-amd64` |
|
|
30
|
-
|
|
31
|
-
Grant execute permission to the downloaded files:
|
|
32
|
-
|
|
33
|
-
```shell
|
|
34
|
-
chmod +x xiaohongshu-mcp-darwin-arm64 xiaohongshu-login-darwin-arm64
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
### Step 2: Login (First Time Only)
|
|
38
|
-
|
|
39
|
-
Run the login tool. It will open a browser window with a QR code. Scan it with your Xiaohongshu mobile app.
|
|
40
|
-
|
|
41
|
-
```shell
|
|
42
|
-
./xiaohongshu-login-darwin-arm64
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
> **Important**: Do not log into the same Xiaohongshu account on any other web browser, as this will invalidate the server's session.
|
|
46
|
-
|
|
47
|
-
### Step 3: Start the MCP Server
|
|
48
|
-
|
|
49
|
-
Run the MCP server in a separate terminal window. It will run in the background.
|
|
50
|
-
|
|
51
|
-
```shell
|
|
52
|
-
# Run in headless mode (recommended)
|
|
53
|
-
./xiaohongshu-mcp-darwin-arm64
|
|
54
|
-
|
|
55
|
-
# Or, run with a visible browser for debugging
|
|
56
|
-
./xiaohongshu-mcp-darwin-arm64 -headless=false
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
The server will be available at `http://localhost:18060`.
|
|
60
|
-
|
|
61
|
-
## 2. Using the Skill
|
|
62
|
-
|
|
63
|
-
This skill includes a Python client (`scripts/xhs_client.py`) to interact with the local server. You can use it directly from the shell.
|
|
64
|
-
|
|
65
|
-
### Available Commands
|
|
66
|
-
|
|
67
|
-
| Command | Description | Example |
|
|
68
|
-
| ------------------------------------ | -------------------- | -------------------------------------------------------------------- |
|
|
69
|
-
| `status` | Check login status | `python scripts/xhs_client.py status` |
|
|
70
|
-
| `search <keyword>` | Search for notes | `python scripts/xhs_client.py search "咖啡"` |
|
|
71
|
-
| `detail <id> <token>` | Get note details | `python scripts/xhs_client.py detail "note_id" "xsec_token"` |
|
|
72
|
-
| `feeds` | Get recommended feed | `python scripts/xhs_client.py feeds` |
|
|
73
|
-
| `publish <title> <content> <images>` | Publish a note | `python scripts/xhs_client.py publish "Title" "Content" "url1,url2"` |
|
|
74
|
-
|
|
75
|
-
### Example Workflow: Market Research
|
|
76
|
-
|
|
77
|
-
1. **Check Status**: First, ensure the server is running and you are logged in.
|
|
78
|
-
|
|
79
|
-
```shell
|
|
80
|
-
python ~/clawd/skills/xiaohongshu-mcp/scripts/xhs_client.py status
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
2. **Search for a Keyword**: Find notes related to your research topic. The output will include the `feed_id` and `xsec_token` needed for the next step.
|
|
84
|
-
|
|
85
|
-
```shell
|
|
86
|
-
python ~/clawd/skills/xiaohongshu-mcp/scripts/xhs_client.py search "户外电源"
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
3. **Get Note Details**: Use the `feed_id` and `xsec_token` from the search results to get the full content and comments of a specific note.
|
|
90
|
-
|
|
91
|
-
```shell
|
|
92
|
-
python ~/clawd/skills/xiaohongshu-mcp/scripts/xhs_client.py detail "64f1a2b3c4d5e6f7a8b9c0d1" "security_token_here"
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
4. **Analyze**: Review the note's content, comments, and engagement data to gather insights.
|