@ethlete/agent-rules 0.1.0-next.7 → 0.1.0-next.9

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.
Files changed (38) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/README.md +54 -13
  3. package/content/skills/api-source/SKILL.md +118 -0
  4. package/content/skills/git-flow/SKILL.md +4 -0
  5. package/content/skills/sdk-docs/SKILL.md +9 -2
  6. package/content/skills/sdk-source/SKILL.md +1 -1
  7. package/content/skills/styleguide/STYLEGUIDE.md +1 -1
  8. package/content/skills/timetrack/SKILL.md +64 -0
  9. package/package.json +1 -1
  10. package/src/index.js +6 -0
  11. package/src/index.js.map +1 -1
  12. package/src/lib/config.d.ts +9 -16
  13. package/src/lib/config.js +6 -1
  14. package/src/lib/config.js.map +1 -1
  15. package/src/lib/git-flow/index.d.ts +1 -0
  16. package/src/lib/git-flow/index.js +1 -0
  17. package/src/lib/git-flow/index.js.map +1 -1
  18. package/src/lib/git-flow/rename.d.ts +24 -0
  19. package/src/lib/git-flow/rename.js +70 -0
  20. package/src/lib/git-flow/rename.js.map +1 -0
  21. package/src/lib/git-flow/start.d.ts +27 -0
  22. package/src/lib/git-flow/start.js +34 -1
  23. package/src/lib/git-flow/start.js.map +1 -1
  24. package/src/lib/git-flow-repair.js +7 -11
  25. package/src/lib/git-flow-repair.js.map +1 -1
  26. package/src/lib/git-flow-start.js +14 -29
  27. package/src/lib/git-flow-start.js.map +1 -1
  28. package/src/lib/plan.js +31 -3
  29. package/src/lib/plan.js.map +1 -1
  30. package/src/lib/timetrack-command.d.ts +11 -0
  31. package/src/lib/timetrack-command.js +187 -0
  32. package/src/lib/timetrack-command.js.map +1 -0
  33. package/src/lib/timetrack.d.ts +74 -0
  34. package/src/lib/timetrack.js +110 -0
  35. package/src/lib/timetrack.js.map +1 -0
  36. package/src/lib/jira.d.ts +0 -28
  37. package/src/lib/jira.js +0 -83
  38. package/src/lib/jira.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,26 @@
1
1
  # @ethlete/agent-rules
2
2
 
