@ethlete/agent-rules 0.1.0-next.14 → 0.1.0-next.16

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 (52) hide show
  1. package/CHANGELOG.md +73 -0
  2. package/README.md +36 -2
  3. package/THIRD-PARTY-LICENSES.md +35 -0
  4. package/content/hooks/context-warning.py +450 -112
  5. package/content/hooks/subagent-model-policy.py +185 -0
  6. package/content/rules/subagent-models.md +29 -0
  7. package/content/skills/codex-subagent/SKILL.md +90 -0
  8. package/content/skills/codex-subagent/codex-agent.mjs +229 -0
  9. package/content/skills/design-exploration/SKILL.md +203 -0
  10. package/content/skills/design-exploration/check-story.mjs +139 -0
  11. package/content/skills/design-exploration/shoot-template.mjs +61 -0
  12. package/content/skills/domain-modeling/ADR-FORMAT.md +47 -0
  13. package/content/skills/domain-modeling/CONTEXT-FORMAT.md +60 -0
  14. package/content/skills/domain-modeling/SKILL.md +80 -0
  15. package/content/skills/grill-with-docs/SKILL.md +13 -0
  16. package/content/skills/grilling/SKILL.md +34 -0
  17. package/content/skills/handoff/SKILL.md +69 -4
  18. package/content/skills/rxjs-signals/SKILL.md +4 -3
  19. package/content/skills/sdk-update/SKILL.md +2 -1
  20. package/content/skills/styleguide/lint-rule-lookup.md +1 -0
  21. package/content/skills/timetrack/SKILL.md +190 -10
  22. package/package.json +1 -1
  23. package/src/index.js +2 -1
  24. package/src/index.js.map +1 -1
  25. package/src/lib/frontmatter.d.ts +2 -0
  26. package/src/lib/frontmatter.js +2 -1
  27. package/src/lib/frontmatter.js.map +1 -1
  28. package/src/lib/git-flow/config.js +1 -1
  29. package/src/lib/git-flow/config.js.map +1 -1
  30. package/src/lib/git.d.ts +37 -0
  31. package/src/lib/git.js +77 -1
  32. package/src/lib/git.js.map +1 -1
  33. package/src/lib/index.d.ts +1 -0
  34. package/src/lib/index.js +1 -0
  35. package/src/lib/index.js.map +1 -1
  36. package/src/lib/plain-text.d.ts +9 -0
  37. package/src/lib/plain-text.js +22 -0
  38. package/src/lib/plain-text.js.map +1 -0
  39. package/src/lib/targets/claude-hooks.js +2 -1
  40. package/src/lib/targets/claude-hooks.js.map +1 -1
  41. package/src/lib/targets/codex-hooks.js +2 -1
  42. package/src/lib/targets/codex-hooks.js.map +1 -1
  43. package/src/lib/targets/hooks-shared.d.ts +22 -1
  44. package/src/lib/targets/hooks-shared.js +42 -9
  45. package/src/lib/targets/hooks-shared.js.map +1 -1
  46. package/src/lib/targets/shared.js +1 -0
  47. package/src/lib/targets/shared.js.map +1 -1
  48. package/src/lib/timetrack-command.js +449 -20
  49. package/src/lib/timetrack-command.js.map +1 -1
  50. package/src/lib/timetrack.d.ts +241 -0
  51. package/src/lib/timetrack.js +83 -2
  52. package/src/lib/timetrack.js.map +1 -1
@@ -15,15 +15,77 @@ continue in a fresh session. Two modes:
15
15
  - **save** ("handoff", "wrap up") - write a handoff file.
16
16
  - **resume** ("continue from the handoff") - read one and continue the work.
17
17
 
18
- This skill is installed as `ethlete-handoff`, so under Claude Code the commands
19
- are `/ethlete-handoff` and `/ethlete-handoff resume [name]` - there is no
20
- `/handoff`. Name them that way whenever you tell the user what to run.
18
+ Name one invocation form to the user - your own - and never both. The skill is
19
+ installed as `ethlete-handoff`, so under Claude Code the commands are
20
+ `/ethlete-handoff` and `/ethlete-handoff resume [name]`; there is no `/handoff`.
21
+ Codex has no slash commands, so there the same two are plain prompts without the
22
+ leading `/`.
21
23
 
22
24
  Handoff files live in `{%handoffDir%}/` (gitignored - they are personal,
23
25
  ephemeral working state, not team docs).
24
26
 
