@spences10/pi-harness 0.0.2

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Scott Spence
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,118 @@
1
+ # @spences10/pi-harness
2
+
3
+ [![built with Vite+](https://img.shields.io/badge/built%20with-Vite+-646CFF?logo=vite&logoColor=white)](https://viteplus.dev)
4
+ [![tested with Vitest](https://img.shields.io/badge/tested%20with-Vitest-6E9F18?logo=vitest&logoColor=white)](https://vitest.dev)
5
+ [![npm version](https://img.shields.io/npm/v/@spences10/pi-harness?color=CB3837&logo=npm&logoColor=white)](https://www.npmjs.com/package/@spences10/pi-harness)
6
+ [![license](https://img.shields.io/npm/l/@spences10/pi-harness)](https://www.npmjs.com/package/@spences10/pi-harness)
7
+
8
+ ![my-pi package preview](https://raw.githubusercontent.com/spences10/my-pi/main/assets/pi-package-preview.png)
9
+
10
+ Build and run ephemeral task harnesses with my-pi primitives. A
11
+ harness is a `/tmp` runtime containing a machine-readable contract,
12
+ executor prompt, task brief, validation script, review script, logs,
13
+ status, and runtime enforcement.
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ pi install npm:@spences10/pi-harness
19
+ ```
20
+
21
+ Local development from this monorepo:
22
+
23
+ ```bash
24
+ pnpm --filter @spences10/pi-harness run build
25
+ pi install ./packages/pi-harness
26
+ # or for one run only
27
+ pi -e ./packages/pi-harness
28
+ ```
29
+
30
+ ## What it does
31
+
32
+ `pi-harness` adds:
33
+
34
+ - `/harness` command for create, run, review, status, use, and clear
35
+ - `harness_create` tool to create `/tmp/my-pi-harness-*` runtimes
36
+ - `harness_update` tool for phase/status/evidence logging
37
+ - generated `OUTCOME.md` and `outcome.json` review artifacts
38
+ - dirty-baseline tracking so pre-existing repo changes are reported
39
+ but not treated as task drift
40
+ - worktree-aware validate/review scripts for team-mode executors
41
+ - `harness_read` tool for summaries
42
+ - `before_agent_start` context injection for the active harness
43
+ - `tool_call` enforcement for edit/write paths and forbidden commands
44
+ - TUI status/widget for the active harness
45
+ - bundled `create-harness`, `execute-harness`, and `review-harness`
46
+ skills
47
+
48
+ ## Runtime layout
49
+
50
+ ```text
51
+ /tmp/my-pi-harness-<id>/
52
+ harness.json # execution contract
53
+ SYSTEM.md # executor system prompt
54
+ TASK.md # task brief and required loop
55
+ status.json # phase/status/evidence log
56
+ OUTCOME.md # reviewable outcome summary
57
+ outcome.json # machine-readable outcome summary
58
+ outcome.mjs # outcome artifact refresher
59
+ validate.sh # validation runner
60
+ review.sh # drift/review helper
61
+ logs/events.jsonl # append-only event log
62
+ ```
63
+
64
+ ## Commands
65
+
66
+ ```text
67
+ /harness create <task>
68
+ /harness run <dir>
69
+ /harness review <dir>
70
+ /harness status [dir]
71
+ /harness use <dir>
72
+ /harness clear
73
+ ```
74
+
75
+ The create/run/review commands prompt the model to use the bundled
76
+ skills. The tools provide the actual runtime and enforcement layer.
77
+
78
+ Harnesses snapshot dirty files at creation time. Review and outcome
79
+ artifacts focus on changes after that baseline, while still recording
80
+ baseline files in `outcome.json`. If a team-mode executor runs in a
81
+ linked git worktree, run `review.sh` from that worktree or set
82
+ `HARNESS_CWD` so validation, guard checks, and outcome collection use
83
+ the executor workspace.
84
+
85
+ ## Harness loop
86
+
87
+ 1. Context recovery
88
+ 2. Source-of-truth capture
89
+ 3. Assumption challenge
90
+ 4. Alignment checkpoint
91
+ 5. Surgical execution
92
+ 6. Validation evidence
93
+ 7. Drift review
94
+ 8. OUTCOME.md/outcome.json review
95
+ 9. Delta/risk report
96
+
97
+ ## Using from a custom harness
98
+
99
+ ```ts
100
+ import harness from '@spences10/pi-harness';
101
+
102
+ // pass `harness` as an ExtensionFactory to your Pi runtime
103
+ ```
104
+
105
+ `my-pi` imports this package directly and enables it as the built-in
106
+ harness workflow.
107
+
108
+ ## Development
109
+
110
+ ```bash
111
+ pnpm --filter @spences10/pi-harness run check
112
+ pnpm --filter @spences10/pi-harness run test
113
+ pnpm --filter @spences10/pi-harness run build
114
+ ```
115
+
116
+ ## License
117
+
118
+ MIT
@@ -0,0 +1,13 @@
1
+ import type { HarnessContract } from '../schema.js';
2
+ export declare function check_path_allowed(contract: HarnessContract, input_path: string): {
3
+ ok: true;
4
+ } | {
5
+ ok: false;
6
+ reason: string;
7
+ };
8
+ export declare function check_command_allowed(contract: HarnessContract, command: string): {
9
+ ok: true;
10
+ } | {
11
+ ok: false;
12
+ reason: string;
13
+ };
@@ -0,0 +1,85 @@
1
+ import { isAbsolute, relative, resolve } from 'node:path';
2
+ function resolve_project_path(cwd, input_path) {
3
+ return resolve(cwd, input_path);
4
+ }
5
+ function pattern_to_relative(cwd, pattern) {
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 === '.')
15
+ return true;
16
+ if (normalized_pattern.endsWith('/**')) {
17
+ const prefix = normalized_pattern.slice(0, -3);
18
+ return (relative_path === prefix ||
19
+ relative_path.startsWith(`${prefix}/`));
20
+ }
21
+ if (normalized_pattern.includes('*')) {
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));
37
+ }
38
+ export function check_path_allowed(contract, input_path) {
39
+ const cwd = resolve(contract.cwd);
40
+ const absolute_path = resolve_project_path(cwd, input_path);
41
+ const inside_cwd = absolute_path === cwd || absolute_path.startsWith(`${cwd}/`);
42
+ if (!inside_cwd) {
43
+ return {
44
+ ok: false,
45
+ reason: `Harness ${contract.id}: path is outside cwd: ${input_path}`,
46
+ };
47
+ }
48
+ if (contract.forbidden_paths.some((pattern) => pattern_matches(cwd, pattern, absolute_path))) {
49
+ return {
50
+ ok: false,
51
+ reason: `Harness ${contract.id}: path is forbidden: ${input_path}`,
52
+ };
53
+ }
54
+ if (!contract.allow_test_changes && is_test_path(absolute_path)) {
55
+ return {
56
+ ok: false,
57
+ reason: `Harness ${contract.id}: test changes are not allowed by harness.json`,
58
+ };
59
+ }
60
+ if (!contract.allowed_paths.some((pattern) => pattern_matches(cwd, pattern, absolute_path))) {
61
+ return {
62
+ ok: false,
63
+ reason: `Harness ${contract.id}: path is outside allowed_paths: ${input_path}`,
64
+ };
65
+ }
66
+ return { ok: true };
67
+ }
68
+ export function check_command_allowed(contract, command) {
69
+ const blocked = contract.forbidden_commands.find((needle) => command.includes(needle));
70
+ if (blocked) {
71
+ return {
72
+ ok: false,
73
+ reason: `Harness ${contract.id}: command contains forbidden pattern: ${blocked}`,
74
+ };
75
+ }
76
+ if (!contract.allow_test_changes &&
77
+ /\brm\b.*((^|\/)(__tests__|tests?)\/|\.(test|spec)\.)/.test(command)) {
78
+ return {
79
+ ok: false,
80
+ reason: `Harness ${contract.id}: deleting tests is not allowed`,
81
+ };
82
+ }
83
+ return { ok: true };
84
+ }
85
+ //# sourceMappingURL=policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy.js","sourceRoot":"","sources":["../../src/enforcement/policy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { BeforeAgentStartEvent, ExtensionAPI } from '@earendil-works/pi-coding-agent';
2
+ export declare function should_inject_harness_prompt(event: Pick<BeforeAgentStartEvent, 'systemPromptOptions'>): boolean;
3
+ export default function harness(pi: ExtensionAPI): Promise<void>;
@@ -0,0 +1,180 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { check_command_allowed, check_path_allowed, } from './enforcement/policy.js';
3
+ import { harness_paths, read_contract } from './runtime/files.js';
4
+ import { HARNESS_SYSTEM_PROMPT } from './prompt.js';
5
+ import { active_harness_context, create_harness_runtime, format_harness_summary, update_harness_runtime, } from './runtime/index.js';
6
+ import { HARNESS_CUSTOM_TYPE, harness_create_params_schema, harness_read_params_schema, harness_update_params_schema, } from './schema.js';
7
+ function persist_active_harness(pi, harness_dir) {
8
+ pi.appendEntry(HARNESS_CUSTOM_TYPE, {
9
+ active_harness_dir: harness_dir,
10
+ });
11
+ }
12
+ function restore_active_harness(ctx) {
13
+ const entries = ctx.sessionManager.getEntries();
14
+ return entries
15
+ .filter((entry) => entry.type === 'custom' &&
16
+ entry.customType === HARNESS_CUSTOM_TYPE)
17
+ .pop()?.data?.active_harness_dir;
18
+ }
19
+ function update_harness_ui(ctx, harness_dir) {
20
+ if (!harness_dir ||
21
+ !existsSync(harness_paths(harness_dir).contract)) {
22
+ ctx.ui.setStatus('harness', undefined);
23
+ ctx.ui.setWidget('harness', undefined);
24
+ return;
25
+ }
26
+ const summary = format_harness_summary(harness_dir).split('\n');
27
+ ctx.ui.setStatus('harness', `🧪 ${summary[2]?.replace('Status: ', '')}`);
28
+ ctx.ui.setWidget('harness', summary.slice(0, 4));
29
+ }
30
+ function parse_command(args) {
31
+ const [command = 'status', ...rest] = args.trim().split(/\s+/);
32
+ return { command, rest: rest.join(' ').trim() };
33
+ }
34
+ function tool_text(text) {
35
+ return { content: [{ type: 'text', text }], details: {} };
36
+ }
37
+ export function should_inject_harness_prompt(event) {
38
+ const selected_tools = event.systemPromptOptions?.selectedTools;
39
+ return !selected_tools || selected_tools.includes('bash');
40
+ }
41
+ export default async function harness(pi) {
42
+ let active_harness_dir;
43
+ function set_active_harness(harness_dir, ctx) {
44
+ active_harness_dir = harness_dir;
45
+ persist_active_harness(pi, harness_dir);
46
+ update_harness_ui(ctx, harness_dir);
47
+ }
48
+ pi.registerCommand('harness', {
49
+ description: 'Create, use, run, review, and inspect ephemeral /tmp task harnesses',
50
+ handler: async (args, ctx) => {
51
+ const { command, rest } = parse_command(args);
52
+ if (command === 'clear') {
53
+ set_active_harness(undefined, ctx);
54
+ ctx.ui.notify('Cleared active harness', 'info');
55
+ return;
56
+ }
57
+ if (command === 'use') {
58
+ if (!rest) {
59
+ ctx.ui.notify('Usage: /harness use <dir>', 'warning');
60
+ return;
61
+ }
62
+ set_active_harness(rest, ctx);
63
+ ctx.ui.notify(`Active harness: ${rest}`, 'info');
64
+ return;
65
+ }
66
+ if (command === 'status') {
67
+ const harness_dir = rest || active_harness_dir;
68
+ if (!harness_dir) {
69
+ ctx.ui.notify('No active harness', 'warning');
70
+ return;
71
+ }
72
+ ctx.ui.notify(format_harness_summary(harness_dir), 'info');
73
+ return;
74
+ }
75
+ if (command === 'create') {
76
+ pi.sendUserMessage(`Use the create-harness skill to build a complete /tmp my-pi harness for this task. Use harness_create after context gathering. If the team tool is available, also create or reuse a team and add a team task whose description includes the harness directory.\n\n${rest}`);
77
+ return;
78
+ }
79
+ if (command === 'run') {
80
+ const harness_dir = rest || active_harness_dir;
81
+ if (!harness_dir) {
82
+ ctx.ui.notify('Usage: /harness run <dir>', 'warning');
83
+ return;
84
+ }
85
+ set_active_harness(harness_dir, ctx);
86
+ pi.sendUserMessage(`Use the execute-harness skill to run this harness until validation completes: ${harness_dir}. If the team tool is available, create or reuse a team, create a task for this harness, spawn one worktree mutating teammate with member_spawn, and have that teammate execute the harness. Then inspect team status/results before reporting.`);
87
+ return;
88
+ }
89
+ if (command === 'review') {
90
+ const harness_dir = rest || active_harness_dir;
91
+ if (!harness_dir) {
92
+ ctx.ui.notify('Usage: /harness review <dir>', 'warning');
93
+ return;
94
+ }
95
+ set_active_harness(harness_dir, ctx);
96
+ pi.sendUserMessage(`Use the review-harness skill to review drift, shortcuts, validation evidence, and remaining risks for: ${harness_dir}`);
97
+ return;
98
+ }
99
+ ctx.ui.notify('Usage: /harness create|run|review|status|use|clear', 'info');
100
+ },
101
+ });
102
+ pi.registerTool({
103
+ name: 'harness_create',
104
+ label: 'Create Harness',
105
+ description: 'Create an ephemeral /tmp my-pi task harness with machine-readable contract, prompts, scripts, logs, and status.',
106
+ promptSnippet: 'Create /tmp task harnesses for constrained agent execution',
107
+ promptGuidelines: [
108
+ 'Use harness_create after context gathering for ambiguous or high-risk coding tasks.',
109
+ 'Treat harness.json as the execution contract and record progress with harness_update.',
110
+ ],
111
+ parameters: harness_create_params_schema,
112
+ async execute(_tool_call_id, params, _signal, _on_update, ctx) {
113
+ const { harness_dir, contract } = create_harness_runtime(params, ctx.cwd);
114
+ set_active_harness(harness_dir, ctx);
115
+ return tool_text(`Created harness ${contract.id}\n${format_harness_summary(harness_dir)}`);
116
+ },
117
+ });
118
+ pi.registerTool({
119
+ name: 'harness_update',
120
+ label: 'Update Harness',
121
+ description: 'Update harness status, phase, notes, and validation evidence.',
122
+ parameters: harness_update_params_schema,
123
+ async execute(_tool_call_id, params, _signal, _on_update, ctx) {
124
+ const status_file = update_harness_runtime(params);
125
+ set_active_harness(params.harness_dir, ctx);
126
+ return tool_text(`Updated harness ${status_file.id}: ${status_file.status}`);
127
+ },
128
+ });
129
+ pi.registerTool({
130
+ name: 'harness_read',
131
+ label: 'Read Harness',
132
+ description: 'Read a harness contract, status, and runtime file locations.',
133
+ parameters: harness_read_params_schema,
134
+ async execute(_tool_call_id, params) {
135
+ return tool_text(format_harness_summary(params.harness_dir));
136
+ },
137
+ });
138
+ pi.on('session_start', async (_event, ctx) => {
139
+ active_harness_dir = restore_active_harness(ctx);
140
+ update_harness_ui(ctx, active_harness_dir);
141
+ });
142
+ pi.on('before_agent_start', async (event) => {
143
+ let system_prompt = event.systemPrompt;
144
+ if (should_inject_harness_prompt(event)) {
145
+ system_prompt = `${system_prompt}\n\n${HARNESS_SYSTEM_PROMPT}`;
146
+ }
147
+ if (active_harness_dir &&
148
+ existsSync(harness_paths(active_harness_dir).contract)) {
149
+ system_prompt = `${system_prompt}\n\n${active_harness_context(active_harness_dir)}`;
150
+ }
151
+ return { systemPrompt: system_prompt };
152
+ });
153
+ pi.on('tool_call', async (event) => {
154
+ if (!active_harness_dir ||
155
+ !existsSync(harness_paths(active_harness_dir).contract)) {
156
+ return;
157
+ }
158
+ const contract = read_contract(active_harness_dir);
159
+ if (event.toolName === 'bash') {
160
+ const input = event.input;
161
+ const command = input.command ?? '';
162
+ const result = check_command_allowed(contract, command);
163
+ if (!result.ok)
164
+ return { block: true, reason: result.reason };
165
+ }
166
+ if (event.toolName === 'edit' || event.toolName === 'write') {
167
+ const input = event.input;
168
+ if (!input.path)
169
+ return;
170
+ const result = check_path_allowed(contract, input.path);
171
+ if (!result.ok)
172
+ return { block: true, reason: result.reason };
173
+ }
174
+ });
175
+ pi.on('session_shutdown', async (_event, ctx) => {
176
+ ctx.ui.setStatus('harness', undefined);
177
+ ctx.ui.setWidget('harness', undefined);
178
+ });
179
+ }
180
+ //# sourceMappingURL=extension.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extension.js","sourceRoot":"","sources":["../src/extension.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ export { default } from './extension.js';
2
+ export { should_inject_harness_prompt } from './extension.js';
3
+ export { check_command_allowed, check_path_allowed, } from './enforcement/policy.js';
4
+ export { HARNESS_SYSTEM_PROMPT } from './prompt.js';
5
+ export { active_harness_context, create_harness_runtime, format_harness_summary, update_harness_runtime, } from './runtime/index.js';
6
+ export { collect_harness_outcome, render_outcome_markdown, write_outcome_artifacts, } from './runtime/outcome.js';
7
+ export type { HarnessContract, HarnessCreateParams, HarnessLogEntry, HarnessOutcome, HarnessReadParams, HarnessStatus, HarnessStatusFile, HarnessThinking, HarnessUpdateParams, } from './schema.js';
8
+ export { DEFAULT_FORBIDDEN_COMMANDS, HARNESS_CUSTOM_TYPE, HARNESS_VERSION, harness_create_params_schema, harness_read_params_schema, harness_update_params_schema, thinking_levels_schema, } from './schema.js';
9
+ export declare const testing: {
10
+ harness_create_params_schema: import("typebox").TObject<{
11
+ task: import("typebox").TString;
12
+ slug: import("typebox").TOptional<import("typebox").TString>;
13
+ cwd: import("typebox").TOptional<import("typebox").TString>;
14
+ allowed_paths: import("typebox").TOptional<import("typebox").TArray<import("typebox").TString>>;
15
+ forbidden_paths: import("typebox").TOptional<import("typebox").TArray<import("typebox").TString>>;
16
+ validation_commands: import("typebox").TOptional<import("typebox").TArray<import("typebox").TString>>;
17
+ forbidden_commands: import("typebox").TOptional<import("typebox").TArray<import("typebox").TString>>;
18
+ allow_test_changes: import("typebox").TOptional<import("typebox").TBoolean>;
19
+ planner_model: import("typebox").TOptional<import("typebox").TString>;
20
+ planner_thinking: import("typebox").TOptional<import("typebox").TUnion<[import("typebox").TLiteral<"off">, import("typebox").TLiteral<"minimal">, import("typebox").TLiteral<"low">, import("typebox").TLiteral<"medium">, import("typebox").TLiteral<"high">, import("typebox").TLiteral<"xhigh">]>>;
21
+ executor_model: import("typebox").TOptional<import("typebox").TString>;
22
+ executor_thinking: import("typebox").TOptional<import("typebox").TUnion<[import("typebox").TLiteral<"off">, import("typebox").TLiteral<"minimal">, import("typebox").TLiteral<"low">, import("typebox").TLiteral<"medium">, import("typebox").TLiteral<"high">, import("typebox").TLiteral<"xhigh">]>>;
23
+ reviewer_model: import("typebox").TOptional<import("typebox").TString>;
24
+ reviewer_thinking: import("typebox").TOptional<import("typebox").TUnion<[import("typebox").TLiteral<"off">, import("typebox").TLiteral<"minimal">, import("typebox").TLiteral<"low">, import("typebox").TLiteral<"medium">, import("typebox").TLiteral<"high">, import("typebox").TLiteral<"xhigh">]>>;
25
+ }>;
26
+ harness_read_params_schema: import("typebox").TObject<{
27
+ harness_dir: import("typebox").TString;
28
+ }>;
29
+ harness_update_params_schema: import("typebox").TObject<{
30
+ harness_dir: import("typebox").TString;
31
+ status: import("typebox").TOptional<import("typebox").TUnion<[import("typebox").TLiteral<"created">, import("typebox").TLiteral<"running">, import("typebox").TLiteral<"reviewing">, import("typebox").TLiteral<"completed">, import("typebox").TLiteral<"failed">]>>;
32
+ phase: import("typebox").TOptional<import("typebox").TString>;
33
+ note: import("typebox").TOptional<import("typebox").TString>;
34
+ evidence: import("typebox").TOptional<import("typebox").TString>;
35
+ team_status: import("typebox").TOptional<import("typebox").TString>;
36
+ remaining_risks: import("typebox").TOptional<import("typebox").TArray<import("typebox").TString>>;
37
+ changed_files: import("typebox").TOptional<import("typebox").TArray<import("typebox").TString>>;
38
+ }>;
39
+ };
package/dist/index.js ADDED
@@ -0,0 +1,14 @@
1
+ import { harness_create_params_schema, harness_read_params_schema, harness_update_params_schema, } from './schema.js';
2
+ export { default } from './extension.js';
3
+ export { should_inject_harness_prompt } from './extension.js';
4
+ export { check_command_allowed, check_path_allowed, } from './enforcement/policy.js';
5
+ export { HARNESS_SYSTEM_PROMPT } from './prompt.js';
6
+ export { active_harness_context, create_harness_runtime, format_harness_summary, update_harness_runtime, } from './runtime/index.js';
7
+ export { collect_harness_outcome, render_outcome_markdown, write_outcome_artifacts, } from './runtime/outcome.js';
8
+ export { DEFAULT_FORBIDDEN_COMMANDS, HARNESS_CUSTOM_TYPE, HARNESS_VERSION, harness_create_params_schema, harness_read_params_schema, harness_update_params_schema, thinking_levels_schema, } from './schema.js';
9
+ export const testing = {
10
+ harness_create_params_schema,
11
+ harness_read_params_schema,
12
+ harness_update_params_schema,
13
+ };
14
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,4BAA4B,EAC5B,0BAA0B,EAC1B,4BAA4B,GAC5B,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACzC,OAAO,EAAE,4BAA4B,EAAE,MAAM,gBAAgB,CAAC;AAC9D,OAAO,EACN,qBAAqB,EACrB,kBAAkB,GAClB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EACN,sBAAsB,EACtB,sBAAsB,EACtB,sBAAsB,EACtB,sBAAsB,GACtB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACN,uBAAuB,EACvB,uBAAuB,EACvB,uBAAuB,GACvB,MAAM,sBAAsB,CAAC;AAY9B,OAAO,EACN,0BAA0B,EAC1B,mBAAmB,EACnB,eAAe,EACf,4BAA4B,EAC5B,0BAA0B,EAC1B,4BAA4B,EAC5B,sBAAsB,GACtB,MAAM,aAAa,CAAC;AAErB,MAAM,CAAC,MAAM,OAAO,GAAG;IACtB,4BAA4B;IAC5B,0BAA0B;IAC1B,4BAA4B;CAC5B,CAAC"}
@@ -0,0 +1 @@
1
+ export declare const HARNESS_SYSTEM_PROMPT = "## my-pi harness workflow\n\nFor ambiguous, risky, or multi-step coding tasks, prefer a real harness instead of a prose-only plan. A harness is an ephemeral /tmp runtime with harness.json, SYSTEM.md, TASK.md, status.json, validation scripts, logs, and enforcement rules. Use the bundled create-harness skill plus the harness_create tool to build it, then execute inside the active harness until validation and review are complete.";
package/dist/prompt.js ADDED
@@ -0,0 +1,4 @@
1
+ export const HARNESS_SYSTEM_PROMPT = `## my-pi harness workflow
2
+
3
+ For ambiguous, risky, or multi-step coding tasks, prefer a real harness instead of a prose-only plan. A harness is an ephemeral /tmp runtime with harness.json, SYSTEM.md, TASK.md, status.json, validation scripts, logs, and enforcement rules. Use the bundled create-harness skill plus the harness_create tool to build it, then execute inside the active harness until validation and review are complete.`;
4
+ //# sourceMappingURL=prompt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt.js","sourceRoot":"","sources":["../src/prompt.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,qBAAqB,GAAG;;kZAE6W,CAAC"}
@@ -0,0 +1,22 @@
1
+ import type { HarnessContract, HarnessLogEntry, HarnessStatusFile } from '../schema.js';
2
+ export declare function json_read<T>(path: string): T;
3
+ export declare function json_write(path: string, value: unknown): void;
4
+ export declare function shell_quote(value: string): string;
5
+ export declare function harness_paths(harness_dir: string): {
6
+ contract: string;
7
+ system: string;
8
+ task: string;
9
+ status: string;
10
+ outcome: string;
11
+ outcome_markdown: string;
12
+ outcome_script: string;
13
+ validate: string;
14
+ review: string;
15
+ guard: string;
16
+ logs: string;
17
+ };
18
+ export declare function read_contract(harness_dir: string): HarnessContract;
19
+ export declare function read_status(harness_dir: string): HarnessStatusFile;
20
+ export declare function write_status(harness_dir: string, status_file: HarnessStatusFile): void;
21
+ export declare function write_contract(harness_dir: string, contract: HarnessContract): void;
22
+ export declare function append_event(harness_dir: string, entry: HarnessLogEntry): void;
@@ -0,0 +1,46 @@
1
+ import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ export function json_read(path) {
4
+ return JSON.parse(readFileSync(path, 'utf8'));
5
+ }
6
+ export function json_write(path, value) {
7
+ writeFileSync(path, `${JSON.stringify(value, null, 2)}\n`);
8
+ }
9
+ export function shell_quote(value) {
10
+ return `'${value.replaceAll("'", "'\\''")}'`;
11
+ }
12
+ export function harness_paths(harness_dir) {
13
+ return {
14
+ contract: join(harness_dir, 'harness.json'),
15
+ system: join(harness_dir, 'SYSTEM.md'),
16
+ task: join(harness_dir, 'TASK.md'),
17
+ status: join(harness_dir, 'status.json'),
18
+ outcome: join(harness_dir, 'outcome.json'),
19
+ outcome_markdown: join(harness_dir, 'OUTCOME.md'),
20
+ outcome_script: join(harness_dir, 'outcome.mjs'),
21
+ validate: join(harness_dir, 'validate.sh'),
22
+ review: join(harness_dir, 'review.sh'),
23
+ guard: join(harness_dir, 'guard.mjs'),
24
+ logs: join(harness_dir, 'logs'),
25
+ };
26
+ }
27
+ export function read_contract(harness_dir) {
28
+ return json_read(harness_paths(harness_dir).contract);
29
+ }
30
+ export function read_status(harness_dir) {
31
+ return json_read(harness_paths(harness_dir).status);
32
+ }
33
+ export function write_status(harness_dir, status_file) {
34
+ json_write(harness_paths(harness_dir).status, status_file);
35
+ }
36
+ export function write_contract(harness_dir, contract) {
37
+ json_write(harness_paths(harness_dir).contract, contract);
38
+ }
39
+ export function append_event(harness_dir, entry) {
40
+ const paths = harness_paths(harness_dir);
41
+ mkdirSync(paths.logs, { recursive: true });
42
+ writeFileSync(join(paths.logs, 'events.jsonl'), `${JSON.stringify(entry)}\n`, {
43
+ flag: 'a',
44
+ });
45
+ }
46
+ //# sourceMappingURL=files.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"files.js","sourceRoot":"","sources":["../../src/runtime/files.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACjE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAOjC,MAAM,UAAU,SAAS,CAAI,IAAY;IACxC,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAM,CAAC;AACpD,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,IAAY,EAAE,KAAc;IACtD,aAAa,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;AAC5D,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,KAAa;IACxC,OAAO,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC;AAC9C,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,WAAmB;IAChD,OAAO;QACN,QAAQ,EAAE,IAAI,CAAC,WAAW,EAAE,cAAc,CAAC;QAC3C,MAAM,EAAE,IAAI,CAAC,WAAW,EAAE,WAAW,CAAC;QACtC,IAAI,EAAE,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC;QAClC,MAAM,EAAE,IAAI,CAAC,WAAW,EAAE,aAAa,CAAC;QACxC,OAAO,EAAE,IAAI,CAAC,WAAW,EAAE,cAAc,CAAC;QAC1C,gBAAgB,EAAE,IAAI,CAAC,WAAW,EAAE,YAAY,CAAC;QACjD,cAAc,EAAE,IAAI,CAAC,WAAW,EAAE,aAAa,CAAC;QAChD,QAAQ,EAAE,IAAI,CAAC,WAAW,EAAE,aAAa,CAAC;QAC1C,MAAM,EAAE,IAAI,CAAC,WAAW,EAAE,WAAW,CAAC;QACtC,KAAK,EAAE,IAAI,CAAC,WAAW,EAAE,WAAW,CAAC;QACrC,IAAI,EAAE,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC;KAC/B,CAAC;AACH,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,WAAmB;IAChD,OAAO,SAAS,CACf,aAAa,CAAC,WAAW,CAAC,CAAC,QAAQ,CACnC,CAAC;AACH,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,WAAmB;IAC9C,OAAO,SAAS,CACf,aAAa,CAAC,WAAW,CAAC,CAAC,MAAM,CACjC,CAAC;AACH,CAAC;AAED,MAAM,UAAU,YAAY,CAC3B,WAAmB,EACnB,WAA8B;IAE9B,UAAU,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;AAC5D,CAAC;AAED,MAAM,UAAU,cAAc,CAC7B,WAAmB,EACnB,QAAyB;IAEzB,UAAU,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;AAC3D,CAAC;AAED,MAAM,UAAU,YAAY,CAC3B,WAAmB,EACnB,KAAsB;IAEtB,MAAM,KAAK,GAAG,aAAa,CAAC,WAAW,CAAC,CAAC;IACzC,SAAS,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3C,aAAa,CACZ,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,cAAc,CAAC,EAChC,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,EAC5B;QACC,IAAI,EAAE,GAAG;KACT,CACD,CAAC;AACH,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { type HarnessContract, type HarnessCreateParams, type HarnessStatusFile, type HarnessUpdateParams } from '../schema.js';
2
+ export declare function create_harness_runtime(params: HarnessCreateParams, default_cwd: string): {
3
+ harness_dir: string;
4
+ contract: HarnessContract;
5
+ };
6
+ export declare function update_harness_runtime(params: HarnessUpdateParams): HarnessStatusFile;
7
+ export declare function format_harness_summary(harness_dir: string): string;
8
+ export declare function active_harness_context(harness_dir: string): string;