@skitterbyte/skitterspec-linear 15.0.0 → 17.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/MIGRATION.md +218 -0
- package/README.md +34 -1
- package/assets/claude-md-section.md +29 -18
- package/assets/commands/spec-remote-review.md +22 -0
- package/assets/core/SETUP.md +10 -6
- package/assets/core/env.config.json.example +4 -2
- package/assets/core/env.config.md +100 -23
- package/assets/core/linear.config.json.example +2 -1
- package/assets/core/linear.config.md +49 -22
- package/assets/review/page.html +1044 -101
- package/assets/rules/spec-planning.md +35 -3
- package/assets/rules/spec-reports.md +131 -20
- package/assets/skills/spec/SKILL.md +161 -4
- package/assets/skills/spec-bug/SKILL.md +68 -30
- package/assets/skills/spec-cancel/SKILL.md +2 -2
- package/assets/skills/spec-claim/SKILL.md +12 -4
- package/assets/skills/spec-complete/SKILL.md +2 -2
- package/assets/skills/spec-diff/SKILL.md +131 -36
- package/assets/skills/spec-hotfix/SKILL.md +61 -25
- package/assets/skills/spec-linear-setup/SKILL.md +19 -11
- package/assets/skills/spec-next/SKILL.md +121 -58
- package/assets/skills/spec-push/SKILL.md +45 -0
- package/assets/skills/spec-review/SKILL.md +89 -2
- package/assets/skills/spec-reviewed/SKILL.md +31 -5
- package/assets/skills/spec-start/SKILL.md +26 -3
- package/assets/skills/spec-status/SKILL.md +20 -6
- package/assets/skills/spec-sync/SKILL.md +1 -0
- package/package.json +2 -2
- package/src/cli.js +913 -116
- package/src/env/classify.js +87 -2
- package/src/env/config.js +214 -17
- package/src/env/live.js +94 -0
- package/src/env/resolve.js +36 -2
- package/src/env/review.js +542 -21
- package/src/env/serve.js +298 -19
- package/src/env/supervise.js +8 -1
- package/src/init.js +60 -9
- package/src/vendor/linear/api.js +111 -2
- package/src/vendor/linear/cli-sync.js +661 -11
- package/src/vendor/linear/config.js +41 -13
- package/src/vendor/linear/doctor.js +6 -5
- package/src/vendor/sync-core/index.js +11 -3
- package/src/vendor/sync-core/src/compare.js +65 -0
- package/src/vendor/sync-core/src/normalize.js +26 -0
|
@@ -19,7 +19,9 @@ your team ID (and an optional grouping project).
|
|
|
19
19
|
The loader (`src/sync/config.js` → `loadLinearConfig`) merges your file over the
|
|
20
20
|
frozen defaults below and returns `{ config, present }`; `present:false` means no
|
|
21
21
|
live `linear.config.json` was found (the opt-in gate — it never throws on
|
|
22
|
-
absence). A `sync.fieldOwnership` value outside `both|pull|push` is a hard error.
|
|
22
|
+
absence). A `sync.fieldOwnership` value outside `both|pull|push|none` is a hard error.
|
|
23
|
+
`none` is how a repo **declines** a field the defaults own — see
|
|
24
|
+
**Assignment** below, which is the field that needs it.
|
|
23
25
|
|
|
24
26
|
## Fields
|
|
25
27
|
|
|
@@ -40,7 +42,10 @@ absence). A `sync.fieldOwnership` value outside `both|pull|push` is a hard error
|
|
|
40
42
|
"intake": {
|
|
41
43
|
"label": "", // inbox filter — the label the web app files under
|
|
42
44
|
"bugLabels": [], // e.g. ["bug"] — these route to /spec-bug instead
|
|
43
|
-
"hotfixLabels": []
|
|
45
|
+
"hotfixLabels": [], // e.g. ["production"] — these route to /spec-hotfix
|
|
46
|
+
"preserveOriginal": true // keep the reporter's description as a comment
|
|
47
|
+
// before the linking push replaces it. ON by
|
|
48
|
+
// default; false declines.
|
|
44
49
|
},
|
|
45
50
|
|
|
46
51
|
// How a spec's parts map onto Linear objects: a spec is an Issue, each phase a
|
|
@@ -119,7 +124,8 @@ absence). A `sync.fieldOwnership` value outside `both|pull|push` is a hard error
|
|
|
119
124
|
"fieldOwnership": {
|
|
120
125
|
"description": "push",
|
|
121
126
|
"subIssues": "push",
|
|
122
|
-
"workflowState": "push"
|
|
127
|
+
"workflowState": "push",
|
|
128
|
+
"assignee": "push"
|
|
123
129
|
},
|
|
124
130
|
|
|
125
131
|
// Markdown sections of 00-overview.md that are local-only scaffolding and
|
|
@@ -135,37 +141,41 @@ absence). A `sync.fieldOwnership` value outside `both|pull|push` is a hard error
|
|
|
135
141
|
|
|
136
142
|
## Assignment (`sync.fieldOwnership.assignee`)
|
|
137
143
|
|
|
138
|
-
|
|
139
|
-
|
|
144
|
+
**On by default since v16.** The spec issue is assigned to whoever is building
|
|
145
|
+
it: `/spec-start` records them, and the issue is released when the spec
|
|
146
|
+
completes. To decline it, say so:
|
|
140
147
|
|
|
141
148
|
```jsonc
|
|
142
149
|
"fieldOwnership": {
|
|
143
|
-
"
|
|
144
|
-
"subIssues": "push",
|
|
145
|
-
"workflowState": "push",
|
|
146
|
-
"assignee": "push" // <- the whole opt-in
|
|
150
|
+
"assignee": "none" // <- the whole opt-out
|
|
147
151
|
}
|
|
148
152
|
```
|
|
149
153
|
|
|
150
154
|
It is deliberately **not** a config key of its own. `fieldOwnership` is already
|
|
151
155
|
the documented extension point — "any key you add joins the pushed projection" —
|
|
152
|
-
and assignment is exactly one more field the repo owns.
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
156
|
+
and assignment is exactly one more field the repo owns. `none` is a value rather
|
|
157
|
+
than an omitted key because the map merges **per key** onto the defaults: once a
|
|
158
|
+
field is owned by default there is nothing an absent key can subtract.
|
|
159
|
+
|
|
160
|
+
- **`none` = inert.** No writes, no prompts, no drift line, and no assignee hash
|
|
161
|
+
in any snapshot — identical in every respect to a field the config never
|
|
162
|
+
listed. A repo that declines cannot tell the feature exists.
|
|
163
|
+
- **It was opt-in until v16**, and the cost of that was silent in the wrong
|
|
164
|
+
direction: a repo that never added the line looked exactly like one that had
|
|
165
|
+
decided against it, so the only signal was noticing an unassigned issue weeks
|
|
166
|
+
later. Declining is now a decision on the record; forgetting is not a state.
|
|
159
167
|
- **The bucket decides.** The spec's `linear_assignee_id` is pushed while the
|
|
160
168
|
spec is live (`backlog`, `in-progress`) and cleared once it reaches `complete`
|
|
161
169
|
or `cancelled` — so finishing a spec hands the issue back with no unassign
|
|
162
170
|
step for anyone to remember. The stamp stays in the file, and so does
|
|
163
171
|
`> **Developer:**`: they record who *actioned* the work, which outlives who is
|
|
164
172
|
holding it.
|
|
165
|
-
- **Unset means don't touch
|
|
166
|
-
all, so an issue a PM assigned in
|
|
167
|
-
|
|
168
|
-
|
|
173
|
+
- **Unset means don't touch, and this is what makes on-by-default safe.** A
|
|
174
|
+
spec that records nobody sends no assignee at all, so an issue a PM assigned in
|
|
175
|
+
Linear is never overwritten. Only an assignee the repo itself pushed is ever
|
|
176
|
+
cleared — and a snapshot written before the field was owned counts as "never
|
|
177
|
+
pushed", not as "was nobody". Turning the default on widens who gets
|
|
178
|
+
**assigned**; it cannot widen who gets **unassigned**.
|
|
169
179
|
- **Only the spec issue.** Phase sub-issues are never assigned: one person builds
|
|
170
180
|
a spec, and N assigned sub-issues is N notifications for one piece of work.
|
|
171
181
|
They stay independently assignable in Linear.
|
|
@@ -605,8 +615,25 @@ The issue **becomes** the spec's issue: its identifier is stamped as
|
|
|
605
615
|
`linear_identifier`, phases become its sub-issues, and the **linking push**
|
|
606
616
|
— which runs as the spec is created — replaces its description with the spec. The
|
|
607
617
|
reporter's comments, links and subscribers stay on the one issue everyone is
|
|
608
|
-
already watching
|
|
609
|
-
|
|
618
|
+
already watching.
|
|
619
|
+
|
|
620
|
+
**What happens to what they wrote.** Two things, and neither is the issue's
|
|
621
|
+
history:
|
|
622
|
+
|
|
623
|
+
- **Adoption posts it back as a comment**, verbatim, before the push replaces
|
|
624
|
+
the description (`skitterspec spec-sync preserve <spec>`, which the adoption
|
|
625
|
+
skills run for you). A comment is outside `sync.fieldOwnership` by design —
|
|
626
|
+
Linear-native triage that one-way sync never touches — which is exactly what
|
|
627
|
+
makes it safe: no later push can clobber it. It carries a marker so a second
|
|
628
|
+
run posts nothing, and it never fails the adoption: an unreachable Linear, an
|
|
629
|
+
issue with no description or `intake.preserveOriginal: false` all exit 0 and
|
|
630
|
+
say so. Set that key to `false` to turn the whole thing off.
|
|
631
|
+
- **The spec quotes them** in its **Problem** (or **Symptom**) section, which
|
|
632
|
+
*is* pushed as part of the generated description — so the reporter's words are
|
|
633
|
+
in the description too, and they round-trip like everything else.
|
|
634
|
+
|
|
635
|
+
The issue's history does technically hold the pre-adoption text, and it is not
|
|
636
|
+
the answer: a diff viewer is not quotable and nobody opens one.
|
|
610
637
|
|
|
611
638
|
An issue already stamped on a spec can't be adopted twice — `skitterspec spec-sync
|
|
612
639
|
linked` is the list that's checked.
|