@aperant/framework 0.9.0 → 0.10.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/CHANGELOG.md +68 -0
- package/agents/apt-verifier.md +6 -3
- package/dist/cli/commands/init.d.mts.map +1 -1
- package/dist/cli/commands/init.mjs +17 -1
- package/dist/cli/commands/init.mjs.map +1 -1
- package/dist/cli/consistency/parse-review.mjs +5 -3
- package/dist/cli/consistency/parse-review.mjs.map +1 -1
- package/dist/cli/consistency/rules/r5-verdict-consistency.d.mts.map +1 -1
- package/dist/cli/consistency/rules/r5-verdict-consistency.mjs +10 -8
- package/dist/cli/consistency/rules/r5-verdict-consistency.mjs.map +1 -1
- package/dist/cli/gate/gates/review-clean.d.mts.map +1 -1
- package/dist/cli/gate/gates/review-clean.mjs +4 -2
- package/dist/cli/gate/gates/review-clean.mjs.map +1 -1
- package/dist/cli/install/mcp-provision.d.mts +26 -0
- package/dist/cli/install/mcp-provision.d.mts.map +1 -0
- package/dist/cli/install/mcp-provision.mjs +281 -0
- package/dist/cli/install/mcp-provision.mjs.map +1 -0
- package/dist/cli/install/mcp-server-specs.d.mts +80 -0
- package/dist/cli/install/mcp-server-specs.d.mts.map +1 -0
- package/dist/cli/install/mcp-server-specs.mjs +102 -0
- package/dist/cli/install/mcp-server-specs.mjs.map +1 -0
- package/dist/cli/install/runtime-detect.d.mts +1 -0
- package/dist/cli/install/runtime-detect.d.mts.map +1 -1
- package/dist/cli/install/runtime-detect.mjs +5 -0
- package/dist/cli/install/runtime-detect.mjs.map +1 -1
- package/dist/cli/install/toml-merge.d.mts +40 -0
- package/dist/cli/install/toml-merge.d.mts.map +1 -0
- package/dist/cli/install/toml-merge.mjs +134 -0
- package/dist/cli/install/toml-merge.mjs.map +1 -0
- package/dist/cli/util/events-path.d.mts +8 -0
- package/dist/cli/util/events-path.d.mts.map +1 -0
- package/dist/cli/util/events-path.mjs +23 -0
- package/dist/cli/util/events-path.mjs.map +1 -0
- package/dist/cli/util/runtime-capabilities.d.mts +30 -0
- package/dist/cli/util/runtime-capabilities.d.mts.map +1 -0
- package/dist/cli/util/runtime-capabilities.mjs +214 -0
- package/dist/cli/util/runtime-capabilities.mjs.map +1 -0
- package/dist/cli/verify-proof/audit.d.mts +2 -7
- package/dist/cli/verify-proof/audit.d.mts.map +1 -1
- package/dist/cli/verify-proof/audit.mjs +11 -17
- package/dist/cli/verify-proof/audit.mjs.map +1 -1
- package/dist/cli/verify-proof/runtime-detect.d.mts +2 -29
- package/dist/cli/verify-proof/runtime-detect.d.mts.map +1 -1
- package/dist/cli/verify-proof/runtime-detect.mjs +8 -203
- package/dist/cli/verify-proof/runtime-detect.mjs.map +1 -1
- package/dist/plugin/.claude-plugin/plugin.json +1 -1
- package/dist/plugin/agents/apt-verifier.md +6 -3
- package/dist/plugin/skills/apt-pr-review/SKILL.md +54 -0
- package/dist/plugin/skills/apt-verify/SKILL.md +1 -1
- package/dist/plugin/skills/apt-verify-proof/SKILL.md +25 -1
- package/drivers/browser/skill/agent-browser/SKILL.md +51 -0
- package/drivers/tauri/README.md +107 -0
- package/drivers/tauri/driver.mjs +88 -0
- package/drivers/tauri/manifest.json +37 -0
- package/drivers/tauri/scripts/tauri-mcp.sh +41 -0
- package/package.json +1 -1
- package/skills/apt-pr-review/SKILL.md +54 -0
- package/skills/apt-verify/SKILL.md +1 -1
- package/skills/apt-verify-proof/SKILL.md +25 -1
- package/src/cli/commands/init.mjs +19 -0
- package/src/cli/consistency/parse-review.mjs +5 -3
- package/src/cli/consistency/rules/r5-verdict-consistency.mjs +14 -9
- package/src/cli/gate/gates/review-clean.mjs +4 -2
- package/src/cli/install/mcp-provision.mjs +293 -0
- package/src/cli/install/mcp-server-specs.mjs +101 -0
- package/src/cli/install/runtime-detect.mjs +9 -0
- package/src/cli/install/toml-merge.mjs +139 -0
- package/src/cli/util/events-path.mjs +24 -0
- package/src/cli/util/runtime-capabilities.mjs +216 -0
- package/src/cli/verify-proof/audit.mjs +11 -17
- package/src/cli/verify-proof/runtime-detect.mjs +11 -204
- package/templates/config.json +2 -1
|
@@ -1,211 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* runtime-detect.mjs — pure project-shape capability detection.
|
|
2
|
+
* verify-proof/runtime-detect.mjs — pure project-shape capability detection.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* Pattern: pure data in → pure data out. No filesystem walking, no exec.
|
|
10
|
-
* Use loadRuntimeCapabilities(projectDir) for the cwd-rooted variant.
|
|
11
|
-
*
|
|
12
|
-
* v0.8.6 — `loadRuntimeCapabilities` now ALSO walks `apps/*` by default
|
|
13
|
-
* (configurable via the second arg `{monorepo_globs}`) and OR-merges
|
|
14
|
-
* each match's `package.json` capabilities with the root. The default
|
|
15
|
-
* `['apps/*']` matches the canonical Aperant monorepo layout; adopters
|
|
16
|
-
* whose monorepo lives elsewhere (e.g. `packages/apps/*`) pass a
|
|
17
|
-
* custom `monorepo_globs`. Setting `monorepo_globs: []` disables the
|
|
18
|
-
* walk entirely (root-only escape hatch).
|
|
4
|
+
* The implementation now lives in util/runtime-capabilities.mjs so the install
|
|
5
|
+
* layer can share it WITHOUT install/ importing from verify-proof/ (the
|
|
6
|
+
* layer-boundary rule). Re-exported here byte-for-byte so every existing
|
|
7
|
+
* `import { … } from '../verify-proof/runtime-detect.mjs'` call site (and the
|
|
8
|
+
* `RuntimeCapabilities` typedef references) keep working unchanged.
|
|
19
9
|
*/
|
|
20
10
|
|
|
21
|
-
|
|
22
|
-
|
|
11
|
+
export {
|
|
12
|
+
detectFromPackageJson,
|
|
13
|
+
loadRuntimeCapabilities,
|
|
14
|
+
} from '../util/runtime-capabilities.mjs'
|
|
23
15
|
|
|
24
16
|
/**
|
|
25
|
-
* @typedef {
|
|
26
|
-
* @property {boolean} is_electron
|
|
27
|
-
* @property {boolean} is_tauri
|
|
28
|
-
* @property {boolean} is_nextjs
|
|
29
|
-
* @property {boolean} is_nuxt
|
|
30
|
-
* @property {boolean} is_web_frontend
|
|
31
|
-
* @property {boolean} is_expo
|
|
32
|
-
* @property {boolean} is_react_native
|
|
33
|
-
* @property {boolean} has_node
|
|
34
|
-
*/
|
|
35
|
-
|
|
36
|
-
/** A capability record with every flag defaulted to false. */
|
|
37
|
-
function emptyCapabilities() {
|
|
38
|
-
return {
|
|
39
|
-
is_electron: false,
|
|
40
|
-
is_tauri: false,
|
|
41
|
-
is_nextjs: false,
|
|
42
|
-
is_nuxt: false,
|
|
43
|
-
is_web_frontend: false,
|
|
44
|
-
is_expo: false,
|
|
45
|
-
is_react_native: false,
|
|
46
|
-
has_node: false,
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Detect runtime capabilities from a parsed package.json object.
|
|
52
|
-
*
|
|
53
|
-
* @param {Record<string, unknown> | null} packageJson
|
|
54
|
-
* @returns {RuntimeCapabilities}
|
|
55
|
-
*/
|
|
56
|
-
export function detectFromPackageJson(packageJson) {
|
|
57
|
-
const capabilities = emptyCapabilities()
|
|
58
|
-
if (packageJson === null || typeof packageJson !== 'object') return capabilities
|
|
59
|
-
|
|
60
|
-
const allDeps = {
|
|
61
|
-
...(packageJson.dependencies ?? {}) /** @type {Record<string,string>} */,
|
|
62
|
-
...(packageJson.devDependencies ?? {}) /** @type {Record<string,string>} */,
|
|
63
|
-
}
|
|
64
|
-
const deps = new Set(Object.keys(allDeps).map((k) => k.toLowerCase()))
|
|
65
|
-
|
|
66
|
-
if (deps.has('electron') || [...deps].some((d) => d.startsWith('@electron'))) {
|
|
67
|
-
capabilities.is_electron = true
|
|
68
|
-
}
|
|
69
|
-
if (deps.has('@tauri-apps/api') || deps.has('tauri')) {
|
|
70
|
-
capabilities.is_tauri = true
|
|
71
|
-
}
|
|
72
|
-
if (deps.has('expo')) capabilities.is_expo = true
|
|
73
|
-
if (deps.has('react-native')) capabilities.is_react_native = true
|
|
74
|
-
|
|
75
|
-
// Web frontends — react/vue/svelte/angular/solid → frontend. BUT: an
|
|
76
|
-
// Electron app commonly bundles React as its renderer; in that case the
|
|
77
|
-
// runtime is "electron", not "web_frontend". Electron + react-native +
|
|
78
|
-
// expo + tauri all win over the web flag.
|
|
79
|
-
const isNativeContainer =
|
|
80
|
-
capabilities.is_electron ||
|
|
81
|
-
capabilities.is_tauri ||
|
|
82
|
-
capabilities.is_react_native ||
|
|
83
|
-
capabilities.is_expo
|
|
84
|
-
const webFrameworks = ['react', 'vue', 'svelte', 'angular', 'solid']
|
|
85
|
-
if (!isNativeContainer && webFrameworks.some((f) => deps.has(f))) {
|
|
86
|
-
capabilities.is_web_frontend = true
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
if (deps.has('next')) {
|
|
90
|
-
capabilities.is_nextjs = true
|
|
91
|
-
capabilities.is_web_frontend = true
|
|
92
|
-
}
|
|
93
|
-
if (deps.has('nuxt')) {
|
|
94
|
-
capabilities.is_nuxt = true
|
|
95
|
-
capabilities.is_web_frontend = true
|
|
96
|
-
}
|
|
97
|
-
if (deps.has('vite') && !isNativeContainer) {
|
|
98
|
-
capabilities.is_web_frontend = true
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// Node-ish? Anything with a package.json + an entry point counts.
|
|
102
|
-
if (typeof packageJson.main === 'string' || typeof packageJson.module === 'string') {
|
|
103
|
-
capabilities.has_node = true
|
|
104
|
-
}
|
|
105
|
-
if (!capabilities.has_node && packageJson.scripts && typeof packageJson.scripts === 'object') {
|
|
106
|
-
capabilities.has_node = true
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
return capabilities
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* Load and detect capabilities from a project directory's package.json.
|
|
114
|
-
* v0.8.6 — also walks `monorepo_globs` (default `['apps/*']`) and
|
|
115
|
-
* OR-merges each match's capabilities with the root.
|
|
116
|
-
*
|
|
117
|
-
* @param {string} projectDir
|
|
118
|
-
* @param {{monorepo_globs?: string[]}} [opts]
|
|
119
|
-
* @returns {RuntimeCapabilities}
|
|
120
|
-
*/
|
|
121
|
-
export function loadRuntimeCapabilities(projectDir, opts) {
|
|
122
|
-
const root = resolve(projectDir)
|
|
123
|
-
const rootPkgPath = join(root, 'package.json')
|
|
124
|
-
let rootCaps = emptyCapabilities()
|
|
125
|
-
if (existsSync(rootPkgPath)) {
|
|
126
|
-
try {
|
|
127
|
-
rootCaps = detectFromPackageJson(JSON.parse(readFileSync(rootPkgPath, 'utf-8')))
|
|
128
|
-
} catch {
|
|
129
|
-
/* fall through with empty caps */
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
// Default to the canonical Aperant monorepo layout. Passing `[]`
|
|
134
|
-
// disables the walk entirely (root-only escape hatch per spec ID-05).
|
|
135
|
-
const globs = opts && Array.isArray(opts.monorepo_globs) ? opts.monorepo_globs : ['apps/*']
|
|
136
|
-
if (globs.length === 0) return rootCaps
|
|
137
|
-
|
|
138
|
-
let merged = rootCaps
|
|
139
|
-
for (const glob of globs) {
|
|
140
|
-
const matches = expandSimpleGlob(root, glob)
|
|
141
|
-
for (const dir of matches) {
|
|
142
|
-
const childPkgPath = join(dir, 'package.json')
|
|
143
|
-
if (!existsSync(childPkgPath)) continue
|
|
144
|
-
try {
|
|
145
|
-
const childCaps = detectFromPackageJson(JSON.parse(readFileSync(childPkgPath, 'utf-8')))
|
|
146
|
-
merged = orMergeCapabilities(merged, childCaps)
|
|
147
|
-
} catch {
|
|
148
|
-
/* skip malformed package.json */
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
return merged
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* Expand a simple `prefix/*` glob against the root. Supports ONLY the
|
|
157
|
-
* `<dir>/*` shape (matches each direct subdirectory of `<dir>`). Other
|
|
158
|
-
* glob syntax is intentionally rejected — v1 keeps the dep surface
|
|
159
|
-
* small. Fails closed on malformed patterns (returns []).
|
|
160
|
-
*
|
|
161
|
-
* @param {string} root
|
|
162
|
-
* @param {string} glob
|
|
163
|
-
* @returns {string[]}
|
|
164
|
-
*/
|
|
165
|
-
function expandSimpleGlob(root, glob) {
|
|
166
|
-
if (typeof glob !== 'string' || !glob.endsWith('/*')) return []
|
|
167
|
-
const prefix = glob.slice(0, -2)
|
|
168
|
-
if (prefix.length === 0 || prefix.includes('*')) return []
|
|
169
|
-
const dir = join(root, prefix)
|
|
170
|
-
if (!existsSync(dir)) return []
|
|
171
|
-
let entries
|
|
172
|
-
try {
|
|
173
|
-
entries = readdirSync(dir)
|
|
174
|
-
} catch {
|
|
175
|
-
return []
|
|
176
|
-
}
|
|
177
|
-
const matches = []
|
|
178
|
-
for (const name of entries) {
|
|
179
|
-
const sub = join(dir, name)
|
|
180
|
-
try {
|
|
181
|
-
if (statSync(sub).isDirectory()) matches.push(sub)
|
|
182
|
-
} catch {
|
|
183
|
-
/* skip unreadable entries */
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
return matches
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* Boolean OR-merge of two capability records. Any flag true in either
|
|
191
|
-
* input is true in the output. The "Electron wins over web" rule from
|
|
192
|
-
* `detectFromPackageJson` is preserved when this is called repeatedly —
|
|
193
|
-
* each child's flags are honest about that child's own shape, and the
|
|
194
|
-
* OR-merge just unions them.
|
|
195
|
-
*
|
|
196
|
-
* @param {RuntimeCapabilities} a
|
|
197
|
-
* @param {RuntimeCapabilities} b
|
|
198
|
-
* @returns {RuntimeCapabilities}
|
|
17
|
+
* @typedef {import('../util/runtime-capabilities.mjs').RuntimeCapabilities} RuntimeCapabilities
|
|
199
18
|
*/
|
|
200
|
-
function orMergeCapabilities(a, b) {
|
|
201
|
-
return {
|
|
202
|
-
is_electron: a.is_electron || b.is_electron,
|
|
203
|
-
is_tauri: a.is_tauri || b.is_tauri,
|
|
204
|
-
is_nextjs: a.is_nextjs || b.is_nextjs,
|
|
205
|
-
is_nuxt: a.is_nuxt || b.is_nuxt,
|
|
206
|
-
is_web_frontend: a.is_web_frontend || b.is_web_frontend,
|
|
207
|
-
is_expo: a.is_expo || b.is_expo,
|
|
208
|
-
is_react_native: a.is_react_native || b.is_react_native,
|
|
209
|
-
has_node: a.has_node || b.has_node,
|
|
210
|
-
}
|
|
211
|
-
}
|