claudecode-omc 5.6.8 → 5.9.1
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/.local/skills/prompt-optimizer/SKILL.md +262 -19
- package/.omc-curation/ecc-selection.json +80 -0
- package/.omc-curation/governance.json +113 -0
- package/.omc-curation/sources.lock.json +25 -0
- package/README.md +69 -4
- package/bundled/manifest.json +5 -5
- package/bundled/upstream/anthropic-skills/.omc-source/bundle.json +18 -0
- package/bundled/upstream/anthropic-skills/.omc-source/provenance.json +399 -0
- package/bundled/upstream/anthropic-skills/skills/claude-api/SKILL.md +18 -17
- package/bundled/upstream/anthropic-skills/skills/claude-api/curl/examples.md +9 -9
- package/bundled/upstream/anthropic-skills/skills/claude-api/curl/managed-agents.md +4 -4
- package/bundled/upstream/anthropic-skills/skills/claude-api/go/managed-agents/README.md +2 -2
- package/bundled/upstream/anthropic-skills/skills/claude-api/java/claude-api.md +2 -2
- package/bundled/upstream/anthropic-skills/skills/claude-api/java/managed-agents/README.md +2 -2
- package/bundled/upstream/anthropic-skills/skills/claude-api/php/claude-api.md +10 -10
- package/bundled/upstream/anthropic-skills/skills/claude-api/php/managed-agents/README.md +2 -2
- package/bundled/upstream/anthropic-skills/skills/claude-api/python/claude-api/README.md +16 -16
- package/bundled/upstream/anthropic-skills/skills/claude-api/python/claude-api/batches.md +3 -3
- package/bundled/upstream/anthropic-skills/skills/claude-api/python/claude-api/files-api.md +3 -3
- package/bundled/upstream/anthropic-skills/skills/claude-api/python/claude-api/streaming.md +7 -7
- package/bundled/upstream/anthropic-skills/skills/claude-api/python/claude-api/tool-use.md +19 -19
- package/bundled/upstream/anthropic-skills/skills/claude-api/python/managed-agents/README.md +3 -3
- package/bundled/upstream/anthropic-skills/skills/claude-api/ruby/claude-api.md +4 -4
- package/bundled/upstream/anthropic-skills/skills/claude-api/ruby/managed-agents/README.md +2 -2
- package/bundled/upstream/anthropic-skills/skills/claude-api/shared/error-codes.md +5 -5
- package/bundled/upstream/anthropic-skills/skills/claude-api/shared/live-sources.md +3 -1
- package/bundled/upstream/anthropic-skills/skills/claude-api/shared/managed-agents-api-reference.md +10 -4
- package/bundled/upstream/anthropic-skills/skills/claude-api/shared/managed-agents-core.md +19 -1
- package/bundled/upstream/anthropic-skills/skills/claude-api/shared/managed-agents-environments.md +6 -2
- package/bundled/upstream/anthropic-skills/skills/claude-api/shared/managed-agents-multiagent.md +1 -1
- package/bundled/upstream/anthropic-skills/skills/claude-api/shared/managed-agents-onboarding.md +3 -3
- package/bundled/upstream/anthropic-skills/skills/claude-api/shared/managed-agents-overview.md +3 -2
- package/bundled/upstream/anthropic-skills/skills/claude-api/shared/managed-agents-self-hosted-sandboxes.md +173 -0
- package/bundled/upstream/anthropic-skills/skills/claude-api/shared/managed-agents-tools.md +10 -4
- package/bundled/upstream/anthropic-skills/skills/claude-api/shared/model-migration.md +113 -13
- package/bundled/upstream/anthropic-skills/skills/claude-api/shared/models.md +14 -11
- package/bundled/upstream/anthropic-skills/skills/claude-api/shared/prompt-caching.md +2 -2
- package/bundled/upstream/anthropic-skills/skills/claude-api/shared/tool-use-concepts.md +4 -4
- package/bundled/upstream/anthropic-skills/skills/claude-api/typescript/claude-api/README.md +15 -15
- package/bundled/upstream/anthropic-skills/skills/claude-api/typescript/claude-api/batches.md +2 -2
- package/bundled/upstream/anthropic-skills/skills/claude-api/typescript/claude-api/files-api.md +1 -1
- package/bundled/upstream/anthropic-skills/skills/claude-api/typescript/claude-api/streaming.md +5 -5
- package/bundled/upstream/anthropic-skills/skills/claude-api/typescript/claude-api/tool-use.md +15 -15
- package/bundled/upstream/anthropic-skills/skills/claude-api/typescript/managed-agents/README.md +3 -3
- package/bundled/upstream/ecc/.omc-source/bundle.json +2 -1
- package/bundled/upstream/ecc/.omc-source/last-plan-apply.json +108 -24
- package/bundled/upstream/ecc/.omc-source/manifests/.claude-plugin/marketplace.json +3 -3
- package/bundled/upstream/ecc/.omc-source/provenance.json +563 -0
- package/bundled/upstream/ecc/agents/marketing-agent.md +159 -0
- package/bundled/upstream/ecc/agents/react-build-resolver.md +215 -0
- package/bundled/upstream/ecc/agents/react-reviewer.md +167 -0
- package/bundled/upstream/ecc/agents/typescript-reviewer.md +3 -0
- package/bundled/upstream/ecc/commands/harness-audit.md +17 -10
- package/bundled/upstream/ecc/commands/marketing-campaign.md +129 -0
- package/bundled/upstream/ecc/commands/react-build.md +187 -0
- package/bundled/upstream/ecc/commands/react-review.md +170 -0
- package/bundled/upstream/ecc/commands/react-test.md +265 -0
- package/bundled/upstream/ecc/skills/benchmark-optimization-loop/SKILL.md +69 -0
- package/bundled/upstream/ecc/skills/blender-motion-state-inspection/SKILL.md +164 -0
- package/bundled/upstream/ecc/skills/canary-watch/SKILL.md +9 -1
- package/bundled/upstream/ecc/skills/continuous-learning-v2/hooks/observe.sh +31 -9
- package/bundled/upstream/ecc/skills/continuous-learning-v2/scripts/detect-project.sh +38 -4
- package/bundled/upstream/ecc/skills/continuous-learning-v2/scripts/instinct-cli.py +319 -12
- package/bundled/upstream/ecc/skills/data-throughput-accelerator/SKILL.md +72 -0
- package/bundled/upstream/ecc/skills/dynamic-workflow-mode/SKILL.md +123 -0
- package/bundled/upstream/ecc/skills/frontend-a11y/SKILL.md +446 -0
- package/bundled/upstream/ecc/skills/ito-basket-compare/SKILL.md +63 -0
- package/bundled/upstream/ecc/skills/ito-data-atlas-agent/SKILL.md +63 -0
- package/bundled/upstream/ecc/skills/ito-market-intelligence/SKILL.md +60 -0
- package/bundled/upstream/ecc/skills/ito-trade-planner/SKILL.md +67 -0
- package/bundled/upstream/ecc/skills/latency-critical-systems/SKILL.md +73 -0
- package/bundled/upstream/ecc/skills/marketing-campaign/SKILL.md +113 -0
- package/bundled/upstream/ecc/skills/nextjs-turbopack/SKILL.md +13 -0
- package/bundled/upstream/ecc/skills/parallel-execution-optimizer/SKILL.md +72 -0
- package/bundled/upstream/ecc/skills/prediction-market-oracle-research/SKILL.md +63 -0
- package/bundled/upstream/ecc/skills/prediction-market-risk-review/SKILL.md +60 -0
- package/bundled/upstream/ecc/skills/react-patterns/SKILL.md +341 -0
- package/bundled/upstream/ecc/skills/react-performance/SKILL.md +574 -0
- package/bundled/upstream/ecc/skills/react-testing/SKILL.md +423 -0
- package/bundled/upstream/ecc/skills/recsys-pipeline-architect/SKILL.md +114 -0
- package/bundled/upstream/ecc/skills/recursive-decision-ledger/SKILL.md +79 -0
- package/bundled/upstream/ecc/skills/social-publisher/SKILL.md +115 -0
- package/bundled/upstream/ecc/skills/team-agent-orchestration/SKILL.md +110 -0
- package/bundled/upstream/ecc/skills/uncloud/SKILL.md +343 -0
- package/bundled/upstream/ecc/skills/windows-desktop-e2e/SKILL.md +99 -0
- package/bundled/upstream/oh-my-claudecode/.omc-source/bundle.json +2 -1
- package/bundled/upstream/oh-my-claudecode/.omc-source/provenance.json +116 -0
- package/bundled/upstream/oh-my-claudecode/skills/autopilot/SKILL.md +7 -0
- package/bundled/upstream/oh-my-claudecode/skills/cancel/SKILL.md +1 -0
- package/bundled/upstream/oh-my-claudecode/skills/deep-interview/SKILL.md +39 -5
- package/bundled/upstream/oh-my-claudecode/skills/hud/SKILL.md +1 -0
- package/bundled/upstream/oh-my-claudecode/skills/local-build-reminder/SKILL.md +78 -0
- package/bundled/upstream/oh-my-claudecode/skills/omc-doctor/SKILL.md +1 -1
- package/bundled/upstream/oh-my-claudecode/skills/omc-setup/SKILL.md +26 -10
- package/bundled/upstream/oh-my-claudecode/skills/omc-setup/phases/01-install-claude-md.md +3 -3
- package/bundled/upstream/oh-my-claudecode/skills/omc-setup/phases/02-configure.md +6 -4
- package/bundled/upstream/oh-my-claudecode/skills/omc-setup/phases/03-integrations.md +1 -1
- package/bundled/upstream/oh-my-claudecode/skills/omc-setup/phases/04-welcome.md +2 -2
- package/bundled/upstream/oh-my-claudecode/skills/omc-teams/SKILL.md +6 -6
- package/bundled/upstream/oh-my-claudecode/skills/plan/SKILL.md +44 -32
- package/bundled/upstream/oh-my-claudecode/skills/ralph/SKILL.md +45 -21
- package/bundled/upstream/oh-my-claudecode/skills/ralplan/SKILL.md +1 -1
- package/bundled/upstream/oh-my-claudecode/skills/self-improve/SKILL.md +7 -0
- package/bundled/upstream/oh-my-claudecode/skills/self-improve/scripts/resolve-paths.mjs +39 -15
- package/bundled/upstream/oh-my-claudecode/skills/team/SKILL.md +132 -90
- package/bundled/upstream/oh-my-claudecode/skills/ultragoal/SKILL.md +93 -0
- package/bundled/upstream/oh-my-claudecode/skills/ultraqa/SKILL.md +28 -13
- package/bundled/upstream/oh-my-claudecode/skills/ultrawork/SKILL.md +7 -0
- package/bundled/upstream/superpowers/.omc-source/bundle.json +2 -1
- package/bundled/upstream/superpowers/.omc-source/provenance.json +63 -0
- package/package.json +2 -1
- package/src/catalog/source-catalog.js +10 -4
- package/src/cli/index.js +4 -0
- package/src/cli/plan.js +14 -2
- package/src/cli/setup.js +52 -13
- package/src/cli/skill.js +1 -1
- package/src/cli/source.js +265 -14
- package/src/config/sources.js +67 -1
- package/src/merge/content-patch.js +84 -0
- package/templates/merge-config.json +1 -8
- package/bundled/upstream/ecc/skills/strategic-compact/suggest-compact.sh +0 -54
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: social-publisher
|
|
3
|
+
description: Agent-driven scheduling and publishing of social media posts across 13 platforms via SocialClaw. Use when the user wants to publish to X, LinkedIn, Instagram, Facebook Pages, TikTok, Discord, Telegram, YouTube, Reddit, WordPress, or Pinterest — or when managing campaigns, uploading media, or monitoring post delivery status.
|
|
4
|
+
origin: community
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Social Publisher (SocialClaw)
|
|
8
|
+
|
|
9
|
+
Connects Claude Code to [SocialClaw](https://getsocialclaw.com) for agent-driven social media publishing across 13 platforms through a single workspace API key.
|
|
10
|
+
|
|
11
|
+
## When to Activate
|
|
12
|
+
|
|
13
|
+
- publish content to X, LinkedIn, Instagram, TikTok, or other platforms
|
|
14
|
+
- schedule a post campaign across multiple platforms at once
|
|
15
|
+
- upload media for use in social posts
|
|
16
|
+
- validate a post schedule before going live
|
|
17
|
+
- monitor publishing run status and delivery analytics
|
|
18
|
+
|
|
19
|
+
## Setup
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
# Required: workspace API key from https://getsocialclaw.com/dashboard
|
|
23
|
+
export SC_API_KEY="<workspace-key>"
|
|
24
|
+
|
|
25
|
+
# Verify access
|
|
26
|
+
curl -sS -H "Authorization: Bearer $SC_API_KEY" https://getsocialclaw.com/v1/keys/validate
|
|
27
|
+
|
|
28
|
+
# Install CLI (optional but recommended)
|
|
29
|
+
npm install -g socialclaw@0.1.12
|
|
30
|
+
socialclaw login --api-key <workspace-key>
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Core Workflow
|
|
34
|
+
|
|
35
|
+
### 1. List connected accounts
|
|
36
|
+
```bash
|
|
37
|
+
socialclaw accounts list --json
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
If not connected:
|
|
41
|
+
```bash
|
|
42
|
+
socialclaw accounts connect --provider x --open
|
|
43
|
+
socialclaw accounts connect --provider linkedin --open
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### 2. Upload media (optional)
|
|
47
|
+
```bash
|
|
48
|
+
socialclaw assets upload --file ./image.png --json
|
|
49
|
+
# → { "asset_id": "..." }
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### 3. Build schedule.json
|
|
53
|
+
```json
|
|
54
|
+
{
|
|
55
|
+
"posts": [
|
|
56
|
+
{
|
|
57
|
+
"provider": "x",
|
|
58
|
+
"account_id": "<account-id>",
|
|
59
|
+
"text": "Post text here",
|
|
60
|
+
"scheduled_at": "2026-06-01T10:00:00Z"
|
|
61
|
+
}
|
|
62
|
+
]
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### 4. Validate before publishing
|
|
67
|
+
```bash
|
|
68
|
+
socialclaw validate -f schedule.json --json
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### 5. Publish
|
|
72
|
+
```bash
|
|
73
|
+
socialclaw apply -f schedule.json --json
|
|
74
|
+
# → { "run_id": "..." }
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### 6. Monitor
|
|
78
|
+
```bash
|
|
79
|
+
socialclaw status --run-id <run-id> --json
|
|
80
|
+
socialclaw posts list --json
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Supported Providers
|
|
84
|
+
|
|
85
|
+
| Provider | Key |
|
|
86
|
+
|----------|-----|
|
|
87
|
+
| X (Twitter) | `x` |
|
|
88
|
+
| LinkedIn profile | `linkedin` |
|
|
89
|
+
| LinkedIn page | `linkedin_page` |
|
|
90
|
+
| Instagram Business | `instagram_business` |
|
|
91
|
+
| Instagram standalone | `instagram` |
|
|
92
|
+
| Facebook Page | `facebook` |
|
|
93
|
+
| TikTok | `tiktok` |
|
|
94
|
+
| YouTube | `youtube` |
|
|
95
|
+
| Reddit | `reddit` |
|
|
96
|
+
| WordPress | `wordpress` |
|
|
97
|
+
| Discord | `discord` |
|
|
98
|
+
| Telegram | `telegram` |
|
|
99
|
+
| Pinterest | `pinterest` |
|
|
100
|
+
|
|
101
|
+
## Security
|
|
102
|
+
|
|
103
|
+
- Outbound requests go to `getsocialclaw.com` only
|
|
104
|
+
- Provider OAuth is in the SocialClaw dashboard — no per-provider secrets exposed to the agent
|
|
105
|
+
- `SC_API_KEY` is a workspace-scoped key
|
|
106
|
+
|
|
107
|
+
## Related Skills
|
|
108
|
+
|
|
109
|
+
- `x-api` — direct X/Twitter API operations
|
|
110
|
+
- `social-graph-ranker` — network analysis for outreach targeting
|
|
111
|
+
|
|
112
|
+
## Source
|
|
113
|
+
|
|
114
|
+
- npm: `npm install -g socialclaw@0.1.12`
|
|
115
|
+
- Dashboard: [SocialClaw dashboard](https://getsocialclaw.com/dashboard)
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: team-agent-orchestration
|
|
3
|
+
description: "Run team-based orchestration for agent squads using work items, ownership, agent Kanban, merge gates, and control pane handoffs."
|
|
4
|
+
origin: ECC
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Team Agent Orchestration
|
|
8
|
+
|
|
9
|
+
Use this skill when agents are being managed like a team rather than a single assistant. The purpose is to make team-based orchestration reliable: clear work items, explicit ownership, agent Kanban state, branch isolation, control pane visibility, and merge gates.
|
|
10
|
+
|
|
11
|
+
## When To Activate
|
|
12
|
+
|
|
13
|
+
- The task spans multiple agents, tools, harnesses, branches, or worktrees.
|
|
14
|
+
- The user mentions team orchestration, agent Kanban, squad, conductor, control pane, manager, desktop app, Zellij, tmux, Hermes, Devin, Codex, Claude Code, or multi-agent work.
|
|
15
|
+
- A project needs shared workflow state across people and agents.
|
|
16
|
+
- Existing agent fan-out is producing output but not mergeable product.
|
|
17
|
+
|
|
18
|
+
## Operating Model
|
|
19
|
+
|
|
20
|
+
Treat every agent as a teammate with a narrow contract:
|
|
21
|
+
|
|
22
|
+
- **Owner**: the person or agent accountable for the work item.
|
|
23
|
+
- **Scope**: files, branch, tool surface, and forbidden areas.
|
|
24
|
+
- **State**: backlog, ready, running, review, blocked, merged, or archived.
|
|
25
|
+
- **Evidence**: tests, screenshots, logs, review notes, or eval reports.
|
|
26
|
+
- **Merge gate**: the exact condition that allows integration.
|
|
27
|
+
|
|
28
|
+
## Agent Kanban
|
|
29
|
+
|
|
30
|
+
Use agent Kanban when work must be visible across sessions.
|
|
31
|
+
|
|
32
|
+
| Column | Meaning | Exit Criteria |
|
|
33
|
+
| --- | --- | --- |
|
|
34
|
+
| Backlog | Candidate work item, not yet shaped | Acceptance criteria written |
|
|
35
|
+
| Ready | Shaped and assignable | Owner and branch/worktree assigned |
|
|
36
|
+
| Running | Agent is actively working | Handoff artifact and changed files exist |
|
|
37
|
+
| Review | Work is complete but not merged | Tests, diff review, and risk check pass |
|
|
38
|
+
| Blocked | Needs external input or failed gate | Blocker has owner and next action |
|
|
39
|
+
| Merged | Integrated into mainline | PR merged or local main updated |
|
|
40
|
+
| Archived | No longer relevant | Reason recorded |
|
|
41
|
+
|
|
42
|
+
Each card should fit this schema:
|
|
43
|
+
|
|
44
|
+
```json
|
|
45
|
+
{
|
|
46
|
+
"id": "agent-card-001",
|
|
47
|
+
"title": "Build dynamic workflow skill",
|
|
48
|
+
"owner": "codex",
|
|
49
|
+
"state": "running",
|
|
50
|
+
"branch": "product/dynamic-workflow-team-orchestration",
|
|
51
|
+
"worktree": ".",
|
|
52
|
+
"acceptance": [
|
|
53
|
+
"Skill exists",
|
|
54
|
+
"Tests cover required concepts",
|
|
55
|
+
"Content artifact contains video and article angles"
|
|
56
|
+
],
|
|
57
|
+
"merge_gate": "lint, focused tests, and catalog check pass",
|
|
58
|
+
"handoff": "path/to/handoff.md"
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Team-Based Orchestration Flow
|
|
63
|
+
|
|
64
|
+
1. **Shape the board**: convert fuzzy ambition into work items with owners and merge gates.
|
|
65
|
+
2. **Pick execution mode**: single-agent, dynamic workflow mode, dmux/tmux, worktree fan-out, or external desktop orchestrator.
|
|
66
|
+
3. **Assign boundaries**: one owner per card, clear file scope, and no overlapping writes without an integrator.
|
|
67
|
+
4. **Run agents**: each agent writes evidence and handoff notes, not just code.
|
|
68
|
+
5. **Review in sequence**: tests first, then diff review, then security/risk checks, then content/product polish.
|
|
69
|
+
6. **Merge deliberately**: one integrator resolves conflicts and updates the control pane or status artifact.
|
|
70
|
+
7. **Extract reusable skill**: if the card pattern repeats, promote it into `skills/`.
|
|
71
|
+
|
|
72
|
+
## Control Pane Requirements
|
|
73
|
+
|
|
74
|
+
A useful control pane for team orchestration should show:
|
|
75
|
+
|
|
76
|
+
- Active work items and their agent Kanban state.
|
|
77
|
+
- Owner, harness, branch, worktree, and last heartbeat.
|
|
78
|
+
- Links to handoff artifacts, tests, screenshots, and PRs.
|
|
79
|
+
- Blockers grouped by owner and unblock action.
|
|
80
|
+
- Merge readiness by gate, not vibes.
|
|
81
|
+
- Reusable workflow candidates that should become shared skills.
|
|
82
|
+
|
|
83
|
+
Do not add more automation until the operator can answer: who owns this, what changed, what gate failed, and what can safely merge?
|
|
84
|
+
|
|
85
|
+
## Dynamic Workflow Compatibility
|
|
86
|
+
|
|
87
|
+
When a card needs dynamic workflow mode:
|
|
88
|
+
|
|
89
|
+
- Put the task-local harness under the card owner.
|
|
90
|
+
- Store inputs and outputs on the card.
|
|
91
|
+
- Require an eval before moving from Running to Review.
|
|
92
|
+
- Promote the harness to a shared skill only after repeat use.
|
|
93
|
+
|
|
94
|
+
## Failure Modes To Watch
|
|
95
|
+
|
|
96
|
+
- **Agent soup**: many agents running, no owner or merge gate.
|
|
97
|
+
- **Invisible work**: useful output exists only in a chat transcript.
|
|
98
|
+
- **Board theater**: a Kanban board exists but cards have no acceptance criteria.
|
|
99
|
+
- **Overlapping writes**: parallel agents edit the same files without worktrees.
|
|
100
|
+
- **No product artifact**: the process produces docs but no runnable or publishable surface.
|
|
101
|
+
|
|
102
|
+
## Output Standard
|
|
103
|
+
|
|
104
|
+
Finish each orchestration pass with:
|
|
105
|
+
|
|
106
|
+
- Board/card changes.
|
|
107
|
+
- Merged or pending branches.
|
|
108
|
+
- Tests and eval evidence.
|
|
109
|
+
- Blockers with owner and next action.
|
|
110
|
+
- New shared skill candidates.
|
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: uncloud
|
|
3
|
+
description: Use when managing an Uncloud cluster — deploying services, configuring Caddy ingress, adding static proxy routes for non-cluster devices, publishing ports, scaling, inspecting logs, or managing machines and volumes with the `uc` CLI.
|
|
4
|
+
origin: ECC
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Uncloud Cluster Management
|
|
8
|
+
|
|
9
|
+
Reference for the `uc` CLI — a decentralised self-hosting platform using Docker containers, WireGuard mesh networking, and Caddy reverse proxy.
|
|
10
|
+
|
|
11
|
+
## When to Activate
|
|
12
|
+
|
|
13
|
+
Use this skill when working with Uncloud clusters, especially when:
|
|
14
|
+
- Bootstrapping or joining machines with `uc machine`
|
|
15
|
+
- Deploying services from Compose files with `uc deploy`
|
|
16
|
+
- Publishing HTTP, HTTPS, TCP, or UDP ports through Uncloud
|
|
17
|
+
- Configuring Caddy ingress with `x-caddy`, `x-ports`, or `--caddyfile`
|
|
18
|
+
- Routing external LAN devices through the cluster proxy
|
|
19
|
+
- Inspecting logs, service state, volumes, DNS, or machine placement
|
|
20
|
+
|
|
21
|
+
## How It Works
|
|
22
|
+
|
|
23
|
+
Uncloud runs Docker services across peer machines connected by a WireGuard mesh. Each machine is an equal cluster member; services communicate on the overlay network and Caddy runs globally to terminate public HTTP/HTTPS traffic. Compose files can use Uncloud extensions for ingress, placement, and generated Caddy configuration, while the `uc` CLI handles image distribution, scheduling, scaling, logs, and cluster state.
|
|
24
|
+
|
|
25
|
+
## Examples
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
uc machine init user@host --name machine-1
|
|
29
|
+
uc service run --name web -p app.example.com:8080/https nginx:latest
|
|
30
|
+
uc deploy
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Core Concepts
|
|
34
|
+
|
|
35
|
+
- **No central control plane** — all machines are equal peers connected by WireGuard
|
|
36
|
+
- **Caddy** runs as a global service on every machine; auto-obtains TLS from Let's Encrypt
|
|
37
|
+
- **Overlay network** — services communicate via `10.210.0.0/16` by default; DNS provided inside the mesh
|
|
38
|
+
- **Caddyfile is autogenerated** — never edit it directly; use `x-caddy` / `--caddyfile` instead
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## CLI Quick Reference
|
|
43
|
+
|
|
44
|
+
### Machines
|
|
45
|
+
|
|
46
|
+
| Command | Purpose |
|
|
47
|
+
|---------|---------|
|
|
48
|
+
| `uc machine init user@host` | Bootstrap first machine / new cluster |
|
|
49
|
+
| `uc machine add user@host` | Join machine to existing cluster |
|
|
50
|
+
| `uc machine ls` | List machines |
|
|
51
|
+
| `uc machine update NAME --public-ip IP` | Update public IP for ingress |
|
|
52
|
+
| `uc machine rm NAME` | Remove machine |
|
|
53
|
+
|
|
54
|
+
Key `init` flags: `--name`, `--network 10.210.0.0/16`, `--no-caddy`, `--no-dns`, `--public-ip auto\|IP\|none`
|
|
55
|
+
|
|
56
|
+
### Services
|
|
57
|
+
|
|
58
|
+
| Command | Purpose |
|
|
59
|
+
|---------|---------|
|
|
60
|
+
| `uc service ls` / `uc ls` | List services |
|
|
61
|
+
| `uc service run IMAGE` | Run a single container service |
|
|
62
|
+
| `uc deploy` | Deploy from `compose.yaml` |
|
|
63
|
+
| `uc deploy --no-build` | Deploy already-pushed images without rebuilding |
|
|
64
|
+
| `uc deploy --recreate` | Force service recreation |
|
|
65
|
+
| `uc scale SERVICE N` | Set replica count |
|
|
66
|
+
| `uc service logs SERVICE` | View logs |
|
|
67
|
+
| `uc service exec SERVICE` | Shell into container |
|
|
68
|
+
| `uc service inspect SERVICE` | Detailed info |
|
|
69
|
+
| `uc service rm SERVICE` | Remove service (keeps named volumes) |
|
|
70
|
+
| `uc ps` | All containers across cluster |
|
|
71
|
+
|
|
72
|
+
### Images
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
uc image push myapp:latest # Push local image to all machines
|
|
76
|
+
uc image push myapp:latest -m machine1,machine2 # Push to specific machines
|
|
77
|
+
uc images # List images in cluster
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Volumes
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
uc volume ls # All volumes
|
|
84
|
+
uc volume ls -m machine1 # On specific machine
|
|
85
|
+
uc volume create NAME -m MACHINE
|
|
86
|
+
uc volume rm NAME
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Caddy
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
uc caddy config # Show current generated Caddyfile (read-only)
|
|
93
|
+
uc caddy deploy # Deploy/upgrade Caddy across cluster
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### DNS & Context
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
uc dns show # Show reserved *.uncld.dev domain
|
|
100
|
+
uc dns reserve # Reserve a new domain
|
|
101
|
+
uc ctx ls # List cluster contexts
|
|
102
|
+
uc ctx use prod # Switch context
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## Port Publishing
|
|
108
|
+
|
|
109
|
+
### HTTP/HTTPS (via Caddy reverse proxy)
|
|
110
|
+
|
|
111
|
+
```
|
|
112
|
+
-p [hostname:]container_port[/protocol]
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
| Example | Meaning |
|
|
116
|
+
|---------|---------|
|
|
117
|
+
| `-p 8080/https` | HTTPS with auto `service-name.cluster-domain` hostname |
|
|
118
|
+
| `-p app.example.com:8080/https` | HTTPS with custom hostname |
|
|
119
|
+
| `-p 8080/http` | HTTP only, no TLS |
|
|
120
|
+
|
|
121
|
+
### TCP/UDP (host-bound, bypasses Caddy)
|
|
122
|
+
|
|
123
|
+
```
|
|
124
|
+
-p [host_ip:]host_port:container_port[/protocol]@host
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
| Example | Meaning |
|
|
128
|
+
|---------|---------|
|
|
129
|
+
| `-p 5432:5432@host` | TCP 5432 on all interfaces |
|
|
130
|
+
| `-p 127.0.0.1:5432:5432@host` | TCP 5432 loopback only |
|
|
131
|
+
| `-p 53:5353/udp@host` | UDP |
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## Compose File Extensions
|
|
136
|
+
|
|
137
|
+
Uncloud adds these extensions on top of Docker Compose:
|
|
138
|
+
|
|
139
|
+
### `x-ports` — publish ports with domains
|
|
140
|
+
|
|
141
|
+
```yaml
|
|
142
|
+
services:
|
|
143
|
+
app:
|
|
144
|
+
image: app:latest
|
|
145
|
+
x-ports:
|
|
146
|
+
- example.com:8000/https
|
|
147
|
+
- www.example.com:8000/https
|
|
148
|
+
- api.example.com:9000/https
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### `x-caddy` — custom Caddy config for service
|
|
152
|
+
|
|
153
|
+
```yaml
|
|
154
|
+
services:
|
|
155
|
+
app:
|
|
156
|
+
image: app:latest
|
|
157
|
+
x-caddy: |
|
|
158
|
+
example.com {
|
|
159
|
+
redir https://www.example.com{uri} permanent
|
|
160
|
+
}
|
|
161
|
+
www.example.com {
|
|
162
|
+
reverse_proxy {{upstreams 8000}} {
|
|
163
|
+
import common_proxy
|
|
164
|
+
}
|
|
165
|
+
basic_auth /admin/* {
|
|
166
|
+
admin $2a$14$...
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Template functions available inside `x-caddy`:
|
|
172
|
+
- `{{upstreams [service] [port]}}` — healthy container IPs
|
|
173
|
+
- `{{.Name}}` — service name
|
|
174
|
+
- `{{.Upstreams}}` — map of all services → IPs
|
|
175
|
+
|
|
176
|
+
### `x-machines` — placement constraints
|
|
177
|
+
|
|
178
|
+
```yaml
|
|
179
|
+
services:
|
|
180
|
+
db:
|
|
181
|
+
image: postgres:18
|
|
182
|
+
x-machines: db-machine # Single machine name
|
|
183
|
+
app:
|
|
184
|
+
image: app:latest
|
|
185
|
+
x-machines:
|
|
186
|
+
- machine-1
|
|
187
|
+
- machine-2
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### Full multi-service example
|
|
191
|
+
|
|
192
|
+
```yaml
|
|
193
|
+
services:
|
|
194
|
+
api:
|
|
195
|
+
build: ./api
|
|
196
|
+
x-ports:
|
|
197
|
+
- api.example.com:3000/https
|
|
198
|
+
environment:
|
|
199
|
+
DATABASE_URL: postgres://db:5432/mydb
|
|
200
|
+
|
|
201
|
+
web:
|
|
202
|
+
build: ./web
|
|
203
|
+
x-ports:
|
|
204
|
+
- example.com:8000/https
|
|
205
|
+
- www.example.com:8000/https
|
|
206
|
+
environment:
|
|
207
|
+
API_URL: http://api:3000
|
|
208
|
+
|
|
209
|
+
db:
|
|
210
|
+
image: postgres:18
|
|
211
|
+
environment:
|
|
212
|
+
POSTGRES_PASSWORD: ${DB_PASSWORD}
|
|
213
|
+
volumes:
|
|
214
|
+
- db-data:/var/lib/postgresql/data
|
|
215
|
+
x-machines: db-machine
|
|
216
|
+
|
|
217
|
+
volumes:
|
|
218
|
+
db-data:
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## Routing to External (Non-Cluster) Devices
|
|
224
|
+
|
|
225
|
+
To expose an external device (e.g. BMC, NAS, router UI) via Caddy without running a real container:
|
|
226
|
+
|
|
227
|
+
**1. Create a Caddyfile snippet** (e.g. `~/device.caddyfile`):
|
|
228
|
+
|
|
229
|
+
```caddyfile
|
|
230
|
+
https://device.example.com {
|
|
231
|
+
reverse_proxy https://192.168.1.x {
|
|
232
|
+
transport http {
|
|
233
|
+
tls_insecure_skip_verify # needed for self-signed BMC certs
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
log
|
|
237
|
+
}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
For plaintext upstream: `reverse_proxy http://192.168.1.x:port`
|
|
241
|
+
|
|
242
|
+
**2. Register as a named service with no-op container:**
|
|
243
|
+
|
|
244
|
+
```bash
|
|
245
|
+
uc service run \
|
|
246
|
+
--name device-bmc \
|
|
247
|
+
--caddyfile ~/device.caddyfile \
|
|
248
|
+
registry.k8s.io/pause:3.9
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
`pause` is a minimal no-op container — it does nothing, but gives Uncloud a service entry to attach the Caddyfile to.
|
|
252
|
+
|
|
253
|
+
**3. Verify:**
|
|
254
|
+
|
|
255
|
+
```bash
|
|
256
|
+
uc caddy config # device.example.com block should appear
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
> `--caddyfile` cannot be combined with non-`@host` published ports.
|
|
260
|
+
|
|
261
|
+
**DNS tip:** A wildcard record (`*.yourdomain.com → cluster-public-ip`) means any new subdomain works immediately — no DNS change needed per service.
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
## Service DNS (Internal)
|
|
266
|
+
|
|
267
|
+
Services inside the cluster resolve each other by name:
|
|
268
|
+
|
|
269
|
+
| DNS name | Resolves to |
|
|
270
|
+
|----------|------------|
|
|
271
|
+
| `service-name` | Any healthy container |
|
|
272
|
+
| `service-name.internal` | Same |
|
|
273
|
+
| `rr.service-name.internal` | Round-robin |
|
|
274
|
+
| `nearest.service-name.internal` | Machine-local first |
|
|
275
|
+
|
|
276
|
+
---
|
|
277
|
+
|
|
278
|
+
## Scaling & Global Services
|
|
279
|
+
|
|
280
|
+
```bash
|
|
281
|
+
uc scale web 5 # 5 replicas (spread across machines)
|
|
282
|
+
uc scale web 1 # Scale down
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
```yaml
|
|
286
|
+
services:
|
|
287
|
+
caddy:
|
|
288
|
+
deploy:
|
|
289
|
+
mode: global # One container on every machine
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
---
|
|
293
|
+
|
|
294
|
+
## Image Tag Templates (in compose.yaml)
|
|
295
|
+
|
|
296
|
+
```yaml
|
|
297
|
+
image: myapp:{{gitdate "20060102"}}.{{gitsha 7}}
|
|
298
|
+
image: myapp:{{gitsha 7}}.${GITHUB_RUN_ID:-local}
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
| Function | Output |
|
|
302
|
+
|----------|--------|
|
|
303
|
+
| `{{gitsha N}}` | First N chars of commit SHA |
|
|
304
|
+
| `{{gitdate "format"}}` | Git commit date in Go format |
|
|
305
|
+
| `{{date "format"}}` | Current date |
|
|
306
|
+
|
|
307
|
+
---
|
|
308
|
+
|
|
309
|
+
## Common Workflows
|
|
310
|
+
|
|
311
|
+
**Deploy from source:**
|
|
312
|
+
```bash
|
|
313
|
+
uc deploy # Build + push + deploy
|
|
314
|
+
uc build --push && uc deploy --no-build # Separate steps
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
**Inspect a service:**
|
|
318
|
+
```bash
|
|
319
|
+
uc inspect web
|
|
320
|
+
uc logs -f web
|
|
321
|
+
uc logs --since 1h web
|
|
322
|
+
uc exec web # Opens shell
|
|
323
|
+
uc exec web /bin/sh -c "env" # Run specific command
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
**Zero-downtime deploys** happen automatically; Uncloud waits for health checks before terminating old containers.
|
|
327
|
+
|
|
328
|
+
**Force recreate:**
|
|
329
|
+
```bash
|
|
330
|
+
uc deploy --recreate
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
---
|
|
334
|
+
|
|
335
|
+
## Common Mistakes
|
|
336
|
+
|
|
337
|
+
| Mistake | Fix |
|
|
338
|
+
|---------|-----|
|
|
339
|
+
| Editing the Caddyfile directly | Use `x-caddy` in compose or `--caddyfile` on `uc service run` |
|
|
340
|
+
| Proxying an HTTPS upstream with self-signed cert | Add `transport http { tls_insecure_skip_verify }` |
|
|
341
|
+
| `uc caddy config` shows no user-defined blocks | Caddy admin socket unreachable — check `uc inspect caddy` and `uc logs caddy` |
|
|
342
|
+
| Service can't reach external LAN IP from container | Verify Caddy container's host can route to target network |
|
|
343
|
+
| Volumes lost after `uc service rm` | Named volumes persist; only anonymous volumes are auto-removed |
|
|
@@ -366,6 +366,65 @@ def stop_recording(proc):
|
|
|
366
366
|
proc.stdin.write(b"q"); proc.stdin.flush(); proc.wait(timeout=10)
|
|
367
367
|
```
|
|
368
368
|
|
|
369
|
+
## Per-Step Trace (opt-in)
|
|
370
|
+
|
|
371
|
+
The default failure screenshot is often too thin for diagnosing flaky tests. The step-level trace below is **off by default** — enable it only when reproducing a flaky case.
|
|
372
|
+
|
|
373
|
+
### Enable
|
|
374
|
+
|
|
375
|
+
```bash
|
|
376
|
+
E2E_TRACE=1 pytest tests/test_login.py -v
|
|
377
|
+
# Include typed text in the JSONL log (DO NOT use on tests that type credentials/PII):
|
|
378
|
+
E2E_TRACE=1 E2E_TRACE_INCLUDE_TEXT=1 pytest ...
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
### Patch into BasePage
|
|
382
|
+
|
|
383
|
+
```python
|
|
384
|
+
import os, json, time
|
|
385
|
+
TRACE_ENABLED = os.environ.get("E2E_TRACE") == "1"
|
|
386
|
+
TRACE_INCLUDE_TEXT = os.environ.get("E2E_TRACE_INCLUDE_TEXT") == "1"
|
|
387
|
+
|
|
388
|
+
class BasePage:
|
|
389
|
+
_step = 0
|
|
390
|
+
|
|
391
|
+
def _trace(self, action, spec=None, text=None):
|
|
392
|
+
if not TRACE_ENABLED:
|
|
393
|
+
return
|
|
394
|
+
BasePage._step += 1
|
|
395
|
+
idx = f"{BasePage._step:03d}"
|
|
396
|
+
os.makedirs(ARTIFACT_DIR, exist_ok=True)
|
|
397
|
+
try:
|
|
398
|
+
self.window.capture_as_image().save(
|
|
399
|
+
os.path.join(ARTIFACT_DIR, f"step_{idx}_{action}.png"))
|
|
400
|
+
except Exception:
|
|
401
|
+
pass # capture failure must not break the test
|
|
402
|
+
rec = {
|
|
403
|
+
"ts": time.time(), "step": BasePage._step, "action": action,
|
|
404
|
+
"locator": getattr(spec, "criteria", None),
|
|
405
|
+
"text": text if TRACE_INCLUDE_TEXT else ("<redacted>" if text else None),
|
|
406
|
+
}
|
|
407
|
+
with open(os.path.join(ARTIFACT_DIR, "trace.jsonl"), "a") as f:
|
|
408
|
+
f.write(json.dumps(rec) + "\n")
|
|
409
|
+
|
|
410
|
+
def click(self, spec):
|
|
411
|
+
self.wait_visible(spec); self._trace("click_before", spec)
|
|
412
|
+
spec.click_input(); self._trace("click_after", spec)
|
|
413
|
+
|
|
414
|
+
def type_text(self, spec, text):
|
|
415
|
+
self.wait_visible(spec); self._trace("type_before", spec, text)
|
|
416
|
+
# ... existing set_edit_text / keyboard fallback ...
|
|
417
|
+
self._trace("type_after", spec)
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
### Caveats
|
|
421
|
+
|
|
422
|
+
- **PII / credentials**: `type_text` content is `<redacted>` by default. Never set `E2E_TRACE_INCLUDE_TEXT=1` on login or payment flows.
|
|
423
|
+
- **Overhead**: ~50–200ms per action + one PNG per step on disk. Don't enable on the default CI matrix — only on a dedicated flake-repro job.
|
|
424
|
+
- **Artifact bloat**: a long flow produces tens of MB; tune `retention-days` accordingly.
|
|
425
|
+
- **Parallel/rerun hygiene**: this simple example appends to `trace.jsonl` and uses a class-level counter. Clear the artifact directory before reruns, and use per-worker artifact dirs for parallel tests.
|
|
426
|
+
- **Coverage gap**: actions performed outside `BasePage` (raw `pywinauto` calls in test code) are not traced.
|
|
427
|
+
|
|
369
428
|
## Flaky Test Handling
|
|
370
429
|
|
|
371
430
|
```python
|
|
@@ -387,6 +446,8 @@ Common causes and fixes:
|
|
|
387
446
|
| Animation in progress | `wait_until(lambda: not loading_indicator.exists())` |
|
|
388
447
|
| Dialog timing | `wait_window(title, timeout=15)` |
|
|
389
448
|
| CI display not ready | Set `DISPLAY` or use virtual desktop in CI |
|
|
449
|
+
| `set_edit_text` raises NotImplementedError | UIA ValuePattern missing (common on Qt 5.x) — `BasePage.type_text` already falls back to `keyboard.send_keys` |
|
|
450
|
+
| Control exists but `wait_visible` times out | Window minimised or off-screen — call `win.restore()` + `win.set_focus()` before waiting |
|
|
390
451
|
|
|
391
452
|
## Test Isolation & Sandbox
|
|
392
453
|
|
|
@@ -719,6 +780,44 @@ def click_image(template_path, confidence=0.85):
|
|
|
719
780
|
pyautogui.click(*pos)
|
|
720
781
|
```
|
|
721
782
|
|
|
783
|
+
### DPI / Scaling Rules (screenshot mode only)
|
|
784
|
+
|
|
785
|
+
Screenshot matching is brutally sensitive to Windows display scaling (100% / 125% / 150%). Three hard rules:
|
|
786
|
+
|
|
787
|
+
1. **Capture templates at the same scale as the target machine.** Don't try to rescue a mismatch with `PIL.Image.resize` — `cv2.matchTemplate` is very fragile against resampling artefacts.
|
|
788
|
+
2. **Pin the CI display scaling.** On `windows-latest` add a step like `Set-DisplayResolution 1920 1080 -Force` and disable per-monitor DPI scaling, so screenshot dimensions are reproducible.
|
|
789
|
+
3. **Record the scale alongside each artefact.** On capture, write `GetDpiForWindow(hwnd) / 96` to `artifacts/<test>/metadata.json` — postmortems become obvious instead of guess-work.
|
|
790
|
+
|
|
791
|
+
> Process-level DPI awareness (`SetProcessDpiAwarenessContext`) **can conflict with Qt's own DPI handling** when the app under test is Qt-based. Prefer "same-scale templates + CI pin" over flipping process-wide DPI mode in fixtures.
|
|
792
|
+
|
|
793
|
+
### Debugging Match Confidence
|
|
794
|
+
|
|
795
|
+
When tuning the `confidence` threshold, the only sane workflow is to **see** where the match landed. The helper below is diagnosis-only — do not call it from test code.
|
|
796
|
+
|
|
797
|
+
```python
|
|
798
|
+
def debug_match(template_path, out="artifacts/match_debug.png", confidence=0.85):
|
|
799
|
+
"""Diagnosis-only. Draw the best-match rectangle + score back on the current screen.
|
|
800
|
+
|
|
801
|
+
NOT for production tests — use when calibrating confidence or chasing false matches.
|
|
802
|
+
"""
|
|
803
|
+
import os, cv2, pyautogui, numpy as np
|
|
804
|
+
screen = np.array(pyautogui.screenshot())[:, :, ::-1]
|
|
805
|
+
tpl = cv2.imread(template_path)
|
|
806
|
+
if tpl is None:
|
|
807
|
+
raise RuntimeError(f"Template unreadable: {template_path}")
|
|
808
|
+
res = cv2.matchTemplate(screen, tpl, cv2.TM_CCOEFF_NORMED)
|
|
809
|
+
_, mv, _, ml = cv2.minMaxLoc(res)
|
|
810
|
+
h, w = tpl.shape[:2]
|
|
811
|
+
colour = (0, 255, 0) if mv >= confidence else (0, 0, 255) # green pass / red fail
|
|
812
|
+
cv2.rectangle(screen, ml, (ml[0]+w, ml[1]+h), colour, 2)
|
|
813
|
+
cv2.putText(screen, f"score={mv:.3f} thr={confidence}",
|
|
814
|
+
(ml[0], max(20, ml[1]-6)),
|
|
815
|
+
cv2.FONT_HERSHEY_SIMPLEX, 0.7, colour, 2)
|
|
816
|
+
os.makedirs(os.path.dirname(out) or ".", exist_ok=True)
|
|
817
|
+
cv2.imwrite(out, screen)
|
|
818
|
+
return mv
|
|
819
|
+
```
|
|
820
|
+
|
|
722
821
|
**Use sparingly** — image matching breaks on DPI changes, theme switches, and partial occlusion.
|
|
723
822
|
Always try UIA first; fall back to screenshots only for genuinely unreachable controls.
|
|
724
823
|
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
{
|
|
2
|
-
"syncedAt": "2026-
|
|
2
|
+
"syncedAt": "2026-06-05T08:06:20.958Z",
|
|
3
3
|
"sourceName": "oh-my-claudecode",
|
|
4
4
|
"remote": "https://github.com/Yeachan-Heo/oh-my-claudecode.git",
|
|
5
5
|
"ref": "main",
|
|
6
|
+
"commit": "3e945671dcf3ed1c1bcc422862815f92c1999143",
|
|
6
7
|
"kind": "content-repo",
|
|
7
8
|
"harnesses": [
|
|
8
9
|
"claude"
|