pi-harness-runtime 1.1.148 → 1.1.152
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 +7 -0
- package/harness/key-loader.ts +84 -0
- package/harness/langchain/agents.ts +65 -15
- package/harness/langchain/daemon.ts +58 -30
- package/harness/langchain/graph.ts +55 -7
- package/harness/langchain/jev-logger.ts +274 -0
- package/harness/langchain/run.ts +64 -161
- package/harness/langchain/surge.test.ts +42 -0
- package/harness/langchain/surge.ts +22 -1
- package/index.ts +65 -26
- package/package.json +1 -1
- package/packages/a2a-adapter/package.json +1 -1
- package/packages/agent-policy/dist/extension.d.ts +19 -0
- package/packages/agent-policy/dist/extension.d.ts.map +1 -0
- package/packages/agent-policy/dist/extension.js +322 -0
- package/packages/agent-policy/dist/extension.js.map +1 -0
- package/packages/agent-policy/dist/index.d.ts +25 -0
- package/packages/agent-policy/dist/index.d.ts.map +1 -0
- package/packages/agent-policy/dist/index.js +27 -0
- package/packages/agent-policy/dist/index.js.map +1 -0
- package/packages/agent-policy/dist/policy-loader.d.ts +90 -0
- package/packages/agent-policy/dist/policy-loader.d.ts.map +1 -0
- package/packages/agent-policy/dist/policy-loader.js +331 -0
- package/packages/agent-policy/dist/policy-loader.js.map +1 -0
- package/packages/agent-policy/dist/policy-renderer.d.ts +42 -0
- package/packages/agent-policy/dist/policy-renderer.d.ts.map +1 -0
- package/packages/agent-policy/dist/policy-renderer.js +295 -0
- package/packages/agent-policy/dist/policy-renderer.js.map +1 -0
- package/packages/agent-policy/dist/policy-store.d.ts +99 -0
- package/packages/agent-policy/dist/policy-store.d.ts.map +1 -0
- package/packages/agent-policy/dist/policy-store.js +244 -0
- package/packages/agent-policy/dist/policy-store.js.map +1 -0
- package/packages/agent-policy/dist/types.d.ts +237 -0
- package/packages/agent-policy/dist/types.d.ts.map +1 -0
- package/packages/agent-policy/dist/types.js +130 -0
- package/packages/agent-policy/dist/types.js.map +1 -0
- package/packages/agent-policy/package.json +45 -0
- package/packages/agent-policy/src/extension.ts +413 -0
- package/packages/agent-policy/src/index.ts +52 -0
- package/packages/agent-policy/src/policy-loader.ts +398 -0
- package/packages/agent-policy/src/policy-renderer.ts +362 -0
- package/packages/agent-policy/src/policy-store.ts +319 -0
- package/packages/agent-policy/src/types.ts +385 -0
- package/packages/agent-policy/test/policy.test.ts +383 -0
- package/packages/architecture-generator/package.json +1 -1
- package/packages/auth/package.json +1 -1
- package/packages/autonomous-refactor/package.json +1 -1
- package/packages/autonomous-runtime/package.json +1 -1
- package/packages/cache-strategy/package.json +1 -1
- package/packages/capability-registry/package.json +1 -1
- package/packages/checkpoint/package.json +1 -1
- package/packages/cli-plugin-sdk/package.json +1 -1
- package/packages/clipboard/package.json +1 -1
- package/packages/clipboard-plugin/package.json +1 -1
- package/packages/code-generation/package.json +1 -1
- package/packages/code-review/package.json +1 -1
- package/packages/codex-adapter/package.json +1 -1
- package/packages/codex-watcher/dist/src/parser.d.ts.map +1 -1
- package/packages/codex-watcher/dist/src/parser.js +35 -0
- package/packages/codex-watcher/dist/src/parser.js.map +1 -1
- package/packages/codex-watcher/package.json +1 -1
- package/packages/codex-watcher/src/parser.ts +41 -0
- package/packages/config-capture/package.json +1 -1
- package/packages/context-compiler/package.json +1 -1
- package/packages/context-discovery/package.json +1 -1
- package/packages/context-manager/package.json +1 -1
- package/packages/cookie-sanitizer/package.json +1 -1
- package/packages/cost-optimizer/package.json +1 -1
- package/packages/dependency-analyzer/package.json +1 -1
- package/packages/django-plugin/package.json +1 -1
- package/packages/doc-generator/package.json +1 -1
- package/packages/evaluation-engine/package.json +1 -1
- package/packages/evaluation-runner/package.json +1 -1
- package/packages/event-bus/package.json +1 -1
- package/packages/event-store/package.json +1 -1
- package/packages/experience-replay/package.json +1 -1
- package/packages/feedback-collector/package.json +1 -1
- package/packages/file-copy-helper/package.json +1 -1
- package/packages/framework-detector/package.json +1 -1
- package/packages/framework-plugin-sdk/package.json +1 -1
- package/packages/frappe-plugin/package.json +1 -1
- package/packages/generic-web-plugin/package.json +1 -1
- package/packages/health-monitor/package.json +1 -1
- package/packages/intent-analyzer/package.json +1 -1
- package/packages/jev-judge/package.json +1 -1
- package/packages/knowledge-graph/package.json +1 -1
- package/packages/knowledge-retrieval/package.json +1 -1
- package/packages/laravel-plugin/package.json +1 -1
- package/packages/learning-engine/package.json +1 -1
- package/packages/mcp-adapter/package.json +1 -1
- package/packages/memory-engine/package.json +1 -1
- package/packages/milestone-manager/package.json +1 -1
- package/packages/model-registry/package.json +1 -1
- package/packages/nextjs-plugin/package.json +1 -1
- package/packages/notification/dist/adapters/telegram-adapter.d.ts +5 -0
- package/packages/notification/dist/adapters/telegram-adapter.d.ts.map +1 -1
- package/packages/notification/dist/adapters/telegram-adapter.js +54 -0
- package/packages/notification/dist/adapters/telegram-adapter.js.map +1 -1
- package/packages/notification/dist/notification-center.d.ts +13 -0
- package/packages/notification/dist/notification-center.d.ts.map +1 -1
- package/packages/notification/dist/notification-center.js +36 -0
- package/packages/notification/dist/notification-center.js.map +1 -1
- package/packages/notification/package.json +1 -1
- package/packages/notification/src/adapters/telegram-adapter.ts +71 -0
- package/packages/notification/src/notification-center.ts +53 -0
- package/packages/observability/package.json +1 -1
- package/packages/okf-indexer/package.json +1 -1
- package/packages/paperclip-integration/package.json +1 -1
- package/packages/performance-optimizer/package.json +1 -1
- package/packages/privilege-broker/package.json +1 -1
- package/packages/project-analyzer/package.json +1 -1
- package/packages/project-bootstrap/package.json +1 -1
- package/packages/projection-engine/package.json +1 -1
- package/packages/prompt-compiler/package.json +1 -1
- package/packages/prompt-versioning/package.json +1 -1
- package/packages/provider-adapter-sdk/package.json +1 -1
- package/packages/provider-router/package.json +1 -1
- package/packages/provider-selector/package.json +1 -1
- package/packages/providers/package.json +1 -1
- package/packages/qdrant-skills/package.json +1 -1
- package/packages/quota-manager/package.json +1 -1
- package/packages/rate-limiter/package.json +1 -1
- package/packages/react-vite-plugin/package.json +1 -1
- package/packages/release-manager/package.json +1 -1
- package/packages/requirement-compiler/package.json +1 -1
- package/packages/runtime/package.json +1 -1
- package/packages/scheduler/package.json +1 -1
- package/packages/scheduler-adapter/package.json +1 -1
- package/packages/session/package.json +1 -1
- package/packages/session-api/package.json +1 -1
- package/packages/session-export/package.json +1 -1
- package/packages/shared-context/package.json +1 -1
- package/packages/skill-mcp-client/package.json +1 -1
- package/packages/skill-registry/package.json +1 -1
- package/packages/skills/package.json +1 -1
- package/packages/sprint-planner/package.json +1 -1
- package/packages/subscription-engine/package.json +1 -1
- package/packages/task-compiler/package.json +1 -1
- package/packages/tencentdb-memory/package.json +1 -1
- package/packages/tencentdb-sync/package.json +1 -1
- package/packages/test-data-generator/package.json +1 -1
- package/packages/test-generator/package.json +1 -1
- package/packages/todo-bd-sync/package.json +1 -1
- package/packages/token-estimation/package.json +1 -1
- package/packages/token-optimizer/package.json +1 -1
- package/packages/trajectory/package.json +1 -1
- package/packages/tui/package.json +1 -1
- package/packages/types/package.json +1 -1
- package/packages/workflow-events/package.json +1 -1
- package/packages/workspace-scanner/package.json +1 -1
- package/packages/worktree/package.json +1 -1
- package/packages/write-review/package.json +1 -1
- package/proactive-compact.ts +2 -2
- package/scripts/debug-codex-integration.ts +203 -0
- package/scripts/sync-keys-from-pi.ts +188 -0
- package/scripts/test-codex-session.ts +23 -0
- package/scripts/test-openai.ts +14 -0
- package/scripts/test-telegram.ts +34 -0
|
@@ -0,0 +1,413 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Policy Extension
|
|
3
|
+
*
|
|
4
|
+
* Registers the policy runtime with Pi's event system:
|
|
5
|
+
* - before_agent_start: inject system contract
|
|
6
|
+
* - tool_call: gate mutations until policy received
|
|
7
|
+
* - harness_rules tool: retrieve and acknowledge rules
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type {
|
|
11
|
+
ExtensionAPI,
|
|
12
|
+
ToolCallEvent,
|
|
13
|
+
SessionStartEvent,
|
|
14
|
+
BeforeAgentStartEvent,
|
|
15
|
+
} from "@earendil-works/pi-coding-agent";
|
|
16
|
+
import type {
|
|
17
|
+
AgentPolicyConfig,
|
|
18
|
+
HarnessRulesInput,
|
|
19
|
+
} from "./types.js";
|
|
20
|
+
import { PolicyLoader } from "./policy-loader.js";
|
|
21
|
+
import { getPolicyStore } from "./policy-store.js";
|
|
22
|
+
import {
|
|
23
|
+
renderSystemContract,
|
|
24
|
+
renderFullRules,
|
|
25
|
+
} from "./policy-renderer.js";
|
|
26
|
+
import { classifyToolCall } from "./types.js";
|
|
27
|
+
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
// Extension Registration
|
|
30
|
+
// ---------------------------------------------------------------------------
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Register the agent policy runtime with Pi.
|
|
34
|
+
*/
|
|
35
|
+
export function registerAgentPolicy(
|
|
36
|
+
pi: ExtensionAPI,
|
|
37
|
+
config: AgentPolicyConfig
|
|
38
|
+
): void {
|
|
39
|
+
const loader = new PolicyLoader({
|
|
40
|
+
harnessRulesPath: config.harnessRulesPath,
|
|
41
|
+
additionalRulesPaths: config.additionalRulesPaths,
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
const store = getPolicyStore();
|
|
45
|
+
const toolClassifier = config.toolClassifier ?? classifyToolCall;
|
|
46
|
+
|
|
47
|
+
// Track if pi-lens is available
|
|
48
|
+
let piLensAvailable = false;
|
|
49
|
+
|
|
50
|
+
// Check for pi-lens availability on session start
|
|
51
|
+
pi.on("session_start", async (event: SessionStartEvent) => {
|
|
52
|
+
// pi-lens registers its own tools, so we can check for them
|
|
53
|
+
const availableTools = (event as { availableTools?: string[] }).availableTools ?? [];
|
|
54
|
+
piLensAvailable = availableTools.includes("lens_diagnostics");
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// ---------------------------------------------------------------------------
|
|
58
|
+
// before_agent_start: Inject system contract
|
|
59
|
+
// ---------------------------------------------------------------------------
|
|
60
|
+
|
|
61
|
+
pi.on("before_agent_start", async (event: BeforeAgentStartEvent, ctx) => {
|
|
62
|
+
const cwd = getCwdFromContext(ctx);
|
|
63
|
+
|
|
64
|
+
try {
|
|
65
|
+
const manifest = await loader.load(cwd);
|
|
66
|
+
|
|
67
|
+
// Record delivery in store
|
|
68
|
+
const sessionId = getSessionIdFromCtx(ctx);
|
|
69
|
+
const receipt = store.noteDelivered(
|
|
70
|
+
sessionId,
|
|
71
|
+
manifest,
|
|
72
|
+
"system_prompt"
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
// Render and inject contract
|
|
76
|
+
const contract = renderSystemContract(manifest);
|
|
77
|
+
|
|
78
|
+
// Build augmented system prompt
|
|
79
|
+
const augmentedPrompt = event.systemPrompt + "\n\n" + contract;
|
|
80
|
+
|
|
81
|
+
// Log for debugging
|
|
82
|
+
console.log(`[agent-policy] Delivered policy ${manifest.revision} to session ${receipt.sessionId}`);
|
|
83
|
+
|
|
84
|
+
return { systemPrompt: augmentedPrompt };
|
|
85
|
+
} catch (err) {
|
|
86
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
87
|
+
console.error(`[agent-policy] Failed to load policy: ${errorMessage}`);
|
|
88
|
+
|
|
89
|
+
// Return minimal contract on failure - don't block startup
|
|
90
|
+
const fallbackContract = `
|
|
91
|
+
PI-HARNESS POLICY coverage=degraded
|
|
92
|
+
|
|
93
|
+
WARNING: Policy loading failed. Please report this to your administrator.
|
|
94
|
+
Use harness_rules to check policy status.
|
|
95
|
+
`.trim();
|
|
96
|
+
|
|
97
|
+
return { systemPrompt: event.systemPrompt + "\n\n" + fallbackContract };
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
// ---------------------------------------------------------------------------
|
|
102
|
+
// tool_call: Gate mutations until policy received
|
|
103
|
+
// ---------------------------------------------------------------------------
|
|
104
|
+
|
|
105
|
+
pi.on("tool_call", async (event: ToolCallEvent, ctx) => {
|
|
106
|
+
const toolName = event.toolName;
|
|
107
|
+
const input = event.input;
|
|
108
|
+
const capability = toolClassifier(toolName, input);
|
|
109
|
+
|
|
110
|
+
// Skip non-mutating calls
|
|
111
|
+
if (!capability.mutatesProject && !capability.releasesProject && !capability.isChildDelegation) {
|
|
112
|
+
return {};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const cwd = getCwdFromContext(ctx);
|
|
116
|
+
const sessionId = getSessionIdFromCtx(ctx);
|
|
117
|
+
const targetPath = capability.affectedPaths?.[0];
|
|
118
|
+
|
|
119
|
+
try {
|
|
120
|
+
const manifest = await loader.loadForTarget(cwd, targetPath);
|
|
121
|
+
const receipt = store.getReceipt(sessionId, manifest.projectRoot);
|
|
122
|
+
|
|
123
|
+
// Check if current revision is covered
|
|
124
|
+
if (!receipt || receipt.revision !== manifest.revision) {
|
|
125
|
+
const blockReason = receipt
|
|
126
|
+
? `Policy revision changed (expected ${manifest.revision}, received ${receipt.revision})`
|
|
127
|
+
: `Policy revision ${manifest.revision} not yet delivered`;
|
|
128
|
+
|
|
129
|
+
console.log(`[agent-policy] Blocked ${toolName}: ${blockReason}`);
|
|
130
|
+
|
|
131
|
+
const reason = `[POLICY REQUIRED] ${blockReason}\n\n` +
|
|
132
|
+
`Call harness_rules action=read to load the current rules, then retry this operation.\n` +
|
|
133
|
+
`Or call harness_rules action=manifest to see the current policy status.`;
|
|
134
|
+
|
|
135
|
+
return { block: true, reason };
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Optional: Check git guard
|
|
139
|
+
if (config.gitGuardEnabled && capability.releasesProject) {
|
|
140
|
+
// Git operations are gated by pi-lens Git guard if available
|
|
141
|
+
const blockingFindings = await checkForBlockingFindings(ctx, piLensAvailable);
|
|
142
|
+
if (blockingFindings) {
|
|
143
|
+
return {
|
|
144
|
+
block: true,
|
|
145
|
+
reason: `[GIT GUARD] Blocking git operation until findings are resolved.\n\n${blockingFindings}`,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Policy satisfied, allow the call
|
|
151
|
+
return {};
|
|
152
|
+
} catch (err) {
|
|
153
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
154
|
+
console.error(`[agent-policy] Policy check failed: ${errorMessage}`);
|
|
155
|
+
|
|
156
|
+
// On error, fail open for the command but log the issue
|
|
157
|
+
// This matches pi-lens's total handler guard behavior
|
|
158
|
+
return {};
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
// ---------------------------------------------------------------------------
|
|
163
|
+
// harness_rules tool implementation
|
|
164
|
+
// ---------------------------------------------------------------------------
|
|
165
|
+
|
|
166
|
+
pi.registerTool({
|
|
167
|
+
name: "harness_rules",
|
|
168
|
+
label: "Harness Rules",
|
|
169
|
+
description: [
|
|
170
|
+
"Retrieve and acknowledge harness policy rules.",
|
|
171
|
+
"Actions:",
|
|
172
|
+
" - manifest: Show current policy status (revision, coverage, sources)",
|
|
173
|
+
" - read: Get full rule text (optionally filtered by source or section)",
|
|
174
|
+
" - acknowledge: Confirm receipt of a specific revision",
|
|
175
|
+
].join("\n"),
|
|
176
|
+
parameters: {
|
|
177
|
+
type: "object",
|
|
178
|
+
properties: {
|
|
179
|
+
action: {
|
|
180
|
+
type: "string",
|
|
181
|
+
enum: ["manifest", "read", "acknowledge"],
|
|
182
|
+
description: "Action to perform",
|
|
183
|
+
},
|
|
184
|
+
source: {
|
|
185
|
+
type: "string",
|
|
186
|
+
description: "Source path filter (partial match) for read action",
|
|
187
|
+
},
|
|
188
|
+
section: {
|
|
189
|
+
type: "string",
|
|
190
|
+
description: "Section title filter for read action",
|
|
191
|
+
},
|
|
192
|
+
revision: {
|
|
193
|
+
type: "string",
|
|
194
|
+
description: "Revision to acknowledge",
|
|
195
|
+
},
|
|
196
|
+
},
|
|
197
|
+
required: ["action"],
|
|
198
|
+
} as const,
|
|
199
|
+
|
|
200
|
+
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
201
|
+
const cwd = ctx.cwd;
|
|
202
|
+
const sessionId = getSessionIdFromCtx(ctx);
|
|
203
|
+
|
|
204
|
+
try {
|
|
205
|
+
const input = params as HarnessRulesInput;
|
|
206
|
+
|
|
207
|
+
switch (input.action) {
|
|
208
|
+
case "manifest": {
|
|
209
|
+
const manifest = await loader.load(cwd);
|
|
210
|
+
return {
|
|
211
|
+
content: [{
|
|
212
|
+
type: "text" as const,
|
|
213
|
+
text: JSON.stringify({ manifest }, null, 2),
|
|
214
|
+
}],
|
|
215
|
+
details: { manifest },
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
case "read": {
|
|
220
|
+
const manifest = await loader.load(cwd);
|
|
221
|
+
const result = renderFullRules(manifest, {
|
|
222
|
+
source: input.source,
|
|
223
|
+
section: input.section,
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
// Record delivery if not already recorded
|
|
227
|
+
const existingReceipt = store.getReceipt(sessionId, manifest.projectRoot);
|
|
228
|
+
if (!existingReceipt || existingReceipt.revision !== manifest.revision) {
|
|
229
|
+
store.noteDelivered(
|
|
230
|
+
sessionId,
|
|
231
|
+
manifest,
|
|
232
|
+
"tool",
|
|
233
|
+
result.sections?.map(s => s.id) ?? ["*"]
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Format output as readable text
|
|
238
|
+
let output = `Harness Policy Rules (revision: ${manifest.revision})\n`;
|
|
239
|
+
output += "=".repeat(50) + "\n\n";
|
|
240
|
+
|
|
241
|
+
if (result.sections) {
|
|
242
|
+
for (const section of result.sections) {
|
|
243
|
+
output += `[${section.priority.toUpperCase()}] ${section.title}\n`;
|
|
244
|
+
output += `Source: ${section.source}\n`;
|
|
245
|
+
if (section.truncated) {
|
|
246
|
+
output += "(truncated)\n";
|
|
247
|
+
}
|
|
248
|
+
output += "\n" + section.content + "\n\n";
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
return {
|
|
253
|
+
content: [{
|
|
254
|
+
type: "text" as const,
|
|
255
|
+
text: output,
|
|
256
|
+
}],
|
|
257
|
+
details: { sections: result.sections },
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
case "acknowledge": {
|
|
262
|
+
const manifest = await loader.load(cwd);
|
|
263
|
+
|
|
264
|
+
// Reject acknowledgement of wrong revision
|
|
265
|
+
if (input.revision && input.revision !== manifest.revision) {
|
|
266
|
+
return {
|
|
267
|
+
content: [{
|
|
268
|
+
type: "text" as const,
|
|
269
|
+
text: `ERROR: Cannot acknowledge revision ${input.revision}: current revision is ${manifest.revision}`,
|
|
270
|
+
}],
|
|
271
|
+
isError: true,
|
|
272
|
+
details: { error: "revision_mismatch" },
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Record acknowledgement
|
|
277
|
+
const receipt = store.noteDelivered(
|
|
278
|
+
sessionId,
|
|
279
|
+
manifest,
|
|
280
|
+
"tool",
|
|
281
|
+
["*"] // Full content acknowledged
|
|
282
|
+
);
|
|
283
|
+
|
|
284
|
+
return {
|
|
285
|
+
content: [{
|
|
286
|
+
type: "text" as const,
|
|
287
|
+
text: `Policy acknowledged.\nRevision: ${receipt.revision}\nDelivered: ${new Date(receipt.deliveredAt).toISOString()}`,
|
|
288
|
+
}],
|
|
289
|
+
details: { receipt },
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
default: {
|
|
294
|
+
const unknownAction = (input as {action: string}).action;
|
|
295
|
+
return {
|
|
296
|
+
content: [{
|
|
297
|
+
type: "text" as const,
|
|
298
|
+
text: `ERROR: Unknown action: ${unknownAction}`,
|
|
299
|
+
}],
|
|
300
|
+
isError: true,
|
|
301
|
+
details: { error: "unknown_action" },
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
} catch (err) {
|
|
306
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
307
|
+
console.error(`[agent-policy] harness_rules failed: ${errorMessage}`);
|
|
308
|
+
return {
|
|
309
|
+
content: [{
|
|
310
|
+
type: "text" as const,
|
|
311
|
+
text: `Policy operation failed: ${errorMessage}`,
|
|
312
|
+
}],
|
|
313
|
+
isError: true,
|
|
314
|
+
details: { error: errorMessage },
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
},
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
// ---------------------------------------------------------------------------
|
|
321
|
+
// session_start: Initialize session tracking
|
|
322
|
+
// ---------------------------------------------------------------------------
|
|
323
|
+
|
|
324
|
+
pi.on("session_start", (_event: SessionStartEvent, ctx: unknown) => {
|
|
325
|
+
const sessionId = getSessionIdFromCtx(ctx);
|
|
326
|
+
const cwd = getCwdFromContext(ctx);
|
|
327
|
+
|
|
328
|
+
console.log(`[agent-policy] Session started: ${sessionId} in ${cwd}`);
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
// ---------------------------------------------------------------------------
|
|
332
|
+
// agent_end: Cleanup
|
|
333
|
+
// ---------------------------------------------------------------------------
|
|
334
|
+
|
|
335
|
+
pi.on("agent_end", () => {
|
|
336
|
+
console.log("[agent-policy] Agent ended");
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
console.log("[agent-policy] Registered agent policy runtime");
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// ---------------------------------------------------------------------------
|
|
343
|
+
// Helpers
|
|
344
|
+
// ---------------------------------------------------------------------------
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* Extract session ID from context.
|
|
348
|
+
*/
|
|
349
|
+
function getSessionIdFromCtx(ctx: unknown): string {
|
|
350
|
+
const ctxObj = ctx as Record<string, unknown>;
|
|
351
|
+
|
|
352
|
+
if (typeof ctxObj?.sessionId === "string") {
|
|
353
|
+
return ctxObj.sessionId;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
if (typeof ctxObj?.id === "string") {
|
|
357
|
+
return ctxObj.id;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// Fallback to a generated ID
|
|
361
|
+
return `session-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Extract working directory from context.
|
|
366
|
+
*/
|
|
367
|
+
function getCwdFromContext(ctx: unknown): string {
|
|
368
|
+
const ctxObj = ctx as Record<string, unknown>;
|
|
369
|
+
|
|
370
|
+
if (typeof ctxObj?.cwd === "string") {
|
|
371
|
+
return ctxObj.cwd;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
if (typeof ctxObj?.workingDirectory === "string") {
|
|
375
|
+
return ctxObj.workingDirectory;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// Fallback to process cwd
|
|
379
|
+
return process.cwd();
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
* Check for blocking findings (placeholder for pi-lens integration).
|
|
384
|
+
*/
|
|
385
|
+
async function checkForBlockingFindings(
|
|
386
|
+
_ctx: unknown,
|
|
387
|
+
piLensAvailable: boolean
|
|
388
|
+
): Promise<string | null> {
|
|
389
|
+
if (!piLensAvailable) {
|
|
390
|
+
return null; // No blocking findings without pi-lens
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
// TODO: Query pi-lens for fresh blocking findings
|
|
394
|
+
// This would integrate with pi-lens's finding store
|
|
395
|
+
return null;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
// ---------------------------------------------------------------------------
|
|
399
|
+
// Convenience Export
|
|
400
|
+
// ---------------------------------------------------------------------------
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* Register with default configuration pointing to harness AGENTS.md.
|
|
404
|
+
*/
|
|
405
|
+
export function registerDefault(pi: ExtensionAPI): void {
|
|
406
|
+
const harnessRulesPath = new URL("../../../AGENTS.md", import.meta.url);
|
|
407
|
+
|
|
408
|
+
registerAgentPolicy(pi, {
|
|
409
|
+
harnessRulesPath,
|
|
410
|
+
requireReceiptBeforeMutation: true,
|
|
411
|
+
lspMode: "pi-lens",
|
|
412
|
+
});
|
|
413
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Policy Package
|
|
3
|
+
*
|
|
4
|
+
* Provides mandatory policy delivery and mutation gating for pi-harness.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* import { registerAgentPolicy } from "@pi/agent-policy";
|
|
9
|
+
*
|
|
10
|
+
* export default function (pi: ExtensionAPI) {
|
|
11
|
+
* registerAgentPolicy(pi, {
|
|
12
|
+
* harnessRulesPath: new URL("./AGENTS.md", import.meta.url),
|
|
13
|
+
* requireReceiptBeforeMutation: true,
|
|
14
|
+
* lspMode: "pi-lens",
|
|
15
|
+
* });
|
|
16
|
+
* }
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
// Types
|
|
21
|
+
export type {
|
|
22
|
+
AgentPolicyConfig,
|
|
23
|
+
HarnessRulesInput,
|
|
24
|
+
HarnessRulesOutput,
|
|
25
|
+
MinimaxFindingEnvelope,
|
|
26
|
+
PolicyFinding,
|
|
27
|
+
PolicyManifest,
|
|
28
|
+
PolicyReceipt,
|
|
29
|
+
PolicySection,
|
|
30
|
+
PolicySource,
|
|
31
|
+
ToolCallCapability,
|
|
32
|
+
HarnessAgentVerdict,
|
|
33
|
+
} from "./types.js";
|
|
34
|
+
|
|
35
|
+
// Policy Components
|
|
36
|
+
export { PolicyLoader, createPolicyLoader } from "./policy-loader.js";
|
|
37
|
+
export { PolicyStore, getPolicyStore, resetPolicyStore } from "./policy-store.js";
|
|
38
|
+
export {
|
|
39
|
+
renderSystemContract,
|
|
40
|
+
renderFullRules,
|
|
41
|
+
renderManifestSummary,
|
|
42
|
+
renderFindingEnvelope,
|
|
43
|
+
parseSections,
|
|
44
|
+
createCleanEnvelope,
|
|
45
|
+
createDegradedEnvelope,
|
|
46
|
+
} from "./policy-renderer.js";
|
|
47
|
+
|
|
48
|
+
// Extension Registration
|
|
49
|
+
export { registerAgentPolicy, registerDefault } from "./extension.js";
|
|
50
|
+
|
|
51
|
+
// Tool Classifier
|
|
52
|
+
export { classifyToolCall } from "./types.js";
|