27
+ ## Handoff mode
28
+
29
+ Where this repo installs the `context-warning` hook, it names the budget at session start,
30
+ turns handoff mode on at 70% of it, and repeats a short note with the remaining budget on
31
+ every prompt after that. It reaches you at three points, not only when the user types: at
32
+ the start of the session, after a batch of your own tool calls, and as a turn ends. So a
33
+ long autonomous run learns its token count while it works.
34
+
35
+ Handoff mode is not an order to stop. It is the signal to change how you work, so that
36
+ either ending - you finish, or a fresh session takes over - stays cheap:
37
+
38
+ - Work in slices that each end in a committable state. Never leave two half-finished edits
39
+ in the tree.
40
+ - Send bulky reads, searches and test runs to a sub-agent. Its output stays out of your
41
+ context; its answer does not.
42
+ - Write down each decision and dead end as you reach it, in the commit message or in the
43
+ handoff file. Do not save them for a final summary you may have no room for.
44
+ - Start nothing you cannot finish or hand off inside the remaining budget.
45
+
46
+ At the critical tier (85%) the hook asks you to choose one of two, and to tell the user
47
+ which you chose:
48
+
49
+ 1. **Finish the task.** Only when you can name every step that is left, and they plainly
50
+ fit the remaining budget. Finish it, commit, then apply the save test below - the answer
51
+ is then usually that no file is needed at all.
52
+ 2. **Hand off.** Everything else. Finish the in-flight atomic edit, nothing new, then save.
53
+
54
+ "Nearly done" means you can name the last steps now. It does not mean the end feels close.
55
+ At the last tier (95%) the hook takes option 1 away, because a budget that small covers no
56
+ task.
57
+
58
+ ### Ending a turn over the budget
59
+
60
+ From 85% on, the hook also fires as you try to end the turn, and the turn then continues so
61
+ you can act. It adds a third option to the two above:
62
+
63
+ 3. **Cross the boundary on purpose.** Some sessions are worth the premium rate: the task is
64
+ one step from done, or this session holds reasoning that no handoff file survives. Take
65
+ it only for a reason you can name in one sentence right now. Say the reason, say what it
66
+ costs, and keep working.
67
+
68
+ Option 3 is a judgment call, not a way out of the other two. Naming a reason you cannot
69
+ state plainly is the same as taking option 2 late and expensively. The hook asks once per
70
+ tier, so it will not block the end of a turn twice for the same budget.
71
+
25
72
  ## Save mode
26
73
 
74
+ **Decide first whether a handoff is needed at all.** One exists so work can resume, so
75
+ write one only when at least one of these holds:
76
+
77
+ - Uncommitted work from this session sits in the tree.
78
+ - A step the user asked for is unfinished, blocked, or waiting on a result.
79
+ - A decision, dead end, or user constraint from this session is written down nowhere else -
80
+ not in a commit message, a changeset, a docs page, or a plan file.
81
+
82
+ Check it, never assume it: `git status`, `git log`, and the task as the user stated it. A
83
+ context warning is a token count, not evidence that work is left.
84
+
85
+ If none of them holds, write no file. Tell the user in two or three lines what landed, name
86
+ the commits, and say a fresh session needs nothing from this one. A handoff nobody resumes is
87
+ noise, and it costs the next session the tokens to read it.
88
+
27
89
  Write `{%handoffDir%}/<slug>.md` where `<slug>` is a short kebab-case name for
28
90
  the task (use the user-provided slug if they gave one). If the file exists,
29
91
  overwrite it - a handoff always describes the _current_ state.
@@ -94,7 +156,10 @@ resume from it.
94
156
  3. Verify reality still matches: current branch, `git status`, last commit. If
95
157
  they diverge from the handoff (e.g. someone committed in between), say what
96
158
  changed and adapt - the repo is the truth, the handoff is the guide.
97
- 4. Read any focused repository guidance the handoff's work needs - same rules as always.
159
+ 4. **Read only what you are about to change.** The handoff already carries the decisions,
160
+ the constraints and the dead ends, so do not re-read the plan files it summarises, and do
161
+ not survey the directory. Open a source file when you are going to edit it, and load a
162
+ focused guidance file only when the work needs one.
98
163
  5. Continue with the **Next steps** section. Don't redo work listed under
99
164
  _Done_; don't re-open questions under _Decisions_.
100
165
  6. When every next step is complete, decide whether the handoff can be removed. Delete it
@@ -40,9 +40,10 @@ const data = toSignal(obs$);
40
40
  Do not use `takeWhile` as destruction cleanup: without another emission it stays
41
41
  subscribed. Use `take(1)` or `first()` only when one emission is the operation's
42
42
  intended semantics.
43
- - **Place lifecycle teardown after higher-order operators** such as `switchMap`, so their
44
- inner subscriptions are also covered. Other limiting and finalization operators do not
45
- have a universal “last” position; place them where their semantics belong.
43
+ - **`takeUntilDestroyed()` goes last in its pipe** (`ethlete/take-until-destroyed-last`), so
44
+ higher-order operators such as `switchMap` and their inner subscriptions are covered.
45
+ Other limiting and finalization operators do not have a universal “last” position;
46
+ place them where their semantics belong.
46
47
  - **Side effects go in `tap()`**, never in the `subscribe()` callback - keep
47
48
  `subscribe()` empty.
48
49
  - **Don't reach for RxJS inside `effect()`/`computed()`.** Subscribing per run
@@ -40,7 +40,8 @@ Commit or stash first, then:
40
40
  yarn et update
