@skitterbyte/skitterspec-jira 0.0.0-stage → 2.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 (113) hide show
  1. package/MIGRATION.md +1266 -0
  2. package/README.md +44 -2
  3. package/assets/claude-md-section.md +85 -0
  4. package/assets/commands/allow-main.md +33 -0
  5. package/assets/commands/spec-connect.md +13 -0
  6. package/assets/commands/spec-live.md +14 -0
  7. package/assets/commands/spec-remote-review.md +37 -0
  8. package/assets/commands/spec-skip.md +24 -0
  9. package/assets/core/SETUP.md +192 -0
  10. package/assets/core/env.config.json.example +56 -0
  11. package/assets/core/env.config.md +606 -0
  12. package/assets/core/gating.config.json.example +4 -0
  13. package/assets/core/gating.config.md +81 -0
  14. package/assets/core/jira.config.json.example +18 -0
  15. package/assets/core/jira.config.md +88 -0
  16. package/assets/hooks/main-guard.cjs +162 -0
  17. package/assets/hooks/review-gate.cjs +146 -0
  18. package/assets/review/page.html +3384 -0
  19. package/assets/rules/commit-trailers.md +96 -0
  20. package/assets/rules/negative-checks.md +69 -0
  21. package/assets/rules/offered-unblocks.md +100 -0
  22. package/assets/rules/spec-planning.md +702 -0
  23. package/assets/rules/spec-reports.md +572 -0
  24. package/assets/skills/no-spec/SKILL.md +249 -0
  25. package/assets/skills/spec/SKILL.md +714 -0
  26. package/assets/skills/spec-bug/SKILL.md +585 -0
  27. package/assets/skills/spec-cancel/SKILL.md +261 -0
  28. package/assets/skills/spec-complete/SKILL.md +451 -0
  29. package/assets/skills/spec-diff/SKILL.md +870 -0
  30. package/assets/skills/spec-hotfix/SKILL.md +607 -0
  31. package/assets/skills/spec-init/SKILL.md +178 -0
  32. package/assets/skills/spec-jira-setup/SKILL.md +221 -0
  33. package/assets/skills/spec-list/SKILL.md +173 -0
  34. package/assets/skills/spec-next/SKILL.md +678 -0
  35. package/assets/skills/spec-push/SKILL.md +306 -0
  36. package/assets/skills/spec-review/SKILL.md +256 -0
  37. package/assets/skills/spec-reviewed/SKILL.md +284 -0
  38. package/assets/skills/spec-start/SKILL.md +496 -0
  39. package/assets/skills/spec-status/SKILL.md +114 -0
  40. package/assets/skills/spec-sync/SKILL.md +220 -0
  41. package/assets/skills/spec-to-main/SKILL.md +141 -0
  42. package/bin/skitterspec-jira.js +68 -0
  43. package/package.json +40 -4
  44. package/src/cli.js +5967 -0
  45. package/src/deprecate.js +138 -0
  46. package/src/env/bootstrap.js +188 -0
  47. package/src/env/building.js +143 -0
  48. package/src/env/classify.js +176 -0
  49. package/src/env/commitcmd.js +108 -0
  50. package/src/env/config.js +850 -0
  51. package/src/env/dev.js +63 -0
  52. package/src/env/glob.js +34 -0
  53. package/src/env/hooks.js +226 -0
  54. package/src/env/hotfix.js +413 -0
  55. package/src/env/hotfixland.js +302 -0
  56. package/src/env/integrate.js +167 -0
  57. package/src/env/live.js +479 -0
  58. package/src/env/mainguard.js +299 -0
  59. package/src/env/provision.js +466 -0
  60. package/src/env/proxy.js +225 -0
  61. package/src/env/prune.js +119 -0
  62. package/src/env/registry.js +159 -0
  63. package/src/env/render.js +17 -0
  64. package/src/env/resolve.js +716 -0
  65. package/src/env/review.js +2622 -0
  66. package/src/env/reviewers/coderabbit.js +228 -0
  67. package/src/env/reviewers.js +517 -0
  68. package/src/env/serve.js +1044 -0
  69. package/src/env/supervise.js +157 -0
  70. package/src/env/teardown.js +248 -0
  71. package/src/env/trust.js +87 -0
  72. package/src/gating.js +155 -0
  73. package/src/init.js +1150 -0
  74. package/src/lines-diff.js +114 -0
  75. package/src/prompts.js +129 -0
  76. package/src/vendor/jira/adf.js +414 -0
  77. package/src/vendor/jira/api.js +295 -0
  78. package/src/vendor/jira/cli-sync.js +1252 -0
  79. package/src/vendor/jira/commands.js +44 -0
  80. package/src/vendor/jira/config.js +286 -0
  81. package/src/vendor/jira/credentials.js +108 -0
  82. package/src/vendor/jira/dialect.js +45 -0
  83. package/src/vendor/jira/mcp.js +129 -0
  84. package/src/vendor/provider-kit/index.js +41 -0
  85. package/src/vendor/provider-kit/src/adapter.js +23 -0
  86. package/src/vendor/provider-kit/src/apply.js +207 -0
  87. package/src/vendor/provider-kit/src/args.js +68 -0
  88. package/src/vendor/provider-kit/src/assignment.js +277 -0
  89. package/src/vendor/provider-kit/src/config.js +251 -0
  90. package/src/vendor/provider-kit/src/credentials.js +404 -0
  91. package/src/vendor/provider-kit/src/doctor.js +35 -0
  92. package/src/vendor/provider-kit/src/http.js +63 -0
  93. package/src/vendor/provider-kit/src/identity.js +93 -0
  94. package/src/vendor/provider-kit/src/list-assignee.js +71 -0
  95. package/src/vendor/provider-kit/src/list-rows.js +35 -0
  96. package/src/vendor/provider-kit/src/md-compare.js +39 -0
  97. package/src/vendor/provider-kit/src/md-tables.js +94 -0
  98. package/src/vendor/provider-kit/src/prompt.js +50 -0
  99. package/src/vendor/provider-kit/src/released.js +219 -0
  100. package/src/vendor/provider-kit/src/specs.js +248 -0
  101. package/src/vendor/provider-kit/src/transport.js +22 -0
  102. package/src/vendor/sync-core/index.js +92 -0
  103. package/src/vendor/sync-core/src/base.js +81 -0
  104. package/src/vendor/sync-core/src/compare.js +338 -0
  105. package/src/vendor/sync-core/src/dialect.js +51 -0
  106. package/src/vendor/sync-core/src/fields.js +36 -0
  107. package/src/vendor/sync-core/src/legacy.js +100 -0
  108. package/src/vendor/sync-core/src/normalize.js +971 -0
  109. package/src/vendor/sync-core/src/push.js +85 -0
  110. package/src/vendor/sync-core/src/retarget.js +278 -0
  111. package/src/vendor/sync-core/src/task-block.js +308 -0
  112. package/src/vendor/sync-core/src/verify.js +67 -0
  113. package/src/vendor/sync-core/src/write.js +191 -0
