@guilz-dev/belay 0.4.0 → 0.7.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/README.md +27 -2
- package/dist/adapters/claude/runtime-entry.js +54 -25
- package/dist/adapters/layouts/scope.js +3 -2
- package/dist/adapters/shared/gate-runtime.d.ts +8 -2
- package/dist/adapters/shared/gate-runtime.js +579 -181
- package/dist/bundle/claude-runtime.mjs +13574 -6334
- package/dist/bundle/codex-runtime.mjs +13108 -5903
- package/dist/bundle/cursor-runtime.mjs +12676 -5476
- package/dist/cli.js +80 -2
- package/dist/commands/approve.js +34 -10
- package/dist/commands/classify-for-report.js +1 -1
- package/dist/commands/config.d.ts +8 -0
- package/dist/commands/config.js +134 -11
- package/dist/commands/doctor.js +87 -1
- package/dist/commands/explain.js +11 -1
- package/dist/commands/judge.js +3 -2
- package/dist/commands/recovery-checkpoints.d.ts +164 -0
- package/dist/commands/recovery-checkpoints.js +347 -0
- package/dist/commands/revoke.js +19 -7
- package/dist/commands/session.d.ts +20 -0
- package/dist/commands/session.js +51 -0
- package/dist/commands/status.js +7 -0
- package/dist/config-io.js +91 -23
- package/dist/conformance/guarantee-posture.d.ts +21 -0
- package/dist/conformance/guarantee-posture.js +46 -0
- package/dist/conformance/guarantee-table.d.ts +1 -0
- package/dist/conformance/guarantee-table.js +20 -9
- package/dist/conformance/types.d.ts +1 -0
- package/dist/core/approval-replay.d.ts +1 -1
- package/dist/core/approval-replay.js +4 -1
- package/dist/core/approval-service.d.ts +6 -1
- package/dist/core/approval-service.js +87 -24
- package/dist/core/approval.d.ts +4 -0
- package/dist/core/approval.js +19 -5
- package/dist/core/audit-types.d.ts +13 -0
- package/dist/core/capability/approval-state-mutation.d.ts +32 -0
- package/dist/core/capability/approval-state-mutation.js +165 -0
- package/dist/core/capability/approval-v3.d.ts +32 -0
- package/dist/core/capability/approval-v3.js +114 -0
- package/dist/core/capability/attestation.d.ts +16 -0
- package/dist/core/capability/attestation.js +62 -0
- package/dist/core/capability/boundary-attestation-sign.d.ts +21 -0
- package/dist/core/capability/boundary-attestation-sign.js +84 -0
- package/dist/core/capability/boundary-driver-container.d.ts +19 -0
- package/dist/core/capability/boundary-driver-container.js +189 -0
- package/dist/core/capability/boundary-driver.d.ts +29 -0
- package/dist/core/capability/boundary-driver.js +44 -0
- package/dist/core/capability/boundary-egress.d.ts +21 -0
- package/dist/core/capability/boundary-egress.js +109 -0
- package/dist/core/capability/boundary-grant-materialize.d.ts +14 -0
- package/dist/core/capability/boundary-grant-materialize.js +93 -0
- package/dist/core/capability/boundary-profile.d.ts +15 -0
- package/dist/core/capability/boundary-profile.js +25 -0
- package/dist/core/capability/boundary-run.d.ts +48 -0
- package/dist/core/capability/boundary-run.js +51 -0
- package/dist/core/capability/boundary-session.d.ts +61 -0
- package/dist/core/capability/boundary-session.js +138 -0
- package/dist/core/capability/boundary-workspace-mount.d.ts +5 -0
- package/dist/core/capability/boundary-workspace-mount.js +68 -0
- package/dist/core/capability/capability-request-hash.d.ts +2 -0
- package/dist/core/capability/capability-request-hash.js +8 -0
- package/dist/core/capability/gate-latency-ratchet.d.ts +7 -0
- package/dist/core/capability/gate-latency-ratchet.js +18 -0
- package/dist/core/capability/gate-policy-shadow.d.ts +25 -0
- package/dist/core/capability/gate-policy-shadow.js +130 -0
- package/dist/core/capability/gate-shadow-audit.d.ts +1 -0
- package/dist/core/capability/gate-shadow-audit.js +1 -0
- package/dist/core/capability/gate-shadow-ratchet.d.ts +14 -0
- package/dist/core/capability/gate-shadow-ratchet.js +81 -0
- package/dist/core/capability/grant-consumption.d.ts +4 -0
- package/dist/core/capability/grant-consumption.js +11 -0
- package/dist/core/capability/grant-lease.d.ts +44 -0
- package/dist/core/capability/grant-lease.js +243 -0
- package/dist/core/capability/grant-loader.d.ts +12 -0
- package/dist/core/capability/grant-loader.js +23 -0
- package/dist/core/capability/grant-match.d.ts +6 -0
- package/dist/core/capability/grant-match.js +96 -0
- package/dist/core/capability/grant.d.ts +16 -0
- package/dist/core/capability/grant.js +16 -0
- package/dist/core/capability/index.d.ts +8 -0
- package/dist/core/capability/index.js +7 -0
- package/dist/core/capability/limits.d.ts +7 -0
- package/dist/core/capability/limits.js +55 -0
- package/dist/core/capability/policy-bridge.d.ts +18 -0
- package/dist/core/capability/policy-bridge.js +51 -0
- package/dist/core/capability/policy-engine.d.ts +77 -0
- package/dist/core/capability/policy-engine.js +663 -0
- package/dist/core/capability/policy-types.d.ts +20 -0
- package/dist/core/capability/policy-types.js +1 -0
- package/dist/core/capability/request.d.ts +48 -0
- package/dist/core/capability/request.js +1 -0
- package/dist/core/capability/resolver.d.ts +4 -0
- package/dist/core/capability/resolver.js +4 -0
- package/dist/core/classify-subagent.d.ts +2 -1
- package/dist/core/classify-subagent.js +38 -2
- package/dist/core/classify-tool.js +126 -62
- package/dist/core/config.d.ts +34 -3
- package/dist/core/config.js +118 -3
- package/dist/core/effect-ir/audit.d.ts +9 -0
- package/dist/core/effect-ir/audit.js +86 -0
- package/dist/core/effect-ir/build.d.ts +31 -0
- package/dist/core/effect-ir/build.js +277 -0
- package/dist/core/effect-ir/index.d.ts +8 -0
- package/dist/core/effect-ir/index.js +7 -0
- package/dist/core/effect-ir/normalize.d.ts +4 -0
- package/dist/core/effect-ir/normalize.js +104 -0
- package/dist/core/effect-ir/package-exec-eval.d.ts +8 -0
- package/dist/core/effect-ir/package-exec-eval.js +152 -0
- package/dist/core/effect-ir/package-exec.d.ts +29 -0
- package/dist/core/effect-ir/package-exec.js +292 -0
- package/dist/core/effect-ir/policy.d.ts +13 -0
- package/dist/core/effect-ir/policy.js +77 -0
- package/dist/core/effect-ir/types.d.ts +55 -0
- package/dist/core/effect-ir/types.js +1 -0
- package/dist/core/egress/allowlist.d.ts +1 -0
- package/dist/core/egress/allowlist.js +8 -0
- package/dist/core/egress-approval.js +45 -51
- package/dist/core/gate-contract.d.ts +5 -0
- package/dist/core/gate-contract.js +5 -0
- package/dist/core/gate-engine.js +30 -8
- package/dist/core/index.d.ts +3 -1
- package/dist/core/index.js +2 -1
- package/dist/core/judge-cloud-consent.js +29 -15
- package/dist/core/judge-doctor.js +39 -14
- package/dist/core/judge-fallback-hints.d.ts +13 -0
- package/dist/core/judge-fallback-hints.js +108 -0
- package/dist/core/network-endpoint.d.ts +10 -0
- package/dist/core/network-endpoint.js +51 -0
- package/dist/core/path-utils.d.ts +1 -0
- package/dist/core/path-utils.js +5 -2
- package/dist/core/process-runner.d.ts +10 -0
- package/dist/core/process-runner.js +124 -0
- package/dist/core/recover-advice.js +2 -1
- package/dist/core/recovery/artifact-store.d.ts +29 -0
- package/dist/core/recovery/artifact-store.js +336 -0
- package/dist/core/recovery/capability.d.ts +3 -0
- package/dist/core/recovery/capability.js +22 -0
- package/dist/core/recovery/checkpoint.d.ts +25 -0
- package/dist/core/recovery/checkpoint.js +260 -0
- package/dist/core/recovery/fail-closed.d.ts +6 -0
- package/dist/core/recovery/fail-closed.js +25 -0
- package/dist/core/recovery/index.d.ts +5 -0
- package/dist/core/recovery/index.js +4 -0
- package/dist/core/recovery/operator-guidance.d.ts +7 -0
- package/dist/core/recovery/operator-guidance.js +39 -0
- package/dist/core/recovery/reconcile.d.ts +3 -0
- package/dist/core/recovery/reconcile.js +48 -0
- package/dist/core/recovery/resource-identity.d.ts +4 -0
- package/dist/core/recovery/resource-identity.js +34 -0
- package/dist/core/recovery/restore.d.ts +13 -0
- package/dist/core/recovery/restore.js +114 -0
- package/dist/core/recovery/snapshot-node.d.ts +27 -0
- package/dist/core/recovery/snapshot-node.js +261 -0
- package/dist/core/recovery/types.d.ts +104 -0
- package/dist/core/recovery/types.js +1 -0
- package/dist/core/standing-allow.js +3 -0
- package/dist/core/transactional/apply-observed-changes.d.ts +13 -0
- package/dist/core/transactional/apply-observed-changes.js +275 -0
- package/dist/core/transactional/backend-selector.d.ts +8 -0
- package/dist/core/transactional/backend-selector.js +118 -0
- package/dist/core/transactional/backend.d.ts +55 -0
- package/dist/core/transactional/backend.js +1 -0
- package/dist/core/transactional/diff-evaluator.js +4 -1
- package/dist/core/transactional/eligibility.js +4 -0
- package/dist/core/transactional/file-checkpoint-backend.d.ts +3 -0
- package/dist/core/transactional/file-checkpoint-backend.js +278 -0
- package/dist/core/transactional/file-checkpoint-git.d.ts +11 -0
- package/dist/core/transactional/file-checkpoint-git.js +217 -0
- package/dist/core/transactional/file-checkpoint-staging.d.ts +13 -0
- package/dist/core/transactional/file-checkpoint-staging.js +54 -0
- package/dist/core/transactional/file-clone.d.ts +15 -0
- package/dist/core/transactional/file-clone.js +139 -0
- package/dist/core/transactional/file-tree-path.d.ts +7 -0
- package/dist/core/transactional/file-tree-path.js +50 -0
- package/dist/core/transactional/file-tree.d.ts +41 -0
- package/dist/core/transactional/file-tree.js +186 -0
- package/dist/core/transactional/git-worktree-backend.d.ts +2 -0
- package/dist/core/transactional/git-worktree-backend.js +50 -0
- package/dist/core/transactional/git-worktree.d.ts +14 -9
- package/dist/core/transactional/git-worktree.js +62 -87
- package/dist/core/transactional/index.d.ts +11 -0
- package/dist/core/transactional/index.js +10 -0
- package/dist/core/transactional/reasons.d.ts +1 -0
- package/dist/core/transactional/reasons.js +5 -0
- package/dist/core/transactional/runner.js +171 -23
- package/dist/core/transactional/snapshot-node.d.ts +26 -0
- package/dist/core/transactional/snapshot-node.js +87 -0
- package/dist/core/transactional/types.d.ts +21 -1
- package/dist/core/types.d.ts +30 -3
- package/dist/core/verdict/adapter.d.ts +3 -4
- package/dist/core/verdict/adapter.js +24 -12
- package/dist/core/verdict/cursor-acp-client.d.ts +67 -0
- package/dist/core/verdict/cursor-acp-client.js +345 -0
- package/dist/core/verdict/egress-classify.d.ts +2 -2
- package/dist/core/verdict/egress-classify.js +2 -2
- package/dist/core/verdict/git-classifier.d.ts +26 -0
- package/dist/core/verdict/git-classifier.js +533 -0
- package/dist/core/verdict/judge-audit.js +1 -0
- package/dist/core/verdict/judge-baseline.d.ts +1 -1
- package/dist/core/verdict/judge-baseline.js +1 -0
- package/dist/core/verdict/judge-broker-service.js +12 -0
- package/dist/core/verdict/judge-catalog.js +1 -0
- package/dist/core/verdict/judge-cli-fingerprint.d.ts +1 -0
- package/dist/core/verdict/judge-cli-fingerprint.js +6 -0
- package/dist/core/verdict/judge-cli.js +5 -3
- package/dist/core/verdict/judge-provider-matrix.js +1 -1
- package/dist/core/verdict/judge-runtime-config.d.ts +2 -0
- package/dist/core/verdict/judge-runtime-config.js +10 -6
- package/dist/core/verdict/judge-session-broker.d.ts +1 -1
- package/dist/core/verdict/judge-session-broker.js +10 -5
- package/dist/core/verdict/judge-transport.d.ts +5 -1
- package/dist/core/verdict/judge-transport.js +24 -14
- package/dist/core/verdict/judge.d.ts +2 -15
- package/dist/core/verdict/judge.js +5 -68
- package/dist/core/verdict/launcher-resolve.d.ts +2 -0
- package/dist/core/verdict/launcher-resolve.js +14 -16
- package/dist/core/verdict/prescan.d.ts +15 -0
- package/dist/core/verdict/prescan.js +68 -0
- package/dist/core/verdict/shell-policy.d.ts +26 -0
- package/dist/core/verdict/shell-policy.js +40 -0
- package/dist/core/verdict/shell-semantics.d.ts +24 -0
- package/dist/core/verdict/shell-semantics.js +225 -0
- package/dist/core/verdict/types.d.ts +18 -1
- package/dist/core/verdict/verdict.js +313 -178
- package/dist/corpus/evaluate.js +3 -7
- package/dist/corpus/gate-latency-budget.d.ts +39 -0
- package/dist/corpus/gate-latency-budget.js +33 -0
- package/dist/corpus/mutators.d.ts +1 -1
- package/dist/corpus/mutators.js +11 -0
- package/dist/corpus/runtime-match.js +1 -3
- package/dist/corpus/standing-allow-catalog.generated.js +29 -9
- package/dist/judge-broker-daemon.js +15 -1
- package/dist/services/sandbox-service.d.ts +4 -0
- package/dist/services/sandbox-service.js +28 -2
- package/dist/types.d.ts +13 -2
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/skills/belay/SKILL.md +8 -3
- package/skills/belay/belay-approve.md +10 -7
package/dist/corpus/evaluate.js
CHANGED
|
@@ -3,7 +3,6 @@ import path from 'node:path';
|
|
|
3
3
|
import { fileURLToPath } from 'node:url';
|
|
4
4
|
import { classifierOptionsFromConfig, DEFAULT_CONFIG_V3 } from '../core/config.js';
|
|
5
5
|
import { classifyShell } from '../core/verdict/adapter.js';
|
|
6
|
-
import { createDeterministicJudgeStub } from '../core/verdict/judge.js';
|
|
7
6
|
import { computeCategoryGates, isMustAskMiss, } from './gates.js';
|
|
8
7
|
import { defaultCorpusEvalPaths, enrichProvablyBenignRuntimeKeys } from './runtime-match.js';
|
|
9
8
|
import { countByCategory, countProvenanceBySource, parseCorpusCases, } from './types.js';
|
|
@@ -31,9 +30,8 @@ export async function evaluateCorpus(cases, repoRoot = defaultCorpusEvalPaths().
|
|
|
31
30
|
for (const expected of VERDICTS) {
|
|
32
31
|
confusion[expected] = { allow: 0, allow_flagged: 0, deny_pending_approval: 0 };
|
|
33
32
|
}
|
|
34
|
-
const judge = createDeterministicJudgeStub();
|
|
35
33
|
for (const testCase of cases) {
|
|
36
|
-
const result = await classifyShell(testCase.command, cwd, repoRoot, DEFAULT_CONFIG_V3, options
|
|
34
|
+
const result = await classifyShell(testCase.command, cwd, repoRoot, DEFAULT_CONFIG_V3, options);
|
|
37
35
|
results.push({ actual: result.verdict, reason: result.reason });
|
|
38
36
|
confusion[testCase.verdict][result.verdict] += 1;
|
|
39
37
|
const verdictOk = result.verdict === testCase.verdict;
|
|
@@ -83,10 +81,9 @@ export async function runCorpusEvaluation(corpusDir) {
|
|
|
83
81
|
export async function evaluateCommandBatch(cases, repoRoot = defaultCorpusEvalPaths().repoRoot) {
|
|
84
82
|
const { cwd } = defaultCorpusEvalPaths(repoRoot);
|
|
85
83
|
const options = classifierOptionsFromConfig(DEFAULT_CONFIG_V3);
|
|
86
|
-
const judge = createDeterministicJudgeStub();
|
|
87
84
|
const results = [];
|
|
88
85
|
for (const testCase of cases) {
|
|
89
|
-
const result = await classifyShell(testCase.command, cwd, repoRoot, DEFAULT_CONFIG_V3, options
|
|
86
|
+
const result = await classifyShell(testCase.command, cwd, repoRoot, DEFAULT_CONFIG_V3, options);
|
|
90
87
|
const isFn = isMustAskMiss({
|
|
91
88
|
category: 'must-ask',
|
|
92
89
|
command: testCase.command,
|
|
@@ -109,10 +106,9 @@ export async function evaluateCommandBatch(cases, repoRoot = defaultCorpusEvalPa
|
|
|
109
106
|
export async function evaluateFpCommandBatch(cases, repoRoot = defaultCorpusEvalPaths().repoRoot) {
|
|
110
107
|
const { cwd } = defaultCorpusEvalPaths(repoRoot);
|
|
111
108
|
const options = classifierOptionsFromConfig(DEFAULT_CONFIG_V3);
|
|
112
|
-
const judge = createDeterministicJudgeStub();
|
|
113
109
|
const results = [];
|
|
114
110
|
for (const testCase of cases) {
|
|
115
|
-
const result = await classifyShell(testCase.command, cwd, repoRoot, DEFAULT_CONFIG_V3, options
|
|
111
|
+
const result = await classifyShell(testCase.command, cwd, repoRoot, DEFAULT_CONFIG_V3, options);
|
|
116
112
|
results.push({
|
|
117
113
|
command: testCase.command,
|
|
118
114
|
actual: result.verdict,
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gate sync classification latency budgets (measured baselines + CI thresholds).
|
|
3
|
+
* PLAN target: p95 <= 100ms, max <= 500ms for full corpus — ratchet toward these over time.
|
|
4
|
+
*/
|
|
5
|
+
/** Warm local corpus run (2026-08-06). Step 3 uses max(measured × 1.2, Step 1 floor); floors dominate until re-measured and lowered. */
|
|
6
|
+
export declare const GATE_LATENCY_MEASURED_BASELINE: {
|
|
7
|
+
readonly shell: {
|
|
8
|
+
readonly p95Ms: 1;
|
|
9
|
+
readonly maxMs: 1;
|
|
10
|
+
};
|
|
11
|
+
readonly tool: {
|
|
12
|
+
readonly p95Ms: 1;
|
|
13
|
+
readonly maxMs: 1;
|
|
14
|
+
};
|
|
15
|
+
readonly subagent: {
|
|
16
|
+
readonly p95Ms: 7;
|
|
17
|
+
readonly maxMs: 7;
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
/** Step 3 CI thresholds: max(measured p95 × 1.2, Step 1 floor). */
|
|
21
|
+
export declare const GATE_LATENCY_BUDGET: {
|
|
22
|
+
readonly shell: {
|
|
23
|
+
p95Ms: number;
|
|
24
|
+
maxMs: number;
|
|
25
|
+
};
|
|
26
|
+
readonly tool: {
|
|
27
|
+
p95Ms: number;
|
|
28
|
+
maxMs: number;
|
|
29
|
+
};
|
|
30
|
+
readonly subagent: {
|
|
31
|
+
p95Ms: number;
|
|
32
|
+
maxMs: number;
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
/** PLAN acceptance targets (quality-loop ratchet goal). */
|
|
36
|
+
export declare const GATE_LATENCY_PLAN_TARGET: {
|
|
37
|
+
readonly p95Ms: 100;
|
|
38
|
+
readonly maxMs: 500;
|
|
39
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gate sync classification latency budgets (measured baselines + CI thresholds).
|
|
3
|
+
* PLAN target: p95 <= 100ms, max <= 500ms for full corpus — ratchet toward these over time.
|
|
4
|
+
*/
|
|
5
|
+
/** Warm local corpus run (2026-08-06). Step 3 uses max(measured × 1.2, Step 1 floor); floors dominate until re-measured and lowered. */
|
|
6
|
+
export const GATE_LATENCY_MEASURED_BASELINE = {
|
|
7
|
+
shell: { p95Ms: 1, maxMs: 1 },
|
|
8
|
+
tool: { p95Ms: 1, maxMs: 1 },
|
|
9
|
+
subagent: { p95Ms: 7, maxMs: 7 },
|
|
10
|
+
};
|
|
11
|
+
/** Step 1 rollout floors — CI thresholds stay at these until measured × 1.2 exceeds them. */
|
|
12
|
+
const GATE_LATENCY_STEP1_FLOOR = {
|
|
13
|
+
shell: { p95Ms: 200, maxMs: 1000 },
|
|
14
|
+
tool: { p95Ms: 300, maxMs: 1500 },
|
|
15
|
+
subagent: { p95Ms: 200, maxMs: 1000 },
|
|
16
|
+
};
|
|
17
|
+
function ciBudgetFromBaseline(baseline, floor) {
|
|
18
|
+
return {
|
|
19
|
+
p95Ms: Math.max(floor.p95Ms, Math.ceil(baseline.p95Ms * 1.2)),
|
|
20
|
+
maxMs: Math.max(floor.maxMs, Math.ceil(baseline.maxMs * 1.2)),
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
/** Step 3 CI thresholds: max(measured p95 × 1.2, Step 1 floor). */
|
|
24
|
+
export const GATE_LATENCY_BUDGET = {
|
|
25
|
+
shell: ciBudgetFromBaseline(GATE_LATENCY_MEASURED_BASELINE.shell, GATE_LATENCY_STEP1_FLOOR.shell),
|
|
26
|
+
tool: ciBudgetFromBaseline(GATE_LATENCY_MEASURED_BASELINE.tool, GATE_LATENCY_STEP1_FLOOR.tool),
|
|
27
|
+
subagent: ciBudgetFromBaseline(GATE_LATENCY_MEASURED_BASELINE.subagent, GATE_LATENCY_STEP1_FLOOR.subagent),
|
|
28
|
+
};
|
|
29
|
+
/** PLAN acceptance targets (quality-loop ratchet goal). */
|
|
30
|
+
export const GATE_LATENCY_PLAN_TARGET = {
|
|
31
|
+
p95Ms: 100,
|
|
32
|
+
maxMs: 500,
|
|
33
|
+
};
|
|
@@ -18,7 +18,7 @@ export interface MutatedCase {
|
|
|
18
18
|
command: string;
|
|
19
19
|
}
|
|
20
20
|
/** Must-ask catastrophic cores used as mutation seeds. */
|
|
21
|
-
export declare const CATASTROPHIC_CORES: readonly ["rm -rf .git", "git push --force", "dropdb prod", "npm publish", "aws s3 rm s3://bucket/key", "terraform apply", "rm -rf ~"];
|
|
21
|
+
export declare const CATASTROPHIC_CORES: readonly ["rm -rf .git", "git push --force", "git reset --hard", "git clean -fdx", "dropdb prod", "npm publish", "aws s3 rm s3://bucket/key", "terraform apply", "rm -rf ~"];
|
|
22
22
|
/** Phase A initial set — conservative semantics-preserving mutators only. */
|
|
23
23
|
export declare const AUTO_LABEL_MUTATORS: readonly CommandMutator[];
|
|
24
24
|
/** Structural probes and promotion candidates — not used for auto-label in Phase A. */
|
package/dist/corpus/mutators.js
CHANGED
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
export const CATASTROPHIC_CORES = [
|
|
9
9
|
'rm -rf .git',
|
|
10
10
|
'git push --force',
|
|
11
|
+
'git reset --hard',
|
|
12
|
+
'git clean -fdx',
|
|
11
13
|
'dropdb prod',
|
|
12
14
|
'npm publish',
|
|
13
15
|
'aws s3 rm s3://bucket/key',
|
|
@@ -120,6 +122,14 @@ const xargsProbe = {
|
|
|
120
122
|
tests: ['structural-suite MUST-ASK catastrophic bypass equivalence'],
|
|
121
123
|
apply: (core) => `xargs ${core} <<< ''`,
|
|
122
124
|
};
|
|
125
|
+
const findExecProbe = {
|
|
126
|
+
id: 'find_exec',
|
|
127
|
+
purpose: 'find -exec invocation probe',
|
|
128
|
+
preservesSemantics: 'Not semantics-preserving — find -exec changes execution context',
|
|
129
|
+
forbiddenWhen: 'Always probe-only; do not auto-label',
|
|
130
|
+
tests: ['structural-suite MUST-ASK catastrophic bypass equivalence'],
|
|
131
|
+
apply: (core) => `find . -name '*.tmp' -exec ${core} {} \\;`,
|
|
132
|
+
};
|
|
123
133
|
/** Structural probes and promotion candidates — not used for auto-label in Phase A. */
|
|
124
134
|
export const STRUCTURAL_PROBES = [
|
|
125
135
|
nohup,
|
|
@@ -130,6 +140,7 @@ export const STRUCTURAL_PROBES = [
|
|
|
130
140
|
base64PipeSh,
|
|
131
141
|
pythonPipe,
|
|
132
142
|
xargsProbe,
|
|
143
|
+
findExecProbe,
|
|
133
144
|
];
|
|
134
145
|
/** All wrappers for structural-suite catastrophic bypass tests. */
|
|
135
146
|
export const ALL_STRUCTURAL_WRAPPERS = [
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { classifierOptionsFromConfig, DEFAULT_CONFIG_V3 } from '../core/config.js';
|
|
3
3
|
import { classifyShell } from '../core/verdict/adapter.js';
|
|
4
|
-
import { createDeterministicJudgeStub } from '../core/verdict/judge.js';
|
|
5
4
|
import { CorpusSchemaError } from './types.js';
|
|
6
5
|
/** Fixed evaluation harness paths — keep in sync with `evaluateCorpus`. */
|
|
7
6
|
export const DEFAULT_CORPUS_REPO_ROOT = '/workspace/project';
|
|
@@ -14,8 +13,7 @@ export function defaultCorpusEvalPaths(repoRoot = DEFAULT_CORPUS_REPO_ROOT) {
|
|
|
14
13
|
*/
|
|
15
14
|
export async function deriveShellCorpusRuntimeKey(command, repoRoot = DEFAULT_CORPUS_REPO_ROOT, cwd = path.join(repoRoot, 'src')) {
|
|
16
15
|
const options = classifierOptionsFromConfig(DEFAULT_CONFIG_V3);
|
|
17
|
-
const
|
|
18
|
-
const result = await classifyShell(command, cwd, repoRoot, DEFAULT_CONFIG_V3, options, judge);
|
|
16
|
+
const result = await classifyShell(command, cwd, repoRoot, DEFAULT_CONFIG_V3, options);
|
|
19
17
|
return result.fingerprint;
|
|
20
18
|
}
|
|
21
19
|
/**
|
|
@@ -7,6 +7,16 @@ export const STANDING_ALLOW_CATALOG = {
|
|
|
7
7
|
normalizedCommand: 'git status',
|
|
8
8
|
runtimeKey: '37e6be21e63e6268ee6e4212ad811f6f48ab3c3c10ce1b971c1a90d92c753a2a',
|
|
9
9
|
},
|
|
10
|
+
{
|
|
11
|
+
command: 'git branch',
|
|
12
|
+
normalizedCommand: 'git branch',
|
|
13
|
+
runtimeKey: 'd7f8388c566e751503ab82ba1ed22787389803eb32d8b5f2294cc7ca448fa285',
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
command: 'git branch --show-current',
|
|
17
|
+
normalizedCommand: 'git branch --show-current',
|
|
18
|
+
runtimeKey: '98d585412d3cd7c3b5a87a417d91bc36d7b6791e11451b52ced7888e003d9d33',
|
|
19
|
+
},
|
|
10
20
|
{
|
|
11
21
|
command: 'rg plan src',
|
|
12
22
|
normalizedCommand: 'rg plan src',
|
|
@@ -23,19 +33,29 @@ export const STANDING_ALLOW_CATALOG = {
|
|
|
23
33
|
runtimeKey: '782298e3015fcb9c17bee2dad12a395a8859043481f93f0ca596499028bb8af2',
|
|
24
34
|
},
|
|
25
35
|
{
|
|
26
|
-
command: '
|
|
27
|
-
normalizedCommand: '
|
|
28
|
-
runtimeKey: '
|
|
36
|
+
command: 'git -C /workspace/project status',
|
|
37
|
+
normalizedCommand: 'git -C /workspace/project status',
|
|
38
|
+
runtimeKey: '9f88bd017c52277f5dbfeafec7d845460035a7a14bfb37b55724d7e2a9fc238b',
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
command: 'git show-ref --heads',
|
|
42
|
+
normalizedCommand: 'git show-ref --heads',
|
|
43
|
+
runtimeKey: 'aa5aa0106dc7647003f254524becbf549673610d3672f28408ac0f60481124b7',
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
command: 'git reflog -5',
|
|
47
|
+
normalizedCommand: 'git reflog -5',
|
|
48
|
+
runtimeKey: '9213a9357953c24886a4e82c2c8cdc6db2d106c7ff98af525f7fbc2b70a58ff9',
|
|
29
49
|
},
|
|
30
50
|
{
|
|
31
|
-
command: '
|
|
32
|
-
normalizedCommand: '
|
|
33
|
-
runtimeKey: '
|
|
51
|
+
command: 'grep -R pattern src',
|
|
52
|
+
normalizedCommand: 'grep -R pattern src',
|
|
53
|
+
runtimeKey: '40f5e0328e668909241aa0cd13ce2a51af269aa7ae600cc493dceae7b90dd9d8',
|
|
34
54
|
},
|
|
35
55
|
{
|
|
36
|
-
command: '
|
|
37
|
-
normalizedCommand: '
|
|
38
|
-
runtimeKey: '
|
|
56
|
+
command: 'jq . package.json',
|
|
57
|
+
normalizedCommand: 'jq . package.json',
|
|
58
|
+
runtimeKey: 'dd7b14d350b84a41e0e73eae0d1a643c1b6c262df8d9007696987354f4f993e9',
|
|
39
59
|
},
|
|
40
60
|
],
|
|
41
61
|
mustAllow: [
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { mkdir, readFile, unlink, writeFile } from 'node:fs/promises';
|
|
2
2
|
import { createServer } from 'node:net';
|
|
3
3
|
import path from 'node:path';
|
|
4
|
+
import { CursorAcpJudgeRunner } from './core/verdict/cursor-acp-client.js';
|
|
4
5
|
import { cleanupJudgeBrokerArtifacts, JUDGE_BROKER_SESSION, judgeBrokerPaths, } from './core/verdict/judge-broker-service.js';
|
|
5
6
|
import { runCliJsonWithTimeouts } from './core/verdict/judge-cli.js';
|
|
6
7
|
import { DEFAULT_JUDGE_SESSION_CONFIG, normalizeJudgeSessionConfig, resolveSessionEvalTimeoutMs, } from './core/verdict/judge-runtime-config.js';
|
|
@@ -27,9 +28,21 @@ async function main() {
|
|
|
27
28
|
await mkdir(stateDir, { recursive: true, mode: 0o700 });
|
|
28
29
|
const sessionConfig = await loadBrokerSessionConfig(stateDir);
|
|
29
30
|
const defaultEvalTimeoutMs = resolveSessionEvalTimeoutMs(sessionConfig, 25_000);
|
|
31
|
+
const judgeWorkspace = path.join(stateDir, 'judge-workspace');
|
|
32
|
+
await mkdir(judgeWorkspace, { recursive: true, mode: 0o700 });
|
|
33
|
+
const cursorAcp = new CursorAcpJudgeRunner({
|
|
34
|
+
cwd: judgeWorkspace,
|
|
35
|
+
connectTimeoutMs: sessionConfig.connectTimeoutMs,
|
|
36
|
+
});
|
|
30
37
|
const broker = new JudgeSessionBroker({
|
|
31
38
|
config: sessionConfig,
|
|
32
|
-
runCommand: (invocation, timeoutMs) =>
|
|
39
|
+
runCommand: (invocation, timeoutMs) => {
|
|
40
|
+
if (invocation.binary === 'cursor-agent') {
|
|
41
|
+
return cursorAcp.run(invocation, timeoutMs);
|
|
42
|
+
}
|
|
43
|
+
return runCliJsonWithTimeouts(invocation, { evalTimeoutMs: timeoutMs });
|
|
44
|
+
},
|
|
45
|
+
extractResumeId: (providerId) => (providerId === 'cursor' ? cursorAcp.sessionId : null),
|
|
33
46
|
});
|
|
34
47
|
let idleTimer = null;
|
|
35
48
|
let server;
|
|
@@ -43,6 +56,7 @@ async function main() {
|
|
|
43
56
|
};
|
|
44
57
|
const shutdown = async (reason) => {
|
|
45
58
|
broker.stopAll('manual_stop');
|
|
59
|
+
await cursorAcp.stop();
|
|
46
60
|
server?.close();
|
|
47
61
|
await cleanupJudgeBrokerArtifacts(paths);
|
|
48
62
|
process.stderr.write(`judge broker stopped (${reason})\n`);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { loadConfigFile } from '../config-io.js';
|
|
2
|
+
import { evaluateGuaranteePosture } from '../conformance/guarantee-posture.js';
|
|
2
3
|
export interface SandboxServiceOptions {
|
|
3
4
|
targetDir?: string;
|
|
4
5
|
}
|
|
@@ -12,6 +13,7 @@ export interface SandboxStatusReport {
|
|
|
12
13
|
controlPlaneIsolationMode: string;
|
|
13
14
|
controlPlaneIsolationOk: boolean;
|
|
14
15
|
l1FullActive: boolean;
|
|
16
|
+
guaranteePosture: ReturnType<typeof evaluateGuaranteePosture>;
|
|
15
17
|
l1Full: {
|
|
16
18
|
sandbox: boolean;
|
|
17
19
|
egress: boolean;
|
|
@@ -20,6 +22,8 @@ export interface SandboxStatusReport {
|
|
|
20
22
|
approvalSigningRequired: boolean;
|
|
21
23
|
};
|
|
22
24
|
issues: string[];
|
|
25
|
+
/** Quality-loop ratchet hints — do not affect sandbox status exit code. */
|
|
26
|
+
advisories: string[];
|
|
23
27
|
}
|
|
24
28
|
export declare function sandboxStatus(options?: SandboxServiceOptions): Promise<SandboxStatusReport>;
|
|
25
29
|
export declare function createCapabilityApprovalStore(repoRoot: string, config: Awaited<ReturnType<typeof loadConfigFile>>): {
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { loadConfigFile, repoLocalStateDirFor } from '../config-io.js';
|
|
3
|
+
import { evaluateGuaranteePosture } from '../conformance/guarantee-posture.js';
|
|
3
4
|
import { fsScopeAllowlistPath, loadFsScopeAllowlist } from '../core/capability/allowlist.js';
|
|
5
|
+
import { boundaryAttestationPath, loadBoundaryAttestation, } from '../core/capability/boundary-session.js';
|
|
4
6
|
import { evaluateL1FullStatus, isCapabilityBrokerDemotionActive, } from '../core/capability/broker.js';
|
|
7
|
+
import { evaluateGateLatencyRatchetAdvisories } from '../core/capability/gate-latency-ratchet.js';
|
|
8
|
+
import { loadShadowRatchetWarnings } from '../core/capability/gate-shadow-ratchet.js';
|
|
5
9
|
import { trustedWorkspaceRootsPath } from '../core/capability/trusted-workspace-roots.js';
|
|
6
|
-
import { configuredControlPlaneDir } from '../core/config.js';
|
|
10
|
+
import { belayStateDir, configuredControlPlaneDir } from '../core/config.js';
|
|
7
11
|
import { verifyControlPlaneIsolation } from '../core/control-plane-isolation.js';
|
|
8
12
|
import { egressStatus } from './egress-service.js';
|
|
9
13
|
export async function sandboxStatus(options = {}) {
|
|
@@ -14,10 +18,18 @@ export async function sandboxStatus(options = {}) {
|
|
|
14
18
|
const allowlist = await loadFsScopeAllowlist(allowlistPath);
|
|
15
19
|
const egress = await egressStatus({ targetDir: repoRoot });
|
|
16
20
|
const isolation = verifyControlPlaneIsolation(configuredControlPlaneDir(config), config.controlPlane.isolation);
|
|
21
|
+
const egressProxyRunning = egress.running && !egress.foreignProxy && !egress.repoRootMismatch;
|
|
17
22
|
const l1Full = evaluateL1FullStatus({
|
|
18
23
|
config,
|
|
19
|
-
egressProxyRunning
|
|
24
|
+
egressProxyRunning,
|
|
20
25
|
});
|
|
26
|
+
const attestation = await loadBoundaryAttestation(boundaryAttestationPath(repoRoot, config), repoRoot, configuredControlPlaneDir(config));
|
|
27
|
+
const guaranteePosture = evaluateGuaranteePosture({
|
|
28
|
+
config,
|
|
29
|
+
attestation,
|
|
30
|
+
egressProxyRunning,
|
|
31
|
+
});
|
|
32
|
+
const shadowRatchetWarnings = await loadShadowRatchetWarnings(belayStateDir(config, repoLocalStateDir));
|
|
21
33
|
const issues = [...isolation.issues];
|
|
22
34
|
if (config.sandbox.enabled && config.sandbox.runtime === 'none') {
|
|
23
35
|
issues.push('sandbox.enabled is true but sandbox.runtime is none');
|
|
@@ -31,6 +43,10 @@ export async function sandboxStatus(options = {}) {
|
|
|
31
43
|
if (l1Full.sandbox && !l1Full.approvalSigningRequired) {
|
|
32
44
|
issues.push('L1-full requires approvalSigning.required=true');
|
|
33
45
|
}
|
|
46
|
+
if (guaranteePosture.postureMismatch) {
|
|
47
|
+
issues.push(`L1-full is configured but attestation only supports ${guaranteePosture.attestedProfile} (run belay session start)`);
|
|
48
|
+
}
|
|
49
|
+
const advisories = [...evaluateGateLatencyRatchetAdvisories(), ...shadowRatchetWarnings];
|
|
34
50
|
return {
|
|
35
51
|
repoRoot,
|
|
36
52
|
sandboxEnabled: config.sandbox.enabled,
|
|
@@ -41,8 +57,10 @@ export async function sandboxStatus(options = {}) {
|
|
|
41
57
|
controlPlaneIsolationMode: config.controlPlane.isolation.mode,
|
|
42
58
|
controlPlaneIsolationOk: isolation.ok,
|
|
43
59
|
l1FullActive: l1Full.active,
|
|
60
|
+
guaranteePosture,
|
|
44
61
|
l1Full,
|
|
45
62
|
issues,
|
|
63
|
+
advisories,
|
|
46
64
|
};
|
|
47
65
|
}
|
|
48
66
|
export function createCapabilityApprovalStore(repoRoot, config) {
|
|
@@ -84,6 +102,8 @@ export function formatSandboxStatusReport(report) {
|
|
|
84
102
|
`FS-scope allowlist entries: ${report.fsScopeAllowlistCount}`,
|
|
85
103
|
`Control-plane isolation: ${report.controlPlaneIsolationMode} (ok=${report.controlPlaneIsolationOk})`,
|
|
86
104
|
`L1-full active: ${report.l1FullActive}`,
|
|
105
|
+
`Guarantee posture: configured=${report.guaranteePosture.configuredProfile} attested=${report.guaranteePosture.attestedProfile}`,
|
|
106
|
+
` attestationFresh=${report.guaranteePosture.attestationFresh} l1FullConfigured=${report.guaranteePosture.l1FullConfigured} l1FullAttested=${report.guaranteePosture.l1FullAttested}`,
|
|
87
107
|
` sandbox=${report.l1Full.sandbox} egress=${report.l1Full.egress} proxy=${report.l1Full.egressProxyRunning}`,
|
|
88
108
|
` isolation=${report.l1Full.controlPlaneIsolation} signing=${report.l1Full.approvalSigningRequired}`,
|
|
89
109
|
];
|
|
@@ -93,5 +113,11 @@ export function formatSandboxStatusReport(report) {
|
|
|
93
113
|
lines.push(` - ${issue}`);
|
|
94
114
|
}
|
|
95
115
|
}
|
|
116
|
+
if (report.advisories.length > 0) {
|
|
117
|
+
lines.push('Advisories:');
|
|
118
|
+
for (const advisory of report.advisories) {
|
|
119
|
+
lines.push(` - ${advisory}`);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
96
122
|
return `${lines.join('\n')}\n`;
|
|
97
123
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export type { BelayConfig, BelayConfigV1, BelayConfigV2, BelayConfigV3, BelayControlPlaneConfig, BelayEgressConfig,
|
|
2
|
-
export type { ApprovalRecord, ApprovalStateFile, Assessment, ClassifyResult, HookVerdict, } from './core/types.js';
|
|
1
|
+
export type { BelayConfig, BelayConfigV1, BelayConfigV2, BelayConfigV3, BelayControlPlaneConfig, BelayEgressConfig, BelayOverridesConfig, BelayPolicyConfig, BelayRedactionConfig, BelaySandboxConfig, BelayTransactionalConfig, UnknownLocalEffectPolicy, } from './core/config.js';
|
|
2
|
+
export type { ApprovalRecord, ApprovalStateFile, Assessment, BelayMode, ClassifyResult, HookVerdict, } from './core/types.js';
|
|
3
3
|
import type { InstallScope } from './adapters/layouts/scope.js';
|
|
4
4
|
import type { RecentAskEntry } from './core/audit-summary.js';
|
|
5
5
|
import type { BelayEgressConfig, BelayOverridesConfig, BelayPolicyConfig, BelaySandboxConfig } from './core/config.js';
|
|
@@ -138,6 +138,17 @@ export interface StatusReport {
|
|
|
138
138
|
dogfood: DogfoodStatus;
|
|
139
139
|
health: HealthSnapshot;
|
|
140
140
|
visibility: AuditVisibilityReport;
|
|
141
|
+
fileCheckpoint: {
|
|
142
|
+
enabled: boolean;
|
|
143
|
+
allowNonGit: boolean;
|
|
144
|
+
transactionalEnabled: boolean;
|
|
145
|
+
durableCheckpointEnabled: boolean;
|
|
146
|
+
maxFiles: number;
|
|
147
|
+
maxSourceBytes: number;
|
|
148
|
+
maxWorkspaceBytes: number;
|
|
149
|
+
prepareTimeoutMs: number;
|
|
150
|
+
copyConcurrency: number;
|
|
151
|
+
};
|
|
141
152
|
}
|
|
142
153
|
export interface ReportOptions {
|
|
143
154
|
targetDir?: string;
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const PACKAGE_VERSION = "0.
|
|
1
|
+
export declare const PACKAGE_VERSION = "0.7.0";
|
package/dist/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Generated by scripts/sync-version.mjs — do not edit.
|
|
2
|
-
export const PACKAGE_VERSION = '0.
|
|
2
|
+
export const PACKAGE_VERSION = '0.7.0';
|
package/package.json
CHANGED
package/skills/belay/SKILL.md
CHANGED
|
@@ -37,9 +37,14 @@ setup (or `npx @guilz-dev/belay init` for non-interactive install). Run
|
|
|
37
37
|
## When belay blocks an action
|
|
38
38
|
|
|
39
39
|
1. Read the approval ID in the deny message.
|
|
40
|
-
2.
|
|
41
|
-
3.
|
|
42
|
-
|
|
40
|
+
2. In the editor, approve once with `/belay-approve <approval-id>`.
|
|
41
|
+
3. With default `approval.flow: one_step`, editor approval atomically claims the one-shot grant and
|
|
42
|
+
replays the exact denied shell action through the configured boundary driver. No follow-up prompt
|
|
43
|
+
is required. Failed or timed-out replay requires fresh approval. Tool and subagent actions still
|
|
44
|
+
require retrying the original action unchanged.
|
|
45
|
+
|
|
46
|
+
An instruction may follow the approval line in the same prompt. Belay runs the approved shell action
|
|
47
|
+
first and continues the remaining prompt only after replay succeeds.
|
|
43
48
|
|
|
44
49
|
For shell-only CLI replay after approval: `belay approve <approval-id> --replay`.
|
|
45
50
|
|
|
@@ -1,21 +1,24 @@
|
|
|
1
1
|
Run after belay denies a high-risk action and returns an approval ID.
|
|
2
2
|
|
|
3
|
-
```
|
|
4
|
-
belay
|
|
3
|
+
```text
|
|
4
|
+
/belay-approve <approval-id>
|
|
5
5
|
```
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
With default `approval.flow: one_step`, the editor hook atomically claims the one-shot grant and
|
|
8
|
+
immediately replays the exact denied shell action through the configured boundary driver. No
|
|
9
|
+
follow-up prompt is required. Failed or timed-out replay requires fresh approval. Tool and subagent
|
|
10
|
+
approvals still require a manual retry of the original action unchanged.
|
|
8
11
|
|
|
9
|
-
|
|
10
|
-
|
|
12
|
+
An instruction may follow the approval line in the same prompt. Belay runs the approved shell action
|
|
13
|
+
first and continues the remaining prompt only after replay succeeds.
|
|
11
14
|
|
|
12
|
-
|
|
15
|
+
For CLI approval, replay remains explicit:
|
|
13
16
|
|
|
14
17
|
```bash
|
|
15
18
|
belay approve <approval-id> --replay
|
|
16
19
|
```
|
|
17
20
|
|
|
18
|
-
|
|
21
|
+
CLI replay claims the one-shot grant before execution. Failure or timeout requires fresh approval.
|
|
19
22
|
|
|
20
23
|
Restore legacy two-step UX in `belay.config.json`:
|
|
21
24
|
|