41
41
  ```
42
42
 
43
- In order, it writes the new ranges into `package.json`, runs the install, reads the migrations out of
43
+ In order, it writes the new ranges into every `package.json` in the repo that declares the package -
44
+ an Nx library manifest included, not only the root one - runs the install, reads the migrations out of
44
45
  the freshly installed packages, runs every codemod, and writes what is left to `.ethlete/update`.
45
46
 
46
47
  If the install or a codemod fails, the run stops and leaves `.ethlete/update/pending.json` behind.
@@ -28,6 +28,7 @@ convention. Run lint with `--fix`; do not hand-check this table before linting.
28
28
  | No redundant `@internal` | `ethlete/no-redundant-internal` |
29
29
  | Observable names end in `$` | `ethlete/require-dollar-suffix` |
30
30
  | No subscribe body, subscribe in pipe, or RxJS in signal derivations | `ethlete/no-subscribe-with-body`, `ethlete/no-subscribe-in-pipe`, `ethlete/no-rxjs-in-effect` |
31
+ | `takeUntilDestroyed()` is the last operator in its pipe | `ethlete/take-until-destroyed-last` |
31
32
  | Effect teardown uses `onCleanup` or `DestroyRef` | `ethlete/no-effect-cleanup-return` |
32
33
  | Prefer `linkedSignal` for writable derived state | `ethlete/prefer-linked-signal` |
33
34
  | Global component CSS encapsulation | `ethlete/require-view-encapsulation-none` |
@@ -1,6 +1,6 @@
1
1
  ---
2
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.
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, add a worklog row, read the evidence a day holds, or list the work that still waits for a ticket. Read whenever a task needs Jira data, a Jira write, or the day's own events, and never put a Jira token in a repo.
4
4
  kind: skill
5
5
  scope: both
6
6
  ---
@@ -16,6 +16,7 @@ npx ethlete-agents timetrack issue FIP-2177 # one issue: summary, type,
16
16
  npx ethlete-agents timetrack search "password" # open issues of the picked projects
17
17
  npx ethlete-agents timetrack project # which project does this repo log into?
18
18
  npx ethlete-agents timetrack instance # the instance's own levels and custom fields
19
+ npx ethlete-agents timetrack standins # work the user named that Jira does not hold yet
19
20
  ```
20
21
 
21
22
  Add `--json` to any of them when you need to read a field rather than a line.
@@ -27,19 +28,198 @@ nobody can rotate.
27
28
 
28
29
  ## What each command is for
29
30
 
30
- | Command | Use it when |
31
- | --------------------------------- | ----------------------------------------------------------------------- |
32
- | `status` | Before anything else, when a Jira command failed and you need the cause |
33
- | `instance` | A setup step needs the instance's levels or its branch-subject field |
34
- | `issue <KEY>` | The user names a key and you need its summary, type or parent |
35
- | `search [text]` | The user describes work but names no key |
36
- | `project [path]` | You need the project a repository files into |
37
- | `create --summary "…"` | The work has no ticket and the user asked for one |
38
- | `log --issue <KEY> --minutes <n>` | The user asks to record time that nothing observed |
31
+ | Command | Use it when |
32
+ | -------------------------------------- | ------------------------------------------------------------------------- |
33
+ | `status` | Before anything else, when a Jira command failed and you need the cause |
34
+ | `instance` | A setup step needs the instance's levels or its branch-subject field |
35
+ | `issue <KEY>` | The user names a key and you need its summary, type or parent |
36
+ | `search [text]` | The user describes work but names no key |
37
+ | `project [path]` | You need the project a repository files into |
38
+ | `create --summary "…"` | The work has no ticket and the user asked for one |
39
+ | `log --issue <KEY> --minutes <n>` | The user asks to record time that nothing observed |
40
+ | `day [YYYY-MM-DD]` | You need the evidence a day holds, not a screenshot of it |
41
+ | `rows [YYYY-MM-DD]` | You need the rows the day drew, and the ids an edit names them by |
42
+ | `edit <row-id> …` | The user asks you to correct one row of a day |
43
+ | `rules` | You need to know why a band was named, or why it was not |
44
+ | `standins` | You need to know which work still waits for a ticket, and for how long |
45
+ | `standins --remove <id>` | A placeholder is wrong or too wide, and the user asked you to delete it |
46
+ | `standins --rename <id> --name <text>` | The name a placeholder carries is wrong, and the user asked you to fix it |
47
+ | `naming [YYYY-MM-DD]` | A checkout was never offered a name and you need the step that stopped |
39
48
 
40
49
  `git-flow start` uses the same channel, so a branch is named from the real issue rather than
41
50
  from a key you typed. Follow the repository's branch workflow when creating a branch.
42
51
 