@@ -0,0 +1,108 @@
1
+ 'use strict'
2
+
3
+ /**
4
+ * Is this shell command a `git commit`?
5
+ *
6
+ * Asked by the review-gate hook, which is handed the command line a tool is
7
+ * about to run and has to decide whether the gate is even relevant. It lives
8
+ * here rather than inside the hook script for one reason: **a check that blocks
9
+ * a commit is an accusation** (`.claude/rules/negative-checks.md`), and an
10
+ * accusation that cannot be unit-tested will be wrong in ways nobody finds. The
11
+ * hook is a stdin shim over `spec-env review gate --check --for-command`; this
12
+ * is the part with the judgement in it.
13
+ *
14
+ * It answers TRUE only on a positive reading — a `git` invocation whose first
15
+ * non-option argument is `commit`. Everything it cannot parse confidently reads
16
+ * FALSE, because the cost of the two mistakes is not symmetric: a false
17
+ * negative lets one commit through a gate the skills also enforce, while a
18
+ * false positive blocks a command that has nothing to do with reviewing and
19
+ * leaves the operator with no idea why.
20
+ */
21
+
22
+ // Shell metacharacters that end one command and begin another. `|` covers `||`
23
+ // too, and `&` covers `&&`; over-splitting is harmless here because each
24
+ // fragment is judged on its own.
25
+ const SEPARATORS = /[;&|\n]+/
26
+
27
+ /**
28
+ * Remove every quoted span. Pure.
29
+ *
30
+ * THE POINT IS WHAT THIS PREVENTS, twice over. `echo "deploy && git commit"`
31
+ * must not read as a commit — splitting a raw string on `&&` would manufacture
32
+ * a fragment out of someone's prose. And `git commit -m "fix the git log"`
33
+ * must still read as one: emptying the quotes leaves the real argv intact,
34
+ * because a verb is never inside quotes.
35
+ *
36
+ * An UNTERMINATED quote empties the rest of the line, so a half-written command
37
+ * reads as nothing rather than as something — the cannot-tell case going to the
38
+ * harmless branch, again.
39
+ */
40
+ function stripQuoted(command) {
41
+ let out = ''
42
+ let quote = null
43
+ for (let i = 0; i < command.length; i++) {
44
+ const c = command[i]
45
+ if (quote) {
46
+ if (c === '\\' && quote === '"') {
47
+ i++
48
+ continue
49
+ }
50
+ if (c === quote) quote = null
51
+ continue
52
+ }
53
+ if (c === '"' || c === "'") {
54
+ quote = c
55
+ continue
56
+ }
57
+ out += c
58
+ }
59
+ return out
60
+ }
61
+
62
+ // git's own options, before the subcommand. Those taking a separate value have
63
+ // to be skipped WITH their value, or `git -C /tmp commit` reads its verb as the
64
+ // path. The `=` forms carry their value already.
65
+ const GIT_OPTS_WITH_VALUE = new Set(['-C', '-c', '--git-dir', '--work-tree', '--namespace', '--exec-path'])
66
+
67
+ /**
68
+ * Does this one fragment invoke `git commit`? Pure.
69
+ *
70
+ * `env`, `sudo`, `time` and the like are NOT unwrapped: a wrapper is not the
71
+ * common case and guessing at one is how a false positive gets built. The
72
+ * binary may be a path (`/usr/bin/git`), because that is ordinary.
73
+ */
74
+ function fragmentCommits(fragment) {
75
+ const tokens = fragment.trim().split(/\s+/).filter(Boolean)
76
+ const at = tokens.findIndex((t) => t === 'git' || /(^|\/)git$/.test(t))
77
+ if (at === -1) return false
78
+
79
+ for (let i = at + 1; i < tokens.length; i++) {
80
+ const t = tokens[i]
81
+ if (GIT_OPTS_WITH_VALUE.has(t)) {
82
+ i++
83
+ continue
84
+ }
85
+ if (t.startsWith('-')) continue
86
+ // The first non-option token is the subcommand, whatever it is. Only one
87
+ // word is a commit.
88
+ return t === 'commit'
89
+ }
90
+ return false
91
+ }
92
+
93
+ /**
94
+ * Does this command line run `git commit` anywhere in it? Pure.
95
+ *
96
+ * WHAT WOULD FOOL THIS, named here so the next reader does not have to
97
+ * rediscover it: a commit hidden inside a quoted script (`sh -c 'git commit'`),
98
+ * behind an alias, or built by string interpolation reads as FALSE. All three
99
+ * are deliberate — they are the unknown case, and the unknown case does not
100
+ * accuse. The gate is still enforced by `/spec-next`, which does not depend on
101
+ * reading anybody's shell.
102
+ */
103
+ function isGitCommit(command) {
104
+ if (typeof command !== 'string' || !command.trim()) return false
105
+ return stripQuoted(command).split(SEPARATORS).some(fragmentCommits)
106
+ }
107
+
108
+ module.exports = { isGitCommit, stripQuoted, fragmentCommits }