@aperant/framework 0.10.0 → 0.12.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 +236 -1
- package/agents/apt-planner.md +15 -0
- package/agents/apt-verifier.md +15 -10
- package/bin/apt-proof-video.mjs +256 -76
- package/dist/cli/commands/apply-recipe.d.mts +6 -0
- package/dist/cli/commands/apply-recipe.d.mts.map +1 -0
- package/dist/cli/commands/apply-recipe.mjs +98 -0
- package/dist/cli/commands/apply-recipe.mjs.map +1 -0
- package/dist/cli/commands/catch-up.d.mts +9 -0
- package/dist/cli/commands/catch-up.d.mts.map +1 -0
- package/dist/cli/commands/catch-up.mjs +64 -0
- package/dist/cli/commands/catch-up.mjs.map +1 -0
- package/dist/cli/commands/mobile-prepare.d.mts +53 -0
- package/dist/cli/commands/mobile-prepare.d.mts.map +1 -0
- package/dist/cli/commands/mobile-prepare.mjs +139 -0
- package/dist/cli/commands/mobile-prepare.mjs.map +1 -0
- package/dist/cli/commands/pr-review.d.mts +16 -4
- package/dist/cli/commands/pr-review.d.mts.map +1 -1
- package/dist/cli/commands/pr-review.mjs +30 -11
- package/dist/cli/commands/pr-review.mjs.map +1 -1
- package/dist/cli/commands/recipe-diff.d.mts +6 -0
- package/dist/cli/commands/recipe-diff.d.mts.map +1 -0
- package/dist/cli/commands/recipe-diff.mjs +75 -0
- package/dist/cli/commands/recipe-diff.mjs.map +1 -0
- package/dist/cli/commands/roadmap.d.mts.map +1 -1
- package/dist/cli/commands/roadmap.mjs +53 -0
- package/dist/cli/commands/roadmap.mjs.map +1 -1
- package/dist/cli/commands/route.d.mts.map +1 -1
- package/dist/cli/commands/route.mjs +92 -2
- package/dist/cli/commands/route.mjs.map +1 -1
- package/dist/cli/commands/verify-sandbox.d.mts +6 -0
- package/dist/cli/commands/verify-sandbox.d.mts.map +1 -0
- package/dist/cli/commands/verify-sandbox.mjs +200 -0
- package/dist/cli/commands/verify-sandbox.mjs.map +1 -0
- package/dist/cli/config/share-policy.d.mts.map +1 -1
- package/dist/cli/config/share-policy.mjs +1 -0
- package/dist/cli/config/share-policy.mjs.map +1 -1
- package/dist/cli/config/upgrade-gitignore.d.mts.map +1 -1
- package/dist/cli/config/upgrade-gitignore.mjs +1 -0
- package/dist/cli/config/upgrade-gitignore.mjs.map +1 -1
- package/dist/cli/consistency/parse-qa.d.mts.map +1 -1
- package/dist/cli/consistency/parse-qa.mjs +18 -4
- package/dist/cli/consistency/parse-qa.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 +11 -10
- package/dist/cli/consistency/rules/r5-verdict-consistency.mjs.map +1 -1
- package/dist/cli/coordination/catch-up.d.mts +26 -0
- package/dist/cli/coordination/catch-up.d.mts.map +1 -0
- package/dist/cli/coordination/catch-up.mjs +239 -0
- package/dist/cli/coordination/catch-up.mjs.map +1 -0
- package/dist/cli/coordination/last-seen.d.mts +45 -0
- package/dist/cli/coordination/last-seen.d.mts.map +1 -0
- package/dist/cli/coordination/last-seen.mjs +128 -0
- package/dist/cli/coordination/last-seen.mjs.map +1 -0
- package/dist/cli/coordination/store.d.mts +15 -0
- package/dist/cli/coordination/store.d.mts.map +1 -1
- package/dist/cli/coordination/store.mjs +16 -0
- package/dist/cli/coordination/store.mjs.map +1 -1
- package/dist/cli/coverage-check/user-outcomes.d.mts +7 -2
- package/dist/cli/coverage-check/user-outcomes.d.mts.map +1 -1
- package/dist/cli/coverage-check/user-outcomes.mjs +50 -17
- package/dist/cli/coverage-check/user-outcomes.mjs.map +1 -1
- package/dist/cli/dispatch.d.mts.map +1 -1
- package/dist/cli/dispatch.mjs +30 -0
- package/dist/cli/dispatch.mjs.map +1 -1
- package/dist/cli/gate/gates/verify-approved.d.mts +0 -48
- package/dist/cli/gate/gates/verify-approved.d.mts.map +1 -1
- package/dist/cli/gate/gates/verify-approved.mjs +23 -80
- package/dist/cli/gate/gates/verify-approved.mjs.map +1 -1
- package/dist/cli/git/default-branch.d.mts +51 -0
- package/dist/cli/git/default-branch.d.mts.map +1 -0
- package/dist/cli/git/default-branch.mjs +234 -0
- package/dist/cli/git/default-branch.mjs.map +1 -0
- package/dist/cli/git/identity.d.mts +3 -5
- package/dist/cli/git/identity.d.mts.map +1 -1
- package/dist/cli/git/identity.mjs +10 -4
- package/dist/cli/git/identity.mjs.map +1 -1
- package/dist/cli/install/legacy-paths.d.mts.map +1 -1
- package/dist/cli/install/legacy-paths.mjs +2 -0
- package/dist/cli/install/legacy-paths.mjs.map +1 -1
- package/dist/cli/install/mcp-server-specs.d.mts +6 -5
- package/dist/cli/install/mcp-server-specs.d.mts.map +1 -1
- package/dist/cli/install/mcp-server-specs.mjs +22 -4
- package/dist/cli/install/mcp-server-specs.mjs.map +1 -1
- package/dist/cli/roadmap/backend-adapter.d.mts +43 -0
- package/dist/cli/roadmap/backend-adapter.d.mts.map +1 -0
- package/dist/cli/roadmap/backend-adapter.mjs +222 -0
- package/dist/cli/roadmap/backend-adapter.mjs.map +1 -0
- package/dist/cli/util/runtime-capabilities.d.mts +7 -0
- package/dist/cli/util/runtime-capabilities.d.mts.map +1 -1
- package/dist/cli/util/runtime-capabilities.mjs +65 -0
- package/dist/cli/util/runtime-capabilities.mjs.map +1 -1
- package/dist/cli/verify-proof/manifest-validator.mjs +13 -0
- package/dist/cli/verify-proof/manifest-validator.mjs.map +1 -1
- package/dist/cli/verify-proof/resolver.d.mts +10 -7
- package/dist/cli/verify-proof/resolver.d.mts.map +1 -1
- package/dist/cli/verify-proof/resolver.mjs +28 -7
- package/dist/cli/verify-proof/resolver.mjs.map +1 -1
- package/dist/cli/verify-proof/sandbox/apply.d.mts +64 -0
- package/dist/cli/verify-proof/sandbox/apply.d.mts.map +1 -0
- package/dist/cli/verify-proof/sandbox/apply.mjs +379 -0
- package/dist/cli/verify-proof/sandbox/apply.mjs.map +1 -0
- package/dist/cli/verify-proof/sandbox/gate-predicate.d.mts +63 -0
- package/dist/cli/verify-proof/sandbox/gate-predicate.d.mts.map +1 -0
- package/dist/cli/verify-proof/sandbox/gate-predicate.mjs +115 -0
- package/dist/cli/verify-proof/sandbox/gate-predicate.mjs.map +1 -0
- package/dist/cli/verify-proof/sandbox/pattern-matcher.d.mts +57 -0
- package/dist/cli/verify-proof/sandbox/pattern-matcher.d.mts.map +1 -0
- package/dist/cli/verify-proof/sandbox/pattern-matcher.mjs +124 -0
- package/dist/cli/verify-proof/sandbox/pattern-matcher.mjs.map +1 -0
- package/dist/cli/verify-proof/sandbox/recipe-diff.d.mts +28 -0
- package/dist/cli/verify-proof/sandbox/recipe-diff.d.mts.map +1 -0
- package/dist/cli/verify-proof/sandbox/recipe-diff.mjs +190 -0
- package/dist/cli/verify-proof/sandbox/recipe-diff.mjs.map +1 -0
- package/dist/cli/verify-proof/sandbox/sandbox-config.d.mts +25 -0
- package/dist/cli/verify-proof/sandbox/sandbox-config.d.mts.map +1 -0
- package/dist/cli/verify-proof/sandbox/sandbox-config.mjs +85 -0
- package/dist/cli/verify-proof/sandbox/sandbox-config.mjs.map +1 -0
- package/dist/cli/verify-proof/sandbox/self-test.d.mts +39 -0
- package/dist/cli/verify-proof/sandbox/self-test.d.mts.map +1 -0
- package/dist/cli/verify-proof/sandbox/self-test.mjs +248 -0
- package/dist/cli/verify-proof/sandbox/self-test.mjs.map +1 -0
- package/dist/plugin/.claude-plugin/plugin.json +2 -1
- package/dist/plugin/agents/apt-planner.md +15 -0
- package/dist/plugin/agents/apt-verifier.md +15 -10
- package/dist/plugin/skills/apt/SKILL.md +29 -0
- package/dist/plugin/skills/apt-catch-up/SKILL.md +79 -0
- package/dist/plugin/skills/apt-plan/SKILL.md +23 -0
- package/dist/plugin/skills/apt-pr-review/SKILL.md +5 -4
- package/dist/plugin/skills/apt-run/SKILL.md +1 -1
- package/dist/plugin/skills/apt-setup/SKILL.md +132 -0
- package/dist/plugin/skills/apt-verify/SKILL.md +20 -15
- package/dist/plugin/skills/apt-verify-proof/SKILL.md +146 -11
- package/dist/proof-report.d.ts.map +1 -1
- package/dist/proof-report.js +4 -1
- package/dist/proof-report.js.map +1 -1
- package/dist/types/config.d.ts +42 -4
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/qa-scoring.d.ts +45 -9
- package/dist/types/qa-scoring.d.ts.map +1 -1
- package/dist/types/qa-scoring.js +34 -13
- package/dist/types/qa-scoring.js.map +1 -1
- package/dist/types/state.d.ts +7 -2
- package/dist/types/state.d.ts.map +1 -1
- package/dist/types/task-record.d.ts +10 -2
- package/dist/types/task-record.d.ts.map +1 -1
- package/drivers/mobile/README.md +40 -0
- package/drivers/mobile/driver.mjs +106 -0
- package/drivers/mobile/manifest.json +49 -0
- package/package.json +1 -1
- package/prompts/inbox-clarification.md +11 -0
- package/prompts/inbox-triage.md +20 -0
- package/prompts/qa_orchestrator_agentic.md +18 -17
- package/prompts/qa_reviewer.md +17 -15
- package/skills/apt/SKILL.md +29 -0
- package/skills/apt-catch-up/SKILL.md +79 -0
- package/skills/apt-plan/SKILL.md +23 -0
- package/skills/apt-pr-review/SKILL.md +5 -4
- package/skills/apt-run/SKILL.md +1 -1
- package/skills/apt-setup/SKILL.md +132 -0
- package/skills/apt-verifier.md +7 -4
- package/skills/apt-verify/SKILL.md +20 -15
- package/skills/apt-verify-proof/SKILL.md +146 -11
- package/src/cli/commands/apply-recipe.mjs +105 -0
- package/src/cli/commands/catch-up.mjs +67 -0
- package/src/cli/commands/mobile-prepare.mjs +151 -0
- package/src/cli/commands/pr-review.mjs +32 -11
- package/src/cli/commands/recipe-diff.mjs +81 -0
- package/src/cli/commands/roadmap.mjs +54 -0
- package/src/cli/commands/route.mjs +92 -1
- package/src/cli/commands/verify-sandbox.mjs +231 -0
- package/src/cli/config/share-policy.mjs +1 -0
- package/src/cli/config/upgrade-gitignore.mjs +1 -0
- package/src/cli/consistency/parse-qa.mjs +20 -4
- package/src/cli/consistency/rules/r5-verdict-consistency.mjs +11 -13
- package/src/cli/coordination/catch-up.mjs +231 -0
- package/src/cli/coordination/last-seen.mjs +131 -0
- package/src/cli/coordination/store.mjs +18 -0
- package/src/cli/coverage-check/user-outcomes.mjs +52 -17
- package/src/cli/dispatch.mjs +29 -0
- package/src/cli/gate/gates/verify-approved.mjs +22 -81
- package/src/cli/git/default-branch.mjs +250 -0
- package/src/cli/git/identity.mjs +9 -3
- package/src/cli/install/legacy-paths.mjs +2 -0
- package/src/cli/install/mcp-server-specs.mjs +24 -4
- package/src/cli/roadmap/backend-adapter.mjs +231 -0
- package/src/cli/util/runtime-capabilities.mjs +67 -0
- package/src/cli/verify-proof/manifest-validator.mjs +15 -0
- package/src/cli/verify-proof/resolver.mjs +27 -7
- package/src/cli/verify-proof/sandbox/apply.mjs +401 -0
- package/src/cli/verify-proof/sandbox/gate-predicate.mjs +126 -0
- package/src/cli/verify-proof/sandbox/pattern-matcher.mjs +127 -0
- package/src/cli/verify-proof/sandbox/recipe-diff.mjs +208 -0
- package/src/cli/verify-proof/sandbox/sandbox-config.mjs +82 -0
- package/src/cli/verify-proof/sandbox/sandbox-schema.json +33 -0
- package/src/cli/verify-proof/sandbox/self-test.mjs +265 -0
- package/templates/config.json +21 -1
- package/templates/proof-verification.md +27 -8
- package/workflows/verify-proof.md +376 -302
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {import('../../util/runtime-capabilities.mjs').RuntimeCapabilities} RuntimeCapabilities
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* @typedef {Object} SandboxRecipe
|
|
6
|
+
* @property {string} recipeId
|
|
7
|
+
* @property {string} recipeVersion
|
|
8
|
+
* @property {string} name
|
|
9
|
+
* @property {string} description
|
|
10
|
+
* @property {{capabilities: string[], deps: string[]}} match
|
|
11
|
+
* @property {{logPattern: string, timeoutMs: number}} readiness
|
|
12
|
+
* @property {Array<object>} changes
|
|
13
|
+
* @property {string[]} compatibleWithApplied
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* @typedef {Object} MatchResult
|
|
17
|
+
* @property {string|null} recipeId
|
|
18
|
+
* @property {string} reason
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* @param {RuntimeCapabilities} runtimeCaps
|
|
22
|
+
* @param {Record<string, unknown> | null} packageJson
|
|
23
|
+
* @param {SandboxRecipe[]} recipes
|
|
24
|
+
* @returns {MatchResult}
|
|
25
|
+
*/
|
|
26
|
+
export function matchPattern(runtimeCaps: RuntimeCapabilities, packageJson: Record<string, unknown> | null, recipes: SandboxRecipe[]): MatchResult;
|
|
27
|
+
/**
|
|
28
|
+
* Convenience overload — load the project's package.json from disk.
|
|
29
|
+
*
|
|
30
|
+
* @param {string} projectDir
|
|
31
|
+
* @param {RuntimeCapabilities} runtimeCaps
|
|
32
|
+
* @param {SandboxRecipe[]} recipes
|
|
33
|
+
* @returns {MatchResult}
|
|
34
|
+
*/
|
|
35
|
+
export function matchPatternForProject(projectDir: string, runtimeCaps: RuntimeCapabilities, recipes: SandboxRecipe[]): MatchResult;
|
|
36
|
+
export type RuntimeCapabilities = import("../../util/runtime-capabilities.mjs").RuntimeCapabilities;
|
|
37
|
+
export type SandboxRecipe = {
|
|
38
|
+
recipeId: string;
|
|
39
|
+
recipeVersion: string;
|
|
40
|
+
name: string;
|
|
41
|
+
description: string;
|
|
42
|
+
match: {
|
|
43
|
+
capabilities: string[];
|
|
44
|
+
deps: string[];
|
|
45
|
+
};
|
|
46
|
+
readiness: {
|
|
47
|
+
logPattern: string;
|
|
48
|
+
timeoutMs: number;
|
|
49
|
+
};
|
|
50
|
+
changes: Array<object>;
|
|
51
|
+
compatibleWithApplied: string[];
|
|
52
|
+
};
|
|
53
|
+
export type MatchResult = {
|
|
54
|
+
recipeId: string | null;
|
|
55
|
+
reason: string;
|
|
56
|
+
};
|
|
57
|
+
//# sourceMappingURL=pattern-matcher.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pattern-matcher.d.mts","sourceRoot":"","sources":["../../../../src/cli/verify-proof/sandbox/pattern-matcher.mjs"],"names":[],"mappings":"AAuBA;;GAEG;AAEH;;;;;;;;;;GAUG;AAEH;;;;GAIG;AAEH;;;;;GAKG;AACH,0CALW,mBAAmB,eACnB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,WAC9B,aAAa,EAAE,GACb,WAAW,CA4BvB;AAED;;;;;;;GAOG;AACH,mDALW,MAAM,eACN,mBAAmB,WACnB,aAAa,EAAE,GACb,WAAW,CAavB;kCA1EY,OAAO,qCAAqC,EAAE,mBAAmB;;cAKhE,MAAM;mBACN,MAAM;UACN,MAAM;iBACN,MAAM;WACN;QAAC,YAAY,EAAE,MAAM,EAAE,CAAC;QAAC,IAAI,EAAE,MAAM,EAAE,CAAA;KAAC;eACxC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAC;aACvC,KAAK,CAAC,MAAM,CAAC;2BACb,MAAM,EAAE;;;cAKR,MAAM,GAAC,IAAI;YACX,MAAM"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pattern-matcher.mjs — sandbox-recipe pattern matcher.
|
|
3
|
+
*
|
|
4
|
+
* Walks the registered recipes' `match.capabilities[]` + `match.deps[]`
|
|
5
|
+
* predicates against the loaded runtime capabilities + package.json deps,
|
|
6
|
+
* and returns the FIRST matching recipe (or null with a human reason).
|
|
7
|
+
*
|
|
8
|
+
* Two-arg shape:
|
|
9
|
+
* - `match.capabilities[]` — every entry must be `true` on the
|
|
10
|
+
* RuntimeCapabilities record (AND semantics — all required).
|
|
11
|
+
* - `match.deps[]` — at least one entry must appear in the merged
|
|
12
|
+
* dependencies + devDependencies of the project's root package.json
|
|
13
|
+
* (OR semantics — any-of).
|
|
14
|
+
*
|
|
15
|
+
* This split lets a recipe say "I need is_electron AND one of
|
|
16
|
+
* [@libsql/client, better-sqlite3]" without enumerating every combination.
|
|
17
|
+
*
|
|
18
|
+
* See: spec ID-04 (v1 ships ONE recipe — electron-libsql), AC5.
|
|
19
|
+
*/
|
|
20
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
21
|
+
import { join, resolve } from 'node:path';
|
|
22
|
+
/**
|
|
23
|
+
* @typedef {import('../../util/runtime-capabilities.mjs').RuntimeCapabilities} RuntimeCapabilities
|
|
24
|
+
*/
|
|
25
|
+
/**
|
|
26
|
+
* @typedef {Object} SandboxRecipe
|
|
27
|
+
* @property {string} recipeId
|
|
28
|
+
* @property {string} recipeVersion
|
|
29
|
+
* @property {string} name
|
|
30
|
+
* @property {string} description
|
|
31
|
+
* @property {{capabilities: string[], deps: string[]}} match
|
|
32
|
+
* @property {{logPattern: string, timeoutMs: number}} readiness
|
|
33
|
+
* @property {Array<object>} changes
|
|
34
|
+
* @property {string[]} compatibleWithApplied
|
|
35
|
+
*/
|
|
36
|
+
/**
|
|
37
|
+
* @typedef {Object} MatchResult
|
|
38
|
+
* @property {string|null} recipeId
|
|
39
|
+
* @property {string} reason
|
|
40
|
+
*/
|
|
41
|
+
/**
|
|
42
|
+
* @param {RuntimeCapabilities} runtimeCaps
|
|
43
|
+
* @param {Record<string, unknown> | null} packageJson
|
|
44
|
+
* @param {SandboxRecipe[]} recipes
|
|
45
|
+
* @returns {MatchResult}
|
|
46
|
+
*/
|
|
47
|
+
export function matchPattern(runtimeCaps, packageJson, recipes) {
|
|
48
|
+
if (!Array.isArray(recipes) || recipes.length === 0) {
|
|
49
|
+
return { recipeId: null, reason: 'no recipes registered' };
|
|
50
|
+
}
|
|
51
|
+
const deps = mergedDeps(packageJson);
|
|
52
|
+
for (const recipe of recipes) {
|
|
53
|
+
const reqCaps = recipe.match?.capabilities ?? [];
|
|
54
|
+
const anyDeps = recipe.match?.deps ?? [];
|
|
55
|
+
const capsOk = reqCaps.every((cap) => runtimeCaps && runtimeCaps[cap] === true);
|
|
56
|
+
if (!capsOk)
|
|
57
|
+
continue;
|
|
58
|
+
// deps[] is any-of — recipe matches if at least one declared dep is in
|
|
59
|
+
// the project. An empty deps[] means "no dep constraint" (cap-only match).
|
|
60
|
+
const depsOk = anyDeps.length === 0 || anyDeps.some((d) => deps.has(d.toLowerCase()));
|
|
61
|
+
if (!depsOk)
|
|
62
|
+
continue;
|
|
63
|
+
return { recipeId: recipe.recipeId, reason: 'matched' };
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
recipeId: null,
|
|
67
|
+
reason: `no recipe available for runtime: ${describeRuntime(runtimeCaps)}`,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Convenience overload — load the project's package.json from disk.
|
|
72
|
+
*
|
|
73
|
+
* @param {string} projectDir
|
|
74
|
+
* @param {RuntimeCapabilities} runtimeCaps
|
|
75
|
+
* @param {SandboxRecipe[]} recipes
|
|
76
|
+
* @returns {MatchResult}
|
|
77
|
+
*/
|
|
78
|
+
export function matchPatternForProject(projectDir, runtimeCaps, recipes) {
|
|
79
|
+
const pkgPath = join(resolve(projectDir), 'package.json');
|
|
80
|
+
let pkg = null;
|
|
81
|
+
if (existsSync(pkgPath)) {
|
|
82
|
+
try {
|
|
83
|
+
pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
/* fall through with pkg=null */
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return matchPattern(runtimeCaps, pkg, recipes);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Build a Set of lowercased package names from dependencies + devDependencies.
|
|
93
|
+
*
|
|
94
|
+
* @param {Record<string, unknown> | null} packageJson
|
|
95
|
+
*/
|
|
96
|
+
function mergedDeps(packageJson) {
|
|
97
|
+
const out = new Set();
|
|
98
|
+
if (packageJson === null || typeof packageJson !== 'object')
|
|
99
|
+
return out;
|
|
100
|
+
const d = /** @type {Record<string, unknown>} */ (packageJson.dependencies);
|
|
101
|
+
const dd = /** @type {Record<string, unknown>} */ (packageJson.devDependencies);
|
|
102
|
+
if (d && typeof d === 'object')
|
|
103
|
+
for (const k of Object.keys(d))
|
|
104
|
+
out.add(k.toLowerCase());
|
|
105
|
+
if (dd && typeof dd === 'object')
|
|
106
|
+
for (const k of Object.keys(dd))
|
|
107
|
+
out.add(k.toLowerCase());
|
|
108
|
+
return out;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* One-line description of the detected runtime shape — used in the
|
|
112
|
+
* no-match reason so an adopter sees what the matcher saw.
|
|
113
|
+
*
|
|
114
|
+
* @param {RuntimeCapabilities} runtimeCaps
|
|
115
|
+
*/
|
|
116
|
+
function describeRuntime(runtimeCaps) {
|
|
117
|
+
if (!runtimeCaps || typeof runtimeCaps !== 'object')
|
|
118
|
+
return 'unknown';
|
|
119
|
+
const active = Object.keys(runtimeCaps).filter((k) => runtimeCaps[k] === true);
|
|
120
|
+
if (active.length === 0)
|
|
121
|
+
return 'no capabilities detected';
|
|
122
|
+
return active.join(', ');
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=pattern-matcher.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pattern-matcher.mjs","sourceRoot":"","sources":["../../../../src/cli/verify-proof/sandbox/pattern-matcher.mjs"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @param {{projectDir: string, recipeId: string, recipes: object[]}} args
|
|
3
|
+
* @returns {{
|
|
4
|
+
* format: 'markdown',
|
|
5
|
+
* body: string,
|
|
6
|
+
* changes: Array<{path: string, kind: string, summary: string}>,
|
|
7
|
+
* envelope: {status: 'ok'|'error', recipe_version: string|null, compatible: boolean}
|
|
8
|
+
* }}
|
|
9
|
+
*/
|
|
10
|
+
export function generateRecipeDiff({ projectDir, recipeId, recipes }: {
|
|
11
|
+
projectDir: string;
|
|
12
|
+
recipeId: string;
|
|
13
|
+
recipes: object[];
|
|
14
|
+
}): {
|
|
15
|
+
format: "markdown";
|
|
16
|
+
body: string;
|
|
17
|
+
changes: Array<{
|
|
18
|
+
path: string;
|
|
19
|
+
kind: string;
|
|
20
|
+
summary: string;
|
|
21
|
+
}>;
|
|
22
|
+
envelope: {
|
|
23
|
+
status: "ok" | "error";
|
|
24
|
+
recipe_version: string | null;
|
|
25
|
+
compatible: boolean;
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
//# sourceMappingURL=recipe-diff.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recipe-diff.d.mts","sourceRoot":"","sources":["../../../../src/cli/verify-proof/sandbox/recipe-diff.mjs"],"names":[],"mappings":"AA8CA;;;;;;;;GAQG;AACH,sEARW;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAC,GACvD;IACR,MAAM,EAAE,UAAU,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,KAAK,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAC,CAAC,CAAC;IAC9D,QAAQ,EAAE;QAAC,MAAM,EAAE,IAAI,GAAC,OAAO,CAAC;QAAC,cAAc,EAAE,MAAM,GAAC,IAAI,CAAC;QAAC,UAAU,EAAE,OAAO,CAAA;KAAC,CAAA;CACnF,CAuDH"}
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* recipe-diff.mjs — read-only Markdown diff generator for a recipe.
|
|
3
|
+
*
|
|
4
|
+
* Loads the recipe, walks `changes[]`, and emits a Markdown report
|
|
5
|
+
* enumerating every proposed write WITH `--- before` / `+++ after`
|
|
6
|
+
* blocks. The generator is pure read — it never writes to the adopter's
|
|
7
|
+
* tree (ID-02). The companion `apply-recipe` command is the only
|
|
8
|
+
* writer.
|
|
9
|
+
*
|
|
10
|
+
* Public contract:
|
|
11
|
+
* generateRecipeDiff({projectDir, recipeId, recipes}) → {
|
|
12
|
+
* format: 'markdown',
|
|
13
|
+
* body: string,
|
|
14
|
+
* changes: [{path, kind, summary}],
|
|
15
|
+
* envelope: {status, recipe_version, compatible}
|
|
16
|
+
* }
|
|
17
|
+
*
|
|
18
|
+
* The Markdown is user-facing and load-bearing — drift = golden-snapshot
|
|
19
|
+
* test failure by design (subtask 2.1 / TD-03).
|
|
20
|
+
*/
|
|
21
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
22
|
+
import { dirname, isAbsolute, join, relative, resolve } from 'node:path';
|
|
23
|
+
import { fileURLToPath } from 'node:url';
|
|
24
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
25
|
+
/**
|
|
26
|
+
* Defense-in-depth path-under-root check. Returns the validated absolute
|
|
27
|
+
* path or null when the candidate escapes the root. The diff generator
|
|
28
|
+
* surfaces a "template not found" envelope rather than throwing (read-
|
|
29
|
+
* only generator stays non-fatal).
|
|
30
|
+
*
|
|
31
|
+
* @param {string} rootAbs
|
|
32
|
+
* @param {string} relPath
|
|
33
|
+
* @returns {string|null}
|
|
34
|
+
*/
|
|
35
|
+
function safeJoinUnderRoot(rootAbs, relPath) {
|
|
36
|
+
if (typeof relPath !== 'string' || relPath.length === 0)
|
|
37
|
+
return null;
|
|
38
|
+
if (isAbsolute(relPath))
|
|
39
|
+
return null;
|
|
40
|
+
const candidate = resolve(rootAbs, relPath);
|
|
41
|
+
const rel = relative(rootAbs, candidate);
|
|
42
|
+
if (rel.startsWith('..') || isAbsolute(rel))
|
|
43
|
+
return null;
|
|
44
|
+
return candidate;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* @param {{projectDir: string, recipeId: string, recipes: object[]}} args
|
|
48
|
+
* @returns {{
|
|
49
|
+
* format: 'markdown',
|
|
50
|
+
* body: string,
|
|
51
|
+
* changes: Array<{path: string, kind: string, summary: string}>,
|
|
52
|
+
* envelope: {status: 'ok'|'error', recipe_version: string|null, compatible: boolean}
|
|
53
|
+
* }}
|
|
54
|
+
*/
|
|
55
|
+
export function generateRecipeDiff({ projectDir, recipeId, recipes }) {
|
|
56
|
+
const recipe = (recipes ?? []).find((r) => r && r.recipeId === recipeId);
|
|
57
|
+
if (!recipe) {
|
|
58
|
+
return {
|
|
59
|
+
format: 'markdown',
|
|
60
|
+
body: `# No recipe available\n\nrecipeId \`${recipeId}\` is not in the registered recipes list.\n`,
|
|
61
|
+
changes: [],
|
|
62
|
+
envelope: { status: 'error', recipe_version: null, compatible: false },
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
const adopterRoot = resolve(projectDir);
|
|
66
|
+
const changeRows = [];
|
|
67
|
+
const sections = [];
|
|
68
|
+
for (const change of recipe.changes ?? []) {
|
|
69
|
+
// Defense-in-depth: a malicious recipe could otherwise read
|
|
70
|
+
// arbitrary host files via `change.path: '../../etc/passwd'`. The
|
|
71
|
+
// diff generator is read-only but the read CONTENT lands in the
|
|
72
|
+
// emitted Markdown — refuse to enumerate paths outside root.
|
|
73
|
+
const targetAbs = safeJoinUnderRoot(adopterRoot, change.path);
|
|
74
|
+
if (targetAbs === null) {
|
|
75
|
+
sections.push(`## ${change.path}\n\n_(rejected: change.path escapes project root — recipe defect)_\n`);
|
|
76
|
+
changeRows.push({
|
|
77
|
+
path: change.path,
|
|
78
|
+
kind: change.kind,
|
|
79
|
+
summary: 'rejected (path escapes root)',
|
|
80
|
+
});
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
const exists = existsSync(targetAbs);
|
|
84
|
+
const before = exists ? safeReadFile(targetAbs) : '';
|
|
85
|
+
const after = renderAfter(change, recipe, adopterRoot);
|
|
86
|
+
const summary = renderChangeSummary(change, exists);
|
|
87
|
+
changeRows.push({ path: change.path, kind: change.kind, summary });
|
|
88
|
+
sections.push(renderChangeSection(change, before, after, exists));
|
|
89
|
+
}
|
|
90
|
+
const body = renderBody(recipe, sections);
|
|
91
|
+
return {
|
|
92
|
+
format: 'markdown',
|
|
93
|
+
body,
|
|
94
|
+
changes: changeRows,
|
|
95
|
+
envelope: {
|
|
96
|
+
status: 'ok',
|
|
97
|
+
recipe_version: recipe.recipeVersion ?? null,
|
|
98
|
+
compatible: true,
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
function renderBody(recipe, sections) {
|
|
103
|
+
const lines = [];
|
|
104
|
+
lines.push(`# Recipe diff: ${recipe.name ?? recipe.recipeId}`);
|
|
105
|
+
lines.push('');
|
|
106
|
+
lines.push(`**Recipe:** \`${recipe.recipeId}\` v${recipe.recipeVersion} ` +
|
|
107
|
+
`(compatibleWithApplied: ${JSON.stringify(recipe.compatibleWithApplied ?? [])})`);
|
|
108
|
+
lines.push('');
|
|
109
|
+
lines.push(recipe.description ?? '');
|
|
110
|
+
lines.push('');
|
|
111
|
+
lines.push(`This recipe proposes **${(recipe.changes ?? []).length}** changes.`);
|
|
112
|
+
lines.push('No file is written until you run `apt-tools apply-recipe . --confirm` ' +
|
|
113
|
+
'and accept each change individually.');
|
|
114
|
+
lines.push('');
|
|
115
|
+
for (const section of sections) {
|
|
116
|
+
lines.push(section);
|
|
117
|
+
lines.push('');
|
|
118
|
+
}
|
|
119
|
+
return lines.join('\n').replace(/\n{3,}/g, '\n\n');
|
|
120
|
+
}
|
|
121
|
+
function renderChangeSummary(change, exists) {
|
|
122
|
+
const verb = change.kind === 'file-create' ? 'create' : change.kind === 'json-merge' ? 'merge into' : 'edit';
|
|
123
|
+
const target = exists ? change.path : `${change.path} (new file)`;
|
|
124
|
+
return `${verb} ${target}`;
|
|
125
|
+
}
|
|
126
|
+
function renderChangeSection(change, before, after, exists) {
|
|
127
|
+
const lines = [];
|
|
128
|
+
lines.push(`## ${change.path}`);
|
|
129
|
+
lines.push('');
|
|
130
|
+
lines.push(`- kind: \`${change.kind}\``, `- marker: \`${change.marker ?? '(none)'}\``, `- target ${exists ? 'exists' : 'does not exist'} on disk`);
|
|
131
|
+
lines.push('');
|
|
132
|
+
lines.push('```diff');
|
|
133
|
+
const beforeBlock = before === '' ? '(empty / file does not exist)' : before;
|
|
134
|
+
for (const line of beforeBlock.split('\n'))
|
|
135
|
+
lines.push(`--- ${line}`);
|
|
136
|
+
lines.push('');
|
|
137
|
+
for (const line of after.split('\n'))
|
|
138
|
+
lines.push(`+++ ${line}`);
|
|
139
|
+
lines.push('```');
|
|
140
|
+
return lines.join('\n');
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Render the "after" content per change kind. For json-merge we stringify
|
|
144
|
+
* the patch payload; for text-insert / file-create we load the template
|
|
145
|
+
* from the recipe directory (when present).
|
|
146
|
+
*/
|
|
147
|
+
function renderAfter(change, recipe, adopterRoot) {
|
|
148
|
+
if (change.kind === 'json-merge') {
|
|
149
|
+
return JSON.stringify(change.after ?? {}, null, 2);
|
|
150
|
+
}
|
|
151
|
+
if (change.template) {
|
|
152
|
+
const tplPath = locateRecipeTemplate(recipe, change.template, adopterRoot);
|
|
153
|
+
if (tplPath && existsSync(tplPath)) {
|
|
154
|
+
return safeReadFile(tplPath);
|
|
155
|
+
}
|
|
156
|
+
return `(template not found on disk: ${change.template})`;
|
|
157
|
+
}
|
|
158
|
+
if (typeof change.after === 'string')
|
|
159
|
+
return change.after;
|
|
160
|
+
return '';
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Resolve a recipe template path relative to the framework's recipes/
|
|
164
|
+
* directory. The framework ships recipes at packages/framework/recipes/
|
|
165
|
+
* <id>/templates/. We compute the directory from this module's location
|
|
166
|
+
* so the resolver works regardless of cwd.
|
|
167
|
+
*/
|
|
168
|
+
function locateRecipeTemplate(recipe, templateName, _adopterRoot) {
|
|
169
|
+
// __dirname → packages/framework/src/cli/verify-proof/sandbox/
|
|
170
|
+
// → up four levels → packages/framework/
|
|
171
|
+
// Defense-in-depth: reject `../` escapes in templateName AND validate
|
|
172
|
+
// recipeId so a crafted id (e.g. '../../evil') cannot shift the anchor
|
|
173
|
+
// outside the framework root. discoverBundledRecipes() skips schema
|
|
174
|
+
// validation, so the ^[a-z][a-z0-9_-]*$ pattern may not have been enforced.
|
|
175
|
+
if (typeof recipe.recipeId !== 'string' || !/^[a-z][a-z0-9_-]*$/.test(recipe.recipeId)) {
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
const frameworkRoot = resolve(__dirname, '..', '..', '..', '..');
|
|
179
|
+
const templatesRoot = join(frameworkRoot, 'recipes', recipe.recipeId, 'templates');
|
|
180
|
+
return safeJoinUnderRoot(templatesRoot, templateName);
|
|
181
|
+
}
|
|
182
|
+
function safeReadFile(path) {
|
|
183
|
+
try {
|
|
184
|
+
return readFileSync(path, 'utf-8');
|
|
185
|
+
}
|
|
186
|
+
catch {
|
|
187
|
+
return '';
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
//# sourceMappingURL=recipe-diff.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recipe-diff.mjs","sourceRoot":"","sources":["../../../../src/cli/verify-proof/sandbox/recipe-diff.mjs"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve the framework's recipes directory at runtime. Works whether
|
|
3
|
+
* the module is loaded from source (packages/framework/src/...) or from
|
|
4
|
+
* the installed dist (.aperant/deps/node_modules/@aperant/framework/...).
|
|
5
|
+
*
|
|
6
|
+
* @returns {string}
|
|
7
|
+
*/
|
|
8
|
+
export function resolveRecipesDir(): string;
|
|
9
|
+
/**
|
|
10
|
+
* Walk the recipes/ directory and return every recipe.json that parses.
|
|
11
|
+
* Each entry is the raw recipe object (NOT validated — callers can
|
|
12
|
+
* call validateManifest if they need schema guarantees).
|
|
13
|
+
*
|
|
14
|
+
* @returns {Array<object>}
|
|
15
|
+
*/
|
|
16
|
+
export function discoverBundledRecipes(): Array<object>;
|
|
17
|
+
/**
|
|
18
|
+
* Read .aperant/config.json's verification.sandbox block, or null when
|
|
19
|
+
* absent / unparseable. Pure read — no defaults injected.
|
|
20
|
+
*
|
|
21
|
+
* @param {string} projectDir
|
|
22
|
+
* @returns {object|null}
|
|
23
|
+
*/
|
|
24
|
+
export function readSandboxConfig(projectDir: string): object | null;
|
|
25
|
+
//# sourceMappingURL=sandbox-config.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sandbox-config.d.mts","sourceRoot":"","sources":["../../../../src/cli/verify-proof/sandbox/sandbox-config.mjs"],"names":[],"mappings":"AA0BA;;;;;;GAMG;AACH,qCAFa,MAAM,CAMlB;AAED;;;;;;GAMG;AACH,0CAFa,KAAK,CAAC,MAAM,CAAC,CAiBzB;AAED;;;;;;GAMG;AACH,8CAHW,MAAM,GACJ,MAAM,GAAC,IAAI,CAavB"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* sandbox-config.mjs — central loader for sandbox recipes + the
|
|
3
|
+
* adopter's verification.sandbox config block.
|
|
4
|
+
*
|
|
5
|
+
* Two responsibilities:
|
|
6
|
+
*
|
|
7
|
+
* 1. discoverBundledRecipes() — walk packages/framework/recipes/<id>/
|
|
8
|
+
* and return every parseable recipe.json. Mirrors the bundled-
|
|
9
|
+
* drivers discovery pattern in commands/detect-runtime.mjs.
|
|
10
|
+
*
|
|
11
|
+
* 2. readSandboxConfig(projectDir) — read .aperant/config.json's
|
|
12
|
+
* verification.sandbox block (or null if absent). Pure read; no
|
|
13
|
+
* merge with config.local.json — sandbox state is shared, not
|
|
14
|
+
* per-device.
|
|
15
|
+
*
|
|
16
|
+
* Stays in src/cli/verify-proof/sandbox/ so consumers under that tree
|
|
17
|
+
* share one loader. The CLI commands (recipe-diff, apply-recipe,
|
|
18
|
+
* verify-sandbox) all import from here.
|
|
19
|
+
*/
|
|
20
|
+
import { existsSync, readdirSync, readFileSync } from 'node:fs';
|
|
21
|
+
import { dirname, join, resolve } from 'node:path';
|
|
22
|
+
import { fileURLToPath } from 'node:url';
|
|
23
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
24
|
+
/**
|
|
25
|
+
* Resolve the framework's recipes directory at runtime. Works whether
|
|
26
|
+
* the module is loaded from source (packages/framework/src/...) or from
|
|
27
|
+
* the installed dist (.aperant/deps/node_modules/@aperant/framework/...).
|
|
28
|
+
*
|
|
29
|
+
* @returns {string}
|
|
30
|
+
*/
|
|
31
|
+
export function resolveRecipesDir() {
|
|
32
|
+
// __dirname → packages/framework/src/cli/verify-proof/sandbox/
|
|
33
|
+
// → up four levels → packages/framework/
|
|
34
|
+
return resolve(__dirname, '..', '..', '..', '..', 'recipes');
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Walk the recipes/ directory and return every recipe.json that parses.
|
|
38
|
+
* Each entry is the raw recipe object (NOT validated — callers can
|
|
39
|
+
* call validateManifest if they need schema guarantees).
|
|
40
|
+
*
|
|
41
|
+
* @returns {Array<object>}
|
|
42
|
+
*/
|
|
43
|
+
export function discoverBundledRecipes() {
|
|
44
|
+
const dir = resolveRecipesDir();
|
|
45
|
+
if (!existsSync(dir))
|
|
46
|
+
return [];
|
|
47
|
+
const out = [];
|
|
48
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
49
|
+
if (!entry.isDirectory())
|
|
50
|
+
continue;
|
|
51
|
+
const recipePath = join(dir, entry.name, 'recipe.json');
|
|
52
|
+
if (!existsSync(recipePath))
|
|
53
|
+
continue;
|
|
54
|
+
try {
|
|
55
|
+
out.push(JSON.parse(readFileSync(recipePath, 'utf-8')));
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
/* skip malformed recipes */
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return out;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Read .aperant/config.json's verification.sandbox block, or null when
|
|
65
|
+
* absent / unparseable. Pure read — no defaults injected.
|
|
66
|
+
*
|
|
67
|
+
* @param {string} projectDir
|
|
68
|
+
* @returns {object|null}
|
|
69
|
+
*/
|
|
70
|
+
export function readSandboxConfig(projectDir) {
|
|
71
|
+
const path = join(resolve(projectDir), '.aperant', 'config.json');
|
|
72
|
+
if (!existsSync(path))
|
|
73
|
+
return null;
|
|
74
|
+
try {
|
|
75
|
+
const config = JSON.parse(readFileSync(path, 'utf-8'));
|
|
76
|
+
const v = config?.verification;
|
|
77
|
+
if (v === null || typeof v !== 'object')
|
|
78
|
+
return null;
|
|
79
|
+
return v.sandbox ?? null;
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=sandbox-config.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sandbox-config.mjs","sourceRoot":"","sources":["../../../../src/cli/verify-proof/sandbox/sandbox-config.mjs"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAC/D,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAExC,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;AAEzD;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB;IAChC,+DAA+D;IAC/D,yCAAyC;IACzC,OAAO,OAAO,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,CAAC,CAAA;AAC7D,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,sBAAsB;IACrC,MAAM,GAAG,GAAG,iBAAiB,EAAE,CAAA;IAC/B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,CAAA;IAC/B,MAAM,GAAG,GAAG,EAAE,CAAA;IACd,KAAK,MAAM,KAAK,IAAI,WAAW,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;QAC/D,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE;YAAE,SAAQ;QAClC,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,EAAE,aAAa,CAAC,CAAA;QACvD,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC;YAAE,SAAQ;QACrC,IAAI,CAAC;YACJ,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC,CAAA;QACxD,CAAC;QAAC,MAAM,CAAC;YACR,4BAA4B;QAC7B,CAAC;IACF,CAAC;IACD,OAAO,GAAG,CAAA;AACX,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,UAAU;IAC3C,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,UAAU,EAAE,aAAa,CAAC,CAAA;IACjE,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAA;IAClC,IAAI,CAAC;QACJ,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAA;QACtD,MAAM,CAAC,GAAG,MAAM,EAAE,YAAY,CAAA;QAC9B,IAAI,CAAC,KAAK,IAAI,IAAI,OAAO,CAAC,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAA;QACpD,OAAO,CAAC,CAAC,OAAO,IAAI,IAAI,CAAA;IACzB,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,IAAI,CAAA;IACZ,CAAC;AACF,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {Object} SelfTestVerdict
|
|
3
|
+
* @property {boolean} verified
|
|
4
|
+
* @property {'approved'|'needs_human'} verdict
|
|
5
|
+
* @property {null|'self_test_failed_sqlite_busy'|'self_test_failed_port_conflict'|'self_test_failed_app_init_timeout'} reason
|
|
6
|
+
* @property {number} durationMs
|
|
7
|
+
* @property {{A: ChildOutcome, B: ChildOutcome}} children
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* @typedef {Object} ChildOutcome
|
|
11
|
+
* @property {boolean} ready
|
|
12
|
+
* @property {string|null} failureReason
|
|
13
|
+
* @property {string} stderrTail
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* @param {{projectDir: string, recipeId: string, recipes: object[]}} args
|
|
17
|
+
* @returns {Promise<SelfTestVerdict>}
|
|
18
|
+
*/
|
|
19
|
+
export function runSelfTest({ projectDir, recipeId, recipes }: {
|
|
20
|
+
projectDir: string;
|
|
21
|
+
recipeId: string;
|
|
22
|
+
recipes: object[];
|
|
23
|
+
}): Promise<SelfTestVerdict>;
|
|
24
|
+
export type SelfTestVerdict = {
|
|
25
|
+
verified: boolean;
|
|
26
|
+
verdict: "approved" | "needs_human";
|
|
27
|
+
reason: null | "self_test_failed_sqlite_busy" | "self_test_failed_port_conflict" | "self_test_failed_app_init_timeout";
|
|
28
|
+
durationMs: number;
|
|
29
|
+
children: {
|
|
30
|
+
A: ChildOutcome;
|
|
31
|
+
B: ChildOutcome;
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
export type ChildOutcome = {
|
|
35
|
+
ready: boolean;
|
|
36
|
+
failureReason: string | null;
|
|
37
|
+
stderrTail: string;
|
|
38
|
+
};
|
|
39
|
+
//# sourceMappingURL=self-test.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"self-test.d.mts","sourceRoot":"","sources":["../../../../src/cli/verify-proof/sandbox/self-test.mjs"],"names":[],"mappings":"AAgCA;;;;;;;GAOG;AAEH;;;;;GAKG;AAEH;;;GAGG;AACH,+DAHW;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAC,GACvD,OAAO,CAAC,eAAe,CAAC,CA4CpC;;cA5Da,OAAO;aACP,UAAU,GAAC,aAAa;YACxB,IAAI,GAAC,8BAA8B,GAAC,gCAAgC,GAAC,mCAAmC;gBACxG,MAAM;cACN;QAAC,CAAC,EAAE,YAAY,CAAC;QAAC,CAAC,EAAE,YAAY,CAAA;KAAC;;;WAKlC,OAAO;mBACP,MAAM,GAAC,IAAI;gBACX,MAAM"}
|