@skitterbyte/skitterspec-linear 1.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.
Files changed (45) hide show
  1. package/README.md +56 -0
  2. package/assets/claude-md-section.md +39 -0
  3. package/assets/core/env.config.json.example +28 -0
  4. package/assets/core/env.config.md +99 -0
  5. package/assets/core/linear.config.json.example +39 -0
  6. package/assets/core/linear.config.md +121 -0
  7. package/assets/rules/spec-planning.md +152 -0
  8. package/assets/skills/spec/SKILL.md +232 -0
  9. package/assets/skills/spec-bug/SKILL.md +110 -0
  10. package/assets/skills/spec-cancel/SKILL.md +61 -0
  11. package/assets/skills/spec-complete/SKILL.md +87 -0
  12. package/assets/skills/spec-env/SKILL.md +63 -0
  13. package/assets/skills/spec-env-down/SKILL.md +64 -0
  14. package/assets/skills/spec-go/SKILL.md +134 -0
  15. package/assets/skills/spec-init/SKILL.md +84 -0
  16. package/assets/skills/spec-pull/SKILL.md +46 -0
  17. package/assets/skills/spec-push/SKILL.md +53 -0
  18. package/assets/skills/spec-ready/SKILL.md +50 -0
  19. package/assets/skills/spec-review/SKILL.md +69 -0
  20. package/assets/skills/spec-status/SKILL.md +46 -0
  21. package/bin/skitterspec-linear.js +26 -0
  22. package/package.json +38 -0
  23. package/src/cli.js +495 -0
  24. package/src/deprecate.js +138 -0
  25. package/src/env/config.js +165 -0
  26. package/src/env/integrate.js +46 -0
  27. package/src/env/provision.js +76 -0
  28. package/src/env/registry.js +95 -0
  29. package/src/env/render.js +26 -0
  30. package/src/env/resolve.js +202 -0
  31. package/src/env/teardown.js +109 -0
  32. package/src/env/trust.js +87 -0
  33. package/src/init.js +311 -0
  34. package/src/prompts.js +56 -0
  35. package/src/vendor/linear/cli-sync.js +256 -0
  36. package/src/vendor/linear/config.js +198 -0
  37. package/src/vendor/linear/mcp.js +112 -0
  38. package/src/vendor/sync-core/index.js +35 -0
  39. package/src/vendor/sync-core/src/apply.js +66 -0
  40. package/src/vendor/sync-core/src/base.js +83 -0
  41. package/src/vendor/sync-core/src/compare.js +99 -0
  42. package/src/vendor/sync-core/src/normalize.js +249 -0
  43. package/src/vendor/sync-core/src/pull.js +84 -0
  44. package/src/vendor/sync-core/src/push.js +106 -0
  45. package/src/vendor/sync-core/src/write.js +86 -0
@@ -0,0 +1,86 @@
1
+ 'use strict'
2
+
3
+ /**
4
+ * Local snapshot writes for pull (remote → repo).
5
+ *
6
+ * Phase 2 applies **frontmatter-mapped** pulled fields — the `pull`-owned data
7
+ * remote genuinely owns (`workflowState` → `spec_status`, `priority`, `labels`)
8
+ * plus sync bookkeeping (`last_synced_at`, ids) — by surgically editing the YAML
9
+ * frontmatter of `00-overview.md` and leaving the markdown body byte-for-byte
10
+ * untouched. Existing keys are updated in place (order preserved); new keys are
11
+ * appended; a file with no frontmatter gets one prepended.
12
+ *
13
+ * Body/`both`-owned fields (`description`, `milestones`, …) are NOT written back
14
+ * here — that denormalizer is a tracked follow-up (see the spec). Callers advance
15
+ * the base only for fields they actually applied, so an un-applied remote edit
16
+ * stays pending rather than being silently marked synced.
17
+ */
18
+
19
+ const fs = require('node:fs')
20
+ const path = require('node:path')
21
+
22
+ // Serialize a JS value as a YAML-ish frontmatter scalar. null/undefined → the
23
+ // key is dropped (caller shouldn't pass those).
24
+ function serialize(value) {
25
+ if (Array.isArray(value)) return JSON.stringify(value)
26
+ if (typeof value === 'number' || typeof value === 'boolean') return String(value)
27
+ return JSON.stringify(String(value)) // quoted string
28
+ }
29
+
30
+ // Split `---\n…\n---\n` frontmatter off the top. Returns { fmLines, body, had }.
31
+ function splitFrontmatter(raw) {
32
+ const m = /^---\n([\s\S]*?)\n---\n?/.exec(raw)
33
+ if (!m) return { fmLines: [], body: raw, had: false }
34
+ return { fmLines: m[1].split('\n'), body: raw.slice(m[0].length), had: true }
35
+ }
36
+
37
+ // Apply a key→value patch onto frontmatter lines, preserving order.
38
+ function patchFrontmatterLines(lines, patch) {
39
+ const keys = new Set(Object.keys(patch))
40
+ const out = []
41
+ const seen = new Set()
42
+ for (const line of lines) {
43
+ const kv = /^([A-Za-z0-9_-]+):\s*(.*)$/.exec(line)
44
+ if (kv && keys.has(kv[1])) {
45
+ out.push(`${kv[1]}: ${serialize(patch[kv[1]])}`)
46
+ seen.add(kv[1])
47
+ } else {
48
+ out.push(line)
49
+ }
50
+ }
51
+ // Append any new keys not already present.
52
+ for (const key of Object.keys(patch)) {
53
+ if (!seen.has(key)) out.push(`${key}: ${serialize(patch[key])}`)
54
+ }
55
+ return out
56
+ }
57
+
58
+ /**
59
+ * Update `00-overview.md` frontmatter under `snapshotDir` with `patch`
60
+ * (key → value; nullish values are skipped). Returns the list of keys written.
61
+ */
62
+ function writeFrontmatter(snapshotDir, config, patch) {
63
+ const overviewFile = (config && config.snapshot && config.snapshot.overviewFile) || '00-overview.md'
64
+ const file = path.join(snapshotDir, overviewFile)
65
+ const raw = fs.readFileSync(file, 'utf-8')
66
+
67
+ const clean = {}
68
+ for (const [k, v] of Object.entries(patch)) {
69
+ if (v !== null && v !== undefined) clean[k] = v
70
+ }
71
+ if (!Object.keys(clean).length) return []
72
+
73
+ const { fmLines, body, had } = splitFrontmatter(raw)
74
+ const patched = patchFrontmatterLines(fmLines, clean)
75
+ const frontmatter = `---\n${patched.join('\n')}\n---\n`
76
+ const next = had ? frontmatter + body : frontmatter + '\n' + raw
77
+
78
+ fs.writeFileSync(file, next, 'utf-8')
79
+ return Object.keys(clean)
80
+ }
81
+
82
+ module.exports = {
83
+ writeFrontmatter,
84
+ splitFrontmatter,
85
+ serialize,
86
+ }