52
+ ## Reading a day
53
+
54
+ The app's store is encrypted, so no shell reads a day off disk. `day` is the only way in:
55
+
56
+ ```bash
57
+ npx ethlete-agents timetrack day # today: how many events, and of which kind
58
+ npx ethlete-agents timetrack day 2026-09-10 --out /tmp/day.json
59
+ ```
60
+
61
+ A real day holds thousands of events, so **never print them**. Write them to a file with
62
+ `--out`, then read that file from a test or a script. Without `--out` the command reports
63
+ only the counts, which is what tells you whether a day holds the source you are looking for.
64
+
65
+ `--out` writes a new file, readable by its owner alone. A destination that already exists is
66
+ refused until you pass `--overwrite`, and a symlink is never written through. The file holds the
67
+ day as it was observed - window titles, paths and messages - so delete it when you are done.
68
+
69
+ ## Reading and correcting the rows a day drew
70
+
71
+ `day` answers what the collectors saw. `rows` answers what the app made of it - the bands on the
72
+ timeline, with the id every edit names a row by, the day's totals and its warnings.
73
+
74
+ ```bash
75
+ npx ethlete-agents timetrack rows # today
76
+ npx ethlete-agents timetrack rows 2026-09-10 --json
77
+ ```
78
+
79
+ `edit` changes one row. Pass exactly one change per call:
80
+
81
+ ```bash
82
+ npx ethlete-agents timetrack edit 'ABC-1@2026-09-10T11:00:00.000Z' --day 2026-09-10 \
83
+ --from 2026-09-10T13:15:00Z --to 2026-09-10T17:00:00Z
84
+ npx ethlete-agents timetrack edit '<row-id>' --issue ABC-2
85
+ npx ethlete-agents timetrack edit '<row-id>' --state rejected
86
+ ```
87
+
88
+ Both commands move the app's own review to that day, so the user sees what you read and what you
89
+ changed. `applied` says how many edits found their row: a running day is re-cut on every collector
90
+ tick, so read `rows` again rather than reusing an id from minutes ago.
91
+
92
+ An edit may correct a row's times, its name, its note and whether it syncs. It may not split, merge
93
+ or delete one - restructuring a day is the user's own decision, made on the screen.
94
+
95
+ ## Why a band carries the name it does
96
+
97
+ `rules` reads the settings that name a day's work - the attribution rules, the project links,
98
+ the background projects and the applications the user has ruled in or out. It holds no host, no
99
+ account and no token, so it is safe to quote back to the user.
100
+
101
+ ```bash
102
+ npx ethlete-agents timetrack rules # a summary of the rules
103
+ npx ethlete-agents timetrack rules --json # the whole answer
104
+ ```
105
+
106
+ Read it before claiming a band should have been named something: a rule that donates its time
107
+ carries no issue key, and a project in `backgroundProjects` keeps only the minutes no other
108
+ band claims.
109
+
110
+ ## Work with no ticket yet
111
+
112
+ A **stand-in** is a name the user gave work that Jira does not hold yet. It takes bands across
113
+ days and across checkouts, and it books nothing. `standins` lists them:
114
+
115
+ ```bash
116
+ npx ethlete-agents timetrack standins # the open ones, oldest first
117
+ npx ethlete-agents timetrack standins --json # the whole answer, resolved ones included
118
+ ```
119
+
120
+ **Never open or resolve a stand-in.** The name is the user's own word for their work, and the
121
+ app is the only place they give it. If the user asks for a ticket, use `create` and tell them
122
+ to resolve the stand-in in Timetrack.
123
+
124
+ A placeholder is drawn per branch, and per directory where the branch names no piece of work.
125
+ A base branch, or no branch at all, says nothing about what was worked on, so the directory the
126
+ commits touched answers instead. That directory is the project the repository declares - the one
127
+ carrying the `project.json` or `package.json` above the changed files. A repository that declares
128
+ none lets its own commits pick the grain between them. A directory named with a leading dot is
129
+ the checkout's own tooling, so it never answers: a commit in `.changeset` or `.github` is
130
+ bookkeeping for another piece of work.
131
+
132
+ Where the directories cannot answer either, the branch the checkout was next cut onto does. A
133
+ branch is very often cut once the work on it has started, so the minutes before the cut sit on
134
+ the base branch although they are that branch's work.
135
+
136
+ One placeholder written before any of that was true covers a whole checkout, and it blocks a
137
+ per-branch placeholder for every branch of it. The list says so:
138
+
139
+ ```
140
+ Competition journey spec frontend in FIFAGG 3d old, 3 day(s) of work
141
+ covers all of /home/tom/dev/fifagg/specs, so no branch of it gets one of its own
142
+ ```
143
+
144
+ Two separate things cause that, and either alone is enough: the record names no branch, or the
145
+ rule naming it names no branch. The line above reports both, so take it at its word rather than
146
+ reading `--json` yourself.
147
+
148
+ ### Give one another name
149
+
150
+ The name is only wrong, and the work behind it is right:
151
+
152
+ ```bash
153
+ npx ethlete-agents timetrack standins --rename <id> --name '20260921 competition navigation rework'
154
+ ```
155
+
156
+ The days it holds and the rules that name it stay, which is what a delete and a fresh record would
157
+ lose. Rename one only when the user asks. The name is their own word for their work, so a name you
158
+ find unclear is not a fault to correct.
159
+
160
+ ### Re-cut one that named two pieces of work
161
+
162
+ A record covering a whole checkout is repaired rather than deleted, because a delete strands its
163
+ days. `--split` re-cuts it into one record per directory, and moves each day onto the right one:
164
+
165
+ ```bash
166
+ npx ethlete-agents timetrack standins --split <id> # the plan, writes nothing
167
+ npx ethlete-agents timetrack standins --split <id> --force # carry it out
168
+ ```
169
+
170
+ Without `--force` it prints every directory the commits name, with its commit count and its days,
171
+ then says which of them it would write. A directory under three commits is an edit made in
172
+ passing rather than a piece of work, so it is listed but not written. Pass
173
+ `--paths <dir>,<dir>` to pick the pieces yourself.
174
+
175
+ The commits are read across every branch, and only the ones the checkout's own `user.email`
176
+ authored. That is the history the collector that opened the record read, so work left on an
177
+ unmerged branch still counts and a colleague's commits never shape a piece. `--author <email>`
178
+ overrides the address.
179
+
180
+ A day the record covers that holds no commit of yours goes back to unnamed, and the split names
181
+ it. That is the honest answer: nothing says which directory it was. The day review is where it
182
+ gets named, and `--claim <dir>` gives every such day to one directory instead.
183
+
184
+ The record and its checkout-wide rule always go, even when a day is left unnamed. Both are read
185
+ as covering every branch of the checkout, so keeping either would block any later branch from
186
+ getting a record of its own — which is the fault the repair exists to cure.
187
+
188
+ The record must name the checkout it was opened for. One the user opened by hand names none, and
189
+ the split refuses it.
190
+
191
+ You may delete one, because that takes a name away rather than putting one on the day:
192
+
193
+ ```bash
194
+ npx ethlete-agents timetrack standins --remove <id>
195
+ ```
196
+
197
+ The rule that named it goes with it, and what happens next is worth knowing before you ask:
198
+
199
+ - The record names a branch. The delete refuses that branch, and no second one opens for it.
200
+ - It names none. The delete refuses nothing, so the next pass opens one per branch instead.
201
+
202
+ **Deleting one strands every day but today.** Only the day the app next reviews gets a new
203
+ placeholder; every earlier day the record covered then reads as unnamed, with nothing left to
204
+ say what it was. The command refuses such a delete and lists the days, and `--force` makes it
205
+ anyway. Ask the user before you use `--force`, and tell them which days they will lose.
206
+
207
+ ## Why a checkout was never offered a name
208
+
209
+ The day screen offers a whole checkout one issue when the user's own record already answers it. The
210
+ card is either drawn or it is not, and every step that can stop it is invisible from the screen.
211
+ `naming` names the step:
212
+
213
+ ```bash
214
+ npx ethlete-agents timetrack naming # today
215
+ npx ethlete-agents timetrack naming 2026-09-14
216
+ ```
217
+
218
+ It reports whether a Tempo token is stored, how far the read of the worklog history got, and for each
219
+ checkout the day saw either the offer or the reason there is none - `already-named`,
220
+ `no-project-link`, `no-history`, `project-too-small`, `too-few-days` or `share-too-low`. A `history`
221
+ of `failed` or `no-token` explains every checkout at once, so read that line first.
222
+
43
223
  ## Writes
