@ethlete/agent-rules 0.1.0-next.1 → 0.1.0-next.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +101 -0
- package/README.md +296 -21
- package/content/git-hooks/post-checkout.sh +10 -0
- package/content/git-hooks/pre-push.sh +5 -0
- package/content/hooks/context-warning.py +284 -69
- package/content/output-styles/ste-clarity.md +131 -0
- package/content/rules/comments.md +50 -20
- package/content/skills/angular-patterns/SKILL.md +1 -1
- package/content/skills/api-source/SKILL.md +118 -0
- package/content/skills/figma-export/SKILL.md +193 -0
- package/content/skills/figma-export/dump-figma-layers.py +83 -0
- package/content/skills/figma-export/dump-figma-svg.py +235 -0
- package/content/skills/figma-export/measure-template.mjs +87 -0
- package/content/skills/git-commit/SKILL.md +6 -7
- package/content/skills/git-flow/SKILL.md +87 -0
- package/content/skills/handoff/SKILL.md +4 -0
- package/content/skills/query/SKILL.md +23 -13
- package/content/skills/rxjs-signals/SKILL.md +1 -1
- package/content/skills/sdk-docs/SKILL.md +10 -2
- package/content/skills/sdk-local-build/SKILL.md +115 -0
- package/content/skills/sdk-source/SKILL.md +133 -0
- package/content/skills/styleguide/STYLEGUIDE.md +2 -2
- package/content/skills/theming/SKILL.md +14 -7
- package/content/skills/timetrack/SKILL.md +66 -0
- package/package.json +12 -1
- package/src/index.js +23 -10
- package/src/index.js.map +1 -1
- package/src/lib/commitlint.d.ts +10 -0
- package/src/lib/commitlint.js +51 -0
- package/src/lib/commitlint.js.map +1 -0
- package/src/lib/config.d.ts +35 -6
- package/src/lib/config.js +26 -3
- package/src/lib/config.js.map +1 -1
- package/src/lib/git-flow/build.d.ts +35 -0
- package/src/lib/git-flow/build.js +24 -0
- package/src/lib/git-flow/build.js.map +1 -0
- package/src/lib/git-flow/config.d.ts +59 -0
- package/src/lib/git-flow/config.js +50 -0
- package/src/lib/git-flow/config.js.map +1 -0
- package/src/lib/git-flow/index.d.ts +6 -0
- package/src/lib/git-flow/index.js +10 -0
- package/src/lib/git-flow/index.js.map +1 -0
- package/src/lib/git-flow/parse.d.ts +49 -0
- package/src/lib/git-flow/parse.js +274 -0
- package/src/lib/git-flow/parse.js.map +1 -0
- package/src/lib/git-flow/rename.d.ts +24 -0
- package/src/lib/git-flow/rename.js +70 -0
- package/src/lib/git-flow/rename.js.map +1 -0
- package/src/lib/git-flow/start.d.ts +49 -0
- package/src/lib/git-flow/start.js +57 -0
- package/src/lib/git-flow/start.js.map +1 -0
- package/src/lib/git-flow/validate.d.ts +34 -0
- package/src/lib/git-flow/validate.js +72 -0
- package/src/lib/git-flow/validate.js.map +1 -0
- package/src/lib/git-flow-command.d.ts +4 -0
- package/src/lib/git-flow-command.js +157 -0
- package/src/lib/git-flow-command.js.map +1 -0
- package/src/lib/git-flow-repair.d.ts +17 -0
- package/src/lib/git-flow-repair.js +146 -0
- package/src/lib/git-flow-repair.js.map +1 -0
- package/src/lib/git-flow-start.d.ts +20 -0
- package/src/lib/git-flow-start.js +132 -0
- package/src/lib/git-flow-start.js.map +1 -0
- package/src/lib/git.d.ts +27 -0
- package/src/lib/git.js +49 -0
- package/src/lib/git.js.map +1 -0
- package/src/lib/gitlab.d.ts +35 -0
- package/src/lib/gitlab.js +98 -0
- package/src/lib/gitlab.js.map +1 -0
- package/src/lib/index.d.ts +1 -0
- package/src/lib/index.js +1 -0
- package/src/lib/index.js.map +1 -1
- package/src/lib/output-style-command.d.ts +3 -0
- package/src/lib/output-style-command.js +69 -0
- package/src/lib/output-style-command.js.map +1 -0
- package/src/lib/output-style.d.ts +38 -0
- package/src/lib/output-style.js +126 -0
- package/src/lib/output-style.js.map +1 -0
- package/src/lib/owned-paths.js +19 -1
- package/src/lib/owned-paths.js.map +1 -1
- package/src/lib/plan.d.ts +0 -1
- package/src/lib/plan.js +83 -9
- package/src/lib/plan.js.map +1 -1
- package/src/lib/prompt.d.ts +8 -0
- package/src/lib/prompt.js +27 -0
- package/src/lib/prompt.js.map +1 -0
- package/src/lib/render.d.ts +20 -2
- package/src/lib/render.js +31 -8
- package/src/lib/render.js.map +1 -1
- package/src/lib/sync.d.ts +0 -1
- package/src/lib/sync.js +2 -2
- package/src/lib/sync.js.map +1 -1
- package/src/lib/targets/claude-hooks.d.ts +1 -23
- package/src/lib/targets/claude-hooks.js +15 -84
- package/src/lib/targets/claude-hooks.js.map +1 -1
- package/src/lib/targets/claude.js +1 -1
- package/src/lib/targets/claude.js.map +1 -1
- package/src/lib/targets/codex-hooks.d.ts +12 -0
- package/src/lib/targets/codex-hooks.js +33 -0
- package/src/lib/targets/codex-hooks.js.map +1 -0
- package/src/lib/targets/codex.js +1 -1
- package/src/lib/targets/codex.js.map +1 -1
- package/src/lib/targets/copilot.js +1 -1
- package/src/lib/targets/copilot.js.map +1 -1
- package/src/lib/targets/cursor.js +1 -1
- package/src/lib/targets/cursor.js.map +1 -1
- package/src/lib/targets/git-hooks.d.ts +24 -0
- package/src/lib/targets/git-hooks.js +70 -0
- package/src/lib/targets/git-hooks.js.map +1 -0
- package/src/lib/targets/hooks-shared.d.ts +37 -0
- package/src/lib/targets/hooks-shared.js +95 -0
- package/src/lib/targets/hooks-shared.js.map +1 -0
- package/src/lib/targets/shared.d.ts +0 -1
- package/src/lib/targets/shared.js +1 -1
- package/src/lib/targets/shared.js.map +1 -1
- package/src/lib/timetrack-command.d.ts +11 -0
- package/src/lib/timetrack-command.js +199 -0
- package/src/lib/timetrack-command.js.map +1 -0
- package/src/lib/timetrack.d.ts +86 -0
- package/src/lib/timetrack.js +112 -0
- package/src/lib/timetrack.js.map +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,106 @@
|
|
|
1
1
|
# @ethlete/agent-rules
|
|
2
2
|
|
|
3
|
+
## 0.1.0-next.11
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [`16ae17e`](https://github.com/ethlete-io/ethdk/commit/16ae17e30238ef4539f3e168ca8299a4546ac292) Thanks [@TomTomB](https://github.com/TomTomB)! - The theming skill now states that a component which tints with `--et-theme-color-primary-opacity`
|
|
8
|
+
must compose the color itself, and that an `@property` `initial-value` cannot use a font-relative or
|
|
9
|
+
container unit.
|
|
10
|
+
|
|
11
|
+
## 0.1.0-next.10
|
|
12
|
+
|
|
13
|
+
### Minor Changes
|
|
14
|
+
|
|
15
|
+
- [#3067](https://github.com/ethlete-io/ethdk/pull/3067) [`226fd3d`](https://github.com/ethlete-io/ethdk/commit/226fd3d0b52f1a131ccbaa417ffe96682752d3f8) Thanks [@github-actions](https://github.com/apps/github-actions)! - New `ethlete-agents output-style` command: it installs the `ste-clarity` ASD-STE100 output style into Claude Code's user config and switches to it. Claude Code only.
|
|
16
|
+
|
|
17
|
+
- [#3067](https://github.com/ethlete-io/ethdk/pull/3067) [`3657156`](https://github.com/ethlete-io/ethdk/commit/36571560c755468459a87da9d9ec5764d976ee96) Thanks [@github-actions](https://github.com/apps/github-actions)! - `ethlete-agents timetrack instance` reports the Jira instance's own levels and the custom fields a
|
|
18
|
+
branch subject could go in, so a setup step reads the answer instead of guessing it.
|
|
19
|
+
|
|
20
|
+
## 0.1.0-next.9
|
|
21
|
+
|
|
22
|
+
### Minor Changes
|
|
23
|
+
|
|
24
|
+
- [`ae165cc`](https://github.com/ethlete-io/ethdk/commit/ae165cc4123e3f2abaa88c5cfd8262b13aac81d1) Thanks [@TomTomB](https://github.com/TomTomB)! - New `api-source` skill reads the API repo of the app you are in, from the local config's new `apiRepoPaths` map (`{ "hub": "../fut-hub-backend" }`).
|
|
25
|
+
|
|
26
|
+
- [`f132d0b`](https://github.com/ethlete-io/ethdk/commit/f132d0b64e322c5823c9f50adeedecf388c5aa65) Thanks [@TomTomB](https://github.com/TomTomB)! - `ethlete-agents timetrack` reaches Jira through the running Timetrack app, so no repository holds a
|
|
27
|
+
token any more — the `jira` credentials in the local config and the `JIRA_*` variables are gone.
|
|
28
|
+
|
|
29
|
+
- [#3066](https://github.com/ethlete-io/ethdk/pull/3066) [`fef4586`](https://github.com/ethlete-io/ethdk/commit/fef45868b10b0a0f01efff741958d65d9e405a31) Thanks [@github-actions](https://github.com/apps/github-actions)! - `git-flow`: add `conformingNameFor()`, which names what a non-conforming branch should be renamed to, and `git-flow repair` now handles a keyless branch it previously refused.
|
|
30
|
+
|
|
31
|
+
- [#3066](https://github.com/ethlete-io/ethdk/pull/3066) [`fef4586`](https://github.com/ethlete-io/ethdk/commit/fef45868b10b0a0f01efff741958d65d9e405a31) Thanks [@github-actions](https://github.com/apps/github-actions)! - `git-flow`: export `featureBranchesFor()` and `nestedSpecFor()`, so a host can plan a nested branch without running the CLI.
|
|
32
|
+
|
|
33
|
+
## 0.1.0-next.8
|
|
34
|
+
|
|
35
|
+
### Patch Changes
|
|
36
|
+
|
|
37
|
+
- [#3058](https://github.com/ethlete-io/ethdk/pull/3058) [`7074ffc`](https://github.com/ethlete-io/ethdk/commit/7074ffcb99812faed82a4e32fa3f8a1a43fcaf9d) Thanks [@github-actions](https://github.com/apps/github-actions)! - The `sdk-docs` skill points agents at the docs site's `llms.txt` index and the `.md` suffix on any page URL, so a page can be found and read without guessing a URL from the hardcoded domain list.
|
|
38
|
+
|
|
39
|
+
- [#3058](https://github.com/ethlete-io/ethdk/pull/3058) [`86fce5b`](https://github.com/ethlete-io/ethdk/commit/86fce5b87770ef4d5b069e59fec745eae93fda7b) Thanks [@github-actions](https://github.com/apps/github-actions)! - The `sdk-source` skill points at `apps/storybook/`, the SDK repo's renamed Storybook host.
|
|
40
|
+
|
|
41
|
+
## 0.1.0-next.7
|
|
42
|
+
|
|
43
|
+
### Minor Changes
|
|
44
|
+
|
|
45
|
+
- [#3056](https://github.com/ethlete-io/ethdk/pull/3056) [`8aec5ff`](https://github.com/ethlete-io/ethdk/commit/8aec5ff1a3ea6dd459d0e00bc691468019dcaca6) Thanks [@github-actions](https://github.com/apps/github-actions)! - Generated files no longer stamp the package version into their banner, so a release bump alone no longer reports every repo as out of sync - only real content changes do.
|
|
46
|
+
|
|
47
|
+
### Patch Changes
|
|
48
|
+
|
|
49
|
+
- [#3056](https://github.com/ethlete-io/ethdk/pull/3056) [`b5f72d6`](https://github.com/ethlete-io/ethdk/commit/b5f72d6bf35dd0e49cf14588b651012fb5d6a7c5) Thanks [@github-actions](https://github.com/apps/github-actions)! - The git-commit guide now presents its format as the repo's own convention unless a commitlint config is actually there, instead of pointing every repo at a `commitlint.config.js` it may not have.
|
|
50
|
+
|
|
51
|
+
## 0.1.0-next.6
|
|
52
|
+
|
|
53
|
+
### Minor Changes
|
|
54
|
+
|
|
55
|
+
- [#3055](https://github.com/ethlete-io/ethdk/pull/3055) [`86cd6e9`](https://github.com/ethlete-io/ethdk/commit/86cd6e97072d38436650ddc94a15527da34fa946) Thanks [@github-actions](https://github.com/apps/github-actions)! - Add the git-flow branch convention: a `git-flow` skill, `ethlete-agents git-flow start|check|repair|explain`, opt-in git hooks, and the parser at `@ethlete/agent-rules/git-flow`.
|
|
56
|
+
|
|
57
|
+
### Patch Changes
|
|
58
|
+
|
|
59
|
+
- [#3055](https://github.com/ethlete-io/ethdk/pull/3055) [`01b0797`](https://github.com/ethlete-io/ethdk/commit/01b0797d80df17e740419402034bc3eec739daaf) Thanks [@github-actions](https://github.com/apps/github-actions)! - The context-warning hook now points at `/ethlete-handoff`, the name the generated skill actually has, instead of a `/handoff` command that does not exist in a consumer repo.
|
|
60
|
+
|
|
61
|
+
## 0.1.0-next.5
|
|
62
|
+
|
|
63
|
+
### Minor Changes
|
|
64
|
+
|
|
65
|
+
- [#3048](https://github.com/ethlete-io/ethdk/pull/3048) [`6e19999`](https://github.com/ethlete-io/ethdk/commit/6e199997f51b88aaa1860a56a6b96be057ba1205) Thanks [@github-actions](https://github.com/apps/github-actions)! - The `context-warning` hook now runs under Codex as well as Claude Code, registered in
|
|
66
|
+
`.codex/hooks.json` whenever the `codex` target is on.
|
|
67
|
+
|
|
68
|
+
- [#3049](https://github.com/ethlete-io/ethdk/pull/3049) [`a606dda`](https://github.com/ethlete-io/ethdk/commit/a606dda0695ac8cc4370816bf3ff1c0814436091) Thanks [@TomTomB](https://github.com/TomTomB)! - Add the `figma-export` skill, guiding agents through reconciling a component against a Figma "copy as CSS" export.
|
|
69
|
+
|
|
70
|
+
### Patch Changes
|
|
71
|
+
|
|
72
|
+
- [#3048](https://github.com/ethlete-io/ethdk/pull/3048) [`fc56189`](https://github.com/ethlete-io/ethdk/commit/fc56189450a45f2b5819d40945a71205a6d67ba0) Thanks [@github-actions](https://github.com/apps/github-actions)! - The `query` skill now says to prefer `withArgs` over passing `args` to `execute()`, and when the imperative form is still right.
|
|
73
|
+
|
|
74
|
+
- [#3048](https://github.com/ethlete-io/ethdk/pull/3048) [`a16cc69`](https://github.com/ethlete-io/ethdk/commit/a16cc698a3cd3f14d0419d8f9710929fb41b4711) Thanks [@github-actions](https://github.com/apps/github-actions)! - Figma export skill: read an SVG frame as well as the CSS dump, with a `dump-figma-svg.py`
|
|
75
|
+
that prints its box tree and measures the auto-layout gaps.
|
|
76
|
+
|
|
77
|
+
## 0.1.0-next.4
|
|
78
|
+
|
|
79
|
+
### Minor Changes
|
|
80
|
+
|
|
81
|
+
- [#3045](https://github.com/ethlete-io/ethdk/pull/3045) [`fcd14f0`](https://github.com/ethlete-io/ethdk/commit/fcd14f09b4b09f81b5bde9f128a0fac4b0e2245c) Thanks [@github-actions](https://github.com/apps/github-actions)! - Add `disableAutoHandoffSave` to `ethlete-agents.config.local.json`, to opt out of the context-warning hook's auto-mode auto-save at the critical tier while keeping its normal warnings.
|
|
82
|
+
|
|
83
|
+
### Patch Changes
|
|
84
|
+
|
|
85
|
+
- [#3045](https://github.com/ethlete-io/ethdk/pull/3045) [`eb1b0a9`](https://github.com/ethlete-io/ethdk/commit/eb1b0a9cfb4e868b13a2b8eb6fd13221a6e0a654) Thanks [@github-actions](https://github.com/apps/github-actions)! - `context-warning` hook: in auto mode, the critical-tier warning now saves a `/handoff` immediately instead of just recommending it.
|
|
86
|
+
|
|
87
|
+
## 0.1.0-next.3
|
|
88
|
+
|
|
89
|
+
### Patch Changes
|
|
90
|
+
|
|
91
|
+
- [`ca0bf2f`](https://github.com/ethlete-io/ethdk/commit/ca0bf2f09cd5bd925da52bdb17c93bb62bda8735) Thanks [@TomTomB](https://github.com/TomTomB)! - The `comments` rule is now an allowlist: four kinds of comment are allowed and everything else gets deleted.
|
|
92
|
+
|
|
93
|
+
## 0.1.0-next.2
|
|
94
|
+
|
|
95
|
+
### Minor Changes
|
|
96
|
+
|
|
97
|
+
- [#3043](https://github.com/ethlete-io/ethdk/pull/3043) [`a311f80`](https://github.com/ethlete-io/ethdk/commit/a311f80455bc9cc9a925fe8f72ac945a1b057315) Thanks [@github-actions](https://github.com/apps/github-actions)! - New `sdk-source` and `sdk-local-build` skills let an agent read the SDK's own sources and test an unreleased build via `file:`, from the checkout named by the local config's new `sdkSourcePath`.
|
|
98
|
+
|
|
99
|
+
### Patch Changes
|
|
100
|
+
|
|
101
|
+
- [#3043](https://github.com/ethlete-io/ethdk/pull/3043) [`9627646`](https://github.com/ethlete-io/ethdk/commit/96276462e1c2ecde5394b8b1eafcebbb9f56a973) Thanks [@github-actions](https://github.com/apps/github-actions)! - Styleguide: changeset notes are now capped at one to two sentences, with mechanism and API inventories
|
|
102
|
+
explicitly sent to the docs instead.
|
|
103
|
+
|
|
3
104
|
## 0.1.0-next.1
|
|
4
105
|
|
|
5
106
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -103,7 +103,14 @@ Prettier rewrites them and `check` then reports drift on every run:
|
|
|
103
103
|
authoring-side guides are not overwritten by the consumer-side versions.
|
|
104
104
|
- **`vars`** - values for the template tokens a guide declares. Defaults live in
|
|
105
105
|
`content/defaults.json`; a guide whose variable has no default and no value is
|
|
106
|
-
skipped with a warning rather than emitted with a dangling placeholder.
|
|
106
|
+
skipped with a warning rather than emitted with a dangling placeholder. Some are
|
|
107
|
+
derived from the repo instead of defaulted - the `gitFlow*` ones from the `gitFlow`
|
|
108
|
+
block, and `commitRuleSource` / `commitValidation` from whether a commitlint config
|
|
109
|
+
exists (`commitlint.config.*`, `.commitlintrc*`, or a `commitlint` key in
|
|
110
|
+
`package.json`). Without one, the git-commit guide presents the format as the repo's
|
|
111
|
+
convention and never mentions a `commitlint` run - an agent that goes looking for a
|
|
112
|
+
promised validator and finds nothing reports the discrepancy instead of just
|
|
113
|
+
committing. Setting either one in `vars` overrides the detection.
|
|
107
114
|
- **`exclude`** - content names to skip entirely.
|
|
108
115
|
- **`claudeMdImportsAgentsMd`** - set (usually by `migrate`) when `CLAUDE.md` is an
|
|
109
116
|
`@AGENTS.md` import or symlink; the claude target then skips `.claude/rules/ethlete/`
|
|
@@ -113,10 +120,160 @@ Prettier rewrites them and `check` then reports drift on every run:
|
|
|
113
120
|
Content that declares `requires` is only emitted when those packages are installed, so
|
|
114
121
|
a repo without `@ethlete/query` never sees the query guide.
|
|
115
122
|
|
|
123
|
+
## Git flow
|
|
124
|
+
|
|
125
|
+
The branch convention lives in the same config, as one machine-readable grammar that the
|
|
126
|
+
CLI, a git hook, a CI job and `@ethlete/timetrack` all read:
|
|
127
|
+
|
|
128
|
+
```json
|
|
129
|
+
{
|
|
130
|
+
"gitFlow": {
|
|
131
|
+
"keyPrefixes": ["FIP"],
|
|
132
|
+
"baseBranches": { "development": "next", "production": "main" }
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
npx ethlete-agents git-flow start FIP-2177 # name it and branch off the right base
|
|
139
|
+
npx ethlete-agents git-flow check # the current branch
|
|
140
|
+
npx ethlete-agents git-flow check "$SOURCE" --target "$TARGET"
|
|
141
|
+
npx ethlete-agents git-flow check --all # adoption report
|
|
142
|
+
npx ethlete-agents git-flow repair dev-game-codes --key FIP-2900
|
|
143
|
+
npx ethlete-agents git-flow explain feat/FIP-2177-user-management
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
The shapes:
|
|
147
|
+
|
|
148
|
+
| Shape | Branch from | Merges into |
|
|
149
|
+
| ------------------------------------------ | ----------------------- | ------------------------------ |
|
|
150
|
+
| `feat/<KEY>-<subject>` | development | development |
|
|
151
|
+
| `sub/feat/<KEY>-<subject>/<KEY>-<subject>` | the main feature branch | the main feature branch |
|
|
152
|
+
| `release/<YYYY.MM.DD>` | development | development **and** production |
|
|
153
|
+
| `sub/release/<YYYY.MM.DD>/<KEY>-<subject>` | the release branch | the release branch |
|
|
154
|
+
| `hotfix/<KEY>-<subject>` | production | production |
|
|
155
|
+
|
|
156
|
+
**Why nested branches carry a `sub/` prefix.** Git refuses a ref that is both a branch and
|
|
157
|
+
a directory of branches, so `feat/FIP-2177-user-management/FIP-2178-reset` cannot exist
|
|
158
|
+
while `feat/FIP-2177-user-management` does - the push is rejected with `refname conflict`.
|
|
159
|
+
The prefix moves the nested tree out of the way while keeping the parent's full path inside
|
|
160
|
+
the child's name, so the merge request target is still derivable from the name alone. The
|
|
161
|
+
unprefixed spelling still parses, reports why it cannot exist, and `repair` moves it.
|
|
162
|
+
Configurable as `subPrefix`.
|
|
163
|
+
|
|
164
|
+
- **`enforcement`** - `"advisory"` (default) reports everything and blocks nothing, so a
|
|
165
|
+
repo can adopt the convention before it gates on it. `"gated"` applies each rule's
|
|
166
|
+
`severity`. A direct push to a base branch is blocked in both modes, and
|
|
167
|
+
`wrong-mr-target` can be raised to `"error"` on its own without ending the naming
|
|
168
|
+
grace period.
|
|
169
|
+
- **`keyPrefixes`** - the project's issue prefixes. Leave it empty and anything shaped
|
|
170
|
+
like `keyPattern` counts, which reads `chore/angular-22` as issue `ANGULAR-22`.
|
|
171
|
+
- **`severity`** - per rule: `unknown-type`, `missing-key`, `key-case`,
|
|
172
|
+
`missing-subject`, `type-alias`, `deprecated-prefix`, `release-date`,
|
|
173
|
+
`wrong-mr-target`, `protected-push`.
|
|
174
|
+
- **`deprecatedShapes`** - legacy spellings that still classify correctly and only earn a
|
|
175
|
+
rename suggestion. `dev-*` ships as the old spelling of a main feature branch.
|
|
176
|
+
|
|
177
|
+
The grammar is also importable on its own - `@ethlete/agent-rules/git-flow` has no
|
|
178
|
+
dependencies and touches no Node built-ins, so it runs in a browser:
|
|
179
|
+
|
|
180
|
+
```ts
|
|
181
|
+
import { parseBranch, planStart, resolveGitFlowConfig } from '@ethlete/agent-rules/git-flow';
|
|
182
|
+
|
|
183
|
+
const { storyKey, taskKey, findings } = parseBranch({ branch, config: resolveGitFlowConfig() });
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### `start` - the prospective flow
|
|
187
|
+
|
|
188
|
+
`git-flow start <KEY>` reads the issue from Jira, computes the name from the grammar and
|
|
189
|
+
creates the branch off the correct base. It prints the plan first and asks before writing;
|
|
190
|
+
`--dry-run` stops after the plan and `--yes` skips the question. It refuses on a dirty
|
|
191
|
+
working tree, when the branch already exists, and when the base branch is nowhere to be
|
|
192
|
+
found.
|
|
193
|
+
|
|
194
|
+
A Task with a parent Story nests under that Story's feature branch, which therefore has to
|
|
195
|
+
exist already - `start` says so rather than inventing a parent. `--of <branch>` picks the
|
|
196
|
+
parent explicitly, `--hotfix` branches off production, `--release <date>` makes a release
|
|
197
|
+
branch, and `--subject <text>` skips Jira entirely.
|
|
198
|
+
|
|
199
|
+
The issue is read through the Timetrack app - see [Jira, through Timetrack](#jira-through-timetrack).
|
|
200
|
+
No repository holds a Jira credential, so the only thing the committed config still says about
|
|
201
|
+
Jira is how an issue type becomes a branch type:
|
|
202
|
+
|
|
203
|
+
```json
|
|
204
|
+
{
|
|
205
|
+
"jira": {
|
|
206
|
+
"typeByIssueType": { "Bug": "fix" }
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
- **`typeByIssueType`** - the branch type per Jira issue type; anything unlisted becomes
|
|
212
|
+
`feat`. `--type` overrides it per call.
|
|
213
|
+
|
|
214
|
+
The branch subject comes from the instance's own subject field, which Timetrack resolves
|
|
215
|
+
because the field id is a property of the instance rather than of this repo. An issue that
|
|
216
|
+
sets no subject falls back to its summary, and the printed plan says which of the two it used.
|
|
217
|
+
|
|
218
|
+
### `repair` - renaming a branch that does not conform
|
|
219
|
+
|
|
220
|
+
`git-flow repair [ref]` derives the conforming name (`--key FIP-2900` when the old name
|
|
221
|
+
carries no issue key, `--to <branch>` to override), renames the branch locally and on the
|
|
222
|
+
remote, and retargets the open merge requests aimed at it through the GitLab API.
|
|
223
|
+
`GITLAB_TOKEN` needs the `api` scope.
|
|
224
|
+
|
|
225
|
+
Everything is checked before the first mutation, and it refuses rather than half-finishing:
|
|
226
|
+
|
|
227
|
+
- An open merge request whose **source** is the branch blocks the repair. GitLab cannot
|
|
228
|
+
move a merge request to another source branch, and closing it would lose its discussion -
|
|
229
|
+
merge or close it first.
|
|
230
|
+
- A branch that is pushed but whose merge requests cannot be listed (no token, or a remote
|
|
231
|
+
that is not GitLab) blocks too. `--no-mr-check` asserts that none point at it.
|
|
232
|
+
- If a retarget fails halfway, the old branch is still there and the recovery commands are
|
|
233
|
+
printed.
|
|
234
|
+
|
|
235
|
+
## Jira, through Timetrack
|
|
236
|
+
|
|
237
|
+
A Jira token in every repository is a secret nobody can rotate. There is one on this machine
|
|
238
|
+
instead, in the Timetrack app's keychain entry, and every repository asks the running app:
|
|
239
|
+
|
|
240
|
+
```bash
|
|
241
|
+
npx ethlete-agents timetrack status # is it reachable, and what does it hold?
|
|
242
|
+
npx ethlete-agents timetrack issue FIP-2177 # summary, type, parent, branch subject
|
|
243
|
+
npx ethlete-agents timetrack search "password" # open issues of the picked projects
|
|
244
|
+
npx ethlete-agents timetrack project # which project does this repo log into?
|
|
245
|
+
npx ethlete-agents timetrack create --summary "…" # file a ticket with the instance's settings
|
|
246
|
+
npx ethlete-agents timetrack log --issue FIP-2177 --minutes 45
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
`--json` prints the raw answer instead of lines. `git-flow start` uses the same channel.
|
|
250
|
+
|
|
251
|
+
**How it connects.** The app binds a loopback socket and writes its port and a fresh token
|
|
252
|
+
into `agent.json` in its own data directory (`~/.local/share/io.ethlete.timetrack/` on Linux,
|
|
253
|
+
`~/Library/Application Support/…` on macOS, `%APPDATA%\…` on Windows), readable by its owner
|
|
254
|
+
alone. The token lives no longer than the run, so a caller left over from an earlier one is
|
|
255
|
+
refused rather than trusted, and a request carrying an `Origin` header is refused outright -
|
|
256
|
+
a page the user happens to have open must not reach Jira through a port it guessed.
|
|
257
|
+
`TIMETRACK_AGENT_DISCOVERY` names the file for a machine that keeps it elsewhere.
|
|
258
|
+
|
|
259
|
+
**What the app answers, not this package.** The instance, the credentials, the picked
|
|
260
|
+
projects, the subject field and the ticket shape are all settings there. That is what makes
|
|
261
|
+
`create` file a ticket indistinguishable from one the app filed, and it is why none of them
|
|
262
|
+
appear in a repo's config any more.
|
|
263
|
+
|
|
264
|
+
**`log` writes to the day, not to Tempo.** It adds the same row the app's own timeline draws
|
|
265
|
+
for work nothing observed, and the user reviews the day before syncing it. A worklog posted
|
|
266
|
+
behind the review would double-book against whatever the evidence already proposed for that
|
|
267
|
+
hour.
|
|
268
|
+
|
|
269
|
+
**When the app is not running** every command says so and exits non-zero. There is no
|
|
270
|
+
fallback to an environment variable on purpose - a fallback is how the per-repo secret comes
|
|
271
|
+
back.
|
|
272
|
+
|
|
116
273
|
## Hooks (opt-in)
|
|
117
274
|
|
|
118
|
-
|
|
119
|
-
|
|
275
|
+
Hooks run commands on the developer's machine, so none are emitted by default - opt in
|
|
276
|
+
per hook in the config:
|
|
120
277
|
|
|
121
278
|
```json
|
|
122
279
|
{
|
|
@@ -124,35 +281,148 @@ default - opt in per hook in the config:
|
|
|
124
281
|
}
|
|
125
282
|
```
|
|
126
283
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
284
|
+
They are emitted for whichever of the `claude` and `codex` targets is enabled:
|
|
285
|
+
|
|
286
|
+
| Target | Script | Registered in |
|
|
287
|
+
| -------- | ------------------------ | ----------------------- |
|
|
288
|
+
| `claude` | `.claude/hooks/ethlete/` | `.claude/settings.json` |
|
|
289
|
+
| `codex` | `.codex/hooks/ethlete/` | `.codex/hooks.json` |
|
|
290
|
+
|
|
291
|
+
Your own entries in those files are left untouched; removing the name from `hooks`
|
|
292
|
+
unregisters and deletes the script again. Codex only loads project-local hooks once the
|
|
293
|
+
`.codex/` layer is trusted, and honours `[features] hooks = false`.
|
|
130
294
|
|
|
131
295
|
Available hooks:
|
|
132
296
|
|
|
133
|
-
- **`context-warning`** - warns once per tier (and instructs
|
|
134
|
-
context crosses 70% / 85% of the token budget, recommending
|
|
135
|
-
capped at the 200k long-context pricing boundary: on 1M-window models every
|
|
136
|
-
past 200k input tokens bills the whole context at a premium rate, so the
|
|
137
|
-
fire at ~140k/~170k instead of deep into the expensive range.
|
|
297
|
+
- **`context-warning`** - warns once per tier (and instructs the agent) when the session
|
|
298
|
+
context crosses 70% / 85% of the token budget, recommending a handoff. Under Claude the
|
|
299
|
+
budget is capped at the 200k long-context pricing boundary: on 1M-window models every
|
|
300
|
+
request past 200k input tokens bills the whole context at a premium rate, so the
|
|
301
|
+
warnings fire at ~140k/~170k instead of deep into the expensive range. Codex has no
|
|
302
|
+
such boundary, so its budget is the model's own reported context window and the
|
|
303
|
+
warnings are pure occupancy.
|
|
138
304
|
|
|
139
|
-
|
|
305
|
+
Two things are Claude-only: the separate user-facing line (Codex documents only
|
|
306
|
+
`additionalContext`, so there the warning is folded into the text the model is told to
|
|
307
|
+
relay), and the auto-mode escalation that writes the handoff file unprompted - Codex's
|
|
308
|
+
`permission_mode` values are undocumented, so no value enables it.
|
|
140
309
|
|
|
141
|
-
|
|
142
|
-
|
|
310
|
+
Hooks can be turned off per machine - see the local config below.
|
|
311
|
+
|
|
312
|
+
## Git hooks (opt-in)
|
|
313
|
+
|
|
314
|
+
Separate from the agent hooks above, and opt-in for the same reason - a generated block
|
|
315
|
+
that can reject a push is a higher-stakes artifact than a markdown one:
|
|
143
316
|
|
|
144
317
|
```json
|
|
145
318
|
{
|
|
146
|
-
"
|
|
319
|
+
"gitHooks": ["pre-push", "post-checkout"]
|
|
147
320
|
}
|
|
148
321
|
```
|
|
149
322
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
323
|
+
Each one is written as an `# ethlete:git-flow:start` … `end` block **appended** to your
|
|
324
|
+
`.husky/<name>`, so an existing hook there (a git-lfs hook, typically) keeps working and
|
|
325
|
+
keeps reading stdin first - which is why the block never reads stdin itself. Removing the
|
|
326
|
+
name from `gitHooks` takes the block back out and leaves the rest of the file alone.
|
|
327
|
+
|
|
328
|
+
- **`pre-push`** - runs `git-flow check --push` on the current branch. In `advisory` mode
|
|
329
|
+
only a direct push to a base branch can actually stop it.
|
|
330
|
+
- **`post-checkout`** - reports a non-conforming name on a branch that is on no remote yet,
|
|
331
|
+
which is the whole window in which renaming it is free.
|
|
332
|
+
|
|
333
|
+
Only `.husky/` is written, never `.git/hooks/`: the generated files are committed and CI's
|
|
334
|
+
`check` diffs them, so a hook outside the working tree could never be in sync. Without a
|
|
335
|
+
`.husky/` directory `sync` warns and writes nothing. The block calls
|
|
336
|
+
`node_modules/.bin/ethlete-agents` directly rather than through `npx`, so a repo where the
|
|
337
|
+
package is missing gets silence instead of a registry lookup that would fail the push.
|
|
338
|
+
`ETHLETE_GIT_FLOW_SKIP=1` silences both hooks on one machine.
|
|
339
|
+
|
|
340
|
+
## CI job
|
|
341
|
+
|
|
342
|
+
On GitLab, the merge request target is the half no local hook can see. The job needs no
|
|
343
|
+
configuration beyond the predefined variables:
|
|
344
|
+
|
|
345
|
+
```yaml
|
|
346
|
+
Git Flow:
|
|
347
|
+
stage: Checks
|
|
348
|
+
rules:
|
|
349
|
+
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
|
350
|
+
allow_failure: true
|
|
351
|
+
script:
|
|
352
|
+
- >
|
|
353
|
+
npx ethlete-agents git-flow check "$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME"
|
|
354
|
+
--target "$CI_MERGE_REQUEST_TARGET_BRANCH_NAME"
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
`allow_failure: true` on top of `advisory` mode is deliberate belt and braces: the job
|
|
358
|
+
reports for a whole grace period before it can ever be the reason a merge request is red.
|
|
359
|
+
|
|
360
|
+
## Output styles (Claude Code)
|
|
361
|
+
|
|
362
|
+
An output style replaces Claude Code's own answer style for a whole session. This package
|
|
363
|
+
ships one - **`ste-clarity`**, which writes every answer in ASD-STE100 Simplified Technical
|
|
364
|
+
English - and installs it into the machine's Claude config rather than into a repo, because
|
|
365
|
+
that is where Claude Code reads styles from:
|
|
366
|
+
|
|
367
|
+
```bash
|
|
368
|
+
npx ethlete-agents output-style # install ste-clarity and switch to it
|
|
369
|
+
npx ethlete-agents output-style --dry-run # print what would change
|
|
370
|
+
npx ethlete-agents output-style --remove # take it back out
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
Two files, both under `~/.claude` (or `$CLAUDE_CONFIG_DIR`, or `--config-dir <path>`):
|
|
374
|
+
|
|
375
|
+
| File | What changes |
|
|
376
|
+
| ------------------------------ | ------------------------------------------------------------------ |
|
|
377
|
+
| `output-styles/ste-clarity.md` | The style itself, written whole |
|
|
378
|
+
| `settings.json` | `"outputStyle": "ste-clarity"` - every other setting is left alone |
|
|
379
|
+
|
|
380
|
+
- **`--no-activate`** writes the style file but not the setting, so switching to it is then
|
|
381
|
+
`/output-style ste-clarity` inside a session.
|
|
382
|
+
- A style file this command did not write is never overwritten or deleted - it says so and
|
|
383
|
+
stops, and `--force` is the way through. A copy of the same style that differs only in
|
|
384
|
+
layout still counts as its own.
|
|
385
|
+
- Nothing here is repo-local, so `sync` and `check` neither write nor diff it. `--remove`
|
|
386
|
+
clears `outputStyle` only while it still points at that style.
|
|
387
|
+
|
|
388
|
+
**Claude Code only.** Codex has no output-style mechanism - everything it is told comes
|
|
389
|
+
from `AGENTS.md`, which `sync` already writes.
|
|
390
|
+
|
|
391
|
+
## Per-machine local config
|
|
392
|
+
|
|
393
|
+
A gitignored `ethlete-agents.config.local.json` at the repo root holds the values that
|
|
394
|
+
differ per developer, without touching any committed file:
|
|
395
|
+
|
|
396
|
+
```json
|
|
397
|
+
{
|
|
398
|
+
"disableHooks": true,
|
|
399
|
+
"sdkSourcePath": "/absolute/path/to/ethlete-sdk",
|
|
400
|
+
"apiRepoPaths": { "hub": "../fut-hub-backend" }
|
|
401
|
+
}
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
- **`disableHooks`** - `true` disables every generated hook; an array
|
|
405
|
+
(`["context-warning"]`) just the named ones. The hook scripts read the file at
|
|
406
|
+
runtime, so toggling takes effect on the next prompt - no `sync` needed.
|
|
407
|
+
- **`disableAutoHandoffSave`** - keeps the `context-warning` hook's tiered warnings but
|
|
408
|
+
drops the auto-mode escalation: at the critical tier it recommends `/ethlete-handoff`
|
|
409
|
+
instead of saving the handoff file itself.
|
|
410
|
+
- **`sdkSourcePath`** - a local `ethlete-sdk` checkout. The `sdk-source` and
|
|
411
|
+
`sdk-local-build` skills read it when the agent needs the SDK's own sources, or has to
|
|
412
|
+
build the SDK and install it here through a `file:` dependency. A relative path is
|
|
413
|
+
resolved from the repo root.
|
|
414
|
+
- **`apiRepoPaths`** - one checkout per app, keyed by the app's project name
|
|
415
|
+
(`{ "hub": "../fut-hub-backend" }`). The `api-source` skill reads it to confirm a
|
|
416
|
+
response shape, a status code or an enum in the API's own source instead of guessing it
|
|
417
|
+
from the client. Relative paths resolve from the repo root; a map with a single entry is
|
|
418
|
+
used for whatever app is in play.
|
|
419
|
+
|
|
420
|
+
Everything in this file is read at runtime, never by `sync`: the generated files stay
|
|
421
|
+
identical on every machine and in CI, which is what lets `check` diff them. That is also
|
|
422
|
+
why the file takes nothing beyond these keys - `sync`/`check` warn about unknown keys,
|
|
423
|
+
about an `sdkSourcePath` that is missing or is not an SDK checkout, and about an
|
|
424
|
+
`apiRepoPaths` entry that is not a directory. Add the filename to your repo's
|
|
425
|
+
`.gitignore`.
|
|
156
426
|
|
|
157
427
|
## Authoring content
|
|
158
428
|
|
|
@@ -171,6 +441,11 @@ vars: [docsBaseUrl] # optional
|
|
|
171
441
|
---
|
|
172
442
|
```
|
|
173
443
|
|
|
444
|
+
`content/output-styles/<name>.md` is a third kind, and the only one this package does not
|
|
445
|
+
compile: it is a Claude Code output style verbatim, so its frontmatter is Claude's
|
|
446
|
+
(`name`, `description`, `keep-coding-instructions`) and `output-style` installs the file
|
|
447
|
+
as it is, apart from a marker line that records where it came from.
|
|
448
|
+
|
|
174
449
|
In a body, `{% varName %}` substitutes a variable, `{% skill:other-name %}` links to
|
|
175
450
|
another guide the way the current target expects, and `{% resource:file.mjs %}` links to
|
|
176
451
|
a bundled file. The delimiter is `{% … %}`, not `{{ … }}`, so Angular templates in
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
if [ "$3" = "1" ] && [ -z "$ETHLETE_GIT_FLOW_SKIP" ] && [ -x node_modules/.bin/ethlete-agents ]; then
|
|
2
|
+
ethlete_branch=$(git rev-parse --abbrev-ref HEAD)
|
|
3
|
+
|
|
4
|
+
# Only while the branch is on no remote: that is the whole window in which renaming it is free.
|
|
5
|
+
if [ -z "$(git for-each-ref --format='%(refname)' "refs/remotes/*/$ethlete_branch")" ]; then
|
|
6
|
+
node_modules/.bin/ethlete-agents git-flow check || true
|
|
7
|
+
fi
|
|
8
|
+
|
|
9
|
+
unset ethlete_branch
|
|
10
|
+
fi
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# Never `npx`: it reaches the registry when the package is absent, and a network error here would
|
|
2
|
+
# reject the push. A missing binary must make this block do nothing at all.
|
|
3
|
+
if [ -z "$ETHLETE_GIT_FLOW_SKIP" ] && [ -x node_modules/.bin/ethlete-agents ]; then
|
|
4
|
+
node_modules/.bin/ethlete-agents git-flow check --push || exit 1
|
|
5
|
+
fi
|