@runcore-sh/runcore 0.4.0 → 0.5.1
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/dictionary.json +2 -2
- package/dist/activity/log.js +2 -2
- package/dist/activity/log.js.map +1 -1
- package/dist/agents/governed-spawn.d.ts.map +1 -1
- package/dist/cli.js +101 -11
- package/dist/cli.js.map +1 -1
- package/dist/extensions/cache.d.ts +57 -0
- package/dist/extensions/cache.d.ts.map +1 -0
- package/dist/extensions/cache.js +173 -0
- package/dist/extensions/cache.js.map +1 -0
- package/dist/extensions/client.d.ts +55 -0
- package/dist/extensions/client.d.ts.map +1 -0
- package/dist/extensions/client.js +120 -0
- package/dist/extensions/client.js.map +1 -0
- package/dist/extensions/index.d.ts +13 -0
- package/dist/extensions/index.d.ts.map +1 -0
- package/dist/extensions/index.js +12 -0
- package/dist/extensions/index.js.map +1 -0
- package/dist/extensions/loader.d.ts +50 -0
- package/dist/extensions/loader.d.ts.map +1 -0
- package/dist/extensions/loader.js +166 -0
- package/dist/extensions/loader.js.map +1 -0
- package/dist/extensions/manifest.d.ts +38 -0
- package/dist/extensions/manifest.d.ts.map +1 -0
- package/dist/extensions/manifest.js +17 -0
- package/dist/extensions/manifest.js.map +1 -0
- package/dist/extensions/stubs.d.ts +27 -0
- package/dist/extensions/stubs.d.ts.map +1 -0
- package/dist/extensions/stubs.js +45 -0
- package/dist/extensions/stubs.js.map +1 -0
- package/dist/lib/audit.js +2 -2
- package/dist/lib/audit.js.map +1 -1
- package/dist/lib/brain-migrate.d.ts +21 -0
- package/dist/lib/brain-migrate.d.ts.map +1 -0
- package/dist/lib/brain-migrate.js +137 -0
- package/dist/lib/brain-migrate.js.map +1 -0
- package/dist/lib/paths.d.ts +27 -0
- package/dist/lib/paths.d.ts.map +1 -1
- package/dist/lib/paths.js +65 -0
- package/dist/lib/paths.js.map +1 -1
- package/dist/llm/call-log.d.ts +40 -0
- package/dist/llm/call-log.d.ts.map +1 -0
- package/dist/llm/call-log.js +35 -0
- package/dist/llm/call-log.js.map +1 -0
- package/dist/llm/complete.d.ts +6 -0
- package/dist/llm/complete.d.ts.map +1 -1
- package/dist/llm/complete.js +27 -0
- package/dist/llm/complete.js.map +1 -1
- package/dist/mcp-server.js +118 -2
- package/dist/mcp-server.js.map +1 -1
- package/dist/memory/file-backed.d.ts +4 -0
- package/dist/memory/file-backed.d.ts.map +1 -1
- package/dist/memory/file-backed.js +4 -0
- package/dist/memory/file-backed.js.map +1 -1
- package/dist/memory/vector-index.d.ts +4 -12
- package/dist/memory/vector-index.d.ts.map +1 -1
- package/dist/memory/vector-index.js +11 -93
- package/dist/memory/vector-index.js.map +1 -1
- package/dist/search/brain-docs.d.ts +17 -7
- package/dist/search/brain-docs.d.ts.map +1 -1
- package/dist/search/brain-docs.js +170 -52
- package/dist/search/brain-docs.js.map +1 -1
- package/dist/search/brain-rag.d.ts +45 -0
- package/dist/search/brain-rag.d.ts.map +1 -0
- package/dist/search/brain-rag.js +275 -0
- package/dist/search/brain-rag.js.map +1 -0
- package/dist/search/chunker.d.ts +24 -0
- package/dist/search/chunker.d.ts.map +1 -0
- package/dist/search/chunker.js +95 -0
- package/dist/search/chunker.js.map +1 -0
- package/dist/search/embedder.d.ts +16 -0
- package/dist/search/embedder.d.ts.map +1 -0
- package/dist/search/embedder.js +108 -0
- package/dist/search/embedder.js.map +1 -0
- package/dist/search/file-watcher.d.ts +11 -0
- package/dist/search/file-watcher.d.ts.map +1 -0
- package/dist/search/file-watcher.js +86 -0
- package/dist/search/file-watcher.js.map +1 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +814 -472
- package/dist/server.js.map +1 -1
- package/dist/sessions/store.d.ts +9 -0
- package/dist/sessions/store.d.ts.map +1 -1
- package/dist/sessions/store.js.map +1 -1
- package/dist/settings.d.ts +26 -0
- package/dist/settings.d.ts.map +1 -1
- package/dist/settings.js +78 -2
- package/dist/settings.js.map +1 -1
- package/dist/tracing/init.d.ts +1 -1
- package/dist/tracing/init.d.ts.map +1 -1
- package/dist/utils/logger.js +2 -2
- package/dist/utils/logger.js.map +1 -1
- package/module-tiers.json +164 -0
- package/package.json +9 -13
- package/public/avatar/cache/1184385ec5522b57.mp4 +0 -0
- package/public/avatar/cache/1f15f6a1ebd7e439.mp4 +0 -0
- package/public/avatar/cache/2c7e47ff0bdeb8d1.mp4 +0 -0
- package/public/avatar/cache/5f308566f7abb8f2.mp4 +0 -0
- package/public/avatar/cache/62f9cfba848d724e.mp4 +0 -0
- package/public/avatar/cache/6d64e657e6bf2aab.mp4 +0 -0
- package/public/avatar/cache/763ad0349e0b6f26.mp4 +0 -0
- package/public/avatar/cache/81a516cfd461b2b9.mp4 +0 -0
- package/public/avatar/cache/9366de15fd6910ca.mp4 +0 -0
- package/public/avatar/cache/ade41a846b283895.mp4 +0 -0
- package/public/avatar/cache/b6066e5c65383eec.mp4 +0 -0
- package/public/avatar/cache/edadb75d37891fc7.mp4 +0 -0
- package/public/avatar/cache/f0ae159640621dd9.mp4 +0 -0
- package/public/avatar/cache/fc2e5419adf29d96.mp4 +0 -0
- package/public/index.html +379 -59
- package/dist/agents/autonomous.js +0 -749
- package/dist/agents/autonomous.js.map +0 -1
- package/dist/agents/commit.js +0 -113
- package/dist/agents/commit.js.map +0 -1
- package/dist/agents/continue.js +0 -158
- package/dist/agents/continue.js.map +0 -1
- package/dist/agents/cooldown.js +0 -397
- package/dist/agents/cooldown.js.map +0 -1
- package/dist/agents/dedup-guard.js +0 -131
- package/dist/agents/dedup-guard.js.map +0 -1
- package/dist/agents/feed.js +0 -176
- package/dist/agents/feed.js.map +0 -1
- package/dist/agents/governance.js +0 -292
- package/dist/agents/governance.js.map +0 -1
- package/dist/agents/governed-spawn.js +0 -192
- package/dist/agents/governed-spawn.js.map +0 -1
- package/dist/agents/heartbeat.js +0 -324
- package/dist/agents/heartbeat.js.map +0 -1
- package/dist/agents/instance-manager.js +0 -850
- package/dist/agents/instance-manager.js.map +0 -1
- package/dist/agents/issue-reporter.js +0 -123
- package/dist/agents/issue-reporter.js.map +0 -1
- package/dist/agents/issues.js +0 -141
- package/dist/agents/issues.js.map +0 -1
- package/dist/agents/locks.js +0 -234
- package/dist/agents/locks.js.map +0 -1
- package/dist/agents/memory.js +0 -93
- package/dist/agents/memory.js.map +0 -1
- package/dist/agents/monitor.js +0 -235
- package/dist/agents/monitor.js.map +0 -1
- package/dist/agents/orchestration.js +0 -715
- package/dist/agents/orchestration.js.map +0 -1
- package/dist/agents/recover.js +0 -166
- package/dist/agents/recover.js.map +0 -1
- package/dist/agents/reflection.js +0 -199
- package/dist/agents/reflection.js.map +0 -1
- package/dist/agents/runtime/bus.js +0 -174
- package/dist/agents/runtime/bus.js.map +0 -1
- package/dist/agents/runtime/config.js +0 -101
- package/dist/agents/runtime/config.js.map +0 -1
- package/dist/agents/runtime/driver.js +0 -214
- package/dist/agents/runtime/driver.js.map +0 -1
- package/dist/agents/runtime/errors.js +0 -40
- package/dist/agents/runtime/errors.js.map +0 -1
- package/dist/agents/runtime/index.js +0 -54
- package/dist/agents/runtime/index.js.map +0 -1
- package/dist/agents/runtime/lifecycle.js +0 -116
- package/dist/agents/runtime/lifecycle.js.map +0 -1
- package/dist/agents/runtime/manager.js +0 -948
- package/dist/agents/runtime/manager.js.map +0 -1
- package/dist/agents/runtime/registry.js +0 -195
- package/dist/agents/runtime/registry.js.map +0 -1
- package/dist/agents/runtime/resources.js +0 -146
- package/dist/agents/runtime/resources.js.map +0 -1
- package/dist/agents/runtime/types.js +0 -24
- package/dist/agents/runtime/types.js.map +0 -1
- package/dist/agents/spawn-policy.js +0 -202
- package/dist/agents/spawn-policy.js.map +0 -1
- package/dist/agents/spawn.js +0 -970
- package/dist/agents/spawn.js.map +0 -1
- package/dist/agents/triage.js +0 -81
- package/dist/agents/triage.js.map +0 -1
- package/dist/agents/workflow.js +0 -543
- package/dist/agents/workflow.js.map +0 -1
- package/dist/avatar/client.js +0 -172
- package/dist/avatar/client.js.map +0 -1
- package/dist/avatar/sidecar.js +0 -125
- package/dist/avatar/sidecar.js.map +0 -1
- package/dist/browser/sessions.js +0 -122
- package/dist/browser/sessions.js.map +0 -1
- package/dist/capabilities/definitions/browser.js +0 -242
- package/dist/capabilities/definitions/browser.js.map +0 -1
- package/dist/channels/whatsapp.js +0 -200
- package/dist/channels/whatsapp.js.map +0 -1
- package/dist/credentials/store.js +0 -189
- package/dist/credentials/store.js.map +0 -1
- package/dist/files/deep-index.js +0 -337
- package/dist/files/deep-index.js.map +0 -1
- package/dist/files/extract.js +0 -33
- package/dist/files/extract.js.map +0 -1
- package/dist/files/gdrive.js +0 -246
- package/dist/files/gdrive.js.map +0 -1
- package/dist/github/client.js +0 -408
- package/dist/github/client.js.map +0 -1
- package/dist/github/commit-analysis.js +0 -276
- package/dist/github/commit-analysis.js.map +0 -1
- package/dist/github/contributor-stats.js +0 -119
- package/dist/github/contributor-stats.js.map +0 -1
- package/dist/github/issue-sla.js +0 -220
- package/dist/github/issue-sla.js.map +0 -1
- package/dist/github/issue-triage.js +0 -286
- package/dist/github/issue-triage.js.map +0 -1
- package/dist/github/pr-readiness.js +0 -197
- package/dist/github/pr-readiness.js.map +0 -1
- package/dist/github/pr-review.js +0 -410
- package/dist/github/pr-review.js.map +0 -1
- package/dist/github/release-notes.js +0 -227
- package/dist/github/release-notes.js.map +0 -1
- package/dist/github/repo-health.js +0 -303
- package/dist/github/repo-health.js.map +0 -1
- package/dist/github/retry.js +0 -117
- package/dist/github/retry.js.map +0 -1
- package/dist/github/types.js +0 -8
- package/dist/github/types.js.map +0 -1
- package/dist/github/webhooks.js +0 -153
- package/dist/github/webhooks.js.map +0 -1
- package/dist/google/auth.js +0 -325
- package/dist/google/auth.js.map +0 -1
- package/dist/google/calendar-timer.js +0 -91
- package/dist/google/calendar-timer.js.map +0 -1
- package/dist/google/calendar.js +0 -270
- package/dist/google/calendar.js.map +0 -1
- package/dist/google/docs.js +0 -309
- package/dist/google/docs.js.map +0 -1
- package/dist/google/gmail-send.js +0 -219
- package/dist/google/gmail-send.js.map +0 -1
- package/dist/google/gmail-timer.js +0 -223
- package/dist/google/gmail-timer.js.map +0 -1
- package/dist/google/gmail.js +0 -470
- package/dist/google/gmail.js.map +0 -1
- package/dist/google/plugin.js +0 -169
- package/dist/google/plugin.js.map +0 -1
- package/dist/google/tasks-timer.js +0 -107
- package/dist/google/tasks-timer.js.map +0 -1
- package/dist/google/tasks.js +0 -331
- package/dist/google/tasks.js.map +0 -1
- package/dist/google/temporal.js +0 -176
- package/dist/google/temporal.js.map +0 -1
- package/dist/integrations/gate.js +0 -100
- package/dist/integrations/gate.js.map +0 -1
- package/dist/integrations/github.js +0 -331
- package/dist/integrations/github.js.map +0 -1
- package/dist/integrations/google-tasks.js +0 -432
- package/dist/integrations/google-tasks.js.map +0 -1
- package/dist/mdns.js +0 -110
- package/dist/mdns.js.map +0 -1
- package/dist/notifications/channel.js +0 -83
- package/dist/notifications/channel.js.map +0 -1
- package/dist/notifications/channels/adapter.js +0 -55
- package/dist/notifications/channels/adapter.js.map +0 -1
- package/dist/notifications/channels/index.js +0 -6
- package/dist/notifications/channels/index.js.map +0 -1
- package/dist/notifications/channels/log.js +0 -29
- package/dist/notifications/channels/log.js.map +0 -1
- package/dist/notifications/email.js +0 -72
- package/dist/notifications/email.js.map +0 -1
- package/dist/notifications/engine.js +0 -198
- package/dist/notifications/engine.js.map +0 -1
- package/dist/notifications/index.js +0 -24
- package/dist/notifications/index.js.map +0 -1
- package/dist/notifications/phone.js +0 -48
- package/dist/notifications/phone.js.map +0 -1
- package/dist/notifications/sms.js +0 -65
- package/dist/notifications/sms.js.map +0 -1
- package/dist/notifications/types.js +0 -14
- package/dist/notifications/types.js.map +0 -1
- package/dist/notifications/webhook.js +0 -65
- package/dist/notifications/webhook.js.map +0 -1
- package/dist/resend/inbox.js +0 -199
- package/dist/resend/inbox.js.map +0 -1
- package/dist/resend/webhooks.js +0 -244
- package/dist/resend/webhooks.js.map +0 -1
- package/dist/search/browse.js +0 -225
- package/dist/search/browse.js.map +0 -1
- package/dist/search/perplexity.js +0 -41
- package/dist/search/perplexity.js.map +0 -1
- package/dist/slack/channels.js +0 -277
- package/dist/slack/channels.js.map +0 -1
- package/dist/slack/client.js +0 -468
- package/dist/slack/client.js.map +0 -1
- package/dist/slack/retry.js +0 -100
- package/dist/slack/retry.js.map +0 -1
- package/dist/slack/types.js +0 -52
- package/dist/slack/types.js.map +0 -1
- package/dist/slack/webhooks.js +0 -285
- package/dist/slack/webhooks.js.map +0 -1
- package/dist/stt/client.js +0 -66
- package/dist/stt/client.js.map +0 -1
- package/dist/stt/sidecar.js +0 -115
- package/dist/stt/sidecar.js.map +0 -1
- package/dist/tracing/bridge.js +0 -70
- package/dist/tracing/bridge.js.map +0 -1
- package/dist/tracing/correlation.js +0 -49
- package/dist/tracing/correlation.js.map +0 -1
- package/dist/tracing/index.js +0 -18
- package/dist/tracing/index.js.map +0 -1
- package/dist/tracing/init.js +0 -81
- package/dist/tracing/init.js.map +0 -1
- package/dist/tracing/instrument.js +0 -145
- package/dist/tracing/instrument.js.map +0 -1
- package/dist/tracing/middleware.js +0 -69
- package/dist/tracing/middleware.js.map +0 -1
- package/dist/tracing/tracer.js +0 -327
- package/dist/tracing/tracer.js.map +0 -1
- package/dist/tts/client.js +0 -48
- package/dist/tts/client.js.map +0 -1
- package/dist/tts/sidecar.js +0 -148
- package/dist/tts/sidecar.js.map +0 -1
- package/dist/twilio/call.js +0 -79
- package/dist/twilio/call.js.map +0 -1
- package/dist/vault/matcher.js +0 -197
- package/dist/vault/matcher.js.map +0 -1
- package/dist/vault/personal.js +0 -163
- package/dist/vault/personal.js.map +0 -1
- package/dist/vault/policy.js +0 -159
- package/dist/vault/policy.js.map +0 -1
- package/dist/vault/store.js +0 -122
- package/dist/vault/store.js.map +0 -1
- package/dist/vault/transfer.js +0 -188
- package/dist/vault/transfer.js.map +0 -1
- package/dist/volumes/index.js +0 -2
- package/dist/volumes/index.js.map +0 -1
- package/dist/volumes/manager.js +0 -462
- package/dist/volumes/manager.js.map +0 -1
- package/dist/volumes/types.js +0 -8
- package/dist/volumes/types.js.map +0 -1
- package/dist/webhooks/config.js +0 -214
- package/dist/webhooks/config.js.map +0 -1
- package/dist/webhooks/event-log.js +0 -132
- package/dist/webhooks/event-log.js.map +0 -1
- package/dist/webhooks/handler.js +0 -103
- package/dist/webhooks/handler.js.map +0 -1
- package/dist/webhooks/handlers.js +0 -231
- package/dist/webhooks/handlers.js.map +0 -1
- package/dist/webhooks/index.js +0 -33
- package/dist/webhooks/index.js.map +0 -1
- package/dist/webhooks/mount.js +0 -400
- package/dist/webhooks/mount.js.map +0 -1
- package/dist/webhooks/registry.js +0 -143
- package/dist/webhooks/registry.js.map +0 -1
- package/dist/webhooks/relay.js +0 -53
- package/dist/webhooks/relay.js.map +0 -1
- package/dist/webhooks/retry.js +0 -270
- package/dist/webhooks/retry.js.map +0 -1
- package/dist/webhooks/router.js +0 -290
- package/dist/webhooks/router.js.map +0 -1
- package/dist/webhooks/twilio.js +0 -129
- package/dist/webhooks/twilio.js.map +0 -1
- package/dist/webhooks/types.js +0 -8
- package/dist/webhooks/types.js.map +0 -1
- package/dist/webhooks/verify.js +0 -154
- package/dist/webhooks/verify.js.map +0 -1
package/dist/github/pr-review.js
DELETED
|
@@ -1,410 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* PR review automation — analyzes pull requests and provides feedback.
|
|
3
|
-
*
|
|
4
|
-
* Checks for: size, test coverage signals, doc changes, large/binary files,
|
|
5
|
-
* naming conventions, security patterns, and breaking changes.
|
|
6
|
-
* Does NOT use LLM — purely heuristic-based for speed and reliability.
|
|
7
|
-
*/
|
|
8
|
-
import { createLogger } from "../utils/logger.js";
|
|
9
|
-
import { logActivity } from "../activity/log.js";
|
|
10
|
-
import * as client from "./client.js";
|
|
11
|
-
const log = createLogger("github.pr-review");
|
|
12
|
-
// ── Size thresholds ──────────────────────────────────────────────────────────
|
|
13
|
-
const SIZE_THRESHOLDS = {
|
|
14
|
-
small: 100,
|
|
15
|
-
medium: 300,
|
|
16
|
-
large: 500,
|
|
17
|
-
huge: 1000,
|
|
18
|
-
};
|
|
19
|
-
const BINARY_EXTENSIONS = new Set([
|
|
20
|
-
".png", ".jpg", ".jpeg", ".gif", ".ico", ".svg",
|
|
21
|
-
".woff", ".woff2", ".ttf", ".eot",
|
|
22
|
-
".zip", ".tar", ".gz", ".exe", ".dll",
|
|
23
|
-
".mp3", ".mp4", ".wav", ".avi",
|
|
24
|
-
".pdf", ".doc", ".docx",
|
|
25
|
-
]);
|
|
26
|
-
const TEST_PATTERNS = [
|
|
27
|
-
/\.test\.[jt]sx?$/,
|
|
28
|
-
/\.spec\.[jt]sx?$/,
|
|
29
|
-
/__tests__\//,
|
|
30
|
-
/test\//,
|
|
31
|
-
/tests\//,
|
|
32
|
-
];
|
|
33
|
-
const DOC_PATTERNS = [
|
|
34
|
-
/\.md$/i,
|
|
35
|
-
/docs?\//i,
|
|
36
|
-
/readme/i,
|
|
37
|
-
/changelog/i,
|
|
38
|
-
];
|
|
39
|
-
const SECURITY_PATTERNS = [
|
|
40
|
-
/password/i,
|
|
41
|
-
/secret/i,
|
|
42
|
-
/api[_-]?key/i,
|
|
43
|
-
/token/i,
|
|
44
|
-
/\.env/,
|
|
45
|
-
/credentials/i,
|
|
46
|
-
/auth[_-]?token/i,
|
|
47
|
-
/private[_-]?key/i,
|
|
48
|
-
];
|
|
49
|
-
const DEPENDENCY_FILES = new Set([
|
|
50
|
-
"package.json",
|
|
51
|
-
"package-lock.json",
|
|
52
|
-
"yarn.lock",
|
|
53
|
-
"pnpm-lock.yaml",
|
|
54
|
-
"bun.lockb",
|
|
55
|
-
"requirements.txt",
|
|
56
|
-
"Pipfile.lock",
|
|
57
|
-
"Gemfile.lock",
|
|
58
|
-
"go.sum",
|
|
59
|
-
"Cargo.lock",
|
|
60
|
-
"composer.lock",
|
|
61
|
-
]);
|
|
62
|
-
const LOCK_FILES = new Set([
|
|
63
|
-
"package-lock.json",
|
|
64
|
-
"yarn.lock",
|
|
65
|
-
"pnpm-lock.yaml",
|
|
66
|
-
"bun.lockb",
|
|
67
|
-
"Pipfile.lock",
|
|
68
|
-
"Gemfile.lock",
|
|
69
|
-
"go.sum",
|
|
70
|
-
"Cargo.lock",
|
|
71
|
-
"composer.lock",
|
|
72
|
-
]);
|
|
73
|
-
// ── Analysis functions ───────────────────────────────────────────────────────
|
|
74
|
-
function getFileExtension(filename) {
|
|
75
|
-
const dot = filename.lastIndexOf(".");
|
|
76
|
-
return dot >= 0 ? filename.slice(dot).toLowerCase() : "";
|
|
77
|
-
}
|
|
78
|
-
function computeMetrics(pr, files) {
|
|
79
|
-
const hasTests = files.some((f) => TEST_PATTERNS.some((p) => p.test(f.filename)));
|
|
80
|
-
const hasDocChanges = files.some((f) => DOC_PATTERNS.some((p) => p.test(f.filename)));
|
|
81
|
-
const largeFiles = files
|
|
82
|
-
.filter((f) => f.changes > 300)
|
|
83
|
-
.map((f) => f.filename);
|
|
84
|
-
const binaryFiles = files
|
|
85
|
-
.filter((f) => BINARY_EXTENSIONS.has(getFileExtension(f.filename)))
|
|
86
|
-
.map((f) => f.filename);
|
|
87
|
-
return {
|
|
88
|
-
filesChanged: pr.changed_files,
|
|
89
|
-
additions: pr.additions,
|
|
90
|
-
deletions: pr.deletions,
|
|
91
|
-
hasTests,
|
|
92
|
-
hasDocChanges,
|
|
93
|
-
largeFiles,
|
|
94
|
-
binaryFiles,
|
|
95
|
-
};
|
|
96
|
-
}
|
|
97
|
-
function analyzeSize(pr) {
|
|
98
|
-
const findings = [];
|
|
99
|
-
const total = pr.additions + pr.deletions;
|
|
100
|
-
if (total > SIZE_THRESHOLDS.huge) {
|
|
101
|
-
findings.push({
|
|
102
|
-
severity: "error",
|
|
103
|
-
category: "size",
|
|
104
|
-
message: `Very large PR (${total} lines changed). Consider breaking into smaller PRs for easier review.`,
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
|
-
else if (total > SIZE_THRESHOLDS.large) {
|
|
108
|
-
findings.push({
|
|
109
|
-
severity: "warning",
|
|
110
|
-
category: "size",
|
|
111
|
-
message: `Large PR (${total} lines changed). Smaller PRs are reviewed faster and more thoroughly.`,
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
if (pr.changed_files > 20) {
|
|
115
|
-
findings.push({
|
|
116
|
-
severity: "warning",
|
|
117
|
-
category: "size",
|
|
118
|
-
message: `${pr.changed_files} files changed. Consider scoping this PR more narrowly.`,
|
|
119
|
-
});
|
|
120
|
-
}
|
|
121
|
-
return findings;
|
|
122
|
-
}
|
|
123
|
-
function analyzeTestCoverage(files) {
|
|
124
|
-
const findings = [];
|
|
125
|
-
const srcFiles = files.filter((f) => f.status !== "removed" &&
|
|
126
|
-
!TEST_PATTERNS.some((p) => p.test(f.filename)) &&
|
|
127
|
-
!DOC_PATTERNS.some((p) => p.test(f.filename)) &&
|
|
128
|
-
(f.filename.endsWith(".ts") || f.filename.endsWith(".tsx") || f.filename.endsWith(".js") || f.filename.endsWith(".jsx")));
|
|
129
|
-
const testFiles = files.filter((f) => TEST_PATTERNS.some((p) => p.test(f.filename)));
|
|
130
|
-
if (srcFiles.length > 0 && testFiles.length === 0) {
|
|
131
|
-
findings.push({
|
|
132
|
-
severity: "warning",
|
|
133
|
-
category: "testing",
|
|
134
|
-
message: `${srcFiles.length} source file(s) changed but no test files modified. Consider adding tests.`,
|
|
135
|
-
});
|
|
136
|
-
}
|
|
137
|
-
return findings;
|
|
138
|
-
}
|
|
139
|
-
function analyzeSecurityPatterns(files) {
|
|
140
|
-
const findings = [];
|
|
141
|
-
for (const file of files) {
|
|
142
|
-
if (!file.patch)
|
|
143
|
-
continue;
|
|
144
|
-
// Only check added lines (lines starting with +)
|
|
145
|
-
const addedLines = file.patch.split("\n").filter((l) => l.startsWith("+") && !l.startsWith("+++"));
|
|
146
|
-
for (const line of addedLines) {
|
|
147
|
-
for (const pattern of SECURITY_PATTERNS) {
|
|
148
|
-
if (pattern.test(line)) {
|
|
149
|
-
// Skip if it's clearly a test or mock
|
|
150
|
-
if (/mock|test|fake|dummy|example|placeholder/i.test(line))
|
|
151
|
-
continue;
|
|
152
|
-
findings.push({
|
|
153
|
-
severity: "warning",
|
|
154
|
-
category: "security",
|
|
155
|
-
message: `Potential sensitive value in ${file.filename} — review for hardcoded credentials.`,
|
|
156
|
-
file: file.filename,
|
|
157
|
-
});
|
|
158
|
-
break; // One finding per file per pattern check
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
// Deduplicate by file
|
|
164
|
-
const seen = new Set();
|
|
165
|
-
return findings.filter((f) => {
|
|
166
|
-
if (f.file && seen.has(f.file))
|
|
167
|
-
return false;
|
|
168
|
-
if (f.file)
|
|
169
|
-
seen.add(f.file);
|
|
170
|
-
return true;
|
|
171
|
-
});
|
|
172
|
-
}
|
|
173
|
-
function analyzeDependencyChanges(files) {
|
|
174
|
-
const findings = [];
|
|
175
|
-
const depFiles = files.filter((f) => {
|
|
176
|
-
const basename = f.filename.split("/").pop() ?? "";
|
|
177
|
-
return DEPENDENCY_FILES.has(basename);
|
|
178
|
-
});
|
|
179
|
-
if (depFiles.length === 0)
|
|
180
|
-
return findings;
|
|
181
|
-
const manifestFiles = depFiles.filter((f) => {
|
|
182
|
-
const basename = f.filename.split("/").pop() ?? "";
|
|
183
|
-
return !LOCK_FILES.has(basename);
|
|
184
|
-
});
|
|
185
|
-
const lockFiles = depFiles.filter((f) => {
|
|
186
|
-
const basename = f.filename.split("/").pop() ?? "";
|
|
187
|
-
return LOCK_FILES.has(basename);
|
|
188
|
-
});
|
|
189
|
-
// Manifest changed but no lock file — might be missing install
|
|
190
|
-
if (manifestFiles.length > 0 && lockFiles.length === 0) {
|
|
191
|
-
findings.push({
|
|
192
|
-
severity: "warning",
|
|
193
|
-
category: "convention",
|
|
194
|
-
message: `Dependency manifest changed (${manifestFiles.map((f) => f.filename).join(", ")}) but no lock file updated. Run install to update the lock file.`,
|
|
195
|
-
});
|
|
196
|
-
}
|
|
197
|
-
// Lock file changed — flag for review
|
|
198
|
-
if (lockFiles.length > 0) {
|
|
199
|
-
findings.push({
|
|
200
|
-
severity: "info",
|
|
201
|
-
category: "security",
|
|
202
|
-
message: `Lock file(s) changed: ${lockFiles.map((f) => f.filename).join(", ")}. Verify dependency updates are intentional.`,
|
|
203
|
-
});
|
|
204
|
-
}
|
|
205
|
-
// Check for new dependency additions in patch
|
|
206
|
-
for (const f of manifestFiles) {
|
|
207
|
-
if (!f.patch)
|
|
208
|
-
continue;
|
|
209
|
-
const addedLines = f.patch.split("\n").filter((l) => l.startsWith("+") && !l.startsWith("+++"));
|
|
210
|
-
if (addedLines.length > 10) {
|
|
211
|
-
findings.push({
|
|
212
|
-
severity: "info",
|
|
213
|
-
category: "security",
|
|
214
|
-
message: `Significant dependency changes in ${f.filename} (${addedLines.length} additions). Review new dependencies for supply chain risk.`,
|
|
215
|
-
file: f.filename,
|
|
216
|
-
});
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
return findings;
|
|
220
|
-
}
|
|
221
|
-
function analyzeBreakingChanges(files) {
|
|
222
|
-
const findings = [];
|
|
223
|
-
const deletedFiles = files.filter((f) => f.status === "removed");
|
|
224
|
-
const renamedFiles = files.filter((f) => f.status === "renamed");
|
|
225
|
-
// Exported source files being deleted
|
|
226
|
-
const deletedSrcFiles = deletedFiles.filter((f) => /\.(ts|js|tsx|jsx)$/.test(f.filename) &&
|
|
227
|
-
!TEST_PATTERNS.some((p) => p.test(f.filename)));
|
|
228
|
-
if (deletedSrcFiles.length > 0) {
|
|
229
|
-
findings.push({
|
|
230
|
-
severity: "warning",
|
|
231
|
-
category: "breaking_change",
|
|
232
|
-
message: `${deletedSrcFiles.length} source file(s) deleted: ${deletedSrcFiles.slice(0, 3).map((f) => f.filename).join(", ")}${deletedSrcFiles.length > 3 ? "..." : ""}. Verify no external consumers depend on these.`,
|
|
233
|
-
});
|
|
234
|
-
}
|
|
235
|
-
// Renamed files may break imports
|
|
236
|
-
if (renamedFiles.length > 0) {
|
|
237
|
-
findings.push({
|
|
238
|
-
severity: "info",
|
|
239
|
-
category: "breaking_change",
|
|
240
|
-
message: `${renamedFiles.length} file(s) renamed. Verify all import paths have been updated.`,
|
|
241
|
-
});
|
|
242
|
-
}
|
|
243
|
-
// Check patches for removed exports
|
|
244
|
-
for (const f of files) {
|
|
245
|
-
if (!f.patch || f.status === "removed")
|
|
246
|
-
continue;
|
|
247
|
-
if (!/\.(ts|js|tsx|jsx)$/.test(f.filename))
|
|
248
|
-
continue;
|
|
249
|
-
const removedLines = f.patch.split("\n").filter((l) => l.startsWith("-") && !l.startsWith("---"));
|
|
250
|
-
const removedExports = removedLines.filter((l) => /^\-\s*export\s/.test(l));
|
|
251
|
-
if (removedExports.length > 0) {
|
|
252
|
-
findings.push({
|
|
253
|
-
severity: "warning",
|
|
254
|
-
category: "breaking_change",
|
|
255
|
-
message: `${removedExports.length} export(s) removed in ${f.filename}. This may break downstream consumers.`,
|
|
256
|
-
file: f.filename,
|
|
257
|
-
});
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
return findings;
|
|
261
|
-
}
|
|
262
|
-
function analyzeReviewStaleness(pr) {
|
|
263
|
-
const findings = [];
|
|
264
|
-
const createdMs = new Date(pr.created_at).getTime();
|
|
265
|
-
const nowMs = Date.now();
|
|
266
|
-
const ageDays = (nowMs - createdMs) / (24 * 60 * 60 * 1000);
|
|
267
|
-
if (ageDays > 14) {
|
|
268
|
-
findings.push({
|
|
269
|
-
severity: "warning",
|
|
270
|
-
category: "convention",
|
|
271
|
-
message: `PR has been open for ${Math.round(ageDays)} days. Consider merging, closing, or rebasing.`,
|
|
272
|
-
});
|
|
273
|
-
}
|
|
274
|
-
else if (ageDays > 7) {
|
|
275
|
-
findings.push({
|
|
276
|
-
severity: "info",
|
|
277
|
-
category: "convention",
|
|
278
|
-
message: `PR has been open for ${Math.round(ageDays)} days. A prompt review keeps momentum.`,
|
|
279
|
-
});
|
|
280
|
-
}
|
|
281
|
-
return findings;
|
|
282
|
-
}
|
|
283
|
-
function analyzeConventions(pr, files) {
|
|
284
|
-
const findings = [];
|
|
285
|
-
// Check PR title
|
|
286
|
-
if (pr.title.length < 10) {
|
|
287
|
-
findings.push({
|
|
288
|
-
severity: "info",
|
|
289
|
-
category: "convention",
|
|
290
|
-
message: "PR title is very short. A descriptive title helps reviewers and shows in git history.",
|
|
291
|
-
});
|
|
292
|
-
}
|
|
293
|
-
// Check for WIP / draft signals
|
|
294
|
-
if (/\bwip\b/i.test(pr.title) && !pr.draft) {
|
|
295
|
-
findings.push({
|
|
296
|
-
severity: "info",
|
|
297
|
-
category: "convention",
|
|
298
|
-
message: "PR title contains 'WIP' but is not marked as draft.",
|
|
299
|
-
});
|
|
300
|
-
}
|
|
301
|
-
// Check for empty body
|
|
302
|
-
if (!pr.body || pr.body.trim().length < 20) {
|
|
303
|
-
findings.push({
|
|
304
|
-
severity: "info",
|
|
305
|
-
category: "documentation",
|
|
306
|
-
message: "PR description is empty or very short. Consider explaining the what and why of this change.",
|
|
307
|
-
});
|
|
308
|
-
}
|
|
309
|
-
return findings;
|
|
310
|
-
}
|
|
311
|
-
function determineRecommendation(findings) {
|
|
312
|
-
const hasErrors = findings.some((f) => f.severity === "error");
|
|
313
|
-
if (hasErrors)
|
|
314
|
-
return "request_changes";
|
|
315
|
-
const warningCount = findings.filter((f) => f.severity === "warning").length;
|
|
316
|
-
if (warningCount >= 3)
|
|
317
|
-
return "request_changes";
|
|
318
|
-
if (warningCount > 0)
|
|
319
|
-
return "comment";
|
|
320
|
-
return "approve";
|
|
321
|
-
}
|
|
322
|
-
// ── Public API ───────────────────────────────────────────────────────────────
|
|
323
|
-
/**
|
|
324
|
-
* Analyze a pull request and produce a review with findings and metrics.
|
|
325
|
-
*/
|
|
326
|
-
export async function reviewPR(owner, repo, prNumber) {
|
|
327
|
-
log.info(`Reviewing PR ${owner}/${repo}#${prNumber}`);
|
|
328
|
-
const [pr, files] = await Promise.all([
|
|
329
|
-
client.getPullRequest(owner, repo, prNumber),
|
|
330
|
-
client.getPRFiles(owner, repo, prNumber),
|
|
331
|
-
]);
|
|
332
|
-
if (!pr || !files) {
|
|
333
|
-
log.warn(`Failed to fetch PR data for ${owner}/${repo}#${prNumber}`);
|
|
334
|
-
return null;
|
|
335
|
-
}
|
|
336
|
-
const metrics = computeMetrics(pr, files);
|
|
337
|
-
const findings = [
|
|
338
|
-
...analyzeSize(pr),
|
|
339
|
-
...analyzeTestCoverage(files),
|
|
340
|
-
...analyzeSecurityPatterns(files),
|
|
341
|
-
...analyzeDependencyChanges(files),
|
|
342
|
-
...analyzeBreakingChanges(files),
|
|
343
|
-
...analyzeReviewStaleness(pr),
|
|
344
|
-
...analyzeConventions(pr, files),
|
|
345
|
-
];
|
|
346
|
-
// Binary file warnings
|
|
347
|
-
if (metrics.binaryFiles.length > 0) {
|
|
348
|
-
findings.push({
|
|
349
|
-
severity: "info",
|
|
350
|
-
category: "size",
|
|
351
|
-
message: `${metrics.binaryFiles.length} binary file(s) included: ${metrics.binaryFiles.slice(0, 3).join(", ")}${metrics.binaryFiles.length > 3 ? "..." : ""}`,
|
|
352
|
-
});
|
|
353
|
-
}
|
|
354
|
-
const recommendation = determineRecommendation(findings);
|
|
355
|
-
const summary = buildSummary(pr, metrics, findings, recommendation);
|
|
356
|
-
const result = {
|
|
357
|
-
prNumber,
|
|
358
|
-
repo: `${owner}/${repo}`,
|
|
359
|
-
summary,
|
|
360
|
-
findings,
|
|
361
|
-
metrics,
|
|
362
|
-
recommendation,
|
|
363
|
-
reviewedAt: new Date().toISOString(),
|
|
364
|
-
};
|
|
365
|
-
logActivity({
|
|
366
|
-
source: "board",
|
|
367
|
-
summary: `PR review: ${owner}/${repo}#${prNumber} — ${recommendation} (${findings.length} findings)`,
|
|
368
|
-
});
|
|
369
|
-
return result;
|
|
370
|
-
}
|
|
371
|
-
/**
|
|
372
|
-
* Review a PR and post the review as a GitHub comment.
|
|
373
|
-
*/
|
|
374
|
-
export async function reviewAndComment(owner, repo, prNumber) {
|
|
375
|
-
const result = await reviewPR(owner, repo, prNumber);
|
|
376
|
-
if (!result)
|
|
377
|
-
return null;
|
|
378
|
-
// Post as PR comment (not a formal review, to avoid blocking)
|
|
379
|
-
await client.addIssueComment(owner, repo, prNumber, result.summary);
|
|
380
|
-
return result;
|
|
381
|
-
}
|
|
382
|
-
// ── Summary formatting ───────────────────────────────────────────────────────
|
|
383
|
-
function buildSummary(pr, metrics, findings, recommendation) {
|
|
384
|
-
const lines = [];
|
|
385
|
-
lines.push(`## Automated PR Review`);
|
|
386
|
-
lines.push("");
|
|
387
|
-
lines.push(`**${pr.title}** (#${pr.number})`);
|
|
388
|
-
lines.push("");
|
|
389
|
-
lines.push(`| Metric | Value |`);
|
|
390
|
-
lines.push(`|--------|-------|`);
|
|
391
|
-
lines.push(`| Files changed | ${metrics.filesChanged} |`);
|
|
392
|
-
lines.push(`| Additions | +${metrics.additions} |`);
|
|
393
|
-
lines.push(`| Deletions | -${metrics.deletions} |`);
|
|
394
|
-
lines.push(`| Tests included | ${metrics.hasTests ? "Yes" : "No"} |`);
|
|
395
|
-
lines.push(`| Docs updated | ${metrics.hasDocChanges ? "Yes" : "No"} |`);
|
|
396
|
-
lines.push("");
|
|
397
|
-
if (findings.length > 0) {
|
|
398
|
-
lines.push(`### Findings (${findings.length})`);
|
|
399
|
-
lines.push("");
|
|
400
|
-
for (const f of findings) {
|
|
401
|
-
const icon = f.severity === "error" ? "🔴" : f.severity === "warning" ? "🟡" : "🔵";
|
|
402
|
-
const loc = f.file ? ` (${f.file}${f.line ? `:${f.line}` : ""})` : "";
|
|
403
|
-
lines.push(`- ${icon} **${f.category}**${loc}: ${f.message}`);
|
|
404
|
-
}
|
|
405
|
-
lines.push("");
|
|
406
|
-
}
|
|
407
|
-
lines.push(`**Recommendation:** ${recommendation.replace("_", " ")}`);
|
|
408
|
-
return lines.join("\n");
|
|
409
|
-
}
|
|
410
|
-
//# sourceMappingURL=pr-review.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"pr-review.js","sourceRoot":"","sources":["../../src/github/pr-review.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,227 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Release notes generator — produces structured release notes from commits.
|
|
3
|
-
*
|
|
4
|
-
* Groups commits by type (features, fixes, etc.) using conventional commit
|
|
5
|
-
* parsing. Detects breaking changes and lists contributors.
|
|
6
|
-
* Outputs structured data + formatted markdown.
|
|
7
|
-
*/
|
|
8
|
-
import { createLogger } from "../utils/logger.js";
|
|
9
|
-
import { logActivity } from "../activity/log.js";
|
|
10
|
-
import * as client from "./client.js";
|
|
11
|
-
const log = createLogger("github.release-notes");
|
|
12
|
-
// ── Conventional commit parsing ──────────────────────────────────────────────
|
|
13
|
-
const CONVENTIONAL_RE = /^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(?:\((.+?)\))?(!)?:\s(.+)/;
|
|
14
|
-
function parseCommitMessage(sha, message, author) {
|
|
15
|
-
const firstLine = message.split("\n")[0].trim();
|
|
16
|
-
const match = firstLine.match(CONVENTIONAL_RE);
|
|
17
|
-
if (match) {
|
|
18
|
-
return {
|
|
19
|
-
type: match[1],
|
|
20
|
-
scope: match[2] || undefined,
|
|
21
|
-
breaking: match[3] === "!" || /BREAKING.CHANGE/i.test(message),
|
|
22
|
-
description: match[4],
|
|
23
|
-
sha,
|
|
24
|
-
author,
|
|
25
|
-
raw: firstLine,
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
// Non-conventional: try to categorize by keywords
|
|
29
|
-
const lower = firstLine.toLowerCase();
|
|
30
|
-
let type = "other";
|
|
31
|
-
if (/^merge\s/i.test(lower))
|
|
32
|
-
type = "merge";
|
|
33
|
-
else if (/\b(fix|bug|patch|hotfix)\b/.test(lower))
|
|
34
|
-
type = "fix";
|
|
35
|
-
else if (/\b(add|feat|feature|implement|new)\b/.test(lower))
|
|
36
|
-
type = "feat";
|
|
37
|
-
else if (/\b(doc|readme)\b/.test(lower))
|
|
38
|
-
type = "docs";
|
|
39
|
-
else if (/\b(refactor|restructure|cleanup)\b/.test(lower))
|
|
40
|
-
type = "refactor";
|
|
41
|
-
else if (/\b(test|spec)\b/.test(lower))
|
|
42
|
-
type = "test";
|
|
43
|
-
else if (/\b(ci|pipeline|workflow)\b/.test(lower))
|
|
44
|
-
type = "ci";
|
|
45
|
-
else if (/\b(perf|optimize|speed)\b/.test(lower))
|
|
46
|
-
type = "perf";
|
|
47
|
-
return {
|
|
48
|
-
type,
|
|
49
|
-
breaking: /BREAKING.CHANGE/i.test(message),
|
|
50
|
-
description: firstLine,
|
|
51
|
-
sha,
|
|
52
|
-
author,
|
|
53
|
-
raw: firstLine,
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
const SECTION_ORDER = [
|
|
57
|
-
{ title: "Breaking Changes", icon: "💥", types: [] }, // Special: populated from breaking flag
|
|
58
|
-
{ title: "Features", icon: "✨", types: ["feat"] },
|
|
59
|
-
{ title: "Bug Fixes", icon: "🐛", types: ["fix"] },
|
|
60
|
-
{ title: "Performance", icon: "⚡", types: ["perf"] },
|
|
61
|
-
{ title: "Documentation", icon: "📝", types: ["docs"] },
|
|
62
|
-
{ title: "Refactoring", icon: "♻️", types: ["refactor"] },
|
|
63
|
-
{ title: "Tests", icon: "🧪", types: ["test"] },
|
|
64
|
-
{ title: "CI/CD", icon: "🔧", types: ["ci", "build"] },
|
|
65
|
-
{ title: "Chores", icon: "🧹", types: ["chore"] },
|
|
66
|
-
{ title: "Other", icon: "📦", types: ["other", "revert", "style"] },
|
|
67
|
-
];
|
|
68
|
-
// ── Public API ───────────────────────────────────────────────────────────────
|
|
69
|
-
/**
|
|
70
|
-
* Generate release notes from commits between two refs (tags, SHAs, or branches).
|
|
71
|
-
*/
|
|
72
|
-
export async function generateReleaseNotes(owner, repo, opts) {
|
|
73
|
-
const to = opts.to ?? "HEAD";
|
|
74
|
-
log.info(`Generating release notes for ${owner}/${repo}: ${opts.from}..${to}`);
|
|
75
|
-
const comparison = await client.compareBranches(owner, repo, opts.from, to);
|
|
76
|
-
if (!comparison) {
|
|
77
|
-
log.warn(`Failed to compare ${opts.from}..${to}`);
|
|
78
|
-
return null;
|
|
79
|
-
}
|
|
80
|
-
if (comparison.commits.length === 0) {
|
|
81
|
-
log.info("No commits found between the two refs.");
|
|
82
|
-
return {
|
|
83
|
-
repo: `${owner}/${repo}`,
|
|
84
|
-
version: opts.version ?? to,
|
|
85
|
-
from: opts.from,
|
|
86
|
-
to,
|
|
87
|
-
generatedAt: new Date().toISOString(),
|
|
88
|
-
sections: [],
|
|
89
|
-
breakingChanges: [],
|
|
90
|
-
contributors: [],
|
|
91
|
-
markdown: `## ${opts.version ?? to}\n\nNo changes.`,
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
|
-
// Parse all commits
|
|
95
|
-
const parsed = comparison.commits
|
|
96
|
-
.filter((c) => !c.commit.message.startsWith("Merge ")) // Skip merge commits
|
|
97
|
-
.map((c) => parseCommitMessage(c.sha, c.commit.message, c.commit.author?.name ?? "Unknown"));
|
|
98
|
-
// Collect breaking changes
|
|
99
|
-
const breakingChanges = parsed
|
|
100
|
-
.filter((c) => c.breaking)
|
|
101
|
-
.map((c) => c.scope ? `**${c.scope}:** ${c.description}` : c.description);
|
|
102
|
-
// Collect unique contributors
|
|
103
|
-
const contributors = [...new Set(parsed.map((c) => c.author))].sort();
|
|
104
|
-
// Build sections
|
|
105
|
-
const sections = [];
|
|
106
|
-
for (const def of SECTION_ORDER) {
|
|
107
|
-
// Skip the "Breaking Changes" section (handled separately in markdown)
|
|
108
|
-
if (def.types.length === 0)
|
|
109
|
-
continue;
|
|
110
|
-
const entries = parsed
|
|
111
|
-
.filter((c) => def.types.includes(c.type))
|
|
112
|
-
.map((c) => ({
|
|
113
|
-
sha: c.sha.slice(0, 7),
|
|
114
|
-
message: c.description,
|
|
115
|
-
author: c.author,
|
|
116
|
-
scope: c.scope,
|
|
117
|
-
}));
|
|
118
|
-
if (entries.length > 0) {
|
|
119
|
-
sections.push({ title: def.title, icon: def.icon, commits: entries });
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
const version = opts.version ?? to;
|
|
123
|
-
const markdown = formatReleaseNotes(version, sections, breakingChanges, contributors);
|
|
124
|
-
const result = {
|
|
125
|
-
repo: `${owner}/${repo}`,
|
|
126
|
-
version,
|
|
127
|
-
from: opts.from,
|
|
128
|
-
to,
|
|
129
|
-
generatedAt: new Date().toISOString(),
|
|
130
|
-
sections,
|
|
131
|
-
breakingChanges,
|
|
132
|
-
contributors,
|
|
133
|
-
markdown,
|
|
134
|
-
};
|
|
135
|
-
logActivity({
|
|
136
|
-
source: "board",
|
|
137
|
-
summary: `Release notes: ${owner}/${repo} ${version} — ${parsed.length} commits, ${contributors.length} contributors`,
|
|
138
|
-
});
|
|
139
|
-
return result;
|
|
140
|
-
}
|
|
141
|
-
/**
|
|
142
|
-
* Generate release notes from the latest tag to HEAD.
|
|
143
|
-
*/
|
|
144
|
-
export async function generateReleaseNotesFromLatestTag(owner, repo, opts) {
|
|
145
|
-
const tags = await client.listTags(owner, repo, { per_page: 1 });
|
|
146
|
-
if (!tags || tags.length === 0) {
|
|
147
|
-
log.warn(`No tags found for ${owner}/${repo}`);
|
|
148
|
-
return null;
|
|
149
|
-
}
|
|
150
|
-
return generateReleaseNotes(owner, repo, {
|
|
151
|
-
from: tags[0].name,
|
|
152
|
-
to: "HEAD",
|
|
153
|
-
version: opts?.version,
|
|
154
|
-
});
|
|
155
|
-
}
|
|
156
|
-
// ── Formatting ───────────────────────────────────────────────────────────────
|
|
157
|
-
function formatReleaseNotes(version, sections, breakingChanges, contributors) {
|
|
158
|
-
const lines = [];
|
|
159
|
-
lines.push(`## ${version}`);
|
|
160
|
-
lines.push("");
|
|
161
|
-
if (breakingChanges.length > 0) {
|
|
162
|
-
lines.push("### 💥 Breaking Changes");
|
|
163
|
-
lines.push("");
|
|
164
|
-
for (const bc of breakingChanges) {
|
|
165
|
-
lines.push(`- ${bc}`);
|
|
166
|
-
}
|
|
167
|
-
lines.push("");
|
|
168
|
-
}
|
|
169
|
-
for (const section of sections) {
|
|
170
|
-
lines.push(`### ${section.icon} ${section.title}`);
|
|
171
|
-
lines.push("");
|
|
172
|
-
for (const entry of section.commits) {
|
|
173
|
-
const scope = entry.scope ? `**${entry.scope}:** ` : "";
|
|
174
|
-
lines.push(`- ${scope}${entry.message} (${entry.sha})`);
|
|
175
|
-
}
|
|
176
|
-
lines.push("");
|
|
177
|
-
}
|
|
178
|
-
if (contributors.length > 0) {
|
|
179
|
-
lines.push("### Contributors");
|
|
180
|
-
lines.push("");
|
|
181
|
-
lines.push(contributors.map((c) => `@${c}`).join(", "));
|
|
182
|
-
lines.push("");
|
|
183
|
-
}
|
|
184
|
-
return lines.join("\n").trimEnd();
|
|
185
|
-
}
|
|
186
|
-
/**
|
|
187
|
-
* Generate release notes purely from commit data (no API calls).
|
|
188
|
-
* Useful for testing or when commit data is already available.
|
|
189
|
-
*/
|
|
190
|
-
export function generateReleaseNotesFromCommits(repo, version, commits) {
|
|
191
|
-
const parsed = commits
|
|
192
|
-
.filter((c) => !c.message.startsWith("Merge "))
|
|
193
|
-
.map((c) => parseCommitMessage(c.sha, c.message, c.author));
|
|
194
|
-
const breakingChanges = parsed
|
|
195
|
-
.filter((c) => c.breaking)
|
|
196
|
-
.map((c) => c.scope ? `**${c.scope}:** ${c.description}` : c.description);
|
|
197
|
-
const contributors = [...new Set(parsed.map((c) => c.author))].sort();
|
|
198
|
-
const sections = [];
|
|
199
|
-
for (const def of SECTION_ORDER) {
|
|
200
|
-
if (def.types.length === 0)
|
|
201
|
-
continue;
|
|
202
|
-
const entries = parsed
|
|
203
|
-
.filter((c) => def.types.includes(c.type))
|
|
204
|
-
.map((c) => ({
|
|
205
|
-
sha: c.sha.slice(0, 7),
|
|
206
|
-
message: c.description,
|
|
207
|
-
author: c.author,
|
|
208
|
-
scope: c.scope,
|
|
209
|
-
}));
|
|
210
|
-
if (entries.length > 0) {
|
|
211
|
-
sections.push({ title: def.title, icon: def.icon, commits: entries });
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
const markdown = formatReleaseNotes(version, sections, breakingChanges, contributors);
|
|
215
|
-
return {
|
|
216
|
-
repo,
|
|
217
|
-
version,
|
|
218
|
-
from: "",
|
|
219
|
-
to: "",
|
|
220
|
-
generatedAt: new Date().toISOString(),
|
|
221
|
-
sections,
|
|
222
|
-
breakingChanges,
|
|
223
|
-
contributors,
|
|
224
|
-
markdown,
|
|
225
|
-
};
|
|
226
|
-
}
|
|
227
|
-
//# sourceMappingURL=release-notes.js.map
|