44
224
 
45
225
  Two commands write, so both need the user to have asked for them in this conversation:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ethlete/agent-rules",
3
- "version": "0.1.0-next.14",
3
+ "version": "0.1.0-next.16",
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 output_style_command_1 = require("./lib/output-style-command");
11
+ const plain_text_1 = require("./lib/plain-text");
11
12
  const sync_1 = require("./lib/sync");
12
13
  const timetrack_command_1 = require("./lib/timetrack-command");
13
14
  const USAGE = `ethlete-agents — compile @ethlete agent rules and skills into your repo
@@ -93,7 +94,7 @@ if (require.main === module) {
93
94
  .then(() => run(process.argv.slice(2)))
94
95
  .then((code) => process.exit(code))
95
96
  .catch((error) => {
96
- console.error(error instanceof Error ? error.message : error);
97
+ console.error((0, plain_text_1.plain)(error instanceof Error ? error.message : String(error)));
97
98
  process.exit(1);
98
99
  });
99
100
  }
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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"}
@@ -10,6 +10,8 @@ export type Frontmatter = {
10
10
  requires: string[];
11
11
  paths: string[];
12
12
  vars: string[];
13
+ /** `false` keeps an agent from invoking the skill on its own, so only the user can start it. */
14
+ modelInvocation: boolean;
13
15
  };
14
16
  export type ParsedDocument = {
15
17
  frontmatter: Frontmatter;
@@ -4,7 +4,7 @@ exports.parseFrontmatter = exports.CONTENT_SCOPES = exports.CONTENT_KINDS = void
4
4
  exports.CONTENT_KINDS = ['rule', 'skill'];
5
5
  exports.CONTENT_SCOPES = ['consumer', 'sdk', 'both'];
6
6
  const FENCE = '---';
7
- const KNOWN_KEYS = ['name', 'description', 'kind', 'scope', 'requires', 'paths', 'vars'];
7
+ const KNOWN_KEYS = ['name', 'description', 'kind', 'scope', 'requires', 'paths', 'vars', 'modelInvocation'];
8
8
  const LIST_KEYS = ['requires', 'paths', 'vars'];
9
9
  const unquote = (value) => {
10
10
  const trimmed = value.trim();
@@ -109,6 +109,7 @@ const parseFrontmatter = (source, origin) => {
109
109
  requires: readList('requires'),
110
110
  paths: readList('paths'),
111
111
  vars: readList('vars'),
112
+ modelInvocation: readText('modelInvocation') !== 'false',
112
113
  },
113
114
  body: body.trimEnd(),
114
115
  };
@@ -1 +1 @@
1
- {"version":3,"file":"frontmatter.js","sourceRoot":"","sources":["../../../../../libs/agent-rules/src/lib/frontmatter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"frontmatter.js","sourceRoot":"","sources":["../../../../../libs/agent-rules/src/lib/frontmatter.ts"],"names":[],"mappings":"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"}
@@ -25,7 +25,7 @@ exports.DEFAULT_GIT_FLOW_CONFIG = {
25
25
  keyPattern: '[A-Z]{2,10}-\\d+',
26
26
  keyPrefixes: [],
27
27
  baseBranches: { development: 'next', production: 'main' },
28
- types: ['feat', 'fix', 'refactor', 'chore', 'docs', 'perf', 'test', 'style', 'build', 'ci'],
28
+ types: ['feat', 'fix', 'refactor', 'chore', 'docs', 'spec', 'perf', 'test', 'style', 'build', 'ci'],
29
29
  typeAliases: { feature: 'feat', bugfix: 'fix' },
30
30
  releasePrefix: 'release',
31
31
  releasePattern: '\\d{4}\\.\\d{2}\\.\\d{2}',
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../../../../../../libs/agent-rules/src/lib/git-flow/config.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;;AAEU,QAAA,cAAc,GAAG;IAC5B,cAAc;IACd,aAAa;IACb,UAAU;IACV,iBAAiB;IACjB,YAAY;IACZ,mBAAmB;IACnB,cAAc;IACd,iBAAiB;IACjB,gBAAgB;CACR,CAAC;AAiDE,QAAA,uBAAuB,GAAkB;IACpD,WAAW,EAAE,UAAU;IACvB,SAAS,EAAE,KAAK;IAChB,UAAU,EAAE,kBAAkB;IAC9B,WAAW,EAAE,EAAE;IACf,YAAY,EAAE,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE;IACzD,KAAK,EAAE,CAAC,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC;IAC3F,WAAW,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE;IAC/C,aAAa,EAAE,SAAS;IACxB,cAAc,EAAE,0BAA0B;IAC1C,YAAY,EAAE,QAAQ;IACtB,WAAW,EAAE,OAAO;IACpB,gBAAgB,EAAE,CAAC,EAAE,KAAK,EAAE,sBAAsB,EAAE,IAAI,EAAE,cAAc,EAAE,QAAQ,EAAE,sBAAsB,EAAE,CAAC;IAC7G,QAAQ,EAAE;QACR,cAAc,EAAE,MAAM;QACtB,aAAa,EAAE,MAAM;QACrB,UAAU,EAAE,MAAM;QAClB,iBAAiB,EAAE,MAAM;QACzB,YAAY,EAAE,MAAM;QACpB,mBAAmB,EAAE,MAAM;QAC3B,cAAc,EAAE,MAAM;QACtB,iBAAiB,EAAE,MAAM;QACzB,gBAAgB,EAAE,OAAO;KAC1B;CACF,CAAC;AAQF,uEAAuE;AAChE,MAAM,oBAAoB,GAAG,CAAC,GAAsB,EAAiB,EAAE,CAAC,+CAC1E,+BAAuB,GACvB,GAAG,KACN,YAAY,kCAAO,+BAAuB,CAAC,YAAY,GAAK,GAAG,aAAH,GAAG,uBAAH,GAAG,CAAE,YAAY,GAC7E,WAAW,kCAAO,+BAAuB,CAAC,WAAW,GAAK,GAAG,aAAH,GAAG,uBAAH,GAAG,CAAE,WAAW,GAC1E,QAAQ,kCAAO,+BAAuB,CAAC,QAAQ,GAAK,GAAG,aAAH,GAAG,uBAAH,GAAG,CAAE,QAAQ,KACjE,CAAC;AANU,QAAA,oBAAoB,wBAM9B"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../../../../../libs/agent-rules/src/lib/git-flow/config.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;;AAEU,QAAA,cAAc,GAAG;IAC5B,cAAc;IACd,aAAa;IACb,UAAU;IACV,iBAAiB;IACjB,YAAY;IACZ,mBAAmB;IACnB,cAAc;IACd,iBAAiB;IACjB,gBAAgB;CACR,CAAC;AAiDE,QAAA,uBAAuB,GAAkB;IACpD,WAAW,EAAE,UAAU;IACvB,SAAS,EAAE,KAAK;IAChB,UAAU,EAAE,kBAAkB;IAC9B,WAAW,EAAE,EAAE;IACf,YAAY,EAAE,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE;IACzD,KAAK,EAAE,CAAC,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC;IACnG,WAAW,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE;IAC/C,aAAa,EAAE,SAAS;IACxB,cAAc,EAAE,0BAA0B;IAC1C,YAAY,EAAE,QAAQ;IACtB,WAAW,EAAE,OAAO;IACpB,gBAAgB,EAAE,CAAC,EAAE,KAAK,EAAE,sBAAsB,EAAE,IAAI,EAAE,cAAc,EAAE,QAAQ,EAAE,sBAAsB,EAAE,CAAC;IAC7G,QAAQ,EAAE;QACR,cAAc,EAAE,MAAM;QACtB,aAAa,EAAE,MAAM;QACrB,UAAU,EAAE,MAAM;QAClB,iBAAiB,EAAE,MAAM;QACzB,YAAY,EAAE,MAAM;QACpB,mBAAmB,EAAE,MAAM;QAC3B,cAAc,EAAE,MAAM;QACtB,iBAAiB,EAAE,MAAM;QACzB,gBAAgB,EAAE,OAAO;KAC1B;CACF,CAAC;AAQF,uEAAuE;AAChE,MAAM,oBAAoB,GAAG,CAAC,GAAsB,EAAiB,EAAE,CAAC,+CAC1E,+BAAuB,GACvB,GAAG,KACN,YAAY,kCAAO,+BAAuB,CAAC,YAAY,GAAK,GAAG,aAAH,GAAG,uBAAH,GAAG,CAAE,YAAY,GAC7E,WAAW,kCAAO,+BAAuB,CAAC,WAAW,GAAK,GAAG,aAAH,GAAG,uBAAH,GAAG,CAAE,WAAW,GAC1E,QAAQ,kCAAO,+BAAuB,CAAC,QAAQ,GAAK,GAAG,aAAH,GAAG,uBAAH,GAAG,CAAE,QAAQ,KACjE,CAAC;AANU,QAAA,oBAAoB,wBAM9B"}
package/src/lib/git.d.ts CHANGED
@@ -8,7 +8,23 @@ export declare const gitLoud: (options: {
8
8
  args: string[];
9
9
  }) => string;
10
10
  export declare const currentBranch: (root: string) => string;
11
+ /**
12
+ * The identity a checkout commits under, which is how somebody else's commits stay out of a repair.
13
+ * A work checkout and a personal one are often two addresses, so this is read per checkout.
14
+ */
15
+ export declare const commitAuthorOf: (root: string) => string | undefined;
11
16
  export declare const allBranches: (root: string) => string[];
17
+ /**
18
+ * The directories a checkout declares as projects, relative to it, deepest last.
19
+ *
20
+ * A repository states its own boundaries in the files its tooling reads, and those beat any depth a
21
+ * rule could pick: two sibling libraries stay apart, and one library's own subdirectories fold into
22
+ * it. The checkout root is left out on purpose - it is the whole checkout under another name.
23
+ *
24
+ * Read through `git ls-files` rather than the filesystem, so an ignored or vendored copy under
25
+ * `node_modules` never counts as a project.
26
+ */
27
+ export declare const projectRootsOf: (root: string) => string[];
12
28
  export declare const isDirty: (root: string) => boolean;
13
29
  export declare const localBranchExists: (options: {
14
30
  root: string;
@@ -25,3 +41,24 @@ export declare const remoteUrl: (options: {
25
41
  root: string;
26
42
  remote: string;
27
43
  }) => string;
44
+ /** One commit as a repair reads it: the local day it was made on, and the files it changed. */
45
+ export type CommitPaths = {
46
+ day: string;
47
+ paths: string[];
48
+ };
49
+ /**
50
+ * The commits of the given local days, with the files each changed.
51
+ *
52
+ * `%cd` with `--date=format-local:%F` is the day in the machine's own zone, which is the grain
53
+ * Timetrack keys a day by. The span is read from the days given, so one `git log` answers them all,
54
+ * and a commit on a day outside the list is dropped.
55
+ *
56
+ * `--branches` and the author filter must stay in step with the collector that opened the record
57
+ * (`gitLogArgs` in `libs/timetrack/src/lib/git/scan.ts`). Read a narrower history than the collector
58
+ * did and a day the record holds looks empty, which makes a repair refuse or drop it.
59
+ */
60
+ export declare const commitPathsOnDays: (options: {
61
+ root: string;
62
+ days: readonly string[];
63
+ author?: string;
64
+ }) => CommitPaths[];
package/src/lib/git.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.remoteUrl = exports.defaultRemote = exports.remoteBranchExists = exports.localBranchExists = exports.isDirty = exports.allBranches = exports.currentBranch = exports.gitLoud = exports.git = void 0;
3
+ exports.commitPathsOnDays = exports.remoteUrl = exports.defaultRemote = exports.remoteBranchExists = exports.localBranchExists = exports.isDirty = exports.projectRootsOf = exports.allBranches = exports.commitAuthorOf = exports.currentBranch = exports.gitLoud = exports.git = void 0;
4
4
  const child_process_1 = require("child_process");
5
5
  const git_flow_1 = require("./git-flow");
6
6
  const git = (options) => (0, child_process_1.execFileSync)('git', options.args, { cwd: options.root, encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'] }).trim();
@@ -10,6 +10,19 @@ const gitLoud = (options) => (0, child_process_1.execFileSync)('git', options.ar
10
10
  exports.gitLoud = gitLoud;
11
11
  const currentBranch = (root) => (0, exports.git)({ root, args: ['rev-parse', '--abbrev-ref', 'HEAD'] });
12
12
  exports.currentBranch = currentBranch;
13
+ /**
14
+ * The identity a checkout commits under, which is how somebody else's commits stay out of a repair.
15
+ * A work checkout and a personal one are often two addresses, so this is read per checkout.
16
+ */
17
+ const commitAuthorOf = (root) => {
18
+ try {
19
+ return (0, exports.git)({ root, args: ['config', '--get', 'user.email'] }) || undefined;
20
+ }
21
+ catch (_a) {
22
+ return undefined;
23
+ }
24
+ };
25
+ exports.commitAuthorOf = commitAuthorOf;
13
26
  const allBranches = (root) => {
14
27
  const refs = (0, exports.git)({ root, args: ['for-each-ref', '--format=%(refname)', 'refs/heads', 'refs/remotes'] });
15
28
  const names = refs
@@ -19,6 +32,26 @@ const allBranches = (root) => {
19
32
  return [...new Set(names)].sort();
20
33
  };
21
34
  exports.allBranches = allBranches;
35
+ /**
36
+ * The directories a checkout declares as projects, relative to it, deepest last.
37
+ *
38
+ * A repository states its own boundaries in the files its tooling reads, and those beat any depth a
39
+ * rule could pick: two sibling libraries stay apart, and one library's own subdirectories fold into
40
+ * it. The checkout root is left out on purpose - it is the whole checkout under another name.
41
+ *
42
+ * Read through `git ls-files` rather than the filesystem, so an ignored or vendored copy under
43
+ * `node_modules` never counts as a project.
44
+ */
45
+ const projectRootsOf = (root) => {
46
+ const out = (0, exports.git)({ root, args: ['ls-files', '--', '*/project.json', '*/package.json'] });
47
+ const roots = out
48
+ .split('\n')
49
+ .filter(Boolean)
50
+ .filter((path) => !path.includes('node_modules/'))
51
+ .map((path) => path.slice(0, path.lastIndexOf('/')));
52
+ return [...new Set(roots)].sort();
53
+ };
54
+ exports.projectRootsOf = projectRootsOf;
22
55
  const isDirty = (root) => (0, exports.git)({ root, args: ['status', '--porcelain'] }).length > 0;
23
56
  exports.isDirty = isDirty;
24
57
  const refExists = (options) => {
@@ -46,4 +79,47 @@ const defaultRemote = (root) => {
46
79
  exports.defaultRemote = defaultRemote;
47
80
  const remoteUrl = (options) => (0, exports.git)({ root: options.root, args: ['remote', 'get-url', options.remote] });
48
81
  exports.remoteUrl = remoteUrl;
82
+ /**
83
+ * The commits of the given local days, with the files each changed.
84
+ *
85
+ * `%cd` with `--date=format-local:%F` is the day in the machine's own zone, which is the grain
86
+ * Timetrack keys a day by. The span is read from the days given, so one `git log` answers them all,
87
+ * and a commit on a day outside the list is dropped.
88
+ *
89
+ * `--branches` and the author filter must stay in step with the collector that opened the record
90
+ * (`gitLogArgs` in `libs/timetrack/src/lib/git/scan.ts`). Read a narrower history than the collector
91
+ * did and a day the record holds looks empty, which makes a repair refuse or drop it.
92
+ */
93
+ const commitPathsOnDays = (options) => {
94
+ const wanted = new Set(options.days);
95
+ const sorted = [...wanted].sort();
96
+ const first = sorted[0];
97
+ const last = sorted[sorted.length - 1];
98
+ if (!first || !last)
99
+ return [];
100
+ const out = (0, exports.git)({
101
+ root: options.root,
102
+ args: [
103
+ 'log',
104
+ '--branches',
105
+ '--name-only',
106
+ '--no-merges',
107
+ '--pretty=format:%x00%cd',
108
+ '--date=format-local:%F',
109
+ `--since=${first} 00:00`,
110
+ `--until=${last} 23:59:59`,
111
+ ...(options.author ? [`--author=${options.author}`] : []),
112
+ ],
113
+ });
114
+ return out
115
+ .split('\0')
116
+ .flatMap((block) => {
117
+ var _a;
118
+ const lines = block.split('\n').filter(Boolean);
119
+ const day = (_a = lines.shift()) !== null && _a !== void 0 ? _a : '';
120
+ return wanted.has(day) && lines.length ? { day, paths: lines } : [];
121
+ })
122
+ .reverse();
123
+ };
124
+ exports.commitPathsOnDays = commitPathsOnDays;
49
125
  //# sourceMappingURL=git.js.map