pi-warden 0.71.0 → 0.74.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/CHANGELOG.md +54 -0
- package/dist/adaptive.d.ts +3 -2
- package/dist/adaptive.js +4 -3
- package/dist/backend.d.ts +33 -14
- package/dist/backend.js +27 -14
- package/dist/config.d.ts +13 -8
- package/dist/config.js +20 -20
- package/dist/conscience.d.ts +1 -1
- package/dist/extension.d.ts +14 -3
- package/dist/extension.js +410 -64
- package/dist/guard.d.ts +2 -1
- package/dist/guard.js +4 -4
- package/dist/holds.d.ts +1 -1
- package/dist/holds.js +3 -2
- package/dist/host-compat.d.ts +2 -0
- package/dist/host-compat.js +132 -0
- package/dist/host-dirs.d.ts +10 -0
- package/dist/host-dirs.js +21 -0
- package/dist/index-cmd.d.ts +6 -5
- package/dist/index-cmd.js +16 -24
- package/dist/index.d.ts +12 -4
- package/dist/index.js +6 -2
- package/dist/init.js +31 -3
- package/dist/learning.d.ts +12 -11
- package/dist/learning.js +60 -38
- package/dist/loops.d.ts +2 -1
- package/dist/loops.js +3 -2
- package/dist/panel.d.ts +4 -1
- package/dist/panel.js +11 -6
- package/dist/prefs.d.ts +1 -1
- package/dist/prefs.js +3 -2
- package/dist/rules-audit.d.ts +208 -0
- package/dist/rules-audit.js +417 -0
- package/dist/rules-calibrate.d.ts +196 -0
- package/dist/rules-calibrate.js +474 -0
- package/dist/rules-lint.d.ts +2 -0
- package/dist/rules-lint.js +7 -2
- package/dist/rules-log.d.ts +6 -1
- package/dist/rules-log.js +9 -3
- package/dist/rules-report.d.ts +3 -0
- package/dist/rules-report.js +5 -0
- package/dist/rules.d.ts +72 -5
- package/dist/rules.js +116 -54
- package/dist/shape.js +8 -2
- package/dist/turn-rules.d.ts +86 -0
- package/dist/turn-rules.js +232 -0
- package/dist/widget-render.d.ts +23 -0
- package/dist/widget-render.js +82 -0
- package/dist/widget.d.ts +5 -22
- package/dist/widget.js +3 -80
- package/package.json +5 -3
package/dist/guard.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import type { IntegrationErrorCode, Judge, Questions } from "pi-typesafe";
|
|
|
3
3
|
import type { ActionGuardConfig, ArmingRule, CommandRule, LargeOutputConfig, PathRule, RulesConfig, SecurityConfig, SlopGuardConfig } from "./config.js";
|
|
4
4
|
import type { TaskSpine } from "./shape.js";
|
|
5
5
|
import type { RulesSourceConfig } from "./rules.js";
|
|
6
|
+
import type { HostDirs } from "./host-dirs.js";
|
|
6
7
|
export type Level = "allow" | "warn" | "confirm" | "deny";
|
|
7
8
|
export type Severity = "destructive" | "risky" | "sensitive" | "deny";
|
|
8
9
|
export type ViolationSource = "pattern" | "rules-guard" | "security-guard" | "slop-guard";
|
|
@@ -279,7 +280,7 @@ export declare function hostPaths(env?: NodeJS.ProcessEnv): string[];
|
|
|
279
280
|
* write. The rest of Pi's agent directory stays held: `auth.json`, `settings.json`, pi-warden's own `config.json`, and
|
|
280
281
|
* other extensions' data.
|
|
281
282
|
*/
|
|
282
|
-
export declare function wardenHostPaths(env?: NodeJS.ProcessEnv): string[];
|
|
283
|
+
export declare function wardenHostPaths(env?: NodeJS.ProcessEnv, dirs?: HostDirs): string[];
|
|
283
284
|
/** The temp root a real path lies strictly under; a temp root itself has none. */
|
|
284
285
|
export declare function tempRootOf(real: string, roots?: string[]): string | undefined;
|
|
285
286
|
/** How much of the target trees one rm segment may walk: entries seen, and the clock time it must finish by. */
|
package/dist/guard.js
CHANGED
|
@@ -468,16 +468,16 @@ export function hostPaths(env = process.env) {
|
|
|
468
468
|
* write. The rest of Pi's agent directory stays held: `auth.json`, `settings.json`, pi-warden's own `config.json`, and
|
|
469
469
|
* other extensions' data.
|
|
470
470
|
*/
|
|
471
|
-
export function wardenHostPaths(env = process.env) {
|
|
472
|
-
const index = safeIndexDir(env);
|
|
471
|
+
export function wardenHostPaths(env = process.env, dirs) {
|
|
472
|
+
const index = safeIndexDir(env, dirs);
|
|
473
473
|
return [...new Set([...hostPaths(env), ...(index ? [index] : [])])];
|
|
474
474
|
}
|
|
475
475
|
/**
|
|
476
476
|
* The real index directory, or undefined when a symlink could move it: the index directory or a directory between it
|
|
477
477
|
* and the agent directory is a symlink, or its real path is not inside the real agent directory.
|
|
478
478
|
*/
|
|
479
|
-
function safeIndexDir(env) {
|
|
480
|
-
const index = resolve(indexDir(env));
|
|
479
|
+
function safeIndexDir(env, dirs) {
|
|
480
|
+
const index = resolve(indexDir(env, dirs));
|
|
481
481
|
// indexDir is `<agent dir>/pi-warden/index`.
|
|
482
482
|
const agent = dirname(dirname(index));
|
|
483
483
|
for (let dir = index; dir !== agent && dirname(dir) !== dir; dir = dirname(dir)) {
|
package/dist/holds.d.ts
CHANGED
|
@@ -134,7 +134,7 @@ export declare function formatHolds(snapshot: HoldSnapshot, logPath?: string): s
|
|
|
134
134
|
/** The session id as a file name part: no separators or dots, so it cannot leave the directory it is joined to. */
|
|
135
135
|
export declare function sessionFileId(sessionId: string): string;
|
|
136
136
|
/** Per-session file beside the user config: `<agent dir>/pi-warden/holds/<date>-<session>.jsonl`. */
|
|
137
|
-
export declare function holdLogPath(sessionId: string, at?: Date): string;
|
|
137
|
+
export declare function holdLogPath(sessionId: string, at?: Date, dirs?: import("./host-dirs.js").HostDirs): string;
|
|
138
138
|
/** Rewrites the session's records as JSON lines, owner-only, one write at a time so outcomes never interleave. */
|
|
139
139
|
export declare class HoldLog {
|
|
140
140
|
readonly path: string;
|
package/dist/holds.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
2
2
|
import { dirname, join } from "node:path";
|
|
3
3
|
import { userConfigPath } from "./config.js";
|
|
4
|
+
import { defaultHostDirs } from "./host-dirs.js";
|
|
4
5
|
const REGRET_THRESHOLD = 0.7;
|
|
5
6
|
function scoresOf(verdict) {
|
|
6
7
|
const { judgment } = verdict;
|
|
@@ -211,9 +212,9 @@ export function sessionFileId(sessionId) {
|
|
|
211
212
|
return sessionId.replace(/[^A-Za-z0-9_-]/g, "").slice(0, 40) || String(process.pid);
|
|
212
213
|
}
|
|
213
214
|
/** Per-session file beside the user config: `<agent dir>/pi-warden/holds/<date>-<session>.jsonl`. */
|
|
214
|
-
export function holdLogPath(sessionId, at = new Date()) {
|
|
215
|
+
export function holdLogPath(sessionId, at = new Date(), dirs = defaultHostDirs()) {
|
|
215
216
|
const day = at.toISOString().slice(0, 10);
|
|
216
|
-
return join(dirname(userConfigPath()), "holds", `${day}-${sessionFileId(sessionId)}.jsonl`);
|
|
217
|
+
return join(dirname(userConfigPath(dirs)), "holds", `${day}-${sessionFileId(sessionId)}.jsonl`);
|
|
217
218
|
}
|
|
218
219
|
/** Rewrites the session's records as JSON lines, owner-only, one write at a time so outcomes never interleave. */
|
|
219
220
|
export class HoldLog {
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/** Bind-through view: overrides win, functions bind to the target so `this` keeps working. */
|
|
2
|
+
function overlay(target, overrides) {
|
|
3
|
+
return new Proxy(target, {
|
|
4
|
+
get(target, property) {
|
|
5
|
+
if (Object.hasOwn(overrides, property))
|
|
6
|
+
return overrides[property];
|
|
7
|
+
const value = Reflect.get(target, property, target);
|
|
8
|
+
return typeof value === "function" ? value.bind(target) : value;
|
|
9
|
+
},
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
export function adaptHost(pi) {
|
|
13
|
+
const session = pi.pi;
|
|
14
|
+
const getActiveSkills = session?.getActiveSkills;
|
|
15
|
+
if (typeof getActiveSkills !== "function")
|
|
16
|
+
return pi;
|
|
17
|
+
const systemPromptOptions = () => ({ skills: getActiveSkills.call(session).map(toPiSkill) });
|
|
18
|
+
const register = pi.on.bind(pi);
|
|
19
|
+
const asyncWorkEnds = new WeakSet();
|
|
20
|
+
// Capture the async-work pause before later agent_end handlers can await I/O. A job may
|
|
21
|
+
// cancel during one of those handlers and leave no snapshot or follow-up agent_end.
|
|
22
|
+
register("agent_end", (event, ctx) => {
|
|
23
|
+
if (event?.willContinue !== true)
|
|
24
|
+
return;
|
|
25
|
+
const snapshot = asyncJobSnapshot(ctx);
|
|
26
|
+
if (snapshot && hasAsyncWork(snapshot))
|
|
27
|
+
asyncWorkEnds.add(event);
|
|
28
|
+
});
|
|
29
|
+
let endGeneration = 0;
|
|
30
|
+
// Pi emits agent_settled once per prompt, after every agent_end handler and continuation.
|
|
31
|
+
// Register its host stand-in after extension setup. omp then owns each callback's timeout
|
|
32
|
+
// and error report, and advances to the stand-in even if one callback times out.
|
|
33
|
+
// Other extensions may still have agent_end handlers after ours; the stand-in reads only
|
|
34
|
+
// pi-warden's state.
|
|
35
|
+
const on = (event, handler) => {
|
|
36
|
+
if (event === "before_agent_start")
|
|
37
|
+
return register(event, (e, ctx) => beforeAgentStart(e, ctx, handler, systemPromptOptions()));
|
|
38
|
+
if (event === "input")
|
|
39
|
+
return register(event, async (e, ctx) => inputResult(await handler(e, ctx)));
|
|
40
|
+
if (event === "agent_settled") {
|
|
41
|
+
queueMicrotask(() => register("agent_end", (e, ctx) => {
|
|
42
|
+
const generation = ++endGeneration;
|
|
43
|
+
if (e?.willContinue === true) {
|
|
44
|
+
// A cancelled background job can drain without another agent_end. The host drops
|
|
45
|
+
// awaitingAsyncWork before extensions see the event, so an earlier extension may
|
|
46
|
+
// drain it before our observer runs. Give an empty snapshot one host-dispatch grace
|
|
47
|
+
// period; a later agent_end or a running continuation suppresses the fallback.
|
|
48
|
+
const snapshot = asyncJobSnapshot(ctx);
|
|
49
|
+
if (snapshot) {
|
|
50
|
+
const hadAsyncWork = asyncWorkEnds.has(e) || hasAsyncWork(snapshot);
|
|
51
|
+
watchAsyncWork(ctx, handler, () => generation === endGeneration, hadAsyncWork ? 500 : 1000);
|
|
52
|
+
}
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
setImmediate(() => {
|
|
56
|
+
if (generation === endGeneration)
|
|
57
|
+
settle(handler, ctx);
|
|
58
|
+
});
|
|
59
|
+
}));
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
return register(event, handler);
|
|
63
|
+
};
|
|
64
|
+
const registerCommand = (name, options) => pi.registerCommand(name, { ...options, handler: (args, ctx) => options.handler(args, withSystemPromptOptions(ctx, systemPromptOptions)) });
|
|
65
|
+
return overlay(pi, { on, registerCommand });
|
|
66
|
+
}
|
|
67
|
+
function toPiSkill(skill) {
|
|
68
|
+
return {
|
|
69
|
+
name: skill.name,
|
|
70
|
+
description: skill.description,
|
|
71
|
+
filePath: skill.filePath,
|
|
72
|
+
baseDir: skill.baseDir ?? "",
|
|
73
|
+
disableModelInvocation: skill.hide === true,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
async function beforeAgentStart(event, ctx, handler, options) {
|
|
77
|
+
const result = await handler({ ...event, systemPromptOptions: options }, ctx);
|
|
78
|
+
if (!options.appendSystemPrompt)
|
|
79
|
+
return result;
|
|
80
|
+
const prompt = systemPromptOf(result) ?? systemPromptOf(event) ?? [];
|
|
81
|
+
return { ...result, systemPrompt: [...(Array.isArray(prompt) ? prompt : [prompt]), options.appendSystemPrompt] };
|
|
82
|
+
}
|
|
83
|
+
function systemPromptOf(value) {
|
|
84
|
+
if (!value || typeof value !== "object" || !("systemPrompt" in value))
|
|
85
|
+
return undefined;
|
|
86
|
+
const prompt = value.systemPrompt;
|
|
87
|
+
return typeof prompt === "string" || Array.isArray(prompt) ? prompt : undefined;
|
|
88
|
+
}
|
|
89
|
+
function inputResult(result) {
|
|
90
|
+
const action = result?.action;
|
|
91
|
+
return action === "handled" ? { ...result, handled: true } : result;
|
|
92
|
+
}
|
|
93
|
+
function asyncJobSnapshot(ctx) {
|
|
94
|
+
const get = ctx?.getAsyncJobSnapshot;
|
|
95
|
+
if (typeof get !== "function")
|
|
96
|
+
return undefined;
|
|
97
|
+
const snapshot = get.call(ctx);
|
|
98
|
+
return snapshot && Array.isArray(snapshot.running) ? snapshot : undefined;
|
|
99
|
+
}
|
|
100
|
+
function hasAsyncWork(snapshot) {
|
|
101
|
+
return snapshot.running.length > 0 || (snapshot.delivery?.queued ?? 0) > 0 || snapshot.delivery?.delivering === true;
|
|
102
|
+
}
|
|
103
|
+
function watchAsyncWork(ctx, handler, isCurrent, delayMs) {
|
|
104
|
+
const check = () => {
|
|
105
|
+
if (!isCurrent())
|
|
106
|
+
return;
|
|
107
|
+
const snapshot = asyncJobSnapshot(ctx);
|
|
108
|
+
if (snapshot && hasAsyncWork(snapshot)) {
|
|
109
|
+
setTimeout(check, 500).unref();
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
settle(handler, ctx);
|
|
113
|
+
};
|
|
114
|
+
setTimeout(check, delayMs).unref();
|
|
115
|
+
}
|
|
116
|
+
function settle(handler, ctx) {
|
|
117
|
+
if (!isIdle(ctx))
|
|
118
|
+
return;
|
|
119
|
+
void Promise.resolve()
|
|
120
|
+
.then(() => handler({ type: "agent_settled" }, ctx))
|
|
121
|
+
.catch(error => console.error("pi-warden: agent_settled handler failed:", error));
|
|
122
|
+
}
|
|
123
|
+
/** A context without isIdle() cannot report a continuation, so it counts as idle. */
|
|
124
|
+
function isIdle(ctx) {
|
|
125
|
+
const check = ctx?.isIdle;
|
|
126
|
+
return typeof check === "function" ? check.call(ctx) !== false : true;
|
|
127
|
+
}
|
|
128
|
+
function withSystemPromptOptions(ctx, options) {
|
|
129
|
+
if (typeof ctx.getSystemPromptOptions === "function")
|
|
130
|
+
return ctx;
|
|
131
|
+
return overlay(ctx, { getSystemPromptOptions: options });
|
|
132
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface HostDirs {
|
|
2
|
+
/** The host's agent directory: `~/.pi/agent` on Pi, `~/.omp/agent` on oh-my-pi. */
|
|
3
|
+
agentDir: string;
|
|
4
|
+
/** The project config directory name: `.pi` on Pi, `.omp` on oh-my-pi. */
|
|
5
|
+
configDirName: string;
|
|
6
|
+
}
|
|
7
|
+
/** Expand a leading `~` or `~/` to the home directory; anything else comes back trimmed. */
|
|
8
|
+
export declare function expandHome(value: string): string;
|
|
9
|
+
/** Resolve the agent directory the way the host would: `PI_CODING_AGENT_DIR`, else Pi's default. */
|
|
10
|
+
export declare function defaultHostDirs(env?: NodeJS.ProcessEnv): HostDirs;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Host directories for pi-warden's own data. The library carries no runtime import of the optional
|
|
3
|
+
* Pi peer; the extension (src/extension.ts) builds these once from the host and passes them to every
|
|
4
|
+
* path call. `defaultHostDirs` covers the plain-library and test cases: `PI_CODING_AGENT_DIR` wins,
|
|
5
|
+
* `~` expands to the home directory, and the fallback matches Pi's own agent directory.
|
|
6
|
+
*/
|
|
7
|
+
import { homedir } from "node:os";
|
|
8
|
+
import { join } from "node:path";
|
|
9
|
+
/** Expand a leading `~` or `~/` to the home directory; anything else comes back trimmed. */
|
|
10
|
+
export function expandHome(value) {
|
|
11
|
+
const configured = value.trim();
|
|
12
|
+
return configured === "~" || configured.startsWith("~/") ? join(homedir(), configured.slice(1)) : configured;
|
|
13
|
+
}
|
|
14
|
+
/** Resolve the agent directory the way the host would: `PI_CODING_AGENT_DIR`, else Pi's default. */
|
|
15
|
+
export function defaultHostDirs(env = process.env) {
|
|
16
|
+
const configured = env.PI_CODING_AGENT_DIR?.trim();
|
|
17
|
+
return {
|
|
18
|
+
agentDir: configured ? expandHome(configured) : join(homedir(), ".pi", "agent"),
|
|
19
|
+
configDirName: ".pi",
|
|
20
|
+
};
|
|
21
|
+
}
|
package/dist/index-cmd.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Skill } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import type { CapabilityRole } from "./conscience.js";
|
|
3
|
+
import type { HostDirs } from "./host-dirs.js";
|
|
3
4
|
export { fileContentHash, toolSourceHash } from "./hashing.js";
|
|
4
5
|
export type SourceQuality = "strong" | "weak" | "thin";
|
|
5
6
|
export interface IndexEntry {
|
|
@@ -28,10 +29,10 @@ export interface IndexFile {
|
|
|
28
29
|
model: string;
|
|
29
30
|
entries: IndexEntry[];
|
|
30
31
|
}
|
|
31
|
-
/** The directory
|
|
32
|
-
export declare function indexDir(env?: NodeJS.ProcessEnv): string;
|
|
33
|
-
export declare function indexPath(kind: "global" | "project", projectRoot?: string): string;
|
|
34
|
-
export declare function ensureIndexDir(kind: "global" | "project"): void;
|
|
32
|
+
/** The index directory: `PI_WARDEN_INDEX_DIR` wins, then `PI_CODING_AGENT_DIR`, then the host directories. A `~` or `~/` prefix expands to the home directory. */
|
|
33
|
+
export declare function indexDir(env?: NodeJS.ProcessEnv, dirs?: HostDirs): string;
|
|
34
|
+
export declare function indexPath(kind: "global" | "project", projectRoot?: string, env?: NodeJS.ProcessEnv, dirs?: HostDirs): string;
|
|
35
|
+
export declare function ensureIndexDir(kind: "global" | "project", env?: NodeJS.ProcessEnv, dirs?: HostDirs): void;
|
|
35
36
|
/** Compute a sourceHash for a skill from its file content. */
|
|
36
37
|
export declare function skillSourceHash(skill: Skill): string;
|
|
37
38
|
export declare function readIndex(filePath: string): IndexFile | undefined;
|
|
@@ -76,7 +77,7 @@ export declare function buildIndexPrompt(cwd: string, skills: Array<{
|
|
|
76
77
|
}>, outputPaths: {
|
|
77
78
|
global: string;
|
|
78
79
|
project: string;
|
|
79
|
-
}): string;
|
|
80
|
+
}, dirs?: HostDirs): string;
|
|
80
81
|
/** Find an index entry by name and sourceHash. */
|
|
81
82
|
export declare function findEntry(name: string, sourceHash: string, globalIndex: IndexFile | undefined, projectIndex: IndexFile | undefined): IndexEntry | undefined;
|
|
82
83
|
/** Check whether all cached skills have matching entries in the index. */
|
package/dist/index-cmd.js
CHANGED
|
@@ -4,39 +4,30 @@
|
|
|
4
4
|
* entries in a fixed format; the extension validates and sanitizes them.
|
|
5
5
|
*/
|
|
6
6
|
import { readFileSync, writeFileSync, mkdirSync } from "node:fs";
|
|
7
|
-
import { join } from "node:path";
|
|
7
|
+
import { dirname, join } from "node:path";
|
|
8
8
|
import { createHash } from "node:crypto";
|
|
9
|
-
import { homedir } from "node:os";
|
|
10
9
|
import { sanitizeDescription } from "./conscience.js";
|
|
11
10
|
import { fileContentHash, toolSourceHash } from "./hashing.js";
|
|
11
|
+
import { PACKAGE_NAME } from "./config.js";
|
|
12
|
+
import { defaultHostDirs, expandHome } from "./host-dirs.js";
|
|
12
13
|
export { fileContentHash, toolSourceHash } from "./hashing.js";
|
|
13
14
|
/* ─── Path resolution ───────────────────────────────────────────────── */
|
|
14
|
-
/**
|
|
15
|
-
function
|
|
16
|
-
const configured = env.PI_WARDEN_INDEX_DIR?.trim()
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const expanded = configured === "~" || configured.startsWith("~/")
|
|
20
|
-
? join(homedir(), configured.slice(1))
|
|
21
|
-
: configured;
|
|
22
|
-
return expanded;
|
|
23
|
-
}
|
|
24
|
-
return join(homedir(), ".pi", "agent");
|
|
25
|
-
}
|
|
26
|
-
/** The directory `/warden index` asks the agent to write its index files into. */
|
|
27
|
-
export function indexDir(env = process.env) {
|
|
28
|
-
return join(resolveAgentDir(env), "pi-warden", "index");
|
|
15
|
+
/** The index directory: `PI_WARDEN_INDEX_DIR` wins, then `PI_CODING_AGENT_DIR`, then the host directories. A `~` or `~/` prefix expands to the home directory. */
|
|
16
|
+
export function indexDir(env = process.env, dirs = defaultHostDirs(env)) {
|
|
17
|
+
const configured = env.PI_WARDEN_INDEX_DIR?.trim() || env.PI_CODING_AGENT_DIR?.trim();
|
|
18
|
+
const base = configured ? expandHome(configured) : dirs.agentDir;
|
|
19
|
+
return join(base, PACKAGE_NAME, "index");
|
|
29
20
|
}
|
|
30
|
-
export function indexPath(kind, projectRoot) {
|
|
31
|
-
const base = indexDir();
|
|
21
|
+
export function indexPath(kind, projectRoot, env = process.env, dirs) {
|
|
22
|
+
const base = indexDir(env, dirs);
|
|
32
23
|
if (kind === "global")
|
|
33
24
|
return join(base, "global.json");
|
|
34
25
|
// Project index keyed by first 12 hex chars of SHA-256(projectRoot)
|
|
35
26
|
const hash = createHash("sha256").update(projectRoot ?? "").digest("hex").slice(0, 12);
|
|
36
27
|
return join(base, "projects", `${hash}.json`);
|
|
37
28
|
}
|
|
38
|
-
export function ensureIndexDir(kind) {
|
|
39
|
-
const dir = kind === "global" ? indexDir() : join(indexDir(), "projects");
|
|
29
|
+
export function ensureIndexDir(kind, env = process.env, dirs) {
|
|
30
|
+
const dir = kind === "global" ? indexDir(env, dirs) : join(indexDir(env, dirs), "projects");
|
|
40
31
|
mkdirSync(dir, { recursive: true });
|
|
41
32
|
}
|
|
42
33
|
/* ─── Content hashing ───────────────────────────────────────────────── */
|
|
@@ -58,7 +49,8 @@ export function readIndex(filePath) {
|
|
|
58
49
|
}
|
|
59
50
|
}
|
|
60
51
|
export function writeIndex(filePath, index) {
|
|
61
|
-
|
|
52
|
+
// The target's parent: `<index dir>/projects` for a project file, the index dir for the global one.
|
|
53
|
+
mkdirSync(dirname(filePath), { recursive: true });
|
|
62
54
|
writeFileSync(filePath, JSON.stringify(index, null, 2), "utf8");
|
|
63
55
|
}
|
|
64
56
|
function isIndexFile(value) {
|
|
@@ -237,7 +229,7 @@ const WRITING_RULES = `## Entry writing rules
|
|
|
237
229
|
* Build the user message that asks the session model to produce index entries.
|
|
238
230
|
* The prompt includes the format spec, writing rules, and both absolute output paths.
|
|
239
231
|
*/
|
|
240
|
-
export function buildIndexPrompt(cwd, skills, tools, outputPaths) {
|
|
232
|
+
export function buildIndexPrompt(cwd, skills, tools, outputPaths, dirs = defaultHostDirs()) {
|
|
241
233
|
const skillLines = skills.map(s => `- ${s.name}: ${s.description} (file: ${s.filePath})`).join("\n");
|
|
242
234
|
const toolLines = tools.map(t => `- ${t.name}: ${t.description}`).join("\n");
|
|
243
235
|
return [
|
|
@@ -280,7 +272,7 @@ export function buildIndexPrompt(cwd, skills, tools, outputPaths) {
|
|
|
280
272
|
"```",
|
|
281
273
|
"",
|
|
282
274
|
"## Scope",
|
|
283
|
-
|
|
275
|
+
`- Skills from ${dirs.agentDir}/skills/ and user-level directories: scope \`global\``,
|
|
284
276
|
"- Skills from the project directory: scope `project`",
|
|
285
277
|
"- All tools: scope `global`",
|
|
286
278
|
"",
|
package/dist/index.d.ts
CHANGED
|
@@ -32,20 +32,26 @@ export type { ContextLedgerSnapshot, RecallKind } from "./saver.js";
|
|
|
32
32
|
export type { ShapeResult } from "./shape.js";
|
|
33
33
|
export { CONFIG_SCHEMA, defaultConfig, loadConfig, applyUserOverrides, applyProjectOverrides, isMode, isRecallTool, userConfigPath, projectConfigPath, readUserConfig, writeUserConfig, setUserSetting, setNestedValue, getNestedValue, parseConfigValue, PACKAGE_NAME } from "./config.js";
|
|
34
34
|
export type { ActionGuardConfig, OffTaskThreshold, StuckGuardConfig, DoneGuardConfig, VisualToolsConfig, SlopGuardConfig, ProseConfig, SecurityConfig, RulesConfig, ContextConfig, LargeOutputConfig, RunawayConfig, NotifyConfig, SubagentConfig, RecallTool, Threshold, WardenConfig, WardenMode, LoadOptions } from "./config.js";
|
|
35
|
+
export { defaultHostDirs } from "./host-dirs.js";
|
|
36
|
+
export type { HostDirs } from "./host-dirs.js";
|
|
35
37
|
export { commandOf, outputReportsFailure, COMMAND_TOOLS } from "./tools.js";
|
|
36
38
|
export type { CommandView } from "./tools.js";
|
|
37
39
|
export { renderTemplate, actionTokens, stuckTokens, doneTokens, proseTokens, runawayTokens, rulesTokens, defaultWidgetConfig, DEFAULT_TEMPLATES, SENTENCE_TEMPLATES, pickSentenceTemplate, TOKEN_NAMES } from "./widget.js";
|
|
38
40
|
export type { WidgetConfig, WidgetPlacement, WidgetBarMode, Tokens } from "./widget.js";
|
|
39
41
|
export { Trace, actionDetails, stuckDetails, doneDetails, proseDetails, runawayDetails, rulesDetails } from "./trace.js";
|
|
40
42
|
export type { TraceEntry, GuardName } from "./trace.js";
|
|
41
|
-
export { parseRules, condense, isRuleShaped, globToRegExp, matchGlob, projectPath, RuleStore, rulesFor, describeRuleSet, formatRuleSetDetails, describeTarget, buildRulesRequest, ruleQuestion, evaluateRules, skipReason, rulesSteer, formatRules, pathNotes, pathNoteSteer, RulesGuard, RULES_FILE, FALLBACK_FILES, MAX_RULES, AGGREGATE_QUESTION, LOCATOR_QUESTION } from "./rules.js";
|
|
42
|
-
export type { Rule, RuleSet, RuleOutcome, RuleScore, RuleFinding, RulesVerdict, RulesOptions, RulesTarget, EditView, PathNote, RulesCallRef, RulesTier, RulesSourceConfig } from "./rules.js";
|
|
43
|
-
export {
|
|
43
|
+
export { parseRules, condense, isRuleShaped, globToRegExp, matchGlob, projectPath, RuleStore, rulesFor, describeRuleSet, formatRuleSetDetails, describeTarget, buildRulesRequest, ruleQuestion, scoreRuleAnswers, evaluateRules, skipReason, rulesSteer, formatRules, pathNotes, pathNoteSteer, RulesGuard, RULES_FILE, FALLBACK_FILES, MAX_RULES, MAX_EDITS, EDIT_TEXT_LIMIT, EDIT_CONTEXT_LINES, AGGREGATE_QUESTION, LOCATOR_QUESTION, editRulesFor, turnRulesFor, evaluateRulesTarget, scoreAnswers } from "./rules.js";
|
|
44
|
+
export type { Rule, RuleSet, RuleOutcome, RuleScore, RuleFinding, RuleAnswer, RuleScoring, RulesVerdict, RulesOptions, RulesTarget, EditView, PathNote, RulesCallRef, RulesTier, RulesSourceConfig, RuleWhen, RuleScoreEntry } from "./rules.js";
|
|
45
|
+
export { snapshotTree, diffSince, unjudgedFiles, evaluateTurnRules, evaluateTurnRun, buildTurnRequest, turnRuleQuestion, turnSteer, TURN_PATH, TURN_QUESTION_PREFIX } from "./turn-rules.js";
|
|
46
|
+
export type { SnapshotResult, TurnDiff, TurnFileDiff, TurnRunOptions, TurnRunResult, TurnRulesOptions } from "./turn-rules.js";
|
|
47
|
+
export { checkRules, formatRulesCheck, formatRuleCheck, checkReasons, buildRulesCheckRequest, ruleCheckView, judgeableQuestion, mechanicalQuestion, MECHANICAL_CUTOFF, CHECK_ABOUT, JUDGEABILITY_REASONS, JUDGEABLE_PREFIX, MECHANICAL_PREFIX } from "./rules-lint.js";
|
|
44
48
|
export type { RuleCheck, RuleCheckView, RuleJudgeability, RulesCheckOptions, RulesCheckRequest, RulesCheckResult, RulesCheckSource } from "./rules-lint.js";
|
|
45
49
|
export { rulesLogPath, readRulesLog, trimRecords, RuleClearTracker, RulesLog, RULES_LOG_MAX_RECORDS } from "./rules-log.js";
|
|
46
50
|
export type { RuleRecord, RuleObservation, RulesLogOptions } from "./rules-log.js";
|
|
47
51
|
export { buildRulesReport, formatRulesReport, compareRows, REPORT_DEFAULT_DAYS, NEVER_FIRES_MIN, FIRES_RATE_MAX, UNDECIDED_LOW, UNDECIDED_HIGH } from "./rules-report.js";
|
|
48
|
-
export type { RuleFlag, RuleReportRow, RulesReport } from "./rules-report.js";
|
|
52
|
+
export type { RuleFlag, RuleReportRow, RulesReport, ReportSource } from "./rules-report.js";
|
|
53
|
+
export { parseHistory, collectHistory, changeSkipReason, editViews, planCalibration, calibrate, formatCalibration, calibrateGate, calibrationNotice, tuneTargets, buildTunePrompt, tuneRequest, CALIBRATE_DEFAULT_COMMITS, CALIBRATE_DEFAULT_MAX } from "./rules-calibrate.js";
|
|
54
|
+
export type { HistoryHunk, HistoryFile, HistoryCommit, CalibrateSkip, CalibrateSample, CalibratePlan, PlanOptions, RuleCalibration, Calibration, CalibrateOptions, CalibrateGate, TuneRule, TuneRequest } from "./rules-calibrate.js";
|
|
49
55
|
export { resolveRulesFile, extractRules, checkPiWardenMissing } from "./rules-file.js";
|
|
50
56
|
export type { ResolvedRulesFile } from "./rules-file.js";
|
|
51
57
|
export { writeStarterRules, generateStarterRules, detectProjectType, buildProjectContext, buildInitPrompt } from "./init.js";
|
|
@@ -54,3 +60,5 @@ export { initSchema, recordHold, recordOutcome as recordHoldOutcome, querySmartH
|
|
|
54
60
|
export type { HoldRecord, HoldScores, HoldLevel, HoldOutcome, HoldContext, SmartHistory, ConfidenceResult, SkipResult, ThresholdAdjustment, PatternInsight, ContextRecommendation, SteerEffectivenessReport } from "./learning.js";
|
|
55
61
|
export { buildAuditPrompt, snapshotReport, reportOutcome } from "./audit.js";
|
|
56
62
|
export type { ReportSnapshot } from "./audit.js";
|
|
63
|
+
export { parseRulesAuditArgs, parseBenchArgs, collectAuditFiles, runRulesAudit, ruleAuditRows, flaggedAuditFiles, formatRulesAuditRows, formatRulesAuditFiles, formatRulesAudit, rulesAuditMarkdown, writeRulesAuditReport, runBench, formatBench, percentile, BENCH_SAMPLE, AUDIT_DEFAULT_MAX, AUDIT_CONCURRENCY, AUDIT_REPORT_FILE, RULES_AUDIT_USAGE, BENCH_USAGE } from "./rules-audit.js";
|
|
64
|
+
export type { RulesAuditArgs, BenchArgs, AuditFilePlan, RulesAuditFileResult, RulesAuditRow, RulesAuditOutcome, RulesAuditResult, RulesAuditOptions, RulesAuditFlag, RulesAuditFileFlags, BenchUsage, BenchOptions, BenchResult } from "./rules-audit.js";
|
package/dist/index.js
CHANGED
|
@@ -16,14 +16,18 @@ export { completeConfig, shapeWarning, EXPECTED_SCHEMA } from "./shape.js";
|
|
|
16
16
|
export { ContextLedger, formatLedger } from "./saver.js";
|
|
17
17
|
export { HoldLedger, HoldLog, holdLogPath, formatHolds, outcomeNote, regretsAt, textRegrets } from "./holds.js";
|
|
18
18
|
export { CONFIG_SCHEMA, defaultConfig, loadConfig, applyUserOverrides, applyProjectOverrides, isMode, isRecallTool, userConfigPath, projectConfigPath, readUserConfig, writeUserConfig, setUserSetting, setNestedValue, getNestedValue, parseConfigValue, PACKAGE_NAME } from "./config.js";
|
|
19
|
+
export { defaultHostDirs } from "./host-dirs.js";
|
|
19
20
|
export { commandOf, outputReportsFailure, COMMAND_TOOLS } from "./tools.js";
|
|
20
21
|
export { renderTemplate, actionTokens, stuckTokens, doneTokens, proseTokens, runawayTokens, rulesTokens, defaultWidgetConfig, DEFAULT_TEMPLATES, SENTENCE_TEMPLATES, pickSentenceTemplate, TOKEN_NAMES } from "./widget.js";
|
|
21
22
|
export { Trace, actionDetails, stuckDetails, doneDetails, proseDetails, runawayDetails, rulesDetails } from "./trace.js";
|
|
22
|
-
export { parseRules, condense, isRuleShaped, globToRegExp, matchGlob, projectPath, RuleStore, rulesFor, describeRuleSet, formatRuleSetDetails, describeTarget, buildRulesRequest, ruleQuestion, evaluateRules, skipReason, rulesSteer, formatRules, pathNotes, pathNoteSteer, RulesGuard, RULES_FILE, FALLBACK_FILES, MAX_RULES, AGGREGATE_QUESTION, LOCATOR_QUESTION } from "./rules.js";
|
|
23
|
-
export {
|
|
23
|
+
export { parseRules, condense, isRuleShaped, globToRegExp, matchGlob, projectPath, RuleStore, rulesFor, describeRuleSet, formatRuleSetDetails, describeTarget, buildRulesRequest, ruleQuestion, scoreRuleAnswers, evaluateRules, skipReason, rulesSteer, formatRules, pathNotes, pathNoteSteer, RulesGuard, RULES_FILE, FALLBACK_FILES, MAX_RULES, MAX_EDITS, EDIT_TEXT_LIMIT, EDIT_CONTEXT_LINES, AGGREGATE_QUESTION, LOCATOR_QUESTION, editRulesFor, turnRulesFor, evaluateRulesTarget, scoreAnswers } from "./rules.js";
|
|
24
|
+
export { snapshotTree, diffSince, unjudgedFiles, evaluateTurnRules, evaluateTurnRun, buildTurnRequest, turnRuleQuestion, turnSteer, TURN_PATH, TURN_QUESTION_PREFIX } from "./turn-rules.js";
|
|
25
|
+
export { checkRules, formatRulesCheck, formatRuleCheck, checkReasons, buildRulesCheckRequest, ruleCheckView, judgeableQuestion, mechanicalQuestion, MECHANICAL_CUTOFF, CHECK_ABOUT, JUDGEABILITY_REASONS, JUDGEABLE_PREFIX, MECHANICAL_PREFIX } from "./rules-lint.js";
|
|
24
26
|
export { rulesLogPath, readRulesLog, trimRecords, RuleClearTracker, RulesLog, RULES_LOG_MAX_RECORDS } from "./rules-log.js";
|
|
25
27
|
export { buildRulesReport, formatRulesReport, compareRows, REPORT_DEFAULT_DAYS, NEVER_FIRES_MIN, FIRES_RATE_MAX, UNDECIDED_LOW, UNDECIDED_HIGH } from "./rules-report.js";
|
|
28
|
+
export { parseHistory, collectHistory, changeSkipReason, editViews, planCalibration, calibrate, formatCalibration, calibrateGate, calibrationNotice, tuneTargets, buildTunePrompt, tuneRequest, CALIBRATE_DEFAULT_COMMITS, CALIBRATE_DEFAULT_MAX } from "./rules-calibrate.js";
|
|
26
29
|
export { resolveRulesFile, extractRules, checkPiWardenMissing } from "./rules-file.js";
|
|
27
30
|
export { writeStarterRules, generateStarterRules, detectProjectType, buildProjectContext, buildInitPrompt } from "./init.js";
|
|
28
31
|
export { initSchema, recordHold, recordOutcome as recordHoldOutcome, querySmartHistory, calculateSmartConfidence, shouldSkipHold, analyzeThresholds, analyzePatterns, generateRecommendations, analyzeSteerEffectivenessReport } from "./learning.js";
|
|
29
32
|
export { buildAuditPrompt, snapshotReport, reportOutcome } from "./audit.js";
|
|
33
|
+
export { parseRulesAuditArgs, parseBenchArgs, collectAuditFiles, runRulesAudit, ruleAuditRows, flaggedAuditFiles, formatRulesAuditRows, formatRulesAuditFiles, formatRulesAudit, rulesAuditMarkdown, writeRulesAuditReport, runBench, formatBench, percentile, BENCH_SAMPLE, AUDIT_DEFAULT_MAX, AUDIT_CONCURRENCY, AUDIT_REPORT_FILE, RULES_AUDIT_USAGE, BENCH_USAGE } from "./rules-audit.js";
|
package/dist/init.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
|
-
import { FALLBACK_FILES } from "./rules.js";
|
|
3
|
+
import { FALLBACK_FILES, MAX_RULES } from "./rules.js";
|
|
4
|
+
/** Fallback files whose content is instruction text to compile into small rules; a README-style file stays whole text. */
|
|
5
|
+
const INSTRUCTION_FILES = ["AGENTS.md", "CLAUDE.md"];
|
|
4
6
|
/** Paths to scan for project context when generating a starter rules file. */
|
|
5
7
|
const CONTEXT_CANDIDATES = [
|
|
6
8
|
"package.json",
|
|
@@ -100,6 +102,26 @@ function readExistingPiWarden(cwd) {
|
|
|
100
102
|
return null;
|
|
101
103
|
}
|
|
102
104
|
}
|
|
105
|
+
/** The first instruction file's lines with their 1-based line numbers, or null when none exists. */
|
|
106
|
+
function readNumberedInstructions(cwd) {
|
|
107
|
+
for (const file of INSTRUCTION_FILES) {
|
|
108
|
+
const fullPath = join(cwd, file);
|
|
109
|
+
if (!existsSync(fullPath))
|
|
110
|
+
continue;
|
|
111
|
+
try {
|
|
112
|
+
const lines = readFileSync(fullPath, "utf8").split(/\r\n|\r|\n/);
|
|
113
|
+
if (lines.at(-1) === "")
|
|
114
|
+
lines.pop();
|
|
115
|
+
if (!lines.some(line => line.trim()))
|
|
116
|
+
continue;
|
|
117
|
+
return { file, text: lines.map((line, index) => `${index + 1}: ${line}`).join("\n") };
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
103
125
|
/** Standard safety rules that ship in every starter pi-warden.md. */
|
|
104
126
|
const SAFETY_RULES = `# No hardcoded secrets
|
|
105
127
|
Source code must not contain passwords, API keys, tokens, or connection URLs with credentials.
|
|
@@ -174,8 +196,14 @@ export function buildInitPrompt(cwd) {
|
|
|
174
196
|
if (existingPiWarden) {
|
|
175
197
|
lines.push("", "## Existing pi-warden.md rules (preserve these)", existingPiWarden, "");
|
|
176
198
|
}
|
|
177
|
-
else
|
|
178
|
-
|
|
199
|
+
else {
|
|
200
|
+
const instructions = readNumberedInstructions(cwd);
|
|
201
|
+
if (instructions) {
|
|
202
|
+
lines.push("", `## Existing instructions to compile (from ${instructions.file}, each line prefixed with its line number)`, instructions.text, "", "Compile these instructions into rules: one small rule per instruction that can be judged from one changed file alone, without other files, repository history, or the task.", "- Give each rule a `source: <file>:<line>` header naming the instruction line it came from, for example `source: AGENTS.md:65`.", "- Add a `paths:` header when the instruction concerns certain files only.", "- Keep each rule's wording close to the source instruction.", "- Name the concrete pattern that shows a violation: a symbol, a comment phrase, a command, a file shape.", `- Stay under the rule cap: at most ${MAX_RULES} rules.`, "", "Leave these instructions out of pi-warden.md, and list each left-out instruction in your reply with the reason:", "- an instruction that needs other files, repository history, or the task to judge", "- an instruction that a linter, formatter, or type checker already enforces", "", "In your reply, suggest running `/warden rules check` when the user has a TypeSafe key. Suggest it only; never run it as part of this task.", "");
|
|
203
|
+
}
|
|
204
|
+
else if (existingRules) {
|
|
205
|
+
lines.push("", "## Existing project rules (preserve these)", existingRules, "");
|
|
206
|
+
}
|
|
179
207
|
}
|
|
180
208
|
if (projectType === "typescript" || projectType === "javascript") {
|
|
181
209
|
lines.push("## Type-specific rules", "- No explicit `any` in **/*.ts, **/*.tsx", "- Exported functions declare their return type in src/**/*.ts", "");
|
package/dist/learning.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import type { HostDirs } from "./host-dirs.js";
|
|
1
2
|
import type { CallScores } from "./holds.js";
|
|
2
3
|
export declare const HOLDS_SCHEMA = "\n CREATE TABLE IF NOT EXISTS holds (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n timestamp INTEGER NOT NULL,\n project_root TEXT NOT NULL,\n tool TEXT NOT NULL,\n signature_hash TEXT NOT NULL,\n command_preview TEXT,\n task TEXT,\n plan TEXT,\n context_summary TEXT,\n preceding_actions TEXT,\n scores TEXT NOT NULL,\n level TEXT NOT NULL,\n held INTEGER NOT NULL,\n reasons TEXT,\n agent_reason TEXT,\n outcome TEXT,\n outcome_at INTEGER,\n confidence REAL\n );\n CREATE INDEX IF NOT EXISTS idx_holds_project_signature ON holds(project_root, signature_hash);\n CREATE INDEX IF NOT EXISTS idx_holds_outcome ON holds(outcome);\n CREATE INDEX IF NOT EXISTS idx_holds_timestamp ON holds(timestamp);\n";
|
|
3
|
-
export declare function initSchema(retentionDays?: number): Promise<void>;
|
|
4
|
+
export declare function initSchema(retentionDays?: number, dirs?: HostDirs): Promise<void>;
|
|
4
5
|
export interface HoldScores {
|
|
5
6
|
irreversible: number;
|
|
6
7
|
/** Reason categories from the verdict, used for same-reason queries and destructive-pattern detection. */
|
|
@@ -66,12 +67,12 @@ export declare function toHoldRecord(item: {
|
|
|
66
67
|
scores?: CallScores | undefined;
|
|
67
68
|
held?: boolean | undefined;
|
|
68
69
|
}, projectRoot: string, ctx?: HoldContext): HoldRecord;
|
|
69
|
-
export declare function recordHold(hold: HoldRecord): Promise<number>;
|
|
70
|
-
export declare function recordOutcome(id: number, outcome: string): Promise<void>;
|
|
70
|
+
export declare function recordHold(hold: HoldRecord, dirs?: HostDirs): Promise<number>;
|
|
71
|
+
export declare function recordOutcome(id: number, outcome: string, dirs?: HostDirs): Promise<void>;
|
|
71
72
|
/** Query holds by project and held value. Used by tests and future analytics. */
|
|
72
73
|
export declare function queryHoldsForProject(projectRoot: string, options?: {
|
|
73
74
|
held?: boolean;
|
|
74
|
-
}): Promise<Record<string, unknown>[]>;
|
|
75
|
+
}, dirs?: HostDirs): Promise<Record<string, unknown>[]>;
|
|
75
76
|
/** Lifetime hold statistics for one project root. Matches the precision formula in holds.ts: (declined + replanned) / (approved + declined + replanned). */
|
|
76
77
|
export interface HoldStats {
|
|
77
78
|
/** held = 1 rows for this root. */
|
|
@@ -94,10 +95,10 @@ export interface HoldStats {
|
|
|
94
95
|
oldest: number;
|
|
95
96
|
newest: number;
|
|
96
97
|
}
|
|
97
|
-
export declare function holdStats(projectRoot: string): Promise<HoldStats>;
|
|
98
|
-
export declare function querySmartHistory(tool: string, scores: HoldScores, projectRoot: string): Promise<SmartHistory>;
|
|
98
|
+
export declare function holdStats(projectRoot: string, dirs?: HostDirs): Promise<HoldStats>;
|
|
99
|
+
export declare function querySmartHistory(tool: string, scores: HoldScores, projectRoot: string, dirs?: HostDirs): Promise<SmartHistory>;
|
|
99
100
|
export declare function calculateSmartConfidence(history: SmartHistory): ConfidenceResult;
|
|
100
|
-
export declare function shouldSkipHold(tool: string, scores: HoldScores, projectRoot: string): Promise<SkipResult>;
|
|
101
|
+
export declare function shouldSkipHold(tool: string, scores: HoldScores, projectRoot: string, dirs?: HostDirs): Promise<SkipResult>;
|
|
101
102
|
/** Learn from past outcomes to suggest threshold adjustments. */
|
|
102
103
|
export interface ThresholdAdjustment {
|
|
103
104
|
guard: string;
|
|
@@ -107,7 +108,7 @@ export interface ThresholdAdjustment {
|
|
|
107
108
|
confidence: number;
|
|
108
109
|
}
|
|
109
110
|
/** Analyze hold outcomes to suggest threshold adjustments. */
|
|
110
|
-
export declare function analyzeThresholds(projectRoot: string): Promise<ThresholdAdjustment[]>;
|
|
111
|
+
export declare function analyzeThresholds(projectRoot: string, dirs?: HostDirs): Promise<ThresholdAdjustment[]>;
|
|
111
112
|
/** Learn which patterns are most likely to be false positives. */
|
|
112
113
|
export interface PatternInsight {
|
|
113
114
|
pattern: string;
|
|
@@ -115,14 +116,14 @@ export interface PatternInsight {
|
|
|
115
116
|
sampleSize: number;
|
|
116
117
|
suggestion: string;
|
|
117
118
|
}
|
|
118
|
-
export declare function analyzePatterns(projectRoot: string): Promise<PatternInsight[]>;
|
|
119
|
+
export declare function analyzePatterns(projectRoot: string, dirs?: HostDirs): Promise<PatternInsight[]>;
|
|
119
120
|
export interface ContextRecommendation {
|
|
120
121
|
type: 'threshold' | 'exempt' | 'pattern';
|
|
121
122
|
message: string;
|
|
122
123
|
priority: 'high' | 'medium' | 'low';
|
|
123
124
|
}
|
|
124
125
|
/** Generate recommendations based on learning data. */
|
|
125
|
-
export declare function generateRecommendations(projectRoot: string): Promise<ContextRecommendation[]>;
|
|
126
|
+
export declare function generateRecommendations(projectRoot: string, dirs?: HostDirs): Promise<ContextRecommendation[]>;
|
|
126
127
|
/** Analyze which types of steers are most effective at changing agent behavior. */
|
|
127
128
|
export interface SteerEffectivenessReport {
|
|
128
129
|
/** Overall effectiveness rate (0-1). */
|
|
@@ -143,4 +144,4 @@ export interface SteerEffectivenessReport {
|
|
|
143
144
|
}>;
|
|
144
145
|
}
|
|
145
146
|
/** Analyze steer effectiveness from hold outcomes. */
|
|
146
|
-
export declare function analyzeSteerEffectivenessReport(projectRoot: string): Promise<SteerEffectivenessReport>;
|
|
147
|
+
export declare function analyzeSteerEffectivenessReport(projectRoot: string, dirs?: HostDirs): Promise<SteerEffectivenessReport>;
|