3
+ ## 0.1.0-next.9
4
+
5
+ ### Minor Changes
6
+
7
+ - [`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" }`).
8
+
9
+ - [`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
10
+ token any more — the `jira` credentials in the local config and the `JIRA_*` variables are gone.
11
+
12
+ - [#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.
13
+
14
+ - [#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.
15
+
16
+ ## 0.1.0-next.8
17
+
18
+ ### Patch Changes
19
+
20
+ - [#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.
21
+
22
+ - [#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.
23
+
3
24
  ## 0.1.0-next.7
4
25
 
5
26
  ### Minor Changes
package/README.md CHANGED
@@ -196,25 +196,25 @@ exist already - `start` says so rather than inventing a parent. `--of <branch>`
196
196
  parent explicitly, `--hotfix` branches off production, `--release <date>` makes a release
197
197
  branch, and `--subject <text>` skips Jira entirely.
198
198
 
199
- Jira needs a host, an email and an API token. Only the host belongs in the committed
200
- config; the two secrets come from `JIRA_EMAIL` / `JIRA_API_TOKEN` or from the gitignored
201
- local config.
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
202
 
203
203
  ```json
204
204
  {
205
205
  "jira": {
206
- "host": "https://your-team.atlassian.net",
207
- "subjectField": "customfield_10050",
208
206
  "typeByIssueType": { "Bug": "fix" }
209
207
  }
210
208
  }
211
209
  ```
212
210
 
213
- - **`subjectField`** - the field holding a Story's branch subject. Without it the summary
214
- is slugified, which is a paraphrase rather than the agreed subject.
215
211
  - **`typeByIssueType`** - the branch type per Jira issue type; anything unlisted becomes
216
212
  `feat`. `--type` overrides it per call.
217
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
218
  ### `repair` - renaming a branch that does not conform
219
219
 
220
220
  `git-flow repair [ref]` derives the conforming name (`--key FIP-2900` when the old name
@@ -232,6 +232,44 @@ Everything is checked before the first mutation, and it refuses rather than half
232
232
  - If a retarget fails halfway, the old branch is still there and the recovery commands are
233
233
  printed.
234
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
+
235
273
  ## Hooks (opt-in)
236
274
 
237
275
  Hooks run commands on the developer's machine, so none are emitted by default - opt in
@@ -328,7 +366,7 @@ differ per developer, without touching any committed file:
328
366
  {
329
367
  "disableHooks": true,
330
368
  "sdkSourcePath": "/absolute/path/to/ethlete-sdk",
331
- "jira": { "email": "you@example.com", "token": "…" }
369
+ "apiRepoPaths": { "hub": "../fut-hub-backend" }
332
370
  }
333
371
  ```
334
372
 
@@ -338,19 +376,22 @@ differ per developer, without touching any committed file:
338
376
  - **`disableAutoHandoffSave`** - keeps the `context-warning` hook's tiered warnings but
339
377
  drops the auto-mode escalation: at the critical tier it recommends `/ethlete-handoff`
340
378
  instead of saving the handoff file itself.
341
- - **`jira`** - the credentials `git-flow start` needs (`host`, `email`, `token`). This is
342
- the one place in a repo a secret may sit, and only because the file is gitignored;
343
- `JIRA_EMAIL` / `JIRA_API_TOKEN` in the environment are the alternative and win over it.
344
379
  - **`sdkSourcePath`** - a local `ethlete-sdk` checkout. The `sdk-source` and
345
380
  `sdk-local-build` skills read it when the agent needs the SDK's own sources, or has to
346
381
  build the SDK and install it here through a `file:` dependency. A relative path is
347
382
  resolved from the repo root.
383
+ - **`apiRepoPaths`** - one checkout per app, keyed by the app's project name
384
+ (`{ "hub": "../fut-hub-backend" }`). The `api-source` skill reads it to confirm a
385
+ response shape, a status code or an enum in the API's own source instead of guessing it
386
+ from the client. Relative paths resolve from the repo root; a map with a single entry is
387
+ used for whatever app is in play.
348
388
 
349
389
  Everything in this file is read at runtime, never by `sync`: the generated files stay
350
390
  identical on every machine and in CI, which is what lets `check` diff them. That is also
351
391
  why the file takes nothing beyond these keys - `sync`/`check` warn about unknown keys,
352
- and about an `sdkSourcePath` that is missing or is not an SDK checkout. Add the filename
353
- to your repo's `.gitignore`.
392
+ about an `sdkSourcePath` that is missing or is not an SDK checkout, and about an
393
+ `apiRepoPaths` entry that is not a directory. Add the filename to your repo's
394
+ `.gitignore`.
354
395
 
355
396
  ## Authoring content
356
397
 
@@ -0,0 +1,118 @@
1
+ ---
2
+ name: api-source
3
+ description: How to read the source of the API an app in this repo talks to, from a local backend checkout named in ethlete-agents.config.local.json. Read when a response shape, a status code, an error body, an enum or an auth rule has to be confirmed rather than guessed - and never edit that checkout as part of work in this repo.
4
+ kind: skill
5
+ scope: consumer
6
+ ---
7
+
8
+ # Reading the API source
9
+
10
+ The client's types describe what the frontend _expects_. When the two disagree, the
11
+ server is right, so a question about the contract is answered in the API repository -
12
+ not by reading the frontend's own models harder.
13
+
14
+ Reach for the checkout when:
15
+
16
+ - a response arrives with a field, a shape or a `null` the frontend types do not allow
17
+ - you need the exact status code, error body or validation message for a failure path
18
+ - an enum, a permission or a filter parameter has to match the server's list exactly
19
+ - a request fails and you cannot tell whether the client or the server is wrong
20
+ - you are about to report or fix something in the API itself
21
+
22
+ Do not read it to design frontend code that the API does not serve yet. An endpoint in
23
+ the checkout is not deployed until the API team ships it.
24
+
25
+ ## 1. Resolve the checkout for your app
26
+
27
+ One repository can hold several apps, each with its own API, so the paths are a map from
28
+ app to checkout. They are per machine, so the map lives in the gitignored
29
+ `ethlete-agents.config.local.json` at the repo root:
30
+
31
+ ```json
32
+ {
33
+ "apiRepoPaths": {
34
+ "hub": "../fut-hub-backend"
35
+ }
36
+ }
37
+ ```
38
+
39
+ Read that file before searching anywhere. The rules:
40
+
41
+ - **The key is the app** as this repo names it - the workspace project name, which is
42
+ normally also the folder under `apps/`. Match the app you are working in.
43
+ - **A relative path resolves from the repo root**, not from the app folder.
44
+ - **One entry means one API.** If the map holds a single entry, use it whatever it is
45
+ called.
46
+ - **No matching entry - stop and ask.** Do not guess a sibling folder and do not clone
47
+ the repository. Say which app you needed the API for and offer the snippet above; the
48
+ file is gitignored, so adding it changes nothing for anyone else.
49
+
50
+ Without a checkout, fall back to what the running API tells you: the generated API
51
+ description if the project serves one (`/openapi.json`, `/swagger`, `/api/doc`), and the
52
+ real response body of the call you are debugging.
53
+
54
+ ## 2. Check the branch before you read anything
55
+
56
+ A checkout sits on whatever branch its developer left it on, and the code you would
57
+ quote must be the code that serves this app:
58
+
59
+ ```bash
60
+ git -C <apiRepoPath> fetch --quiet # read-only, safe
61
+ git -C <apiRepoPath> status -sb # branch, ahead/behind, dirty files
62
+ ```
63
+
64
+ **The state to expect is the API's own development branch, up to date with its remote.**
65
+ Anything else, and you are describing a different API than the one the app calls.
66
+
67
+ When it is not in that state, **say so and ask** - never switch, pull, stash or reset it
68
+ yourself:
69
+
70
+ - **On another branch** - name it and ask. A feature branch may be exactly the endpoint
71
+ you were sent to look at, but it is not what the app talks to today.
72
+ - **Behind its remote** - report how far. The behaviour you are about to call a bug may
73
+ already be fixed upstream.
74
+ - **Dirty** - it holds someone's work in progress. Say so rather than quoting it as API
75
+ behaviour.
76
+
77
+ ## 3. The checkout is not the environment the app calls
78
+
79
+ Even a clean, current checkout is only the source. The app talks to a deployed
80
+ environment, which can lag it:
81
+
82
+ - Read the app's API base URL from its environment config, and say which environment
83
+ your answer is about.
84
+ - When the source and the observed response disagree, **the observed response wins** for
85
+ what the app has to handle today. Report the difference instead of writing client code
86
+ against the newer source.
87
+
88
+ ## 4. Search it, don't read it whole
89
+
90
+ The stack is whatever the API team chose, so search by the thing you already know - the
91
+ path, the field name, the error message - rather than by an expected file layout:
92
+
93
+ ```bash
94
+ rg -n "api/v1/matches" <apiRepoPath> --glob '!*test*' # the route
95
+ rg -n "kickoffAt" <apiRepoPath> # a field of the payload
96
+ rg -n "MATCH_NOT_FOUND" <apiRepoPath> # an error code you received
97
+ ```
98
+
99
+ Two things to find first, because they answer most questions on their own:
100
+
101
+ - **The API description** the project generates or checks in (OpenAPI, Swagger, GraphQL
102
+ schema, `.http` files). It is the contract, and it is cheaper to read than the code.
103
+ - **The serializer, resource or DTO** for the entity - the field list the client sees,
104
+ which is usually a subset of the database model, and the place where a name is
105
+ rewritten between the two.
106
+
107
+ The API's own tests describe intended behaviour more directly than the implementation:
108
+ they name the status code and the body for each case.
109
+
110
+ ## 5. The checkout is read-only from here
111
+
112
+ It is a different repository with its own branch, review and release process. Never edit
113
+ it while working on a task in this repo, and never change its git state without being
114
+ asked (`fetch` is fine).
115
+
116
+ When the fix belongs in the API, say so precisely: the endpoint, the field, and the
117
+ behaviour it should have. Then handle the API as it is today - a client workaround for a
118
+ server bug is a decision for the user, and it needs a comment naming what it waits on.
@@ -26,6 +26,10 @@ npx ethlete-agents git-flow repair <branch> # rename a non-conforming one,
26
26
  `--dry-run` to see the plan alone. It refuses on a dirty working tree, and a Task nests under
27
27
  its parent Story's branch, so that branch has to exist first.
28
28
 
29
+ It reads the issue through the running Timetrack app, which holds this machine's only Jira
30
+ credentials - see the `timetrack` skill. If it reports that the app is not running, ask the
31
+ user to start it. `--subject <text>` names a branch without reading Jira at all.
32
+
29
33
  ## The five shapes
30
34
 
31
35
  | Shape | Issue | Branch from | MR targets |
@@ -43,8 +43,15 @@ Component domains under `/components/`:
43
43
  `tabs` `text-inputs` `time-picker` `toggletip` `tooltip`
44
44
 
45
45
  So the table guide is `{%docsBaseUrl%}/components/table`, the menu guide
46
- `{%docsBaseUrl%}/components/menu`, and so on. When a name isn't in that list, start at
47
- `{%docsBaseUrl%}/components/` and follow the sidebar rather than guessing a URL.
46
+ `{%docsBaseUrl%}/components/menu`, and so on.
47
+
48
+ That list is a snapshot. The site itself is machine-readable, so fetch rather than guess:
49
+
50
+ - `{%docsBaseUrl%}/llms.txt` - every page's title and path as of the last deploy. Use it
51
+ when a name isn't in the list above, or to check the list hasn't drifted.
52
+ - Append `.md` to any page URL - `{%docsBaseUrl%}/components/button.md` - to get raw
53
+ markdown instead of the rendered page. Prefer this over `/llms-full.txt`, which is the
54
+ entire site in one ~1 MB file.
48
55
 
49
56
  ## How to use them
50
57
 
@@ -94,7 +94,7 @@ Paths are relative to the checkout root:
94
94
  | `libs/cdk/` | The predecessor UI toolkit, maintenance mode - only for code still on it |
95
95
  | `libs/eslint-plugin/src/` | The lint rules, including the message text explaining each one |
96
96
  | `apps/docs/` | The markdown behind {%docsBaseUrl%} |
97
- | `apps/playground/` | The Storybook app - stories also live next to each component |
97
+ | `apps/storybook/` | The Storybook app - stories also live next to each component |
98
98
 
99
99
  Inside a component domain: `<name>.component.ts` with its `.css` next to it,
100
100
  `<name>.imports.ts` (the imports array to spread into a consumer component),
@@ -37,7 +37,7 @@ Run your lint task with `--fix` - the rules below are enforced (and mostly auto-
37
37
  | Max two function parameters | `max-params` |
38
38
  | No `import type` / inline `type` specifiers | `ethlete/no-type-only-import` |
39
39
  | Generic params `T`-prefixed (`TValue`), never bare `T` | `@typescript-eslint/naming-convention` |
40
- | No `async`/`await` - use RxJS | `no-restricted-syntax` |
40
+ | No `async`/`await` - use RxJS | `ethlete/no-async-await` |
41
41
  | Arrow fns standalone; methods in classes; no arrow-fn class props; no `function` keyword | `no-restricted-syntax` |
42
42
  | Blank line before `return` in multi-line guard clauses | `ethlete/guard-return-newline` |
43
43
  | No trivially-inferable explicit return types | `ethlete/no-trivial-return-type` |
@@ -0,0 +1,64 @@
1
+ ---
2
+ name: timetrack
3
+ description: How to reach Jira from any repo through the running Timetrack app - look up an issue, search for one, ask which project a repo logs into, file a ticket, or add a worklog row. Read whenever a task needs Jira data or a Jira write, and never put a Jira token in a repo.
4
+ kind: skill
5
+ scope: both
6
+ ---
7
+
8
+ # Reaching Jira through Timetrack
9
+
10
+ **No repository holds a Jira token.** The Timetrack desktop app holds one set of credentials
11
+ in this machine's keychain, and every repository asks it:
12
+
13
+ ```bash
14
+ npx ethlete-agents timetrack status # is the app reachable, and what does it hold?
15
+ npx ethlete-agents timetrack issue FIP-2177 # one issue: summary, type, parent, subject
16
+ npx ethlete-agents timetrack search "password" # open issues of the picked projects
17
+ npx ethlete-agents timetrack project # which project does this repo log into?
18
+ ```
19
+
20
+ Add `--json` to any of them when you need to read a field rather than a line.
21
+
22
+ **Never ask the user for a Jira token, and never write one into a file.** If a command reports
23
+ that the app is not running, say so and ask the user to start it. That is the whole fix -
24
+ there is no per-repo fallback, by design: a secret copied into every checkout is a secret
25
+ nobody can rotate.
26
+
27
+ ## What each command is for
28
+
29
+ | Command | Use it when |
30
+ | --------------------------------- | ----------------------------------------------------------------------- |
31
+ | `status` | Before anything else, when a Jira command failed and you need the cause |
32
+ | `issue <KEY>` | The user names a key and you need its summary, type or parent |
33
+ | `search [text]` | The user describes work but names no key |
34
+ | `project [path]` | You need the project a repository files into |
35
+ | `create --summary "…"` | The work has no ticket and the user asked for one |
36
+ | `log --issue <KEY> --minutes <n>` | The user asks to record time that nothing observed |
37
+
38
+ `git-flow start` uses the same channel, so a branch is named from the real issue rather than
39
+ from a key you typed - see the `git-flow` skill.
40
+
41
+ ## Writes
42
+
43
+ Two commands write, so both need the user to have asked for them in this conversation:
44
+
45
+ ```bash
46
+ npx ethlete-agents timetrack create --summary "Reset password mail is not sent" --project FIP
47
+ npx ethlete-agents timetrack log --issue FIP-2177 --minutes 45 --description "pairing call"
48
+ ```
49
+
50
+ - **`create`** files the issue with the instance's own ticket settings - its type, its parent
51
+ rule and its subject field all come from the app, so the ticket is shaped like every other.
52
+ `--project` is needed unless the app holds exactly one picked project.
53
+ - **`log`** adds a row to the day in Timetrack. It is **not** a Tempo entry: the user reviews
54
+ the day and syncs it, which is what keeps an agent's row from double-booking against the
55
+ hours the day already observed. `--at <date>` places it; without one it starts now.
56
+
57
+ ## What the app decides, not you
58
+
59
+ - **The projects.** The user picked them in Timetrack. `search` is scoped to them, and
60
+ `--project <KEY>` is how you look outside.
61
+ - **The branch subject.** `issue` returns `subject` when the instance's subject field is set on
62
+ that issue. Prefer it over the summary; the summary is a paraphrase.
63
+ - **The instance.** Its host, its issue types and its hierarchy are settings in the app. Do not
64
+ hardcode any of them in this repo.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ethlete/agent-rules",
3
- "version": "0.1.0-next.7",
3
+ "version": "0.1.0-next.9",
4
4
  "license": "MIT",
5
5
  "type": "commonjs",
6
6
  "exports": {
package/src/index.js CHANGED
@@ -8,6 +8,7 @@ const config_1 = require("./lib/config");
8
8
  const git_flow_command_1 = require("./lib/git-flow-command");
9
9
  const migrate_1 = require("./lib/migrate");
10
10
  const sync_1 = require("./lib/sync");
11
+ const timetrack_command_1 = require("./lib/timetrack-command");
11
12
  const USAGE = `ethlete-agents — compile @ethlete agent rules and skills into your repo
12
13
 
13
14
  ethlete-agents sync Write the generated rules/skills for every detected agent
@@ -15,6 +16,9 @@ const USAGE = `ethlete-agents — compile @ethlete agent rules and skills into y
15
16
  ethlete-agents init Write a starter ${config_1.CONFIG_FILE_NAME}
16
17
  ethlete-agents git-flow Name, check and repair branches against the repo's git flow
17
18
  (start, check, repair, explain)
19
+ ethlete-agents timetrack Ask the running Timetrack app about Jira - it holds this
20
+ machine's credentials, so no repo needs a token
21
+ (status, issue, search, project, create, log)
18
22
  ethlete-agents migrate Convert the repo to the AGENTS.md + .agents/skills layout:
19
23
  CLAUDE.md content moves into AGENTS.md (CLAUDE.md becomes an
20
24
  @AGENTS.md import), hand-written .claude/skills move to
@@ -67,6 +71,8 @@ const run = (argv) => {
67
71
  return init(root);
68
72
  case 'git-flow':
69
73
  return (0, git_flow_command_1.gitFlowCommand)({ root, argv: argv.slice(1) });
74
+ case 'timetrack':
75
+ return (0, timetrack_command_1.timetrackCommand)({ root, argv: argv.slice(1) });
70
76
  case 'migrate':
71
77
  return (0, migrate_1.migrate)(Object.assign(Object.assign({}, options), { dryRun: argv.includes('--dry-run') }));
72
78
  default:
package/src/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../libs/agent-rules/src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../libs/agent-rules/src/index.ts"],"names":[],"mappings":"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"}
@@ -5,16 +5,10 @@ export type AgentTarget = (typeof AGENT_TARGETS)[number];
5
5
  export declare const CONFIG_FILE_NAME = "ethlete-agents.config.json";
6
6
  export declare const LOCAL_CONFIG_FILE_NAME = "ethlete-agents.config.local.json";
7
7
  /**
8
- * Non-secret Jira wiring, committed with the repo — `git-flow start` resolves an issue key through
9
- * it. Credentials never live here; they come from the environment or the gitignored local config.
8
+ * How this repo reads a Jira issue into a branch name. The instance, the credentials and the subject
9
+ * field are not here and cannot be: the Timetrack app holds them, and `git-flow start` asks it.
10
10
  */
11
11
  export type JiraSettings = {
12
- host?: string;
13
- /**
14
- * The instance's field holding a Story's branch subject (`customfield_10050`). Without it the
15
- * summary is slugified instead, which is a paraphrase rather than the agreed subject.
16
- */
17
- subjectField?: string;
18
12
  /** Branch type per Jira issue type, e.g. `{ "Bug": "fix" }`. Anything unlisted becomes `feat`. */
19
13
  typeByIssueType?: Record<string, string>;
20
14
  };
@@ -51,19 +45,18 @@ export type SyncConfig = {
51
45
  * a handoff instead of writing the handoff file automatically.
52
46
  * - `sdkSourcePath` points at a local `ethlete-sdk` checkout, which the SDK source and local-build
53
47
  * skills read when they need the SDK's own sources instead of the published package.
54
- * - `jira` holds the per-user Jira credentials `git-flow start` needs. This is the one place in the
55
- * repo a secret may sit, and only because the file is gitignored; `JIRA_EMAIL`/`JIRA_API_TOKEN`
56
- * in the environment are the alternative.
48
+ * - `apiRepoPaths` maps an app in this repo to the checkout of the API it talks to (`{ "hub":
49
+ * "../fut-hub-backend" }`), which the api-source skill reads to answer a question about the
50
+ * server instead of guessing it from the client.
51
+ *
52
+ * No secret belongs here any more. Jira is reached through the Timetrack app, which holds the token
53
+ * in the machine's keychain — one secret per machine rather than one per checkout.
57
54
  */
58
55
  export type LocalConfig = {
59
56
  disableHooks?: boolean | string[];
60
57
  disableAutoHandoffSave?: boolean;
61
58
  sdkSourcePath?: string;
62
- jira?: {
63
- host?: string;
64
- email?: string;
65
- token?: string;
66
- };
59
+ apiRepoPaths?: Record<string, string>;
67
60
  };
68
61
  export type LocalConfigState = {
69
62
  exists: false;
package/src/lib/config.js CHANGED
@@ -15,7 +15,12 @@ const readRawConfig = (root) => {
15
15
  return {};
16
16
  return JSON.parse((0, fs_1.readFileSync)(path, 'utf8'));
17
17
  };
18
- const LOCAL_CONFIG_KEYS = ['disableHooks', 'disableAutoHandoffSave', 'sdkSourcePath', 'jira'];
18
+ const LOCAL_CONFIG_KEYS = [
19
+ 'disableHooks',
20
+ 'disableAutoHandoffSave',
21
+ 'sdkSourcePath',
22
+ 'apiRepoPaths',
23
+ ];
19
24
  const readLocalConfig = (root) => {
20
25
  const path = (0, path_1.join)(root, exports.LOCAL_CONFIG_FILE_NAME);
21
26
  if (!(0, fs_1.existsSync)(path))
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../../../../../libs/agent-rules/src/lib/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../../../../libs/agent-rules/src/lib/config.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  export * from './build';
2
2
  export * from './config';
3
3
  export * from './parse';
4
+ export * from './rename';
4
5
  export * from './start';
5
6
  export * from './validate';
@@ -4,6 +4,7 @@ const tslib_1 = require("tslib");
4
4
  tslib_1.__exportStar(require("./build"), exports);
5
5
  tslib_1.__exportStar(require("./config"), exports);
6
6
  tslib_1.__exportStar(require("./parse"), exports);
7
+ tslib_1.__exportStar(require("./rename"), exports);
7
8
  tslib_1.__exportStar(require("./start"), exports);
8
9
  tslib_1.__exportStar(require("./validate"), exports);
9
10
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../libs/agent-rules/src/lib/git-flow/index.ts"],"names":[],"mappings":";;;AAAA,kDAAwB;AACxB,mDAAyB;AACzB,kDAAwB;AACxB,kDAAwB;AACxB,qDAA2B"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../libs/agent-rules/src/lib/git-flow/index.ts"],"names":[],"mappings":";;;AAAA,kDAAwB;AACxB,mDAAyB;AACzB,kDAAwB;AACxB,mDAAyB;AACzB,kDAAwB;AACxB,qDAA2B"}
@@ -0,0 +1,24 @@
1
+ import { GitFlowConfig } from './config';
2
+ export type ConformingName = {
3
+ ok: true;
4
+ name: string;
5
+ } | {
6
+ ok: false;
7
+ /**
8
+ * `needs-key` is the only reason a caller can act on: file the issue, then ask again with the
9
+ * key it returned.
10
+ */
11
+ reason: 'already-conforms' | 'needs-key' | 'no-shape';
12
+ };
13
+ /**
14
+ * The conforming name a non-conforming branch should take, once an issue key exists for it.
15
+ *
16
+ * A candidate is returned only after it parses as fully conforming, so a rename always lands on a
17
+ * name the grammar accepts — `parseBranch`'s own `suggestedName` does not guarantee that for a
18
+ * nested branch whose leaf names no issue, and half a rename is worse than none.
19
+ */
20
+ export declare const conformingNameFor: (options: {
21
+ branch: string;
22
+ key?: string;
23
+ config: GitFlowConfig;
24
+ }) => ConformingName;
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.conformingNameFor = void 0;
4
+ const build_1 = require("./build");
5
+ const parse_1 = require("./parse");
6
+ const KEY_PLACEHOLDER = '<KEY>';
7
+ /**
8
+ * The spec that rebuilds a branch whose leaf carries no key at all, which is why `parseBranch` left
9
+ * `suggestedName` unset. Only the kinds the grammar can spell are here — an unrecognised name names
10
+ * no kind, and inventing one would rename the branch to something the user never chose.
11
+ */
12
+ const specFor = (options) => {
13
+ var _a;
14
+ const { parse, key } = options;
15
+ const subject = (_a = parse.subject) !== null && _a !== void 0 ? _a : '';
16
+ switch (parse.kind) {
17
+ case 'main-feature':
18
+ return { kind: 'main-feature', type: parse.type, key, subject };
19
+ case 'hotfix':
20
+ return { kind: 'hotfix', key, subject };
21
+ case 'sub-feature':
22
+ return parse.parent ? { kind: 'sub-feature', parent: parse.parent, key, subject } : undefined;
23
+ case 'release-fix':
24
+ return parse.parent ? { kind: 'release-fix', parent: parse.parent, key, subject } : undefined;
25
+ default:
26
+ return undefined;
27
+ }
28
+ };
29
+ const candidatesFor = (options) => {
30
+ const { parse, key, config } = options;
31
+ const suggested = parse.suggestedName;
32
+ const candidates = [];
33
+ if (suggested && !suggested.includes(KEY_PLACEHOLDER))
34
+ candidates.push(suggested);
35
+ if (key) {
36
+ if (suggested === null || suggested === void 0 ? void 0 : suggested.includes(KEY_PLACEHOLDER))
37
+ candidates.push(suggested.replace(/<KEY>/g, key.toUpperCase()));
38
+ const spec = specFor({ parse, key: key.toUpperCase() });
39
+ if (spec)
40
+ candidates.push((0, build_1.buildBranchName)({ spec, config }));
41
+ }
42
+ return candidates;
43
+ };
44
+ /**
45
+ * The conforming name a non-conforming branch should take, once an issue key exists for it.
46
+ *
47
+ * A candidate is returned only after it parses as fully conforming, so a rename always lands on a
48
+ * name the grammar accepts — `parseBranch`'s own `suggestedName` does not guarantee that for a
49
+ * nested branch whose leaf names no issue, and half a rename is worse than none.
50
+ */
51
+ const conformingNameFor = (options) => {
52
+ var _a;
53
+ const { key, config } = options;
54
+ const parse = (0, parse_1.parseBranch)({ branch: options.branch, config });
55
+ if (parse.ok)
56
+ return { ok: false, reason: 'already-conforms' };
57
+ for (const name of candidatesFor({ parse, key, config })) {
58
+ if (name !== parse.branch && (0, parse_1.parseBranch)({ branch: name, config }).ok)
59
+ return { ok: true, name };
60
+ }
61
+ if (key)
62
+ return { ok: false, reason: 'no-shape' };
63
+ // Whether a key would help is answered by trying one, using a prefix this repo accepts so the
64
+ // probe is not rejected by `keyPrefixes` for a reason the real key would not hit.
65
+ const probe = candidatesFor({ parse, key: `${(_a = config.keyPrefixes[0]) !== null && _a !== void 0 ? _a : 'KEY'}-1`, config });
66
+ const rebuildable = probe.some((name) => (0, parse_1.parseBranch)({ branch: name, config }).ok);
67
+ return { ok: false, reason: rebuildable ? 'needs-key' : 'no-shape' };
68
+ };
69
+ exports.conformingNameFor = conformingNameFor;
70
+ //# sourceMappingURL=rename.js.map