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.
@@ -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(cwd: string): {
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
- const candidates = [projectTemplatesDir(cwd), legacyProjectTemplatesDir(cwd)];
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.0",
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",
@@ -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
- }