pi-harness-delegate 0.7.0 → 0.7.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/README.md +13 -2
- package/extensions/acp-runner.ts +60 -24
- package/extensions/command.ts +145 -21
- package/extensions/concurrency.ts +37 -4
- package/extensions/config.ts +36 -34
- package/extensions/engine.ts +167 -17
- package/extensions/fanout.ts +16 -29
- package/extensions/harnesses/amp.ts +2 -0
- package/extensions/harnesses/claude.ts +5 -0
- package/extensions/harnesses/codex.ts +2 -0
- package/extensions/harnesses/devin.ts +6 -1
- package/extensions/harnesses/opencode.ts +3 -0
- package/extensions/harnesses/registry.ts +51 -13
- package/extensions/harnesses/types.ts +5 -8
- package/extensions/index.ts +162 -184
- package/extensions/notify.ts +18 -5
- package/extensions/progress.ts +9 -3
- package/extensions/runner.ts +3 -20
- package/extensions/stream-caps.ts +46 -0
- package/extensions/templates.ts +21 -2
- package/package.json +2 -1
- package/extensions/run-claude.ts +0 -61
- package/extensions/stream-parse.ts +0 -37
package/extensions/templates.ts
CHANGED
|
@@ -224,13 +224,32 @@ export function resolveNativePermission(
|
|
|
224
224
|
*
|
|
225
225
|
* Pure filesystem inspection — no trust logic. The caller supplies the trust decision.
|
|
226
226
|
*/
|
|
227
|
-
export function projectTemplatePresence(
|
|
227
|
+
export function projectTemplatePresence(
|
|
228
|
+
cwd: string,
|
|
229
|
+
/** Canonical harness names — the only partitions `loadTemplates` ever reads (callers pass the
|
|
230
|
+
* registry's `HARNESS_NAMES`; injected so this module stays free of the harness registry). */
|
|
231
|
+
harnessNames: readonly string[],
|
|
232
|
+
): {
|
|
228
233
|
/** Template dirs that exist and would load if the project were trusted. */
|
|
229
234
|
dirs: string[];
|
|
230
235
|
/** A leftover `.pi/trusted` file — strong evidence the user relied on the removed mechanism. */
|
|
231
236
|
staleTrustFile: boolean;
|
|
232
237
|
} {
|
|
233
|
-
|
|
238
|
+
// the per-harness partitions (`.pi/delegate/templates/<harness>/`) load too — see loadTemplates —
|
|
239
|
+
// so they count as skipped content just like the shared root does. Only real harness partitions:
|
|
240
|
+
// loadTemplates is always called with a canonical name, so `omp/` (an alias), `archive/`,
|
|
241
|
+
// `shared/` etc. are never read and must not trigger the warning either.
|
|
242
|
+
const known = new Set(harnessNames);
|
|
243
|
+
let partitions: string[] = [];
|
|
244
|
+
try {
|
|
245
|
+
partitions = readdirSync(projectTemplatesDir(cwd), { withFileTypes: true })
|
|
246
|
+
.filter(e => e.isDirectory() && known.has(e.name))
|
|
247
|
+
.map(e => projectTemplatesDir(cwd, e.name))
|
|
248
|
+
.sort();
|
|
249
|
+
} catch {
|
|
250
|
+
// absent or unreadable
|
|
251
|
+
}
|
|
252
|
+
const candidates = [projectTemplatesDir(cwd), ...partitions, legacyProjectTemplatesDir(cwd)];
|
|
234
253
|
const dirs: string[] = [];
|
|
235
254
|
for (const dir of candidates) {
|
|
236
255
|
try {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-harness-delegate",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.2",
|
|
4
4
|
"description": "Delegate work to any harness (Claude Code, Muse, OpenCode, Amp, Devin) from the pi coding agent \u2014 code reviews, plans, implementation, security audits, docs, or your own custom templates.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"packageManager": "bun@1.3.14",
|
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
"scripts": {
|
|
41
41
|
"typecheck": "tsc --noEmit",
|
|
42
42
|
"test": "bun test",
|
|
43
|
+
"test:coverage": "bun test --coverage --coverage-reporter=text --coverage-reporter=lcov",
|
|
43
44
|
"lint": "biome check .",
|
|
44
45
|
"lint:fix": "biome check --write .",
|
|
45
46
|
"verify": "bun run lint && bun run typecheck && bun run test",
|
package/extensions/run-claude.ts
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
/** @deprecated use extensions/runner.ts + harnesses/claude.ts directly */
|
|
2
|
-
|
|
3
|
-
import { claudeHarness } from './harnesses/claude.ts';
|
|
4
|
-
import type { ActivityEvent, StreamedResult } from './harnesses/types.ts';
|
|
5
|
-
import { runHarness } from './runner.ts';
|
|
6
|
-
|
|
7
|
-
export interface RunClaudeOptions {
|
|
8
|
-
prompt: string;
|
|
9
|
-
cwd: string;
|
|
10
|
-
permissionMode: string;
|
|
11
|
-
model?: string;
|
|
12
|
-
maxBudgetUsd?: number;
|
|
13
|
-
addDirs?: string[];
|
|
14
|
-
signal?: AbortSignal;
|
|
15
|
-
timeoutMs?: number;
|
|
16
|
-
resumeSessionId?: string;
|
|
17
|
-
onStream?: (text: string) => void;
|
|
18
|
-
onActivity?: (ev: ActivityEvent) => void;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export interface ClaudeResult extends StreamedResult {
|
|
22
|
-
streamedText: string;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export const DEFAULT_TIMEOUT_MS = 600_000;
|
|
26
|
-
|
|
27
|
-
function mapPerm(mode: string): 'readonly' | 'edit' | 'danger' {
|
|
28
|
-
if (mode === 'plan') return 'readonly';
|
|
29
|
-
if (mode === 'bypassPermissions') return 'danger';
|
|
30
|
-
return 'edit';
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export function runClaude(opts: RunClaudeOptions): Promise<ClaudeResult> {
|
|
34
|
-
const perm = mapPerm(opts.permissionMode);
|
|
35
|
-
const _nativePerm =
|
|
36
|
-
perm === 'readonly' && opts.permissionMode !== 'plan'
|
|
37
|
-
? opts.permissionMode
|
|
38
|
-
: perm === 'danger' && opts.permissionMode !== 'bypassPermissions'
|
|
39
|
-
? opts.permissionMode
|
|
40
|
-
: undefined;
|
|
41
|
-
// normalize: if caller passed a non-standard mode, preserve as native
|
|
42
|
-
const isStandard =
|
|
43
|
-
opts.permissionMode === 'plan' ||
|
|
44
|
-
opts.permissionMode === 'acceptEdits' ||
|
|
45
|
-
opts.permissionMode === 'bypassPermissions';
|
|
46
|
-
return runHarness({
|
|
47
|
-
harness: claudeHarness,
|
|
48
|
-
prompt: opts.prompt,
|
|
49
|
-
cwd: opts.cwd,
|
|
50
|
-
permission: perm,
|
|
51
|
-
nativePermission: isStandard ? undefined : opts.permissionMode,
|
|
52
|
-
model: opts.model,
|
|
53
|
-
maxBudgetUsd: opts.maxBudgetUsd,
|
|
54
|
-
addDirs: opts.addDirs,
|
|
55
|
-
signal: opts.signal,
|
|
56
|
-
timeoutMs: opts.timeoutMs,
|
|
57
|
-
resumeSessionId: opts.resumeSessionId,
|
|
58
|
-
onStream: opts.onStream,
|
|
59
|
-
onActivity: opts.onActivity,
|
|
60
|
-
}).then(r => ({ ...r, streamedText: r.streamedText }));
|
|
61
|
-
}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
/** @deprecated use extensions/harnesses/claude.ts parse directly */
|
|
2
|
-
export type {
|
|
3
|
-
ActivityEvent,
|
|
4
|
-
ParseOutcome,
|
|
5
|
-
ParseState,
|
|
6
|
-
StreamedResult,
|
|
7
|
-
StreamedUsage,
|
|
8
|
-
StreamParseOutcome,
|
|
9
|
-
} from './harnesses/types.ts';
|
|
10
|
-
|
|
11
|
-
import { parseClaudeLine } from './harnesses/claude.ts';
|
|
12
|
-
import type { ParseState, StreamParseOutcome } from './harnesses/types.ts';
|
|
13
|
-
|
|
14
|
-
export function parseStreamLines(lines: Iterable<string>): StreamParseOutcome {
|
|
15
|
-
const state: ParseState = { streamedText: '', activities: [], result: null };
|
|
16
|
-
let streamedText = '';
|
|
17
|
-
const activities: StreamParseOutcome['activities'] = [];
|
|
18
|
-
let result: StreamParseOutcome['result'] = null;
|
|
19
|
-
for (const line of lines) {
|
|
20
|
-
const out = parseClaudeLine(line, state);
|
|
21
|
-
if (out.streamedText) {
|
|
22
|
-
streamedText += out.streamedText;
|
|
23
|
-
state.streamedText += out.streamedText;
|
|
24
|
-
}
|
|
25
|
-
if (out.activities) {
|
|
26
|
-
for (const a of out.activities) {
|
|
27
|
-
activities.push(a);
|
|
28
|
-
state.activities.push(a);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
if (out.result) {
|
|
32
|
-
result = out.result;
|
|
33
|
-
state.result = out.result;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
return { streamedText, result, activities };
|
|
37
|
-
}
|