@olegkoval/agent-skills 1.19.1 → 1.20.0
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/.claude-plugin/plugin.json +3 -2
- package/.cursor-plugin/index.json +5 -0
- package/.grok-plugin/index.json +5 -0
- package/.kiro/steering/garmin-watchface.md +201 -0
- package/.windsurf/rules/garmin-watchface.md +200 -0
- package/README.md +7 -1
- package/catalog/skills.json +28 -4
- package/collections/wearables.json +7 -0
- package/package.json +1 -1
- package/packages/marketing/viral-launch/adapters/claude/skills/viral-launch/references/external-skills.md +12 -0
- package/packages/marketing/viral-launch/adapters/claude/skills/viral-launch/references/launch-checklist.md +42 -0
- package/packages/marketing/viral-launch/adapters/cursor/skills/viral-launch/references/external-skills.md +12 -0
- package/packages/marketing/viral-launch/adapters/cursor/skills/viral-launch/references/launch-checklist.md +42 -0
- package/packages/marketing/viral-launch/adapters/grok/skills/viral-launch/references/external-skills.md +12 -0
- package/packages/marketing/viral-launch/adapters/grok/skills/viral-launch/references/launch-checklist.md +42 -0
- package/packages/software-development/qodoloop/adapters/claude/skills/qodoloop/references/graphql-queries.md +151 -0
- package/packages/software-development/qodoloop/adapters/cursor/skills/qodoloop/references/graphql-queries.md +151 -0
- package/packages/software-development/qodoloop/adapters/grok/skills/qodoloop/references/graphql-queries.md +151 -0
- package/packages/software-development/semantic-release-beta/adapters/claude/skills/semantic-release-beta/references/github-actions.md +16 -0
- package/packages/software-development/semantic-release-beta/adapters/claude/skills/semantic-release-beta/references/node-semantic-release.md +13 -0
- package/packages/software-development/semantic-release-beta/adapters/claude/skills/semantic-release-beta/references/preset.md +47 -0
- package/packages/software-development/semantic-release-beta/adapters/claude/skills/semantic-release-beta/references/validation.md +17 -0
- package/packages/software-development/semantic-release-beta/adapters/cursor/skills/semantic-release-beta/references/github-actions.md +16 -0
- package/packages/software-development/semantic-release-beta/adapters/cursor/skills/semantic-release-beta/references/node-semantic-release.md +13 -0
- package/packages/software-development/semantic-release-beta/adapters/cursor/skills/semantic-release-beta/references/preset.md +47 -0
- package/packages/software-development/semantic-release-beta/adapters/cursor/skills/semantic-release-beta/references/validation.md +17 -0
- package/packages/software-development/semantic-release-beta/adapters/grok/skills/semantic-release-beta/references/github-actions.md +16 -0
- package/packages/software-development/semantic-release-beta/adapters/grok/skills/semantic-release-beta/references/node-semantic-release.md +13 -0
- package/packages/software-development/semantic-release-beta/adapters/grok/skills/semantic-release-beta/references/preset.md +47 -0
- package/packages/software-development/semantic-release-beta/adapters/grok/skills/semantic-release-beta/references/validation.md +17 -0
- package/packages/wearables/garmin-watchface/SKILL.md +204 -0
- package/packages/wearables/garmin-watchface/adapters/claude/plugin.json +5 -0
- package/packages/wearables/garmin-watchface/adapters/claude/skills/garmin-watchface/SKILL.md +205 -0
- package/packages/wearables/garmin-watchface/adapters/claude/skills/garmin-watchface/references/devices.md +98 -0
- package/packages/wearables/garmin-watchface/adapters/claude/skills/garmin-watchface/references/display.md +120 -0
- package/packages/wearables/garmin-watchface/adapters/claude/skills/garmin-watchface/references/layout.md +224 -0
- package/packages/wearables/garmin-watchface/adapters/claude/skills/garmin-watchface/references/simulator.md +146 -0
- package/packages/wearables/garmin-watchface/adapters/claude/skills/garmin-watchface/references/store.md +151 -0
- package/packages/wearables/garmin-watchface/adapters/claude/skills/garmin-watchface/references/testing.md +154 -0
- package/packages/wearables/garmin-watchface/adapters/claude/skills/garmin-watchface/scripts/ciq-calibrate +184 -0
- package/packages/wearables/garmin-watchface/adapters/claude/skills/garmin-watchface/scripts/ciq-capture +215 -0
- package/packages/wearables/garmin-watchface/adapters/claude/skills/garmin-watchface/scripts/ciq-devices +177 -0
- package/packages/wearables/garmin-watchface/adapters/claude/skills/garmin-watchface/scripts/ciq-doctor +85 -0
- package/packages/wearables/garmin-watchface/adapters/claude/skills/garmin-watchface/templates/Makefile +72 -0
- package/packages/wearables/garmin-watchface/adapters/claude/skills/garmin-watchface/templates/monkey.jungle +13 -0
- package/packages/wearables/garmin-watchface/adapters/claude/skills/garmin-watchface/templates/monkey.test.jungle +7 -0
- package/packages/wearables/garmin-watchface/adapters/codex/README.md +3 -0
- package/packages/wearables/garmin-watchface/adapters/cursor/plugin.json +6 -0
- package/packages/wearables/garmin-watchface/adapters/cursor/skills/garmin-watchface/SKILL.md +205 -0
- package/packages/wearables/garmin-watchface/adapters/cursor/skills/garmin-watchface/references/devices.md +98 -0
- package/packages/wearables/garmin-watchface/adapters/cursor/skills/garmin-watchface/references/display.md +120 -0
- package/packages/wearables/garmin-watchface/adapters/cursor/skills/garmin-watchface/references/layout.md +224 -0
- package/packages/wearables/garmin-watchface/adapters/cursor/skills/garmin-watchface/references/simulator.md +146 -0
- package/packages/wearables/garmin-watchface/adapters/cursor/skills/garmin-watchface/references/store.md +151 -0
- package/packages/wearables/garmin-watchface/adapters/cursor/skills/garmin-watchface/references/testing.md +154 -0
- package/packages/wearables/garmin-watchface/adapters/cursor/skills/garmin-watchface/scripts/ciq-calibrate +184 -0
- package/packages/wearables/garmin-watchface/adapters/cursor/skills/garmin-watchface/scripts/ciq-capture +215 -0
- package/packages/wearables/garmin-watchface/adapters/cursor/skills/garmin-watchface/scripts/ciq-devices +177 -0
- package/packages/wearables/garmin-watchface/adapters/cursor/skills/garmin-watchface/scripts/ciq-doctor +85 -0
- package/packages/wearables/garmin-watchface/adapters/cursor/skills/garmin-watchface/templates/Makefile +72 -0
- package/packages/wearables/garmin-watchface/adapters/cursor/skills/garmin-watchface/templates/monkey.jungle +13 -0
- package/packages/wearables/garmin-watchface/adapters/cursor/skills/garmin-watchface/templates/monkey.test.jungle +7 -0
- package/packages/wearables/garmin-watchface/adapters/grok/plugin.json +6 -0
- package/packages/wearables/garmin-watchface/adapters/grok/skills/garmin-watchface/SKILL.md +205 -0
- package/packages/wearables/garmin-watchface/adapters/grok/skills/garmin-watchface/references/devices.md +98 -0
- package/packages/wearables/garmin-watchface/adapters/grok/skills/garmin-watchface/references/display.md +120 -0
- package/packages/wearables/garmin-watchface/adapters/grok/skills/garmin-watchface/references/layout.md +224 -0
- package/packages/wearables/garmin-watchface/adapters/grok/skills/garmin-watchface/references/simulator.md +146 -0
- package/packages/wearables/garmin-watchface/adapters/grok/skills/garmin-watchface/references/store.md +151 -0
- package/packages/wearables/garmin-watchface/adapters/grok/skills/garmin-watchface/references/testing.md +154 -0
- package/packages/wearables/garmin-watchface/adapters/grok/skills/garmin-watchface/scripts/ciq-calibrate +184 -0
- package/packages/wearables/garmin-watchface/adapters/grok/skills/garmin-watchface/scripts/ciq-capture +215 -0
- package/packages/wearables/garmin-watchface/adapters/grok/skills/garmin-watchface/scripts/ciq-devices +177 -0
- package/packages/wearables/garmin-watchface/adapters/grok/skills/garmin-watchface/scripts/ciq-doctor +85 -0
- package/packages/wearables/garmin-watchface/adapters/grok/skills/garmin-watchface/templates/Makefile +72 -0
- package/packages/wearables/garmin-watchface/adapters/grok/skills/garmin-watchface/templates/monkey.jungle +13 -0
- package/packages/wearables/garmin-watchface/adapters/grok/skills/garmin-watchface/templates/monkey.test.jungle +7 -0
- package/packages/wearables/garmin-watchface/adapters/kiro/steering/garmin-watchface.md +201 -0
- package/packages/wearables/garmin-watchface/adapters/windsurf/rules/garmin-watchface.md +200 -0
- package/packages/wearables/garmin-watchface/references/devices.md +98 -0
- package/packages/wearables/garmin-watchface/references/display.md +120 -0
- package/packages/wearables/garmin-watchface/references/layout.md +224 -0
- package/packages/wearables/garmin-watchface/references/simulator.md +146 -0
- package/packages/wearables/garmin-watchface/references/store.md +151 -0
- package/packages/wearables/garmin-watchface/references/testing.md +154 -0
- package/packages/wearables/garmin-watchface/scripts/ciq-calibrate +184 -0
- package/packages/wearables/garmin-watchface/scripts/ciq-capture +215 -0
- package/packages/wearables/garmin-watchface/scripts/ciq-devices +177 -0
- package/packages/wearables/garmin-watchface/scripts/ciq-doctor +85 -0
- package/packages/wearables/garmin-watchface/templates/Makefile +72 -0
- package/packages/wearables/garmin-watchface/templates/monkey.jungle +13 -0
- package/packages/wearables/garmin-watchface/templates/monkey.test.jungle +7 -0
- package/scripts/build-adapters.sh +1 -1
- package/scripts/validate-catalog.sh +2 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "olko-agent-skills",
|
|
3
3
|
"description": "Agent-agnostic skill catalog for Codex, Claude, Cursor, Grok, Copilot, Windsurf, Kiro, and other skill-aware tools.",
|
|
4
|
-
"version": "1.19.
|
|
4
|
+
"version": "1.19.1",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Oleg Koval"
|
|
7
7
|
},
|
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
"./packages/software-development/macos-menubar-app",
|
|
33
33
|
"./packages/software-development/skill-budget-audit",
|
|
34
34
|
"./packages/software-development/crash-course",
|
|
35
|
-
"./packages/software-development/qodoloop"
|
|
35
|
+
"./packages/software-development/qodoloop",
|
|
36
|
+
"./packages/wearables/garmin-watchface"
|
|
36
37
|
]
|
|
37
38
|
}
|
|
@@ -110,6 +110,11 @@
|
|
|
110
110
|
"name": "olko:qodoloop",
|
|
111
111
|
"source": "./packages/software-development/qodoloop/adapters/cursor",
|
|
112
112
|
"description": "Iteratively drives a GitHub PR to zero unresolved Qodo findings — reads each finding's own Agent Prompt, applies the fix, replies to the thread, resolves it, pushes, and waits for Qodo's next pass."
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
"name": "olko:garmin-watchface",
|
|
116
|
+
"source": "./packages/wearables/garmin-watchface/adapters/cursor",
|
|
117
|
+
"description": "Build, test, screenshot and publish Garmin Connect IQ watch faces in Monkey C."
|
|
113
118
|
}
|
|
114
119
|
]
|
|
115
120
|
}
|
package/.grok-plugin/index.json
CHANGED
|
@@ -120,6 +120,11 @@
|
|
|
120
120
|
"name": "olko:qodoloop",
|
|
121
121
|
"source": "./packages/software-development/qodoloop/adapters/grok",
|
|
122
122
|
"description": "Iteratively drives a GitHub PR to zero unresolved Qodo findings — reads each finding's own Agent Prompt, applies the fix, replies to the thread, resolves it, pushes, and waits for Qodo's next pass."
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
"name": "olko:garmin-watchface",
|
|
126
|
+
"source": "./packages/wearables/garmin-watchface/adapters/grok",
|
|
127
|
+
"description": "Build, test, screenshot and publish Garmin Connect IQ watch faces in Monkey C."
|
|
123
128
|
}
|
|
124
129
|
]
|
|
125
130
|
}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
<!-- Generated by scripts/build-adapters.sh. Do not edit directly. -->
|
|
2
|
+
|
|
3
|
+
---
|
|
4
|
+
inclusion: manual
|
|
5
|
+
description: "Build, test, screenshot and publish Garmin Connect IQ watch faces in Monkey C."
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Garmin Connect IQ watch faces
|
|
9
|
+
|
|
10
|
+
Monkey C gives you almost no safety net. The compiler is happy to build a face
|
|
11
|
+
that draws off the bottom of the screen, a test suite that contains no tests, and
|
|
12
|
+
a colour that is not the colour you get. Everything below is a failure mode that
|
|
13
|
+
looked like success first.
|
|
14
|
+
|
|
15
|
+
**Read `references/` files as needed — do not read them all up front.**
|
|
16
|
+
|
|
17
|
+
| File | When |
|
|
18
|
+
| --- | --- |
|
|
19
|
+
| `references/display.md` | Choosing colours, anything about brightness or legibility |
|
|
20
|
+
| `references/layout.md` | Positioning anything; content clipped, overlapping, or off-screen |
|
|
21
|
+
| `references/testing.md` | Writing tests; a suspiciously clean test run |
|
|
22
|
+
| `references/simulator.md` | Screenshots, settings not applying, monkeydo hanging |
|
|
23
|
+
| `references/devices.md` | Adding device support, launcher icons, API levels |
|
|
24
|
+
| `references/store.md` | Publishing, listing copy, IP questions |
|
|
25
|
+
|
|
26
|
+
## Tools
|
|
27
|
+
|
|
28
|
+
Run these rather than reinventing them. All are standalone.
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
<skill-dir>/scripts/ciq-doctor # toolchain check: SDK, JDK, key, devices
|
|
32
|
+
<skill-dir>/scripts/ciq-devices # survey installed devices by resolution
|
|
33
|
+
<skill-dir>/scripts/ciq-devices --same-as fenix6pro # products you can add with no code change
|
|
34
|
+
<skill-dir>/scripts/ciq-capture out.png # calibrated simulator screenshot
|
|
35
|
+
<skill-dir>/scripts/ciq-capture out.png --face --size 260 # cropped + masked to the round display
|
|
36
|
+
<skill-dir>/scripts/ciq-calibrate # re-derive the display rect if capture looks wrong
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
`<skill-dir>/scripts/ciq-capture` exists because `screencapture -R` grabs a screen *region*, not
|
|
40
|
+
a window: without a frontmost check it silently photographs whatever is on top,
|
|
41
|
+
and the window moves between simulator restarts. Both failure modes produce a
|
|
42
|
+
plausible PNG of the wrong thing.
|
|
43
|
+
|
|
44
|
+
## The five things that will bite you
|
|
45
|
+
|
|
46
|
+
### 1. `make test` can compile zero tests and report success
|
|
47
|
+
|
|
48
|
+
If `monkey.jungle` sets `base.excludeAnnotations = test`, every `(:test)`
|
|
49
|
+
function is stripped from **every** target, including the unit-test build. You
|
|
50
|
+
get `BUILD SUCCESSFUL` and a green run with nothing compiled — even when the test
|
|
51
|
+
files reference symbols that no longer exist.
|
|
52
|
+
|
|
53
|
+
Fix: a second jungle passed as an additional `-f`. See
|
|
54
|
+
`<skill-dir>/templates/monkey.test.jungle` and the `test` target in `<skill-dir>/templates/Makefile`.
|
|
55
|
+
|
|
56
|
+
**Prove it before you trust it.** Put a deliberately unresolvable symbol in one
|
|
57
|
+
test and confirm the build fails:
|
|
58
|
+
|
|
59
|
+
```monkeyc
|
|
60
|
+
return ThisDoesNotExist.definitelyNotAFunction();
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### 2. Never hardcode a Y coordinate or assume a font height
|
|
64
|
+
|
|
65
|
+
`dc.getFontHeight()` is the only source of truth, and the numbers are larger than
|
|
66
|
+
they look. Measured on fenix 6 Pro:
|
|
67
|
+
|
|
68
|
+
| Font | Height |
|
|
69
|
+
| --- | --- |
|
|
70
|
+
| `FONT_XTINY` | 19 |
|
|
71
|
+
| `FONT_TINY` | 29 |
|
|
72
|
+
| `FONT_SMALL` | 32 |
|
|
73
|
+
| `FONT_NUMBER_MEDIUM` | 74 |
|
|
74
|
+
|
|
75
|
+
Content drawn past the screen height is simply invisible — no error, no warning,
|
|
76
|
+
no clipping indicator. A two-line `FONT_NUMBER_MEDIUM` block is 148px of a 260px
|
|
77
|
+
face.
|
|
78
|
+
|
|
79
|
+
Derive every Y at draw time, and **clamp** so a bottom row cannot be pushed off:
|
|
80
|
+
|
|
81
|
+
```monkeyc
|
|
82
|
+
function clampRuleY(derived as Number, footerH as Number) as Number {
|
|
83
|
+
var reserved = (footerH * 2) + GAP_BELOW_RULE + GAP_BETWEEN_ROWS;
|
|
84
|
+
var maxRuleY = SCREEN - BOTTOM_MARGIN - reserved;
|
|
85
|
+
return derived > maxRuleY ? maxRuleY : derived;
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
See `references/layout.md`.
|
|
90
|
+
|
|
91
|
+
### 3. The screen is round; your layout is not
|
|
92
|
+
|
|
93
|
+
Check content against the bezel curve, not the bounding square. A rectangle
|
|
94
|
+
inscribed in a circle fails at its **corners** long before its sides.
|
|
95
|
+
|
|
96
|
+
```monkeyc
|
|
97
|
+
function halfWidthAt(y as Number) as Number {
|
|
98
|
+
var dy = y - CENTER;
|
|
99
|
+
var inside = (CENTER * CENTER) - (dy * dy);
|
|
100
|
+
return inside <= 0 ? 0 : Math.sqrt(inside).toNumber();
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### 4. Colours are quantised, and brightness is reflectance
|
|
105
|
+
|
|
106
|
+
Many devices snap to a 4×4×4 lattice: `0x00 / 0x55 / 0xAA / 0xFF` per channel. A
|
|
107
|
+
colour not already on it is not the colour that ships.
|
|
108
|
+
|
|
109
|
+
More important: MIP screens are **transflective with no backlight**. A colour's
|
|
110
|
+
brightness *is* how much ambient light it returns. Grey reflects about two-thirds
|
|
111
|
+
of what white does. Choosing a photographically accurate grey for a large area
|
|
112
|
+
makes the whole face read as dim on the wrist while looking fine in the
|
|
113
|
+
simulator's backlit LCD.
|
|
114
|
+
|
|
115
|
+
Corollary: a saturated colour on a glyph reflects only its own channel, making
|
|
116
|
+
the thing you want to read the *dimmest* thing on screen.
|
|
117
|
+
|
|
118
|
+
See `references/display.md`.
|
|
119
|
+
|
|
120
|
+
### 5. The simulator lies about settings
|
|
121
|
+
|
|
122
|
+
It persists app settings and **ignores changed defaults in `properties.xml`**
|
|
123
|
+
until you do File → Reset All App Data. A property will keep reading its old
|
|
124
|
+
value while the XML plainly says otherwise. This looks exactly like broken
|
|
125
|
+
settings code.
|
|
126
|
+
|
|
127
|
+
Reset also drops the loaded device, so relaunch and re-push afterwards.
|
|
128
|
+
|
|
129
|
+
See `references/simulator.md`.
|
|
130
|
+
|
|
131
|
+
## Workflow
|
|
132
|
+
|
|
133
|
+
### Starting a face
|
|
134
|
+
|
|
135
|
+
1. `<skill-dir>/scripts/ciq-doctor` — confirm SDK, JDK, developer key, target device installed.
|
|
136
|
+
2. Copy `<skill-dir>/templates/Makefile`, `<skill-dir>/templates/monkey.jungle`, `<skill-dir>/templates/monkey.test.jungle`.
|
|
137
|
+
3. Generate a fresh app id: `python3 -c "import uuid;print(uuid.uuid4().hex)"`.
|
|
138
|
+
4. Split source by responsibility. This structure has held up well:
|
|
139
|
+
|
|
140
|
+
| Module | Holds |
|
|
141
|
+
| --- | --- |
|
|
142
|
+
| `Palette.mc` | Colours only, all lattice-exact |
|
|
143
|
+
| `Layout.mc` | Geometry, derivations, bezel maths — no drawing |
|
|
144
|
+
| `<Widget>.mc` | Drawing primitives (rows, bars, segments) |
|
|
145
|
+
| `Fields.mc` | Formatting and thresholds — pure, easy to test |
|
|
146
|
+
| `Sensors.mc` | Sensor reads with null handling |
|
|
147
|
+
| `<Name>View.mc` | Composition only |
|
|
148
|
+
|
|
149
|
+
Keeping `Layout` free of `Dc` calls is what makes geometry unit-testable.
|
|
150
|
+
|
|
151
|
+
### Every change
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
make build && make test && make lint
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
`make lint` is level 3 and catches real problems the level 2 build allows.
|
|
158
|
+
|
|
159
|
+
### Before committing
|
|
160
|
+
|
|
161
|
+
Capture and *look at it*. Layout bugs are invisible in a passing test run:
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
make build && make sim
|
|
165
|
+
<skill-dir>/scripts/ciq-capture /tmp/face.png --face --size 260
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Then Read the PNG. Every layout bug in this skill's history was found by looking,
|
|
169
|
+
not by testing.
|
|
170
|
+
|
|
171
|
+
## Monkey C gotchas
|
|
172
|
+
|
|
173
|
+
- Module-level functions take **no** visibility modifier. `private` and `hidden`
|
|
174
|
+
are class-only; at module scope they are syntax errors.
|
|
175
|
+
- `dc.fillPolygon` wants `Array<[Numeric, Numeric]>`. Cast the literal:
|
|
176
|
+
`[[x, y], ...] as Array<[Numeric, Numeric]>`.
|
|
177
|
+
- `getInitialView()` returns
|
|
178
|
+
`[WatchUi.Views] or [WatchUi.Views, WatchUi.InputDelegates]`.
|
|
179
|
+
- `Application.Properties.getValue()` **throws** when a key is absent, which
|
|
180
|
+
happens on a fresh install before settings have ever been written. Wrap every
|
|
181
|
+
read with a default.
|
|
182
|
+
- Integer division everywhere. Centring an odd width leaves a 1px skew — write
|
|
183
|
+
tests that allow it rather than forcing constants to stay even.
|
|
184
|
+
|
|
185
|
+
## Reference watches and homages
|
|
186
|
+
|
|
187
|
+
If reproducing a real object, get these right before anything else, because they
|
|
188
|
+
are what makes it recognisable:
|
|
189
|
+
|
|
190
|
+
- **Display polarity.** A 1970s LCD is *positive*: dark segments on a pale panel,
|
|
191
|
+
the inverse of every modern face. Getting this backwards turns a crystal into a
|
|
192
|
+
screen.
|
|
193
|
+
- **Proportion.** Bezels on vintage digitals are thick; the window is smaller
|
|
194
|
+
than memory suggests.
|
|
195
|
+
- **Where the legends sit** — maker's name on the bezel, not the glass.
|
|
196
|
+
|
|
197
|
+
No system font is a segment display. If you need one, draw it: see
|
|
198
|
+
`references/layout.md` for a working seven-segment renderer, including the ghost
|
|
199
|
+
(unlit) segments that are most of what sells the effect.
|
|
200
|
+
|
|
201
|
+
**Do not print a real brand on the face.** See `references/store.md`.
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
<!-- Generated by scripts/build-adapters.sh. Do not edit directly. -->
|
|
2
|
+
|
|
3
|
+
---
|
|
4
|
+
description: "Build, test, screenshot and publish Garmin Connect IQ watch faces in Monkey C."
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Garmin Connect IQ watch faces
|
|
8
|
+
|
|
9
|
+
Monkey C gives you almost no safety net. The compiler is happy to build a face
|
|
10
|
+
that draws off the bottom of the screen, a test suite that contains no tests, and
|
|
11
|
+
a colour that is not the colour you get. Everything below is a failure mode that
|
|
12
|
+
looked like success first.
|
|
13
|
+
|
|
14
|
+
**Read `references/` files as needed — do not read them all up front.**
|
|
15
|
+
|
|
16
|
+
| File | When |
|
|
17
|
+
| --- | --- |
|
|
18
|
+
| `references/display.md` | Choosing colours, anything about brightness or legibility |
|
|
19
|
+
| `references/layout.md` | Positioning anything; content clipped, overlapping, or off-screen |
|
|
20
|
+
| `references/testing.md` | Writing tests; a suspiciously clean test run |
|
|
21
|
+
| `references/simulator.md` | Screenshots, settings not applying, monkeydo hanging |
|
|
22
|
+
| `references/devices.md` | Adding device support, launcher icons, API levels |
|
|
23
|
+
| `references/store.md` | Publishing, listing copy, IP questions |
|
|
24
|
+
|
|
25
|
+
## Tools
|
|
26
|
+
|
|
27
|
+
Run these rather than reinventing them. All are standalone.
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
<skill-dir>/scripts/ciq-doctor # toolchain check: SDK, JDK, key, devices
|
|
31
|
+
<skill-dir>/scripts/ciq-devices # survey installed devices by resolution
|
|
32
|
+
<skill-dir>/scripts/ciq-devices --same-as fenix6pro # products you can add with no code change
|
|
33
|
+
<skill-dir>/scripts/ciq-capture out.png # calibrated simulator screenshot
|
|
34
|
+
<skill-dir>/scripts/ciq-capture out.png --face --size 260 # cropped + masked to the round display
|
|
35
|
+
<skill-dir>/scripts/ciq-calibrate # re-derive the display rect if capture looks wrong
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
`<skill-dir>/scripts/ciq-capture` exists because `screencapture -R` grabs a screen *region*, not
|
|
39
|
+
a window: without a frontmost check it silently photographs whatever is on top,
|
|
40
|
+
and the window moves between simulator restarts. Both failure modes produce a
|
|
41
|
+
plausible PNG of the wrong thing.
|
|
42
|
+
|
|
43
|
+
## The five things that will bite you
|
|
44
|
+
|
|
45
|
+
### 1. `make test` can compile zero tests and report success
|
|
46
|
+
|
|
47
|
+
If `monkey.jungle` sets `base.excludeAnnotations = test`, every `(:test)`
|
|
48
|
+
function is stripped from **every** target, including the unit-test build. You
|
|
49
|
+
get `BUILD SUCCESSFUL` and a green run with nothing compiled — even when the test
|
|
50
|
+
files reference symbols that no longer exist.
|
|
51
|
+
|
|
52
|
+
Fix: a second jungle passed as an additional `-f`. See
|
|
53
|
+
`<skill-dir>/templates/monkey.test.jungle` and the `test` target in `<skill-dir>/templates/Makefile`.
|
|
54
|
+
|
|
55
|
+
**Prove it before you trust it.** Put a deliberately unresolvable symbol in one
|
|
56
|
+
test and confirm the build fails:
|
|
57
|
+
|
|
58
|
+
```monkeyc
|
|
59
|
+
return ThisDoesNotExist.definitelyNotAFunction();
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### 2. Never hardcode a Y coordinate or assume a font height
|
|
63
|
+
|
|
64
|
+
`dc.getFontHeight()` is the only source of truth, and the numbers are larger than
|
|
65
|
+
they look. Measured on fenix 6 Pro:
|
|
66
|
+
|
|
67
|
+
| Font | Height |
|
|
68
|
+
| --- | --- |
|
|
69
|
+
| `FONT_XTINY` | 19 |
|
|
70
|
+
| `FONT_TINY` | 29 |
|
|
71
|
+
| `FONT_SMALL` | 32 |
|
|
72
|
+
| `FONT_NUMBER_MEDIUM` | 74 |
|
|
73
|
+
|
|
74
|
+
Content drawn past the screen height is simply invisible — no error, no warning,
|
|
75
|
+
no clipping indicator. A two-line `FONT_NUMBER_MEDIUM` block is 148px of a 260px
|
|
76
|
+
face.
|
|
77
|
+
|
|
78
|
+
Derive every Y at draw time, and **clamp** so a bottom row cannot be pushed off:
|
|
79
|
+
|
|
80
|
+
```monkeyc
|
|
81
|
+
function clampRuleY(derived as Number, footerH as Number) as Number {
|
|
82
|
+
var reserved = (footerH * 2) + GAP_BELOW_RULE + GAP_BETWEEN_ROWS;
|
|
83
|
+
var maxRuleY = SCREEN - BOTTOM_MARGIN - reserved;
|
|
84
|
+
return derived > maxRuleY ? maxRuleY : derived;
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
See `references/layout.md`.
|
|
89
|
+
|
|
90
|
+
### 3. The screen is round; your layout is not
|
|
91
|
+
|
|
92
|
+
Check content against the bezel curve, not the bounding square. A rectangle
|
|
93
|
+
inscribed in a circle fails at its **corners** long before its sides.
|
|
94
|
+
|
|
95
|
+
```monkeyc
|
|
96
|
+
function halfWidthAt(y as Number) as Number {
|
|
97
|
+
var dy = y - CENTER;
|
|
98
|
+
var inside = (CENTER * CENTER) - (dy * dy);
|
|
99
|
+
return inside <= 0 ? 0 : Math.sqrt(inside).toNumber();
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### 4. Colours are quantised, and brightness is reflectance
|
|
104
|
+
|
|
105
|
+
Many devices snap to a 4×4×4 lattice: `0x00 / 0x55 / 0xAA / 0xFF` per channel. A
|
|
106
|
+
colour not already on it is not the colour that ships.
|
|
107
|
+
|
|
108
|
+
More important: MIP screens are **transflective with no backlight**. A colour's
|
|
109
|
+
brightness *is* how much ambient light it returns. Grey reflects about two-thirds
|
|
110
|
+
of what white does. Choosing a photographically accurate grey for a large area
|
|
111
|
+
makes the whole face read as dim on the wrist while looking fine in the
|
|
112
|
+
simulator's backlit LCD.
|
|
113
|
+
|
|
114
|
+
Corollary: a saturated colour on a glyph reflects only its own channel, making
|
|
115
|
+
the thing you want to read the *dimmest* thing on screen.
|
|
116
|
+
|
|
117
|
+
See `references/display.md`.
|
|
118
|
+
|
|
119
|
+
### 5. The simulator lies about settings
|
|
120
|
+
|
|
121
|
+
It persists app settings and **ignores changed defaults in `properties.xml`**
|
|
122
|
+
until you do File → Reset All App Data. A property will keep reading its old
|
|
123
|
+
value while the XML plainly says otherwise. This looks exactly like broken
|
|
124
|
+
settings code.
|
|
125
|
+
|
|
126
|
+
Reset also drops the loaded device, so relaunch and re-push afterwards.
|
|
127
|
+
|
|
128
|
+
See `references/simulator.md`.
|
|
129
|
+
|
|
130
|
+
## Workflow
|
|
131
|
+
|
|
132
|
+
### Starting a face
|
|
133
|
+
|
|
134
|
+
1. `<skill-dir>/scripts/ciq-doctor` — confirm SDK, JDK, developer key, target device installed.
|
|
135
|
+
2. Copy `<skill-dir>/templates/Makefile`, `<skill-dir>/templates/monkey.jungle`, `<skill-dir>/templates/monkey.test.jungle`.
|
|
136
|
+
3. Generate a fresh app id: `python3 -c "import uuid;print(uuid.uuid4().hex)"`.
|
|
137
|
+
4. Split source by responsibility. This structure has held up well:
|
|
138
|
+
|
|
139
|
+
| Module | Holds |
|
|
140
|
+
| --- | --- |
|
|
141
|
+
| `Palette.mc` | Colours only, all lattice-exact |
|
|
142
|
+
| `Layout.mc` | Geometry, derivations, bezel maths — no drawing |
|
|
143
|
+
| `<Widget>.mc` | Drawing primitives (rows, bars, segments) |
|
|
144
|
+
| `Fields.mc` | Formatting and thresholds — pure, easy to test |
|
|
145
|
+
| `Sensors.mc` | Sensor reads with null handling |
|
|
146
|
+
| `<Name>View.mc` | Composition only |
|
|
147
|
+
|
|
148
|
+
Keeping `Layout` free of `Dc` calls is what makes geometry unit-testable.
|
|
149
|
+
|
|
150
|
+
### Every change
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
make build && make test && make lint
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
`make lint` is level 3 and catches real problems the level 2 build allows.
|
|
157
|
+
|
|
158
|
+
### Before committing
|
|
159
|
+
|
|
160
|
+
Capture and *look at it*. Layout bugs are invisible in a passing test run:
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
make build && make sim
|
|
164
|
+
<skill-dir>/scripts/ciq-capture /tmp/face.png --face --size 260
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Then Read the PNG. Every layout bug in this skill's history was found by looking,
|
|
168
|
+
not by testing.
|
|
169
|
+
|
|
170
|
+
## Monkey C gotchas
|
|
171
|
+
|
|
172
|
+
- Module-level functions take **no** visibility modifier. `private` and `hidden`
|
|
173
|
+
are class-only; at module scope they are syntax errors.
|
|
174
|
+
- `dc.fillPolygon` wants `Array<[Numeric, Numeric]>`. Cast the literal:
|
|
175
|
+
`[[x, y], ...] as Array<[Numeric, Numeric]>`.
|
|
176
|
+
- `getInitialView()` returns
|
|
177
|
+
`[WatchUi.Views] or [WatchUi.Views, WatchUi.InputDelegates]`.
|
|
178
|
+
- `Application.Properties.getValue()` **throws** when a key is absent, which
|
|
179
|
+
happens on a fresh install before settings have ever been written. Wrap every
|
|
180
|
+
read with a default.
|
|
181
|
+
- Integer division everywhere. Centring an odd width leaves a 1px skew — write
|
|
182
|
+
tests that allow it rather than forcing constants to stay even.
|
|
183
|
+
|
|
184
|
+
## Reference watches and homages
|
|
185
|
+
|
|
186
|
+
If reproducing a real object, get these right before anything else, because they
|
|
187
|
+
are what makes it recognisable:
|
|
188
|
+
|
|
189
|
+
- **Display polarity.** A 1970s LCD is *positive*: dark segments on a pale panel,
|
|
190
|
+
the inverse of every modern face. Getting this backwards turns a crystal into a
|
|
191
|
+
screen.
|
|
192
|
+
- **Proportion.** Bezels on vintage digitals are thick; the window is smaller
|
|
193
|
+
than memory suggests.
|
|
194
|
+
- **Where the legends sit** — maker's name on the bezel, not the glass.
|
|
195
|
+
|
|
196
|
+
No system font is a segment display. If you need one, draw it: see
|
|
197
|
+
`references/layout.md` for a working seven-segment renderer, including the ghost
|
|
198
|
+
(unlit) segments that are most of what sells the effect.
|
|
199
|
+
|
|
200
|
+
**Do not print a real brand on the face.** See `references/store.md`.
|
package/README.md
CHANGED
|
@@ -136,7 +136,7 @@ packages/{category}/{skill}/SKILL.md
|
|
|
136
136
|
|
|
137
137
|
</details>
|
|
138
138
|
|
|
139
|
-
## All
|
|
139
|
+
## All 25 Skills
|
|
140
140
|
|
|
141
141
|
Each entry links to its `SKILL.md`. Reference any skill by its `olko:*` lookup name in a new agent session.
|
|
142
142
|
|
|
@@ -185,6 +185,12 @@ Each entry links to its `SKILL.md`. Reference any skill by its `olko:*` lookup n
|
|
|
185
185
|
|-------|-------------|----------|
|
|
186
186
|
| [gallery](packages/photography/gallery/SKILL.md) | Creates photo galleries with AI-assisted layout curation and sequencing | Building a gallery from photos or planning photo layout, sequencing, and curation |
|
|
187
187
|
|
|
188
|
+
### Wearables (1)
|
|
189
|
+
|
|
190
|
+
| Skill | What it does | Use when |
|
|
191
|
+
|-------|-------------|----------|
|
|
192
|
+
| [garmin-watchface](packages/wearables/garmin-watchface/SKILL.md) | Builds, tests, screenshots, and publishes Garmin Connect IQ watch faces in Monkey C | Working on a Connect IQ watch face — layout that clips or overlaps, simulator screenshots, app settings, device support, or store submission |
|
|
193
|
+
|
|
188
194
|
## How to use skills
|
|
189
195
|
|
|
190
196
|
Install the Codex symlinks, then mention a skill by its lookup name in a new agent session:
|
package/catalog/skills.json
CHANGED
|
@@ -399,7 +399,7 @@
|
|
|
399
399
|
"lookupName": "olko:obsidian-pr-sync",
|
|
400
400
|
"category": "software-development",
|
|
401
401
|
"path": "packages/software-development/obsidian-pr-sync",
|
|
402
|
-
"description": "Fetch open GitHub PRs assigned to you or requesting your review, and write a grouped, age-sorted '## PRs to review' section into today's Obsidian daily note. Idempotent
|
|
402
|
+
"description": "Fetch open GitHub PRs assigned to you or requesting your review, and write a grouped, age-sorted '## PRs to review' section into today's Obsidian daily note. Idempotent \u2014 re-running replaces the section.",
|
|
403
403
|
"tags": [
|
|
404
404
|
"github",
|
|
405
405
|
"obsidian",
|
|
@@ -470,7 +470,7 @@
|
|
|
470
470
|
"lookupName": "olko:macos-menubar-app",
|
|
471
471
|
"category": "software-development",
|
|
472
472
|
"path": "packages/software-development/macos-menubar-app",
|
|
473
|
-
"description": "Build a production-quality macOS menubar or notch app in SwiftUI
|
|
473
|
+
"description": "Build a production-quality macOS menubar or notch app in SwiftUI \u2014 MenuBarExtra, sandbox entitlements, keyboard shortcuts, sound effects, accessibility permissions, and App Store preparation.",
|
|
474
474
|
"tags": [
|
|
475
475
|
"macos",
|
|
476
476
|
"swiftui",
|
|
@@ -495,7 +495,7 @@
|
|
|
495
495
|
"lookupName": "olko:skill-budget-audit",
|
|
496
496
|
"category": "software-development",
|
|
497
497
|
"path": "packages/software-development/skill-budget-audit",
|
|
498
|
-
"description": "Diagnose and fix Claude Code skill context budget overflow
|
|
498
|
+
"description": "Diagnose and fix Claude Code skill context budget overflow \u2014 identify heavy plugin bundles, remove domain-specific ones, and restore skill discoverability.",
|
|
499
499
|
"tags": [
|
|
500
500
|
"claude-code",
|
|
501
501
|
"skills",
|
|
@@ -538,7 +538,7 @@
|
|
|
538
538
|
"lookupName": "olko:qodoloop",
|
|
539
539
|
"category": "software-development",
|
|
540
540
|
"path": "packages/software-development/qodoloop",
|
|
541
|
-
"description": "Iteratively drives a GitHub PR to zero unresolved Qodo findings
|
|
541
|
+
"description": "Iteratively drives a GitHub PR to zero unresolved Qodo findings \u2014 reads each finding's own Agent Prompt, applies the fix, replies to the thread, resolves it, pushes, and waits for Qodo's next pass.",
|
|
542
542
|
"tags": [
|
|
543
543
|
"code-review",
|
|
544
544
|
"qodo",
|
|
@@ -556,6 +556,30 @@
|
|
|
556
556
|
"windsurf",
|
|
557
557
|
"kiro"
|
|
558
558
|
]
|
|
559
|
+
},
|
|
560
|
+
{
|
|
561
|
+
"name": "garmin-watchface",
|
|
562
|
+
"lookupName": "olko:garmin-watchface",
|
|
563
|
+
"category": "wearables",
|
|
564
|
+
"path": "packages/wearables/garmin-watchface",
|
|
565
|
+
"description": "Build, test, screenshot and publish Garmin Connect IQ watch faces in Monkey C.",
|
|
566
|
+
"tags": [
|
|
567
|
+
"garmin",
|
|
568
|
+
"connect-iq",
|
|
569
|
+
"monkey-c",
|
|
570
|
+
"watch-face",
|
|
571
|
+
"wearables",
|
|
572
|
+
"embedded"
|
|
573
|
+
],
|
|
574
|
+
"adapters": [
|
|
575
|
+
"codex",
|
|
576
|
+
"claude",
|
|
577
|
+
"cursor",
|
|
578
|
+
"copilot",
|
|
579
|
+
"windsurf",
|
|
580
|
+
"kiro",
|
|
581
|
+
"grok"
|
|
582
|
+
]
|
|
559
583
|
}
|
|
560
584
|
]
|
|
561
585
|
}
|
package/package.json
CHANGED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# External skills
|
|
2
|
+
|
|
3
|
+
Skill search found these related launch and marketing skills:
|
|
4
|
+
|
|
5
|
+
- `coreyhaines31/marketingskills@launch-strategy` - broad launch strategy skill, about 37K installs in Skills CLI search; source repo `coreyhaines31/marketingskills` has about 20K GitHub stars.
|
|
6
|
+
- `refoundai/lenny-skills@launch-marketing` - product management and launch marketing skill, under 1K installs in Skills CLI search.
|
|
7
|
+
|
|
8
|
+
Prefer this local `olko:viral-launch` skill when the work is specifically to make a repository launch-ready. Consider installing `coreyhaines31/marketingskills@launch-strategy` when the user wants a broader marketing strategy workflow:
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npx skills add coreyhaines31/marketingskills@launch-strategy -g -y
|
|
12
|
+
```
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Launch checklist
|
|
2
|
+
|
|
3
|
+
Use this checklist before calling a project launch-ready.
|
|
4
|
+
|
|
5
|
+
## Repo
|
|
6
|
+
|
|
7
|
+
- README headline says what the project does and for whom.
|
|
8
|
+
- First screen contains a demo, screenshot, or quickstart.
|
|
9
|
+
- Install steps work from a clean checkout.
|
|
10
|
+
- Examples cover the highest-intent use cases.
|
|
11
|
+
- License and contribution expectations are clear.
|
|
12
|
+
- Known limitations are stated without weakening the launch angle.
|
|
13
|
+
|
|
14
|
+
## Message
|
|
15
|
+
|
|
16
|
+
- One-sentence positioning is specific.
|
|
17
|
+
- The hook names a real problem or desire.
|
|
18
|
+
- Differentiation is concrete.
|
|
19
|
+
- Claims are backed by repo content, screenshots, demos, benchmarks, or examples.
|
|
20
|
+
- Copy avoids fake urgency, fake social proof, and generic hype.
|
|
21
|
+
|
|
22
|
+
## Distribution
|
|
23
|
+
|
|
24
|
+
- Launch channels are chosen for the actual audience.
|
|
25
|
+
- Each channel gets native copy, not pasted generic copy.
|
|
26
|
+
- Assets include at least one short post, one longer post, and one direct outreach note.
|
|
27
|
+
- Launch timing includes a response window for comments, issues, and feedback.
|
|
28
|
+
|
|
29
|
+
## Shareability
|
|
30
|
+
|
|
31
|
+
- There is a public artifact people can link to.
|
|
32
|
+
- The demo shows a before/after or clear transformation.
|
|
33
|
+
- Users have a reason to share the output, not only the product.
|
|
34
|
+
- Any referral or waitlist mechanism is tied to user value.
|
|
35
|
+
|
|
36
|
+
## Metrics
|
|
37
|
+
|
|
38
|
+
- Activation event is defined.
|
|
39
|
+
- Share event is defined.
|
|
40
|
+
- Conversion event is defined.
|
|
41
|
+
- Feedback collection path is defined.
|
|
42
|
+
- Launch review date is defined before launch.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# External skills
|
|
2
|
+
|
|
3
|
+
Skill search found these related launch and marketing skills:
|
|
4
|
+
|
|
5
|
+
- `coreyhaines31/marketingskills@launch-strategy` - broad launch strategy skill, about 37K installs in Skills CLI search; source repo `coreyhaines31/marketingskills` has about 20K GitHub stars.
|
|
6
|
+
- `refoundai/lenny-skills@launch-marketing` - product management and launch marketing skill, under 1K installs in Skills CLI search.
|
|
7
|
+
|
|
8
|
+
Prefer this local `olko:viral-launch` skill when the work is specifically to make a repository launch-ready. Consider installing `coreyhaines31/marketingskills@launch-strategy` when the user wants a broader marketing strategy workflow:
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npx skills add coreyhaines31/marketingskills@launch-strategy -g -y
|
|
12
|
+
```
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Launch checklist
|
|
2
|
+
|
|
3
|
+
Use this checklist before calling a project launch-ready.
|
|
4
|
+
|
|
5
|
+
## Repo
|
|
6
|
+
|
|
7
|
+
- README headline says what the project does and for whom.
|
|
8
|
+
- First screen contains a demo, screenshot, or quickstart.
|
|
9
|
+
- Install steps work from a clean checkout.
|
|
10
|
+
- Examples cover the highest-intent use cases.
|
|
11
|
+
- License and contribution expectations are clear.
|
|
12
|
+
- Known limitations are stated without weakening the launch angle.
|
|
13
|
+
|
|
14
|
+
## Message
|
|
15
|
+
|
|
16
|
+
- One-sentence positioning is specific.
|
|
17
|
+
- The hook names a real problem or desire.
|
|
18
|
+
- Differentiation is concrete.
|
|
19
|
+
- Claims are backed by repo content, screenshots, demos, benchmarks, or examples.
|
|
20
|
+
- Copy avoids fake urgency, fake social proof, and generic hype.
|
|
21
|
+
|
|
22
|
+
## Distribution
|
|
23
|
+
|
|
24
|
+
- Launch channels are chosen for the actual audience.
|
|
25
|
+
- Each channel gets native copy, not pasted generic copy.
|
|
26
|
+
- Assets include at least one short post, one longer post, and one direct outreach note.
|
|
27
|
+
- Launch timing includes a response window for comments, issues, and feedback.
|
|
28
|
+
|
|
29
|
+
## Shareability
|
|
30
|
+
|
|
31
|
+
- There is a public artifact people can link to.
|
|
32
|
+
- The demo shows a before/after or clear transformation.
|
|
33
|
+
- Users have a reason to share the output, not only the product.
|
|
34
|
+
- Any referral or waitlist mechanism is tied to user value.
|
|
35
|
+
|
|
36
|
+
## Metrics
|
|
37
|
+
|
|
38
|
+
- Activation event is defined.
|
|
39
|
+
- Share event is defined.
|
|
40
|
+
- Conversion event is defined.
|
|
41
|
+
- Feedback collection path is defined.
|
|
42
|
+
- Launch review date is defined before launch.
|