@spences10/pi-harness 0.1.2 → 0.2.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 +116 -175
- package/dist/assessment.d.ts +4 -12
- package/dist/assessment.js +19 -192
- package/dist/assessment.js.map +1 -1
- package/dist/enforcement/policy.d.ts +2 -0
- package/dist/enforcement/policy.js +47 -73
- package/dist/enforcement/policy.js.map +1 -1
- package/dist/extension.d.ts +1 -1
- package/dist/extension.js +178 -403
- package/dist/extension.js.map +1 -1
- package/dist/index.d.ts +5 -4
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/prompt.d.ts +1 -1
- package/dist/prompt.js +1 -7
- package/dist/prompt.js.map +1 -1
- package/dist/runtime/baseline.d.ts +6 -0
- package/dist/runtime/baseline.js +145 -0
- package/dist/runtime/baseline.js.map +1 -0
- package/dist/runtime/index.d.ts +2 -1
- package/dist/runtime/index.js +72 -29
- package/dist/runtime/index.js.map +1 -1
- package/dist/runtime/outcome.d.ts +1 -2
- package/dist/runtime/outcome.js +21 -35
- package/dist/runtime/outcome.js.map +1 -1
- package/dist/runtime/renderers.js +34 -70
- package/dist/runtime/renderers.js.map +1 -1
- package/dist/runtime/verification.d.ts +15 -0
- package/dist/runtime/verification.js +97 -0
- package/dist/runtime/verification.js.map +1 -0
- package/dist/schema.d.ts +12 -2
- package/dist/schema.js +6 -8
- package/dist/schema.js.map +1 -1
- package/package.json +4 -4
- package/skills/create-harness/SKILL.md +19 -62
- package/skills/execute-harness/SKILL.md +27 -66
- package/skills/review-harness/SKILL.md +21 -54
|
@@ -1,86 +1,60 @@
|
|
|
1
|
-
import { isAbsolute, relative, resolve } from 'node:path';
|
|
2
|
-
function
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const normalized_pattern = pattern.replaceAll('\\', '/');
|
|
7
|
-
if (!isAbsolute(pattern))
|
|
8
|
-
return normalized_pattern;
|
|
9
|
-
return relative(cwd, resolve(pattern)).replaceAll('\\', '/');
|
|
10
|
-
}
|
|
11
|
-
function pattern_matches(cwd, pattern, absolute_path) {
|
|
12
|
-
const normalized_pattern = pattern_to_relative(cwd, pattern);
|
|
13
|
-
const relative_path = relative(cwd, absolute_path).replaceAll('\\', '/');
|
|
14
|
-
if (normalized_pattern === '.')
|
|
1
|
+
import { isAbsolute, matchesGlob, relative, resolve, } from 'node:path';
|
|
2
|
+
export function pattern_matches(cwd, pattern, path) {
|
|
3
|
+
const normalized = (isAbsolute(pattern) ? relative(cwd, pattern) : pattern).replaceAll('\\', '/');
|
|
4
|
+
const candidate = relative(cwd, resolve(cwd, path)).replaceAll('\\', '/');
|
|
5
|
+
if (normalized === '.')
|
|
15
6
|
return true;
|
|
16
|
-
if (
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
relative_path.startsWith(`${prefix}/`));
|
|
7
|
+
if (!/[*?[{]/.test(normalized)) {
|
|
8
|
+
return (candidate === normalized ||
|
|
9
|
+
candidate.startsWith(`${normalized}/`));
|
|
20
10
|
}
|
|
21
|
-
|
|
22
|
-
const regex = new RegExp(`^${normalized_pattern
|
|
23
|
-
.replace(/[.+?^${}()|[\]\\]/g, '\\$&')
|
|
24
|
-
.replaceAll('**', '.*')
|
|
25
|
-
.replaceAll('*', '[^/]*')}$`);
|
|
26
|
-
return regex.test(relative_path);
|
|
27
|
-
}
|
|
28
|
-
const target = isAbsolute(pattern)
|
|
29
|
-
? resolve(pattern)
|
|
30
|
-
: resolve_project_path(cwd, pattern);
|
|
31
|
-
return (absolute_path === target || absolute_path.startsWith(`${target}/`));
|
|
32
|
-
}
|
|
33
|
-
function is_test_path(absolute_path) {
|
|
34
|
-
const path = absolute_path.replaceAll('\\', '/');
|
|
35
|
-
return (/(^|\/)(__tests__|tests?)\//.test(path) ||
|
|
36
|
-
/\.(test|spec)\.[cm]?[jt]sx?$/.test(path));
|
|
11
|
+
return matchesGlob(candidate, normalized);
|
|
37
12
|
}
|
|
38
13
|
export function check_path_allowed(contract, input_path) {
|
|
39
14
|
const cwd = resolve(contract.policy.cwd);
|
|
40
|
-
const absolute_path =
|
|
41
|
-
|
|
42
|
-
if (!
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
48
|
-
if (contract.
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}
|
|
54
|
-
if (!contract.scaffold.
|
|
55
|
-
|
|
56
|
-
|
|
15
|
+
const absolute_path = resolve(cwd, input_path);
|
|
16
|
+
let reason;
|
|
17
|
+
if (absolute_path !== cwd && !absolute_path.startsWith(`${cwd}/`)) {
|
|
18
|
+
reason = 'path is outside cwd';
|
|
19
|
+
}
|
|
20
|
+
else if (contract.policy.forbidden_paths.some((pattern) => pattern_matches(cwd, pattern, input_path))) {
|
|
21
|
+
reason = 'path is forbidden';
|
|
22
|
+
}
|
|
23
|
+
else if ((!contract.scaffold.allow_test_changes ||
|
|
24
|
+
contract.policy.allow_test_changes === false) &&
|
|
25
|
+
(/(^|\/)(__tests__|tests?)\//.test(input_path) ||
|
|
26
|
+
/\.(test|spec)\.[cm]?[jt]sx?$/.test(input_path))) {
|
|
27
|
+
reason = 'test changes are not allowed by harness.json';
|
|
28
|
+
}
|
|
29
|
+
else if (!contract.scaffold.allowed_paths.some((pattern) => pattern_matches(cwd, pattern, input_path)) ||
|
|
30
|
+
!(contract.policy.allowed_paths ?? contract.scaffold.allowed_paths).some((pattern) => pattern_matches(cwd, pattern, input_path))) {
|
|
31
|
+
reason = 'path is outside allowed_paths';
|
|
32
|
+
}
|
|
33
|
+
return reason
|
|
34
|
+
? {
|
|
57
35
|
ok: false,
|
|
58
|
-
reason: `Harness ${contract.id}:
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
if (!contract.scaffold.allowed_paths.some((pattern) => pattern_matches(cwd, pattern, absolute_path))) {
|
|
62
|
-
return {
|
|
63
|
-
ok: false,
|
|
64
|
-
reason: `Harness ${contract.id}: path is outside allowed_paths: ${input_path}`,
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
return { ok: true };
|
|
36
|
+
reason: `Harness ${contract.id}: ${reason}: ${input_path}`,
|
|
37
|
+
}
|
|
38
|
+
: { ok: true };
|
|
68
39
|
}
|
|
69
40
|
export function check_command_allowed(contract, command) {
|
|
70
41
|
const blocked = contract.policy.forbidden_commands.find((needle) => command.includes(needle));
|
|
71
|
-
|
|
72
|
-
|
|
42
|
+
return blocked
|
|
43
|
+
? {
|
|
73
44
|
ok: false,
|
|
74
45
|
reason: `Harness ${contract.id}: command contains forbidden pattern: ${blocked}`,
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
46
|
+
}
|
|
47
|
+
: { ok: true };
|
|
48
|
+
}
|
|
49
|
+
export function build_path_helpers() {
|
|
50
|
+
return String.raw `
|
|
51
|
+
function pattern_matches(pattern, path) {
|
|
52
|
+
const normalized = (isAbsolute(pattern) ? relative(cwd, pattern) : pattern).replaceAll('\\', '/');
|
|
53
|
+
const candidate = relative(cwd, resolve(cwd, path)).replaceAll('\\', '/');
|
|
54
|
+
if (normalized === '.') return true;
|
|
55
|
+
if (!/[*?[{]/.test(normalized)) return candidate === normalized || candidate.startsWith(normalized + '/');
|
|
56
|
+
return matchesGlob(candidate, normalized);
|
|
57
|
+
}
|
|
58
|
+
`;
|
|
85
59
|
}
|
|
86
60
|
//# sourceMappingURL=policy.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"policy.js","sourceRoot":"","sources":["../../src/enforcement/policy.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"policy.js","sourceRoot":"","sources":["../../src/enforcement/policy.ts"],"names":[],"mappings":"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"}
|
package/dist/extension.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { BeforeAgentStartEvent, ExtensionAPI } from '@earendil-works/pi-coding-agent';
|
|
2
2
|
export declare function should_inject_harness_prompt(event: Pick<BeforeAgentStartEvent, 'systemPromptOptions'>): boolean;
|
|
3
|
-
export default function harness(pi: ExtensionAPI):
|
|
3
|
+
export default function harness(pi: ExtensionAPI): void;
|