mtech-ai-local-runner 0.1.86 → 0.1.87
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.
|
@@ -20,6 +20,75 @@ function record(value) {
|
|
|
20
20
|
? value
|
|
21
21
|
: undefined;
|
|
22
22
|
}
|
|
23
|
+
/** References only: never project approval payloads, lease tokens or arbitrary authored instructions. */
|
|
24
|
+
function continuationContext(taskPackage) {
|
|
25
|
+
let projectionTruncated = false;
|
|
26
|
+
const contract = record(taskPackage.contract) ?? {};
|
|
27
|
+
const workflow = record(contract.workflow_contract) ?? {};
|
|
28
|
+
const policy = record(contract.policy) ?? {};
|
|
29
|
+
const scalar = (value) => (typeof value === "string" && value.length <= 512)
|
|
30
|
+
|| (typeof value === "number" && Number.isFinite(value)) || typeof value === "boolean";
|
|
31
|
+
const pick = (value, fields) => {
|
|
32
|
+
const source = record(value) ?? {};
|
|
33
|
+
return Object.fromEntries(fields.filter(key => scalar(source[key])).map(key => [key, source[key]]));
|
|
34
|
+
};
|
|
35
|
+
const items = (value) => {
|
|
36
|
+
if (!Array.isArray(value)) {
|
|
37
|
+
if (value !== undefined)
|
|
38
|
+
projectionTruncated = true;
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
if (value.length > 64)
|
|
42
|
+
projectionTruncated = true;
|
|
43
|
+
return value.slice(0, 64);
|
|
44
|
+
};
|
|
45
|
+
const strings = (value) => {
|
|
46
|
+
const source = items(value);
|
|
47
|
+
const result = source?.filter((item) => typeof item === "string" && item.length <= 512);
|
|
48
|
+
if (source && result?.length !== source.length)
|
|
49
|
+
projectionTruncated = true;
|
|
50
|
+
return result;
|
|
51
|
+
};
|
|
52
|
+
const execution = record(taskPackage.execution);
|
|
53
|
+
const coverage = record(taskPackage.coverage);
|
|
54
|
+
const limitKeys = ["max_turns", "max_runtime_seconds", "max_estimated_cost_usd", "max_correction_rounds",
|
|
55
|
+
"max_iterations", "max_model_input_tokens", "max_model_output_tokens", "max_total_tokens"];
|
|
56
|
+
const context = {
|
|
57
|
+
...pick(contract.identity, ["work_item_id", "execution_actor_id", "environment"]),
|
|
58
|
+
contract: pick(contract, ["id", "content_fingerprint", "status"]),
|
|
59
|
+
delegation: pick(workflow, ["delegation_contract_id", "delegation_fingerprint", "delegation_revision", "acknowledgement_required"]),
|
|
60
|
+
selected_execution_units: strings(workflow.selected_execution_units),
|
|
61
|
+
allowed_execution_units: strings(workflow.allowed_execution_units),
|
|
62
|
+
blocked_execution_units: strings(workflow.blocked_execution_units),
|
|
63
|
+
policy: {
|
|
64
|
+
...pick(policy, ["environment", "policy_key", ...limitKeys]),
|
|
65
|
+
limits: pick(policy.limits, limitKeys),
|
|
66
|
+
allowed_local_actions: strings(policy.allowed_local_actions),
|
|
67
|
+
approval_required_actions: strings(policy.approval_required_actions),
|
|
68
|
+
prohibited_actions: strings(policy.prohibited_actions),
|
|
69
|
+
},
|
|
70
|
+
agent_limits: pick(record(taskPackage.agent_execution)?.limits, limitKeys),
|
|
71
|
+
iteration: pick(taskPackage.iteration, ["id", "number", "lease_expires_at"]),
|
|
72
|
+
decision_references: (items(taskPackage.decisions) ?? []).map(decision => pick(decision, ["id", "decision_key", "revision_number", "content_fingerprint"])),
|
|
73
|
+
...(execution ? { execution: pick(execution, ["mode", "runtime_adapter", "runtime_transport", "limits_mode"]) } : {}),
|
|
74
|
+
coverage: { ...pick(coverage, ["serialized_bytes", "max_bytes"]),
|
|
75
|
+
included_sections: strings(coverage?.included_sections),
|
|
76
|
+
omitted_sections: strings(coverage?.omitted_sections),
|
|
77
|
+
truncated_sections: strings(coverage?.truncated_sections) },
|
|
78
|
+
...(projectionTruncated ? { reference_projection_truncated: true } : {}),
|
|
79
|
+
};
|
|
80
|
+
return "## Continuation references (snapshot, not new authority)\n" + JSON.stringify(context) + "\n"
|
|
81
|
+
+ (projectionTruncated ? "Reference projection was truncated; absence is not permission. Stop affected work until the host resolves missing context. " : "")
|
|
82
|
+
+ (execution?.limits_mode === "unbounded" ? "The host's effective limits mode remains authoritative; historical numeric caps do not override an explicitly admitted unbounded employee session. " : "")
|
|
83
|
+
+ "Reuse valid same-scope authorization for bounded implementation, tests and corrections; do not ask again solely because an AI, session or skill changed. "
|
|
84
|
+
+ "The host revalidates current authority; these decision references and contract snapshots are not approvals or proof of current validity. "
|
|
85
|
+
+ "Missing or omitted decision context does not prove that there are no decisions. Do not fetch Gateway context or manage leases yourself; the Runner owns that work. "
|
|
86
|
+
+ "Stop on changed, expired, revoked, consumed or actor-mismatched authority and server/app permission denial. "
|
|
87
|
+
+ "Stop blocked execution units and units that depend on them; continue only independently allowed work inside the assigned scope. "
|
|
88
|
+
+ "A new paid execution or correction attempt requires existing host admission, current contract, remaining attempts/budget and a valid lease; ordinary local retesting grants none of these. "
|
|
89
|
+
+ "Do not replay a completed side effect. Never answer a human-only question or approve on another actor's behalf. "
|
|
90
|
+
+ "Required review, completion and publication gates remain separate; report only observed work and evidence, not delivery or operational success inferred from a local result.";
|
|
91
|
+
}
|
|
23
92
|
export function compilePrompt(taskPackage, options) {
|
|
24
93
|
const contract = record(taskPackage.contract);
|
|
25
94
|
if (!contract) {
|
|
@@ -50,6 +119,7 @@ export function compilePrompt(taskPackage, options) {
|
|
|
50
119
|
const requiredTests = requiredArray(brief.required_tests ?? [], "required_tests");
|
|
51
120
|
const sections = [
|
|
52
121
|
`# Bounded implementation brief: ${options.workItemLabel}`,
|
|
122
|
+
continuationContext(taskPackage),
|
|
53
123
|
`## Objective\n${objective}`,
|
|
54
124
|
`## Required changes\n${requiredChanges.map((item) => `- ${item}`).join("\n")}`,
|
|
55
125
|
`## Invariants\n${invariants.map((item) => `- ${item}`).join("\n")}`,
|
|
@@ -26,11 +26,48 @@ function scopePath(root, scope) {
|
|
|
26
26
|
throw new Error('DENIED_UNSUPPORTED_SCOPE');
|
|
27
27
|
return path.resolve(root, directory);
|
|
28
28
|
}
|
|
29
|
+
// A blocked pattern as an anchored matcher on the root-relative path: a leading "**/" is any leading folders, a
|
|
30
|
+
// trailing "/**" everything below, "*" and "?" stay within one segment. Brackets and braces stay unsupported and
|
|
31
|
+
// refuse every access.
|
|
32
|
+
function blockedGlob(scope) {
|
|
33
|
+
if (/[\[\]{}]/.test(scope))
|
|
34
|
+
throw new Error('DENIED_UNSUPPORTED_SCOPE');
|
|
35
|
+
let pattern = '';
|
|
36
|
+
for (let i = 0; i < scope.length; i++) {
|
|
37
|
+
const rest = scope.slice(i);
|
|
38
|
+
if (rest.startsWith('**/')) {
|
|
39
|
+
pattern += '(?:.*/)?';
|
|
40
|
+
i += 2;
|
|
41
|
+
}
|
|
42
|
+
else if (rest === '/**') {
|
|
43
|
+
pattern += '(?:/.*)?';
|
|
44
|
+
i += 2;
|
|
45
|
+
}
|
|
46
|
+
else if (rest.startsWith('**')) {
|
|
47
|
+
pattern += '.*';
|
|
48
|
+
i += 1;
|
|
49
|
+
}
|
|
50
|
+
else if (scope[i] === '*')
|
|
51
|
+
pattern += '[^/]*';
|
|
52
|
+
else if (scope[i] === '?')
|
|
53
|
+
pattern += '[^/]';
|
|
54
|
+
else
|
|
55
|
+
pattern += scope[i].replace(/[.+^$()|\\]/g, '\\$&');
|
|
56
|
+
}
|
|
57
|
+
return new RegExp(`^${pattern}$`);
|
|
58
|
+
}
|
|
29
59
|
function exactBlockedScopeContains(root, scope, file) {
|
|
30
60
|
// The compiled repository policy includes this private-file family. Handle
|
|
31
61
|
// it only as a denial, never as a wildcard grant or an ignored block.
|
|
32
62
|
if (scope === '.env.*')
|
|
33
63
|
return file.startsWith(path.join(root, '.env.'));
|
|
64
|
+
// Registered blocks also use patterns such as **/*.keystore or **/.env*. Read only as a denial: a pattern can
|
|
65
|
+
// refuse more paths, never grant one, and allowed scopes keep the plain directory form of scopePath.
|
|
66
|
+
if (/[?*\[\]{}]/.test(scope.endsWith('/**') ? scope.slice(0, -3) : scope)) {
|
|
67
|
+
if (!contains(root, file))
|
|
68
|
+
return false;
|
|
69
|
+
return blockedGlob(scope).test(path.relative(root, file).split(path.sep).join('/'));
|
|
70
|
+
}
|
|
34
71
|
return contains(scopePath(root, scope), file);
|
|
35
72
|
}
|
|
36
73
|
// APFS and HFS+ resolve names regardless of case and Unicode normalization, so app/secrets reaches a blocked
|