@olegkoval/agent-skills 1.78.0 → 1.79.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/adapters/claude/olko-github-pr/skills/lekker-review/scripts/native-dedup.mjs +47 -0
- package/docs/lekker-openrewrite-pilot.md +94 -0
- package/package.json +1 -1
- package/plugins/olko-apple-kit/.claude-plugin/plugin.json +1 -1
- package/plugins/olko-creative/.claude-plugin/plugin.json +1 -1
- package/plugins/olko-garmin-kit/.claude-plugin/plugin.json +1 -1
- package/plugins/olko-git-tools/.claude-plugin/plugin.json +1 -1
- package/plugins/olko-github-pr/.claude-plugin/plugin.json +1 -1
- package/plugins/olko-github-pr/skills/lekker-review/scripts/native-dedup.mjs +47 -0
- package/plugins/olko-obsidian/.claude-plugin/plugin.json +1 -1
- package/plugins/olko-product/.claude-plugin/plugin.json +1 -1
- package/plugins/olko-reflection/.claude-plugin/plugin.json +1 -1
- package/plugins/olko-release/.claude-plugin/plugin.json +1 -1
- package/plugins/olko-skill-meta/.claude-plugin/plugin.json +1 -1
- package/plugins/olko-web-ops/.claude-plugin/plugin.json +1 -1
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { readFileSync, realpathSync } from 'node:fs'
|
|
3
|
+
import { dirname, resolve } from 'node:path'
|
|
4
|
+
import { fileURLToPath } from 'node:url'
|
|
5
|
+
import { loadDedup } from './validate-lines.mjs'
|
|
6
|
+
|
|
7
|
+
const record = value => value && typeof value === 'object' && !Array.isArray(value)
|
|
8
|
+
|
|
9
|
+
export function deduplicateManifest(manifestPath) {
|
|
10
|
+
const path = resolve(manifestPath)
|
|
11
|
+
const manifest = JSON.parse(readFileSync(path, 'utf8'))
|
|
12
|
+
if (!record(manifest) || !Array.isArray(manifest.dimensions) || manifest.dimensions.length === 0) {
|
|
13
|
+
throw new Error('manifest must contain a non-empty dimensions array')
|
|
14
|
+
}
|
|
15
|
+
const dimensions = manifest.dimensions
|
|
16
|
+
if (!dimensions.every(item => record(item) && typeof item.name === 'string' && item.name.trim()
|
|
17
|
+
&& item.name === item.name.trim() && typeof item.path === 'string' && item.path.trim()
|
|
18
|
+
&& item.path === item.path.trim())) throw new Error('each dimension requires a non-empty name and path')
|
|
19
|
+
if (new Set(dimensions.map(item => item.name)).size !== dimensions.length) throw new Error('dimension names must be unique')
|
|
20
|
+
const findings = dimensions.flatMap(({ name, path: resultPath }) => {
|
|
21
|
+
const document = JSON.parse(readFileSync(resolve(dirname(path), resultPath), 'utf8'))
|
|
22
|
+
if (!record(document) || !Array.isArray(document.findings) || document.findings.some(finding => !record(finding))) {
|
|
23
|
+
throw new Error(`${name} result must contain a findings array of objects`)
|
|
24
|
+
}
|
|
25
|
+
return document.findings.map(finding => ({ ...finding, _dimension: name, agreedBy: [name] }))
|
|
26
|
+
})
|
|
27
|
+
return { findings: loadDedup()(findings) }
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function main(args) {
|
|
31
|
+
const [flag, manifestPath, ...extra] = args
|
|
32
|
+
if (flag !== '--manifest' || !manifestPath || manifestPath.startsWith('--') || extra.length) {
|
|
33
|
+
console.error('usage: native-dedup.mjs --manifest <manifest.json>')
|
|
34
|
+
process.exitCode = 2
|
|
35
|
+
return
|
|
36
|
+
}
|
|
37
|
+
try { console.log(JSON.stringify(deduplicateManifest(manifestPath))) } catch (error) {
|
|
38
|
+
console.error(`native-dedup: ${error.message}`)
|
|
39
|
+
process.exitCode = 2
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function isMain() {
|
|
44
|
+
try { return realpathSync(process.argv[1]) === realpathSync(fileURLToPath(import.meta.url)) } catch { return false }
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (isMain()) main(process.argv.slice(2))
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# OpenRewrite native JavaScript pilot
|
|
2
|
+
|
|
3
|
+
This optional fixture experiment runs a shipped OpenRewrite recipe without the
|
|
4
|
+
Moderne CLI. It adds no default review dependency and applies no source fixes.
|
|
5
|
+
It tests a concrete static-analysis opportunity while all six semantic review
|
|
6
|
+
dimensions and Verify/Critic/Prove remain required.
|
|
7
|
+
|
|
8
|
+
## Reproduce in isolation
|
|
9
|
+
|
|
10
|
+
Requires npm and Docker. Run from this repository's root. Installation disables
|
|
11
|
+
package lifecycle scripts. The recipe runs with no network, host mounts or
|
|
12
|
+
forwarded credentials; only the temporary fixture project enters the container.
|
|
13
|
+
|
|
14
|
+
```sh
|
|
15
|
+
pilot_dir=$(mktemp -d)
|
|
16
|
+
npm install --prefix "$pilot_dir" --ignore-scripts --omit=optional \
|
|
17
|
+
--no-audit --no-fund --save-exact @openrewrite/rewrite@8.100.3
|
|
18
|
+
cp tests/openrewrite-pilot.mjs "$pilot_dir/pilot.mjs"
|
|
19
|
+
pilot_container=$(docker create --network none --cap-drop ALL \
|
|
20
|
+
--security-opt no-new-privileges --memory 1g --pids-limit 128 --workdir /work \
|
|
21
|
+
node@sha256:0e1754758c2df4cfa3e68d59e2e1b7374bb7fd9ea6328eaaacf15cc934af8202 \
|
|
22
|
+
node pilot.mjs)
|
|
23
|
+
docker cp "$pilot_dir/." "$pilot_container:/work"
|
|
24
|
+
docker start -a "$pilot_container" > "$pilot_dir/first.stdout" 2> "$pilot_dir/first.stderr"
|
|
25
|
+
docker inspect "$pilot_container" --format '{{.State.ExitCode}}'
|
|
26
|
+
docker cp "$pilot_container:/work/artifacts" "$pilot_dir/first-artifacts"
|
|
27
|
+
docker start -a "$pilot_container" > "$pilot_dir/second.stdout" 2> "$pilot_dir/second.stderr"
|
|
28
|
+
docker inspect "$pilot_container" --format '{{.State.ExitCode}}'
|
|
29
|
+
docker cp "$pilot_container:/work/artifacts" "$pilot_dir/second-artifacts"
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Both exit codes must be zero. Each process checks its two fresh-input passes
|
|
33
|
+
for identical normalized output and validates every expected result. Compare
|
|
34
|
+
the `outputSha256` values across the two stdout files as a separate cold-process
|
|
35
|
+
repeatability gate. Preserve stderr, package-lock.json, expectations, outputs and
|
|
36
|
+
patches before removing the stopped container and temporary directory. A failed
|
|
37
|
+
process is unavailable evidence, never a clean review. No fixtures execute the
|
|
38
|
+
JavaScript being analyzed.
|
|
39
|
+
|
|
40
|
+
## Frozen experiment
|
|
41
|
+
|
|
42
|
+
Package: `@openrewrite/rewrite@8.100.3`.
|
|
43
|
+
Tested runtime: Node v22.23.4 in the pinned Linux/arm64 container image above.
|
|
44
|
+
Recipe: `org.openrewrite.javascript.cleanup.async-callback-in-sync-array-method`.
|
|
45
|
+
The harness uses the package's JavaScriptParser, scheduleRun and TreePrinters;
|
|
46
|
+
it implements no substitute detection rule.
|
|
47
|
+
|
|
48
|
+
| Fixture | Expected and observed |
|
|
49
|
+
|---|---|
|
|
50
|
+
| Array.filter with async callback | Warning |
|
|
51
|
+
| Array.forEach with async callback | Warning |
|
|
52
|
+
| Array.filter with sync callback | Unchanged |
|
|
53
|
+
| Array.map with async callback | Unchanged |
|
|
54
|
+
| Typed custom filter accepting async callback | Unchanged |
|
|
55
|
+
| Known-safe custom filter with erased receiver type | Warning: characterized false positive |
|
|
56
|
+
| Invalid TypeScript syntax | Parse-error / unavailable |
|
|
57
|
+
|
|
58
|
+
The extra untyped custom filter returns the callback's promise to its caller;
|
|
59
|
+
unlike Array.filter, it never interprets that promise as a boolean. The warning
|
|
60
|
+
is therefore not a demonstrated defect. Its expected warning characterizes the
|
|
61
|
+
recipe's limitation, not a passing semantic-quality gate. The `any` annotation
|
|
62
|
+
exists only to make the lost type attribution explicit in this isolated fixture.
|
|
63
|
+
|
|
64
|
+
The original six-fixture 7 November 2026 pilot passed in two cold processes with two
|
|
65
|
+
passes each. All four normalized outputs matched SHA-256
|
|
66
|
+
`ae1a6381c263289b5d006eda96cd73e87d1c9f5cbb95040fdb7c3e916d410bb9`.
|
|
67
|
+
Pass times were 3492/3078 ms and 2880/2136 ms, excluding image/npm setup,
|
|
68
|
+
container startup and coordinator work. These tiny-fixture timings establish
|
|
69
|
+
neither repository-scale speed nor whole-review savings. The local raw archive
|
|
70
|
+
is `~/.local/state/lekker-review-evaluation/runs/20261107-openrewrite-native`.
|
|
71
|
+
The wrapper checks the package version; the retained lockfile pins transitive
|
|
72
|
+
dependencies for that historical run. A fresh install may resolve different
|
|
73
|
+
transitives and is a new experiment, not an exact historical replay.
|
|
74
|
+
The expanded seven-fixture run also makes the forEach callback suspend before
|
|
75
|
+
checking whether its work finished. Including the safe untyped receiver, it produced
|
|
76
|
+
`52ba49e0a0fdc5a7fb0ad13574e04f11a102c19b029cf2e41d95bfab460e2613`.
|
|
77
|
+
|
|
78
|
+
## Adoption limits
|
|
79
|
+
|
|
80
|
+
This proves one recipe/version on synthetic fixtures, not population recall or
|
|
81
|
+
false-positive rates. A false positive on a safe untyped receiver was observed;
|
|
82
|
+
warnings need semantic verification. Preserve parse failures as unavailable.
|
|
83
|
+
Printed markers/patches are evidence only; do not auto-apply them. The fixture
|
|
84
|
+
runner is opt-in and intentionally absent from the normal dependency-free suite.
|
|
85
|
+
|
|
86
|
+
The native package route worked without authentication; this does not prove
|
|
87
|
+
every recipe works without Java/RPC or change the documented Moderne CLI's
|
|
88
|
+
authentication requirements. The JavaScript package uses the Moderne Source
|
|
89
|
+
Available License, distinct from Apache-licensed OpenRewrite core. No package
|
|
90
|
+
redistribution or mandatory production integration is proposed here.
|
|
91
|
+
|
|
92
|
+
References: [JavaScript development environment](https://docs.openrewrite.org/authoring-recipes/javascript-recipe-development-environment),
|
|
93
|
+
[recipe testing example](https://docs.openrewrite.org/authoring-recipes/writing-a-javascript-refactoring-recipe),
|
|
94
|
+
and [licensing](https://docs.openrewrite.org/licensing/openrewrite-licensing).
|
package/package.json
CHANGED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { readFileSync, realpathSync } from 'node:fs'
|
|
3
|
+
import { dirname, resolve } from 'node:path'
|
|
4
|
+
import { fileURLToPath } from 'node:url'
|
|
5
|
+
import { loadDedup } from './validate-lines.mjs'
|
|
6
|
+
|
|
7
|
+
const record = value => value && typeof value === 'object' && !Array.isArray(value)
|
|
8
|
+
|
|
9
|
+
export function deduplicateManifest(manifestPath) {
|
|
10
|
+
const path = resolve(manifestPath)
|
|
11
|
+
const manifest = JSON.parse(readFileSync(path, 'utf8'))
|
|
12
|
+
if (!record(manifest) || !Array.isArray(manifest.dimensions) || manifest.dimensions.length === 0) {
|
|
13
|
+
throw new Error('manifest must contain a non-empty dimensions array')
|
|
14
|
+
}
|
|
15
|
+
const dimensions = manifest.dimensions
|
|
16
|
+
if (!dimensions.every(item => record(item) && typeof item.name === 'string' && item.name.trim()
|
|
17
|
+
&& item.name === item.name.trim() && typeof item.path === 'string' && item.path.trim()
|
|
18
|
+
&& item.path === item.path.trim())) throw new Error('each dimension requires a non-empty name and path')
|
|
19
|
+
if (new Set(dimensions.map(item => item.name)).size !== dimensions.length) throw new Error('dimension names must be unique')
|
|
20
|
+
const findings = dimensions.flatMap(({ name, path: resultPath }) => {
|
|
21
|
+
const document = JSON.parse(readFileSync(resolve(dirname(path), resultPath), 'utf8'))
|
|
22
|
+
if (!record(document) || !Array.isArray(document.findings) || document.findings.some(finding => !record(finding))) {
|
|
23
|
+
throw new Error(`${name} result must contain a findings array of objects`)
|
|
24
|
+
}
|
|
25
|
+
return document.findings.map(finding => ({ ...finding, _dimension: name, agreedBy: [name] }))
|
|
26
|
+
})
|
|
27
|
+
return { findings: loadDedup()(findings) }
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function main(args) {
|
|
31
|
+
const [flag, manifestPath, ...extra] = args
|
|
32
|
+
if (flag !== '--manifest' || !manifestPath || manifestPath.startsWith('--') || extra.length) {
|
|
33
|
+
console.error('usage: native-dedup.mjs --manifest <manifest.json>')
|
|
34
|
+
process.exitCode = 2
|
|
35
|
+
return
|
|
36
|
+
}
|
|
37
|
+
try { console.log(JSON.stringify(deduplicateManifest(manifestPath))) } catch (error) {
|
|
38
|
+
console.error(`native-dedup: ${error.message}`)
|
|
39
|
+
process.exitCode = 2
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function isMain() {
|
|
44
|
+
try { return realpathSync(process.argv[1]) === realpathSync(fileURLToPath(import.meta.url)) } catch { return false }
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (isMain()) main(process.argv.slice(2))
|