@workit-dev/core 0.0.1 → 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 (234) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +22 -43
  3. package/package.json +56 -6
  4. package/schemas/config.json +74 -0
  5. package/schemas/vcs.json +79 -0
  6. package/schemas/workspaces.json +1029 -0
  7. package/schemas/youtrack.json +84 -0
  8. package/scripts/analyze-release-scope.ts +215 -0
  9. package/scripts/bundled-deps.json +131 -0
  10. package/scripts/fixtures/sample-plan.md +15 -0
  11. package/scripts/fixtures/sample-sdd/progress.md +2 -0
  12. package/scripts/install-codex-plugin.sh +28 -0
  13. package/scripts/install-cursor-plugin.sh +146 -0
  14. package/scripts/install-opencode-plugin.sh +79 -0
  15. package/scripts/install-pi-package.sh +56 -0
  16. package/scripts/lib/config-dir.sh +28 -0
  17. package/scripts/publish-changed-packages.ts +395 -0
  18. package/scripts/rewrite-workspace-deps.ts +53 -0
  19. package/scripts/run-cursor-mcp.sh +6 -0
  20. package/scripts/sync-release-manifests.ts +82 -0
  21. package/scripts/sync-runtime.sh +142 -0
  22. package/scripts/validate-cursor-marketplace.ts +171 -0
  23. package/scripts/verify-bundle-sources.ts +134 -0
  24. package/scripts/write-schemas.ts +16 -0
  25. package/skills/workit-architecture/SKILL.md +72 -0
  26. package/skills/workit-architecture/agents/openai.yaml +3 -0
  27. package/skills/workit-architecture/references/instruction-files.md +52 -0
  28. package/skills/workit-architecture/references/vocabulary.md +53 -0
  29. package/skills/workit-bdd/SKILL.md +53 -0
  30. package/skills/workit-continue/SKILL.md +54 -0
  31. package/skills/workit-debug/SKILL.md +45 -0
  32. package/skills/workit-deslop/SKILL.md +58 -0
  33. package/skills/workit-fanout/SKILL.md +71 -0
  34. package/skills/workit-fanout/references/brief.md +141 -0
  35. package/skills/workit-fanout/references/orchestration.md +169 -0
  36. package/skills/workit-implement/SKILL.md +71 -0
  37. package/skills/workit-retro/SKILL.md +72 -0
  38. package/skills/workit-retro/agents/openai.yaml +3 -0
  39. package/skills/workit-retro/references/sources.md +35 -0
  40. package/skills/workit-retro/references/steering.md +39 -0
  41. package/skills/workit-review/SKILL.md +66 -0
  42. package/skills/workit-review/references/impact.md +24 -0
  43. package/skills/workit-shape/SKILL.md +71 -0
  44. package/skills/workit-shape/references/diagrams.md +17 -0
  45. package/skills/workit-shape/references/knowledge.md +61 -0
  46. package/skills/workit-shape/references/mockups.md +15 -0
  47. package/skills/workit-shape/references/slicing.md +44 -0
  48. package/skills/workit-ship/SKILL.md +71 -0
  49. package/skills/workit-ship/references/changelog.md +44 -0
  50. package/skills/workit-ship/references/pr-body.md +32 -0
  51. package/skills/workit-ship/references/release.md +39 -0
  52. package/skills/workit-test-audit/SKILL.md +54 -0
  53. package/skills/workit-verify-app/SKILL.md +68 -0
  54. package/skills/workit-verify-app/references/template.md +51 -0
  55. package/src/autonomy.ts +910 -0
  56. package/src/check-config.ts +613 -0
  57. package/src/checks.ts +534 -0
  58. package/src/ci-waiter.ts +159 -0
  59. package/src/core/boundary.ts +55 -0
  60. package/src/core/branch-policy.ts +112 -0
  61. package/src/core/branch.ts +1192 -0
  62. package/src/core/changelog-gate.ts +349 -0
  63. package/src/core/changelog-merge.ts +214 -0
  64. package/src/core/changelog.ts +392 -0
  65. package/src/core/cleanup.ts +638 -0
  66. package/src/core/cli-locate.ts +173 -0
  67. package/src/core/commit-flavors.ts +65 -0
  68. package/src/core/config-schemas.ts +653 -0
  69. package/src/core/config.ts +351 -0
  70. package/src/core/context-read.ts +144 -0
  71. package/src/core/docs-gate.ts +69 -0
  72. package/src/core/finding-evidence.ts +89 -0
  73. package/src/core/finding-queue.ts +36 -0
  74. package/src/core/git.ts +73 -0
  75. package/src/core/gitignore.ts +52 -0
  76. package/src/core/heavy-eta.ts +170 -0
  77. package/src/core/heavy-lease.ts +290 -0
  78. package/src/core/heavy-rules.ts +373 -0
  79. package/src/core/heavy-scope.ts +131 -0
  80. package/src/core/heavy-words.ts +83 -0
  81. package/src/core/heavy.ts +535 -0
  82. package/src/core/hygiene.ts +149 -0
  83. package/src/core/init.ts +218 -0
  84. package/src/core/live-session.ts +333 -0
  85. package/src/core/logger.ts +310 -0
  86. package/src/core/methods.ts +185 -0
  87. package/src/core/model-fallback.ts +208 -0
  88. package/src/core/node-resolve.mjs +249 -0
  89. package/src/core/operation-input.ts +632 -0
  90. package/src/core/package-root.ts +28 -0
  91. package/src/core/policy/attributes.ts +97 -0
  92. package/src/core/policy/bookkeeping.ts +119 -0
  93. package/src/core/policy/carry.ts +122 -0
  94. package/src/core/policy/check-evidence.ts +115 -0
  95. package/src/core/policy/current-judgment.ts +20 -0
  96. package/src/core/policy/derive.ts +387 -0
  97. package/src/core/policy/judgment.ts +246 -0
  98. package/src/core/policy/lane.ts +562 -0
  99. package/src/core/policy/pr-lane.ts +32 -0
  100. package/src/core/policy/substance.ts +365 -0
  101. package/src/core/policy-resolver.ts +94 -0
  102. package/src/core/pr-create.ts +448 -0
  103. package/src/core/pr-template.ts +162 -0
  104. package/src/core/release-notes.ts +197 -0
  105. package/src/core/release-tracks.ts +779 -0
  106. package/src/core/remotes.ts +436 -0
  107. package/src/core/repo-context.ts +542 -0
  108. package/src/core/repo-paths.ts +29 -0
  109. package/src/core/resources.ts +1299 -0
  110. package/src/core/role-models.ts +603 -0
  111. package/src/core/route-intent.ts +305 -0
  112. package/src/core/rules.ts +65 -0
  113. package/src/core/runtime-identity.ts +63 -0
  114. package/src/core/safe-write.ts +87 -0
  115. package/src/core/scope-glob.ts +56 -0
  116. package/src/core/scripts.ts +6 -0
  117. package/src/core/skill-manifests.ts +173 -0
  118. package/src/core/store-lock.ts +374 -0
  119. package/src/core/support-matrix.ts +24 -0
  120. package/src/core/task-context.ts +247 -0
  121. package/src/core/task-contract.ts +1279 -0
  122. package/src/core/task-delivery.ts +109 -0
  123. package/src/core/task-engine.ts +2248 -0
  124. package/src/core/task-evaluation.ts +1147 -0
  125. package/src/core/task-store.ts +2649 -0
  126. package/src/core/task-view.ts +180 -0
  127. package/src/core/templates.ts +22 -0
  128. package/src/core/tracker-issues.ts +174 -0
  129. package/src/core/vcs-config.ts +540 -0
  130. package/src/core/workers.ts +62 -0
  131. package/src/core/workit-paths.mjs +242 -0
  132. package/src/core/workspace-branch-policy.ts +123 -0
  133. package/src/core/workspaces.ts +1745 -0
  134. package/src/core/youtrack-backend.ts +288 -0
  135. package/src/core/youtrack-tools.ts +260 -0
  136. package/src/core/youtrack-writes.ts +73 -0
  137. package/src/core/youtrack-ytrack.ts +217 -0
  138. package/src/core/youtrack.ts +454 -0
  139. package/src/core/ytrack-skill.ts +297 -0
  140. package/src/core.ts +171 -0
  141. package/src/deslop/lex.ts +271 -0
  142. package/src/deslop/scan.ts +232 -0
  143. package/src/duration.ts +27 -0
  144. package/src/fanout-brief.ts +486 -0
  145. package/src/fanout-check.ts +455 -0
  146. package/src/fanout-landed.ts +370 -0
  147. package/src/fanout-stack.ts +108 -0
  148. package/src/fanout-status.ts +362 -0
  149. package/src/fanout-worktree.ts +893 -0
  150. package/src/fanout.ts +1473 -0
  151. package/src/forge/exec.ts +385 -0
  152. package/src/forge/github.ts +831 -0
  153. package/src/forge/gitlab.ts +906 -0
  154. package/src/forge/issue-forge.ts +209 -0
  155. package/src/forge/issue-link.ts +468 -0
  156. package/src/forge/issue-ops.ts +314 -0
  157. package/src/forge/merge-gate-base-red.ts +72 -0
  158. package/src/forge/pr-body.ts +100 -0
  159. package/src/forge/pr-edit.ts +292 -0
  160. package/src/forge/pr-ops.ts +1109 -0
  161. package/src/forge/pr-status.ts +10 -0
  162. package/src/forge/redact.ts +195 -0
  163. package/src/forge/report.ts +994 -0
  164. package/src/forge/reruns.ts +132 -0
  165. package/src/forge/resolve.ts +509 -0
  166. package/src/forge/types.ts +242 -0
  167. package/src/forge/verify.ts +398 -0
  168. package/src/git/default-base.ts +130 -0
  169. package/src/git/env-redirect.ts +28 -0
  170. package/src/git/facts.ts +122 -0
  171. package/src/git/ops.ts +1823 -0
  172. package/src/git/refs-read.ts +332 -0
  173. package/src/git/release.ts +1020 -0
  174. package/src/git/rev.ts +1175 -0
  175. package/src/git/session-hook.ts +597 -0
  176. package/src/git/stage.ts +63 -0
  177. package/src/hooks/agent-model.ts +149 -0
  178. package/src/hooks/budget-signal.ts +284 -0
  179. package/src/hooks/context.ts +461 -0
  180. package/src/hooks/cwd-normalize.ts +79 -0
  181. package/src/hooks/deadline.ts +228 -0
  182. package/src/hooks/delivery-verbs.ts +182 -0
  183. package/src/hooks/descriptor.ts +124 -0
  184. package/src/hooks/handle.ts +433 -0
  185. package/src/hooks/heavy-gate.ts +99 -0
  186. package/src/hooks/hook-runs.ts +130 -0
  187. package/src/hooks/hosts/claude-code.ts +380 -0
  188. package/src/hooks/hosts/codex.ts +372 -0
  189. package/src/hooks/hosts/cursor.ts +419 -0
  190. package/src/hooks/hosts/fields.ts +98 -0
  191. package/src/hooks/hosts/opencode.ts +79 -0
  192. package/src/hooks/hosts/pi.ts +78 -0
  193. package/src/hooks/index.ts +60 -0
  194. package/src/hooks/model-limit.ts +378 -0
  195. package/src/hooks/model-switch.ts +35 -0
  196. package/src/hooks/policy.ts +29 -0
  197. package/src/hooks/process.ts +48 -0
  198. package/src/hooks/protocol.ts +135 -0
  199. package/src/hooks/raw-git.ts +2289 -0
  200. package/src/hooks/repeat-failure.ts +115 -0
  201. package/src/hooks/run.ts +54 -0
  202. package/src/hooks/session-marker.ts +151 -0
  203. package/src/hooks/shell-words.ts +532 -0
  204. package/src/hooks/skill-nudge.ts +295 -0
  205. package/src/hooks/spawn-gate.ts +72 -0
  206. package/src/hooks/standing-signal.ts +99 -0
  207. package/src/hooks/standing.ts +225 -0
  208. package/src/hooks/steering.ts +74 -0
  209. package/src/hooks/stop.ts +408 -0
  210. package/src/hooks/worktree-confine.ts +415 -0
  211. package/src/hooks/write-gate.ts +1174 -0
  212. package/src/host-session.ts +459 -0
  213. package/src/knowledge.ts +368 -0
  214. package/src/ledger.ts +2913 -0
  215. package/src/stack.ts +2570 -0
  216. package/src/store/event-log.ts +217 -0
  217. package/src/store/notes.ts +29 -0
  218. package/src/store/patch.ts +135 -0
  219. package/src/store/paths.ts +368 -0
  220. package/src/store/reduce.ts +203 -0
  221. package/src/test-audit-mocks.ts +309 -0
  222. package/src/verdict-cover.ts +151 -0
  223. package/src/worktree-deps.ts +142 -0
  224. package/templates/headers.md +3 -0
  225. package/templates/hygiene/.editorconfig +8 -0
  226. package/templates/hygiene/.gitattributes +3 -0
  227. package/templates/hygiene/CHANGELOG.md +14 -0
  228. package/templates/hygiene/CONTRIBUTING.md +3 -0
  229. package/templates/hygiene/LICENSE +21 -0
  230. package/templates/hygiene/README.md +3 -0
  231. package/templates/issue-update.md +5 -0
  232. package/templates/plan-template.md +26 -0
  233. package/templates/spec-template.md +64 -0
  234. package/templates/workit-contract.md +13 -0
