opencode-commit-guard 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.
- package/LICENSE +21 -0
- package/README.md +110 -0
- package/dist/index.js +814 -0
- package/index.ts +1 -0
- package/package.json +45 -0
- package/src/config.ts +80 -0
- package/src/plugin.ts +50 -0
- package/src/shell.ts +671 -0
- package/src/types.ts +60 -0
- package/src/validator.ts +224 -0
package/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from "./src/plugin.js"
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "opencode-commit-guard",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "OpenCode V2 plugin enforcing git commit format rules",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./dist/index.js",
|
|
9
|
+
"./source": "./index.ts"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"dist",
|
|
13
|
+
"index.ts",
|
|
14
|
+
"src"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"lint": "oxlint .",
|
|
18
|
+
"test": "bun test",
|
|
19
|
+
"typecheck": "tsc --noEmit",
|
|
20
|
+
"build": "bun build index.ts --outdir dist --target bun --format esm --external @opencode/plugin",
|
|
21
|
+
"prepack": "bun run build"
|
|
22
|
+
},
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"@opencode/plugin": "2.0.2"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@oxlint/plugins": "1.80.0",
|
|
28
|
+
"@types/bun": "latest",
|
|
29
|
+
"oxlint": "1.80.0",
|
|
30
|
+
"typescript": "latest"
|
|
31
|
+
},
|
|
32
|
+
"engines": {
|
|
33
|
+
"bun": ">=1.2.0"
|
|
34
|
+
},
|
|
35
|
+
"license": "MIT",
|
|
36
|
+
"author": {
|
|
37
|
+
"name": "Omkar Chandorkar",
|
|
38
|
+
"email": "gotenksIN@aospa.co"
|
|
39
|
+
},
|
|
40
|
+
"repository": {
|
|
41
|
+
"type": "git",
|
|
42
|
+
"url": "git+https://github.com/gotenksIN/opencode-commit-guard.git"
|
|
43
|
+
},
|
|
44
|
+
"homepage": "https://github.com/gotenksIN/opencode-commit-guard"
|
|
45
|
+
}
|
package/src/config.ts
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import {
|
|
2
|
+
defaultConfig,
|
|
3
|
+
isJSONBoolean,
|
|
4
|
+
isJSONNumber,
|
|
5
|
+
isJSONString,
|
|
6
|
+
isRecord,
|
|
7
|
+
} from "./types.js"
|
|
8
|
+
import type { CommitGuardConfig, JsonValue } from "./types.js"
|
|
9
|
+
|
|
10
|
+
export function parseConfig(options: JsonValue | undefined): CommitGuardConfig {
|
|
11
|
+
if (options === undefined) {
|
|
12
|
+
return defaultConfig
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (!isRecord(options)) {
|
|
16
|
+
throw new Error("Invalid plugin options; expected an object.")
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const rawRequireScope = options["requireScope"]
|
|
20
|
+
let requireScope = defaultConfig.requireScope
|
|
21
|
+
|
|
22
|
+
if (rawRequireScope !== undefined) {
|
|
23
|
+
if (!isJSONBoolean(rawRequireScope)) {
|
|
24
|
+
throw new Error("Invalid plugin option requireScope; expected a boolean.")
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
requireScope = rawRequireScope
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const rawAllowedScopes = options["allowedScopes"]
|
|
31
|
+
let allowedScopes: readonly string[] | undefined = defaultConfig.allowedScopes
|
|
32
|
+
|
|
33
|
+
if (rawAllowedScopes !== undefined) {
|
|
34
|
+
if (!Array.isArray(rawAllowedScopes)) {
|
|
35
|
+
throw new Error("Invalid plugin option allowedScopes; expected an array of non-empty strings.")
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const scopes: string[] = []
|
|
39
|
+
|
|
40
|
+
for (const item of rawAllowedScopes) {
|
|
41
|
+
if (!isJSONString(item) || item.trim().length === 0) {
|
|
42
|
+
throw new Error("Invalid plugin option allowedScopes; expected an array of non-empty strings.")
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
scopes.push(item.trim())
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
allowedScopes = scopes.length > 0 ? scopes : undefined
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const rawMaxLineLength = options["maxLineLength"]
|
|
52
|
+
let maxLineLength = defaultConfig.maxLineLength
|
|
53
|
+
|
|
54
|
+
if (rawMaxLineLength !== undefined) {
|
|
55
|
+
if (!isJSONNumber(rawMaxLineLength) || !Number.isSafeInteger(rawMaxLineLength) || rawMaxLineLength < 0) {
|
|
56
|
+
throw new Error("Invalid plugin option maxLineLength; expected an integer greater than or equal to 0.")
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// SAFETY: isJSONNumber and Number.isSafeInteger verify rawMaxLineLength is an integer number.
|
|
60
|
+
maxLineLength = rawMaxLineLength as number
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const rawRequireSignoff = options["requireSignoff"]
|
|
64
|
+
let requireSignoff = defaultConfig.requireSignoff
|
|
65
|
+
|
|
66
|
+
if (rawRequireSignoff !== undefined) {
|
|
67
|
+
if (!isJSONBoolean(rawRequireSignoff)) {
|
|
68
|
+
throw new Error("Invalid plugin option requireSignoff; expected a boolean.")
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
requireSignoff = rawRequireSignoff
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return {
|
|
75
|
+
requireScope,
|
|
76
|
+
allowedScopes,
|
|
77
|
+
maxLineLength,
|
|
78
|
+
requireSignoff,
|
|
79
|
+
}
|
|
80
|
+
}
|
package/src/plugin.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Plugin } from "@opencode/plugin"
|
|
2
|
+
import { parseConfig } from "./config.js"
|
|
3
|
+
import { extractGitCommits } from "./shell.js"
|
|
4
|
+
import { isJSONString, isRecord } from "./types.js"
|
|
5
|
+
import type { JsonValue } from "./types.js"
|
|
6
|
+
import { validateGitCommits } from "./validator.js"
|
|
7
|
+
|
|
8
|
+
export const plugin = Plugin.define({
|
|
9
|
+
id: "opencode-commit-guard",
|
|
10
|
+
setup: async (ctx) => {
|
|
11
|
+
// SAFETY: OpenCode plugin options are passed through ctx.options as JsonValue or undefined.
|
|
12
|
+
const config = parseConfig(ctx.options as JsonValue | undefined)
|
|
13
|
+
const sessionDirectory = ctx.location.directory
|
|
14
|
+
|
|
15
|
+
await ctx.tool.hook("execute.before", async (event) => {
|
|
16
|
+
if (event.tool !== "shell" && event.tool !== "bash") {
|
|
17
|
+
return
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// SAFETY: event.input is an unvalidated tool input payload from OpenCode runtime.
|
|
21
|
+
const rawInput = event.input as JsonValue | undefined
|
|
22
|
+
|
|
23
|
+
if (!isRecord(rawInput)) {
|
|
24
|
+
return
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const command = rawInput["command"]
|
|
28
|
+
|
|
29
|
+
if (!isJSONString(command)) {
|
|
30
|
+
return
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const invocations = extractGitCommits(command)
|
|
34
|
+
|
|
35
|
+
if (invocations.length === 0) {
|
|
36
|
+
return
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const workdir = rawInput["workdir"]
|
|
40
|
+
validateGitCommits(
|
|
41
|
+
invocations,
|
|
42
|
+
config,
|
|
43
|
+
command,
|
|
44
|
+
isJSONString(workdir) ? workdir : sessionDirectory,
|
|
45
|
+
)
|
|
46
|
+
})
|
|
47
|
+
},
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
export default plugin
|