@skitterbyte/skitterspec-linear 7.0.1 → 8.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/assets/core/SETUP.md +46 -51
- package/assets/core/linear.config.json.example +2 -2
- package/assets/core/linear.config.md +9 -7
- package/assets/rules/spec-planning.md +13 -7
- package/assets/skills/spec-go/SKILL.md +12 -13
- package/assets/skills/spec-push/SKILL.md +53 -47
- package/assets/skills/spec-status/SKILL.md +31 -26
- package/bin/skitterspec-linear.js +5 -0
- package/package.json +1 -1
- package/src/vendor/linear/cli-sanitise.js +0 -0
- package/src/vendor/linear/cli-sync.js +123 -204
- package/src/vendor/linear/config.js +14 -6
- package/src/vendor/sync-core/index.js +25 -19
- package/src/vendor/sync-core/src/base.js +8 -10
- package/src/vendor/sync-core/src/compare.js +83 -174
- package/src/vendor/sync-core/src/normalize.js +186 -82
- package/src/vendor/sync-core/src/push.js +39 -133
- package/src/vendor/sync-core/src/sanitise.js +143 -0
- package/src/vendor/sync-core/src/task-block.js +104 -11
- package/src/vendor/sync-core/src/write.js +15 -205
- package/assets/skills/spec-pull/SKILL.md +0 -49
- package/src/vendor/sync-core/src/apply.js +0 -66
- package/src/vendor/sync-core/src/pull.js +0 -115
package/assets/core/SETUP.md
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
# Setting up Linear
|
|
1
|
+
# Setting up Linear sync (one-way)
|
|
2
2
|
|
|
3
|
-
A start-to-finish guide to getting `/spec-status
|
|
4
|
-
|
|
5
|
-
the
|
|
6
|
-
|
|
3
|
+
A start-to-finish guide to getting `/spec-status` and `/spec-push` working against
|
|
4
|
+
a real Linear workspace. Sync is **one-way**: the repo is the source of truth and
|
|
5
|
+
the linked Linear project is a **generated mirror** — content is pushed up, never
|
|
6
|
+
read back or merged. Covers the **Linear side** (connecting the MCP server,
|
|
7
|
+
finding your team) that the config reference (`linear.config.md`) assumes you
|
|
8
|
+
already have.
|
|
7
9
|
|
|
8
10
|
> The whole feature is **opt-in**: until `specs/.core/linear.config.json` exists,
|
|
9
11
|
> everything below is inert and the package behaves exactly like the base
|
|
@@ -47,7 +49,7 @@ claude mcp list
|
|
|
47
49
|
```
|
|
48
50
|
|
|
49
51
|
> Read-only trial: use `https://mcp.linear.app/mcp/readonly` to exercise
|
|
50
|
-
> `/spec-status`
|
|
52
|
+
> `/spec-status` (drift report) without granting write access. `/spec-push`
|
|
51
53
|
> needs the full (writable) endpoint.
|
|
52
54
|
|
|
53
55
|
## 3. Find your team id
|
|
@@ -108,33 +110,30 @@ Two ways to get there:
|
|
|
108
110
|
|
|
109
111
|
| Command | Direction | What it does |
|
|
110
112
|
|---------|-----------|--------------|
|
|
111
|
-
| `/spec-status` | — | Read-only
|
|
112
|
-
| `/spec-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
| `
|
|
123
|
-
| `
|
|
124
|
-
| `
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
(`linear_milestone_id`) and inline on task lines (`- [ ] do it (SKI-123)`).
|
|
136
|
-
Deletions are report-only (surfaced by `/spec-status`, never auto-applied). Full
|
|
137
|
-
details in the "Body round-trip" section of `linear.config.md`.
|
|
113
|
+
| `/spec-status` | — | Read-only drift report: what would push (create/update), and whether Linear's workflow-state drifted from the spec. Writes nothing. |
|
|
114
|
+
| `/spec-push` | repo → Linear | Computes a create/update plan vs the last-pushed snapshot and applies it (project description/status, milestones, issues), stamping new ids back into the spec. |
|
|
115
|
+
|
|
116
|
+
Typical loop: edit the spec in-repo → `/spec-status` (what's pending) →
|
|
117
|
+
`/spec-push` (send it up). There is no pull — Linear is a generated mirror.
|
|
118
|
+
|
|
119
|
+
### What gets pushed
|
|
120
|
+
|
|
121
|
+
| Field | What |
|
|
122
|
+
|-------|------|
|
|
123
|
+
| `description` | the spec body (problem, solution, acceptance criteria) as the project description |
|
|
124
|
+
| `milestones` | one per phase (name + goal) |
|
|
125
|
+
| `issues` | one per task — first-sentence **title**, full task text as the **description** |
|
|
126
|
+
| `workflowState` → project status | the spec's lifecycle bucket, mapped via `states` |
|
|
127
|
+
|
|
128
|
+
Priority, labels, cycles and comments are **Linear-native triage** — the PM's to
|
|
129
|
+
set in Linear. One-way sync neither pushes nor reads them, so they're never
|
|
130
|
+
clobbered. A workflow-state a teammate moves in Linear is surfaced by
|
|
131
|
+
`/spec-status` as drift and overwritten on the next push.
|
|
132
|
+
|
|
133
|
+
Phases push as **Milestones** and tasks as **Issues** by default. The link ids
|
|
134
|
+
live in the phase-file frontmatter (`linear_milestone_id`) and inline on task
|
|
135
|
+
lines (`- [ ] do it (SKI-123)`); `/spec-push` stamps them the first time it
|
|
136
|
+
creates each object, so later pushes update instead of recreate.
|
|
138
137
|
|
|
139
138
|
Sections listed in `sync.localOnlySections` (default: **State log**, **Changelog**,
|
|
140
139
|
**Open questions**) are stripped from the pushed description — they never leave
|
|
@@ -142,24 +141,20 @@ the repo.
|
|
|
142
141
|
|
|
143
142
|
## 7. What to commit
|
|
144
143
|
|
|
145
|
-
- **Commit** `specs/.core/linear-base/` — the
|
|
146
|
-
|
|
147
|
-
travel with the branch.
|
|
148
|
-
- **Gitignore** `specs/.core/linear-backups/` — `--force` recovery copies, local
|
|
149
|
-
and per-machine. Add `specs/.core/linear-backups/` to `.gitignore`.
|
|
144
|
+
- **Commit** `specs/.core/linear-base/` — the last-pushed snapshots (content
|
|
145
|
+
hashes per spec, so `/spec-push` knows what changed without reading Linear
|
|
146
|
+
back). Each worktree carries its own, so it must travel with the branch.
|
|
150
147
|
|
|
151
148
|
## 8. Smoke test (verify your setup)
|
|
152
149
|
|
|
153
|
-
With a linked spec, confirm
|
|
150
|
+
With a linked spec, confirm push end-to-end:
|
|
154
151
|
|
|
155
|
-
1. `/spec-status` →
|
|
156
|
-
2. `/spec-
|
|
157
|
-
|
|
158
|
-
3. `/spec-status` again → **
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
4. Edit the spec body locally, `/spec-push` → the change lands on the Linear
|
|
162
|
-
project's description; `/spec-status` returns to **in sync**.
|
|
152
|
+
1. `/spec-status` → shows what would push (`pending — N to create, M to update`).
|
|
153
|
+
2. `/spec-push` → creates the project's milestones/issues and sets the
|
|
154
|
+
description/status; ids are stamped back into the spec.
|
|
155
|
+
3. `/spec-status` again → **up to date** (nothing changed since the last push).
|
|
156
|
+
4. Edit a task locally, `/spec-push` → the matching issue updates;
|
|
157
|
+
`/spec-status` returns to **up to date**.
|
|
163
158
|
|
|
164
159
|
## Troubleshooting
|
|
165
160
|
|
|
@@ -167,9 +162,9 @@ With a linked spec, confirm the round-trip end-to-end:
|
|
|
167
162
|
this session. Re-run step 2; remember a fresh add needs a Claude Code restart.
|
|
168
163
|
- **"missing required tools: projectUpdate"** — you're on the read-only endpoint
|
|
169
164
|
(or a restricted API key). Use `https://mcp.linear.app/mcp` for push.
|
|
170
|
-
- **A
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
165
|
+
- **A configured status name silently does nothing** — Linear ignores an unknown
|
|
166
|
+
project status. Run `/spec-status` (it validates the `states` names against the
|
|
167
|
+
workspace) and fix `linear.config.json` to the real project-status names
|
|
168
|
+
(`Backlog / Planned / In Progress / Completed / Canceled`).
|
|
174
169
|
- **Reconnecting doesn't switch workspace** — Linear ties the OAuth session to one
|
|
175
170
|
workspace. Remove and re-add the server to authenticate against another.
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
# `linear.config.json` — Linear
|
|
2
|
-
|
|
3
|
-
Opt-in config for the
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
**
|
|
1
|
+
# `linear.config.json` — Linear one-way sync config
|
|
2
|
+
|
|
3
|
+
Opt-in config for the Linear sync (`/spec-status`, `/spec-push`, and the
|
|
4
|
+
Linear-aware paths of `/spec` and `/spec-go`). Sync is **one-way**: the repo is
|
|
5
|
+
the source of truth and the Linear project is a **generated mirror**. Content is
|
|
6
|
+
pushed up and never read back or merged — `/spec-push` diffs the spec against a
|
|
7
|
+
committed **last-pushed snapshot** and applies only what changed; `/spec-status`
|
|
8
|
+
is a read-only drift report. The `sync.fieldOwnership` map now just selects the
|
|
9
|
+
projection field set (every field is repo-owned and pushed).
|
|
8
10
|
|
|
9
11
|
**Every Linear step is gated on this file.** While `specs/.core/linear.config.json`
|
|
10
12
|
is absent the feature is simply unused — `/spec`, `/spec-go`, and the CLI's
|
|
@@ -68,13 +68,15 @@ Beneath it, `skitterspec spec-env live <take|release|abort|status>` is the engin
|
|
|
68
68
|
tracker-free: it knows nothing about any specific ticketing system. A
|
|
69
69
|
ticketing provider is installed as its own distribution that plugs into two named
|
|
70
70
|
**seams** in the shared skills (`/spec` Phase E, `/spec-go` step 3b) and fulfils a
|
|
71
|
-
skill-name + CLI contract
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
71
|
+
skill-name + CLI contract. Sync is **one-way**: the repo is the source of truth
|
|
72
|
+
and the tracker is a **generated mirror**. It ships `/spec-push` (repo→tracker;
|
|
73
|
+
computes a create/update plan against a committed last-pushed snapshot and applies
|
|
74
|
+
it) and `/spec-status` (read-only drift report — what would push, and whether the
|
|
75
|
+
tracker's workflow-state drifted), backed by a `spec-sync` CLI. There is no
|
|
76
|
+
content pull — the tracker is never read back or merged. When a provider is
|
|
77
|
+
present, `/spec` also links the spec to the tracker. With no provider installed
|
|
78
|
+
the seams are empty and every skill behaves as a plain filesystem workflow. See
|
|
79
|
+
the provider package's own docs for its config and field reference.
|
|
78
80
|
|
|
79
81
|
## Project conventions (fill this in)
|
|
80
82
|
|
|
@@ -190,3 +192,7 @@ queried directly.)
|
|
|
190
192
|
- Never delete historical notes.
|
|
191
193
|
- The spec file is the single source of truth for implementation progress.
|
|
192
194
|
- Move specs between buckets with `git mv` to preserve history.
|
|
195
|
+
- Never let inline emphasis or a link cross a hard line break — keep a whole
|
|
196
|
+
`**bold**`, `*italic*`, or `[text](url)` on one line (let it overflow the wrap
|
|
197
|
+
column rather than splitting it). Many round-tripping editors mangle a
|
|
198
|
+
`**`/`*`/link span that straddles a newline, so clean source avoids the churn.
|
|
@@ -137,19 +137,18 @@ change to the flow below. Follow the provider's pull steps below (nothing to do
|
|
|
137
137
|
here without one).
|
|
138
138
|
|
|
139
139
|
**Only when `specs/.core/linear.config.json` exists** and the spec carries a
|
|
140
|
-
`linear_project_id
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
-
|
|
148
|
-
`
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
keep any manual status edits minimal to avoid fighting it.
|
|
140
|
+
`linear_project_id`. Otherwise skip this step — no config means zero change.
|
|
141
|
+
|
|
142
|
+
- **No pull.** Linear is a generated mirror in one-way sync, so there is nothing
|
|
143
|
+
to bring down before building — the repo is already the source of truth. (A
|
|
144
|
+
workflow-state a teammate moved in Linear is advisory only; `/spec-status`
|
|
145
|
+
surfaces it. It is overwritten on the next push.)
|
|
146
|
+
- **Optional: refresh the mirror.** If you want Linear to reflect the now
|
|
147
|
+
in-progress spec, run `/spec-push` to send it up. This is optional at
|
|
148
|
+
`/spec-go` time — the mirror can equally be refreshed later.
|
|
149
|
+
- Linear's GitHub branch/PR automation may drive status transitions off the
|
|
150
|
+
branch/PR you pushed in step 2; that's expected and the repo still wins on the
|
|
151
|
+
next `/spec-push`.
|
|
153
152
|
|
|
154
153
|
## 4. Implement the phase
|
|
155
154
|
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: spec-push
|
|
3
|
-
description: Push a spec
|
|
3
|
+
description: Push a spec up to its linked Linear project (repo → Linear, one-way). The repo is the source of truth; Linear is a generated mirror. Runs `skitterspec spec-sync push` to get a create/update plan, applies it over MCP (project description/status, milestones, issues), stamps the returned ids back into the spec, then records the snapshot. Never reads Linear content back. Opt-in — needs specs/.core/linear.config.json. Use when the user says "/spec-push", "push to Linear", "update the Linear project from this spec".
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# /spec-push — send spec
|
|
6
|
+
# /spec-push — send a spec up to Linear (one-way)
|
|
7
7
|
|
|
8
|
-
Repo → Linear.
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
Linear
|
|
8
|
+
Repo → Linear. The repo is the **source of truth**; Linear is a **generated
|
|
9
|
+
mirror**. This skill computes what changed since the last push and applies it —
|
|
10
|
+
it never reads Linear content back or merges. A person editing the mirror in
|
|
11
|
+
Linear will see it overwritten on the next push.
|
|
12
12
|
|
|
13
13
|
**Opt-in**: only runs when `specs/.core/linear.config.json` exists. If absent,
|
|
14
14
|
tell the user how to enable Linear sync and stop.
|
|
@@ -17,58 +17,64 @@ tell the user how to enable Linear sync and stop.
|
|
|
17
17
|
|
|
18
18
|
Use the argument, else the spec in context; ask if unclear.
|
|
19
19
|
|
|
20
|
-
## 2.
|
|
20
|
+
## 2. Get the plan from the engine
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
Linear isn't connected — or the update tool is missing — relay the fix and stop,
|
|
26
|
-
**writing nothing**.
|
|
27
|
-
- Call the read tool and write the project JSON to a temp file.
|
|
22
|
+
```
|
|
23
|
+
skitterspec spec-sync push <spec> --json
|
|
24
|
+
```
|
|
28
25
|
|
|
29
|
-
|
|
26
|
+
The engine prints a JSON **plan** (no network, no remote read):
|
|
30
27
|
|
|
28
|
+
```json
|
|
29
|
+
{
|
|
30
|
+
"project": { "description": "…", "status": "in-progress", "priority": 2, "labels": ["…"] },
|
|
31
|
+
"milestones": { "create": [{ "ref": "01-outbox", "name": "…", "goal": "…" }], "update": [{ "id": "…", "name": "…", "goal": "…" }] },
|
|
32
|
+
"issues": { "create": [{ "ref": "<task text>", "title": "…", "description": "…", "done": false, "milestoneRef": "01-outbox" }], "update": [{ "id": "SKI-1", "title": "…", "description": "…", "done": true }] }
|
|
33
|
+
}
|
|
31
34
|
```
|
|
32
|
-
skitterspec spec-sync push <spec> --remote <tempfile> --out <mergedfile> [--force]
|
|
33
|
-
```
|
|
34
35
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
because they're not pushable).
|
|
40
|
-
- **`--force`** — only when the user explicitly asks. Local wins after the engine
|
|
41
|
-
backs up the remote side under `sync.backupDir`. Relay the backup path.
|
|
36
|
+
An empty plan (no project, no create/update) means the mirror is up to date —
|
|
37
|
+
say so and stop.
|
|
38
|
+
|
|
39
|
+
## 3. Discover the Linear MCP tools
|
|
42
40
|
|
|
43
|
-
|
|
41
|
+
Discover project + milestone + issue **create/update** tools at runtime. If
|
|
42
|
+
Linear isn't connected or a needed tool is missing, relay the fix and stop,
|
|
43
|
+
**writing nothing**.
|
|
44
44
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
45
|
+
**Validate the project states first.** Fetch the workspace's project-status
|
|
46
|
+
names and run `skitterspec spec-sync status <spec> --workspace-states <file>`; if
|
|
47
|
+
it errors (a configured `states` name isn't in the workspace), stop and fix the
|
|
48
|
+
config — Linear silently ignores an unknown project status.
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
engine can't write them itself — apply the plan over MCP:
|
|
50
|
+
## 4. Apply the plan (order matters)
|
|
52
51
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
52
|
+
1. **Milestones create** → create each in Linear; for each, stamp the returned id
|
|
53
|
+
into its phase file: the `ref` is the phase-file basename.
|
|
54
|
+
2. **Issues create** → create each (link to its milestone by `milestoneRef`,
|
|
55
|
+
resolving a `create` ref to the id just minted); stamp the returned identifier
|
|
56
|
+
back onto the matching task line (`ref` is the task's text).
|
|
57
|
+
3. **Milestones/issues update** → save by `id`.
|
|
58
|
+
4. **Project** → set description + status (map `status` — the local bucket — to
|
|
59
|
+
the Linear project-status name via `config.states`). Priority, labels, cycles
|
|
60
|
+
and comments are Linear-native triage — do **not** push them; they're the PM's.
|
|
59
61
|
|
|
60
|
-
|
|
62
|
+
Map the local status bucket to Linear's project status through `config.states`
|
|
63
|
+
(e.g. `complete → Completed`).
|
|
61
64
|
|
|
62
|
-
|
|
65
|
+
## 5. Record the snapshot
|
|
66
|
+
|
|
67
|
+
After everything applied and the ids are stamped into the files:
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
skitterspec spec-sync record <spec>
|
|
71
|
+
```
|
|
63
72
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
- `create`: for each `{ text, done }`, create an issue under the project (attach it
|
|
68
|
-
to the milestone of the phase the task lives in when known), then **stamp the new
|
|
69
|
-
issue identifier inline** on that task line (`… (SKI-123)`), matching by text.
|
|
73
|
+
This writes the last-pushed snapshot from the now-stamped files, so the next
|
|
74
|
+
`/spec-push` produces an empty plan. Commit the stamped spec + snapshot into the
|
|
75
|
+
branch so the mirror-link rides in the PR.
|
|
70
76
|
|
|
71
|
-
##
|
|
77
|
+
## 6. Report
|
|
72
78
|
|
|
73
|
-
|
|
74
|
-
|
|
79
|
+
Summarise what was created/updated in Linear and confirm the snapshot was
|
|
80
|
+
recorded. There is no pull — Linear is a generated mirror.
|
|
@@ -1,46 +1,51 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: spec-status
|
|
3
|
-
description: Show a spec's sync status against
|
|
3
|
+
description: Show a spec's one-way sync status against Linear — a read-only drift report. Reports whether the spec changed since the last push (there's something to push) and, optionally, whether Linear's workflow-state differs from the spec's. Fetches the Linear project over MCP and runs `skitterspec spec-sync status`. Changes nothing. Opt-in — needs specs/.core/linear.config.json. Use when the user says "/spec-status", "is this spec in sync with Linear", "what would push", or "show spec sync status".
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# /spec-status —
|
|
6
|
+
# /spec-status — one-way sync drift report
|
|
7
7
|
|
|
8
|
-
Read-only.
|
|
9
|
-
diverged since the last sync — the `git status` of the hybrid sync. Writes
|
|
10
|
-
nothing to either side.
|
|
8
|
+
Read-only. Reports two things and writes nothing:
|
|
11
9
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
1. **Pending push** — has the spec changed since the last push (are there
|
|
11
|
+
milestones/issues/description to create or update)?
|
|
12
|
+
2. **State drift** — does Linear's project workflow-state differ from the spec's
|
|
13
|
+
status? (The repo wins on the next push; this is just a heads-up, e.g. a card
|
|
14
|
+
moved in Linear.)
|
|
15
|
+
|
|
16
|
+
The repo is the source of truth; Linear is a generated mirror, so there is no
|
|
17
|
+
per-field "conflict" — only "what would the next push send" and "did the mirror
|
|
18
|
+
drift".
|
|
19
|
+
|
|
20
|
+
**Opt-in**: only runs when `specs/.core/linear.config.json` exists. If absent,
|
|
21
|
+
tell the user how to enable Linear sync and stop.
|
|
15
22
|
|
|
16
23
|
## 1. Identify the target spec
|
|
17
24
|
|
|
18
|
-
Use the
|
|
19
|
-
|
|
25
|
+
Use the argument, else the spec in context; ask if unclear.
|
|
26
|
+
|
|
27
|
+
## 2. Fetch the Linear project (optional, for drift)
|
|
20
28
|
|
|
21
|
-
|
|
29
|
+
If the spec has a `linear_project_id`, discover the Linear MCP read tool and write
|
|
30
|
+
the project JSON to a temp file — this lets the report compare workflow-state. If
|
|
31
|
+
Linear isn't connected, skip the drift line (still report pending-push).
|
|
22
32
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
- Discover the connected Linear MCP tools at runtime (the project-read tool). If
|
|
26
|
-
Linear isn't connected, relay "connect the `linear` MCP server" and stop — do
|
|
27
|
-
nothing else.
|
|
28
|
-
- Call the project-read tool for that id and write the returned JSON to a temp
|
|
29
|
-
file (e.g. under the OS temp dir).
|
|
33
|
+
Optionally fetch the workspace project-status names to a file to validate the
|
|
34
|
+
configured `states` at the same time.
|
|
30
35
|
|
|
31
36
|
## 3. Run the engine
|
|
32
37
|
|
|
33
38
|
```
|
|
34
|
-
skitterspec spec-sync status <spec> --remote <
|
|
39
|
+
skitterspec spec-sync status <spec> [--remote <projectfile>] [--workspace-states <statesfile>]
|
|
35
40
|
```
|
|
36
41
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
42
|
+
- Reports `push: pending — N to create, M to update` or `up to date`.
|
|
43
|
+
- With `--remote`, adds a `drift:` line comparing Linear's workflow-state to the
|
|
44
|
+
spec's status.
|
|
45
|
+
- With `--workspace-states`, fails loudly if a configured state name isn't in the
|
|
46
|
+
workspace (Linear would silently no-op it).
|
|
40
47
|
|
|
41
48
|
## 4. Report
|
|
42
49
|
|
|
43
|
-
Relay the engine's
|
|
44
|
-
|
|
45
|
-
`conflict` — resolve locally or use `--force` (which backs up the losing side).
|
|
46
|
-
Never write anything from this skill.
|
|
50
|
+
Relay the engine's output verbatim. Suggest `/spec-push` if a push is pending.
|
|
51
|
+
Never write to either side.
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
const { run } = require('../src/cli.js')
|
|
12
12
|
const { specSync } = require('../src/vendor/linear/cli-sync.js')
|
|
13
|
+
const { specSanitise } = require('../src/vendor/linear/cli-sanitise.js')
|
|
13
14
|
|
|
14
15
|
async function main(argv) {
|
|
15
16
|
const [cmd, ...rest] = argv
|
|
@@ -17,6 +18,10 @@ async function main(argv) {
|
|
|
17
18
|
await specSync(rest)
|
|
18
19
|
return
|
|
19
20
|
}
|
|
21
|
+
if (cmd === 'spec-sanitise') {
|
|
22
|
+
process.exitCode = await specSanitise(rest)
|
|
23
|
+
return
|
|
24
|
+
}
|
|
20
25
|
await run(argv)
|
|
21
26
|
}
|
|
22
27
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@skitterbyte/skitterspec-linear",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "8.0.0",
|
|
4
4
|
"description": "Spec-driven development for Claude Code, with Linear hybrid-sync — a superset of @skitterbyte/skitterspec: the base filesystem workflow plus git-like /spec-status · /spec-pull · /spec-push and the spec-sync CLI. Install this OR the base, not both.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"claude",
|
|
Binary file
|