@@ -0,0 +1,197 @@
1
+ // User-facing release notes for `workit release finish` and `workit release
2
+ // notes`: pure functions from a version's Keep a Changelog section to the
3
+ // forge release body.
4
+ //
5
+ // ## Highlights 1-3 bullets the agent writes in the draft (omitted when empty)
6
+ // ## Breaking changes bullets of the Removed section and any marked BREAKING
7
+ // ## Changes the version's ### Added/Changed/Deprecated/Removed/Fixed/Security
8
+ // **Full changelog**: <compare previous-tag...tag>
9
+
10
+ /** Keep a Changelog's sections, in its order. */
11
+ export const KEEP_A_CHANGELOG_SECTIONS = [
12
+ "Added",
13
+ "Changed",
14
+ "Deprecated",
15
+ "Removed",
16
+ "Fixed",
17
+ "Security",
18
+ ] as const;
19
+
20
+ type Subsection = { heading: string | null; body: string };
21
+
22
+ /** A changelog section split at its `###` headings; text before the first one has no heading. */
23
+ export function changelogSubsections(section: string): Subsection[] {
24
+ const parts: Subsection[] = [];
25
+ let current: { heading: string | null; lines: string[] } = {
26
+ heading: null,
27
+ lines: [],
28
+ };
29
+ const close = () => {
30
+ const body = current.lines.join("\n").trim();
31
+ if (body) parts.push({ heading: current.heading, body });
32
+ };
33
+ for (const line of section.split(/\r?\n/u)) {
34
+ const heading = /^###\s+(.+?)\s*#*\s*$/u.exec(line);
35
+ if (heading) {
36
+ close();
37
+ current = { heading: heading[1], lines: [] };
38
+ } else current.lines.push(line);
39
+ }
40
+ close();
41
+ return parts;
42
+ }
43
+
44
+ type SectionName = (typeof KEEP_A_CHANGELOG_SECTIONS)[number];
45
+
46
+ const canonical = (heading: string): SectionName | null =>
47
+ KEEP_A_CHANGELOG_SECTIONS.find((name) => name.toLowerCase() === heading.trim().toLowerCase()) ??
48
+ null;
49
+
50
+ /** Top-level list items of a Markdown body, each with its indented continuation lines. */
51
+ export function listItems(body: string): string[] {
52
+ const items: string[][] = [];
53
+ let open: string[] | null = null;
54
+ for (const line of body.split(/\r?\n/u)) {
55
+ if (/^[-*+]\s+/u.test(line)) {
56
+ open = [line];
57
+ items.push(open);
58
+ } else if (open && /^\s+\S/u.test(line)) open.push(line);
59
+ else open = null;
60
+ }
61
+ return items.map((lines) => lines.join("\n").trimEnd());
62
+ }
63
+
64
+ const BREAKING = /\bBREAKING\b/u;
65
+
66
+ /** The breaking changes: every item of a Removed section, and any item marked BREAKING. */
67
+ export function breakingChanges(section: string): string[] {
68
+ const found: string[] = [];
69
+ for (const part of changelogSubsections(section)) {
70
+ const removed = part.heading !== null && canonical(part.heading) === "Removed";
71
+ for (const item of listItems(part.body))
72
+ if ((removed || BREAKING.test(item)) && !found.includes(item)) found.push(item);
73
+ }
74
+ return found;
75
+ }
76
+
77
+ /**
78
+ * The `## Changes` body: the Keep a Changelog sections in their order, then
79
+ * any other heading in the order written; text before the first heading leads.
80
+ */
81
+ export function changesBody(section: string): string {
82
+ const parts = changelogSubsections(section);
83
+ const rank = (part: Subsection): number => {
84
+ if (part.heading === null) return -1;
85
+ const name = canonical(part.heading);
86
+ return name ? KEEP_A_CHANGELOG_SECTIONS.indexOf(name) : KEEP_A_CHANGELOG_SECTIONS.length;
87
+ };
88
+ return parts
89
+ .map((part, index) => ({ part, index }))
90
+ .toSorted((a, b) => rank(a.part) - rank(b.part) || a.index - b.index)
91
+ .map(({ part }) =>
92
+ part.heading === null
93
+ ? part.body
94
+ : `### ${canonical(part.heading) ?? part.heading}\n\n${part.body}`,
95
+ )
96
+ .join("\n\n");
97
+ }
98
+
99
+ /** The body of a draft's `## Highlights` section, or null when it has none or it is empty. */
100
+ export function highlightsOf(notes: string): string | null {
101
+ const lines = notes.split(/\r?\n/u);
102
+ const start = lines.findIndex((line) => /^##\s+Highlights\s*$/iu.test(line));
103
+ if (start < 0) return null;
104
+ const end = lines.findIndex((line, index) => index > start && /^#{1,2}\s/u.test(line));
105
+ const body = lines
106
+ .slice(start + 1, end < 0 ? undefined : end)
107
+ .join("\n")
108
+ .trim();
109
+ return body || null;
110
+ }
111
+
112
+ export type ForgeKindName = "github" | "gitlab";
113
+
114
+ /** The forge's compare page from `from` to `to`: GitHub `/compare/a...b`, GitLab `/-/compare/a...b`. */
115
+ export const compareUrl = (
116
+ kind: ForgeKindName,
117
+ webBase: string,
118
+ from: string,
119
+ to: string,
120
+ ): string =>
121
+ `${webBase.replace(/\/+$/u, "")}${kind === "gitlab" ? "/-/compare/" : "/compare/"}${encodeURI(from)}...${encodeURI(to)}`;
122
+
123
+ type ParsedVersion = { main: string[]; pre: string[] };
124
+
125
+ const parseVersion = (version: string): ParsedVersion | null => {
126
+ if (!/^\d/u.test(version)) return null;
127
+ const core = version.split("+")[0];
128
+ const dash = core.indexOf("-");
129
+ const main = (dash < 0 ? core : core.slice(0, dash)).split(".");
130
+ const pre = dash < 0 ? [] : core.slice(dash + 1).split(".");
131
+ return { main, pre };
132
+ };
133
+
134
+ const compareIdentifier = (a: string, b: string): number => {
135
+ const numeric = /^\d+$/u;
136
+ if (numeric.test(a) && numeric.test(b)) return Number(a) - Number(b);
137
+ if (numeric.test(a)) return -1;
138
+ if (numeric.test(b)) return 1;
139
+ return a < b ? -1 : a > b ? 1 : 0;
140
+ };
141
+
142
+ /** Semver-like ordering: numeric parts compare as numbers, a pre-release sorts before its release. */
143
+ export function compareVersions(a: string, b: string): number {
144
+ const left = parseVersion(a);
145
+ const right = parseVersion(b);
146
+ if (!left || !right) return a < b ? -1 : a > b ? 1 : 0;
147
+ for (let index = 0; index < Math.max(left.main.length, right.main.length); index += 1) {
148
+ const diff = compareIdentifier(left.main[index] ?? "0", right.main[index] ?? "0");
149
+ if (diff) return diff;
150
+ }
151
+ if (!left.pre.length || !right.pre.length) return right.pre.length - left.pre.length;
152
+ for (let index = 0; index < Math.max(left.pre.length, right.pre.length); index += 1) {
153
+ if (left.pre[index] === undefined) return -1;
154
+ if (right.pre[index] === undefined) return 1;
155
+ const diff = compareIdentifier(left.pre[index], right.pre[index]);
156
+ if (diff) return diff;
157
+ }
158
+ return 0;
159
+ }
160
+
161
+ /**
162
+ * The latest tag before `version` with the same prefix (`v1.3.0` before
163
+ * `v1.4.0`; `api/v2.0.0` only among `api/v*`), or null when there is none.
164
+ */
165
+ export function previousTag(tags: string[], prefix: string, version: string): string | null {
166
+ let best: { tag: string; version: string } | null = null;
167
+ for (const tag of tags) {
168
+ if (!tag.startsWith(prefix)) continue;
169
+ const candidate = tag.slice(prefix.length);
170
+ if (!parseVersion(candidate) || compareVersions(candidate, version) >= 0) continue;
171
+ if (!best || compareVersions(candidate, best.version) > 0) best = { tag, version: candidate };
172
+ }
173
+ return best?.tag ?? null;
174
+ }
175
+
176
+ /** The release notes Markdown: Highlights, Breaking changes, Changes, Full changelog. */
177
+ export function renderReleaseNotes(input: {
178
+ version: string;
179
+ /** The version's changelog section, or null without one. */
180
+ changelog: string | null;
181
+ /** The Highlights body (bullets), or null to omit the section. */
182
+ highlights?: string | null;
183
+ /** The compare link, or null without a previous tag or a known forge. */
184
+ compare?: string | null;
185
+ }): string {
186
+ const blocks: string[] = [];
187
+ const highlights = input.highlights?.trim();
188
+ if (highlights) blocks.push(`## Highlights\n\n${highlights}`);
189
+ const section = input.changelog?.trim() ?? "";
190
+ const breaking = section ? breakingChanges(section) : [];
191
+ if (breaking.length) blocks.push(`## Breaking changes\n\n${breaking.join("\n")}`);
192
+ const changes = section ? changesBody(section) : "";
193
+ if (changes) blocks.push(`## Changes\n\n${changes}`);
194
+ if (!blocks.length) blocks.push(`Release ${input.version}`);
195
+ if (input.compare) blocks.push(`**Full changelog**: ${input.compare}`);
196
+ return `${blocks.join("\n\n")}\n`;
197
+ }