pi-harness-runtime 0.10.5 → 0.10.7
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/index.ts +51 -0
- package/package.json +1 -1
- package/packages/a2a-adapter/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/code-generation/package.json +1 -1
- package/packages/code-review/package.json +1 -1
- package/packages/codex-adapter/package.json +1 -1
- package/packages/config-capture/package.json +23 -0
- package/packages/config-capture/src/index.ts +357 -0
- 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/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/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/model-registry/package.json +1 -1
- package/packages/nextjs-plugin/package.json +1 -1
- package/packages/notification/package.json +1 -1
- package/packages/observability/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/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/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-registry/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/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/todo-bd-sync/src/task-analyzer.ts +266 -0
- package/packages/token-estimation/package.json +1 -1
- package/packages/token-optimizer/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 +22 -0
- package/packages/write-review/src/blackboard.ts +245 -0
- package/packages/write-review/src/gate.ts +167 -0
- package/packages/write-review/src/index.ts +18 -0
- package/packages/write-review/src/injection.ts +157 -0
- package/packages/write-review/src/review.ts +201 -0
- package/packages/write-review/src/trigger.ts +130 -0
- package/packages/write-review/src/types.ts +88 -0
package/index.ts
CHANGED
|
@@ -78,6 +78,28 @@ async function initTodoBdSync(pi: ExtensionAPI): Promise<void> {
|
|
|
78
78
|
// todo-bd-sync not available
|
|
79
79
|
}
|
|
80
80
|
}
|
|
81
|
+
|
|
82
|
+
// --- config-capture: Auto-detect and document API configuration -------------
|
|
83
|
+
// Lazy import - only loads when packages/config-capture exists
|
|
84
|
+
async function initConfigCapture(pi: ExtensionAPI): Promise<void> {
|
|
85
|
+
try {
|
|
86
|
+
const mod = await import("./packages/config-capture/src/index.js");
|
|
87
|
+
mod.registerConfigCapture(pi, { debug: false });
|
|
88
|
+
} catch {
|
|
89
|
+
// config-capture not available
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// --- write-review: Two-agent write with review loop --------------------------
|
|
94
|
+
// Lazy import - only loads when packages/write-review exists
|
|
95
|
+
async function initWriteReview(pi: ExtensionAPI): Promise<void> {
|
|
96
|
+
try {
|
|
97
|
+
const mod = await import("./packages/write-review/src/index.js");
|
|
98
|
+
mod.injectWriterInstructions(pi);
|
|
99
|
+
} catch {
|
|
100
|
+
// write-review not available
|
|
101
|
+
}
|
|
102
|
+
}
|
|
81
103
|
import { homedir } from "node:os";
|
|
82
104
|
import { appendFileSync, existsSync, mkdirSync } from "node:fs";
|
|
83
105
|
import { join } from "node:path";
|
|
@@ -229,6 +251,12 @@ export default function (pi: ExtensionAPI) {
|
|
|
229
251
|
// Start async init but don't await - runs in background
|
|
230
252
|
void initTodoBdSync(pi);
|
|
231
253
|
|
|
254
|
+
// --- config-capture: Auto-detect API config and document it -----------
|
|
255
|
+
void initConfigCapture(pi);
|
|
256
|
+
|
|
257
|
+
// --- write-review: Two-agent write with review loop ----------------------
|
|
258
|
+
void initWriteReview(pi);
|
|
259
|
+
|
|
232
260
|
// --- Auto-Invoke rpiv-todo via System Prompt ------------------------
|
|
233
261
|
// This makes the todo overlay ALWAYS activate at session start
|
|
234
262
|
const AUTO_TODO_INVOKE_HINT = `
|
|
@@ -241,11 +269,34 @@ When the user gives you a multi-step task:
|
|
|
241
269
|
3. When a task is completed, continue to the next or ask the user
|
|
242
270
|
|
|
243
271
|
The todo overlay persists and helps track progress across your conversation.
|
|
272
|
+
`;
|
|
273
|
+
|
|
274
|
+
const COMMIT_BUILD_CHECKLIST = `
|
|
275
|
+
|
|
276
|
+
BEFORE committing code or triggering builds, ALWAYS check:
|
|
277
|
+
1. Run 'bd ready' to see pending tasks
|
|
278
|
+
2. Mark completed tasks with 'bd close <id> --reason "Done"'
|
|
279
|
+
3. Acknowledge pending tasks before proceeding
|
|
280
|
+
4. Never commit/build without acknowledging pending todos
|
|
281
|
+
`;
|
|
282
|
+
|
|
283
|
+
const WRITE_REVIEW_HINT = `
|
|
284
|
+
|
|
285
|
+
WRITER-REVIEWER WORKFLOW:
|
|
286
|
+
When working on a feature from {project}/wiki/* or {project}/.write-review/:
|
|
287
|
+
1. Read the prompt/task file to understand requirements
|
|
288
|
+
2. Write clean, complete code
|
|
289
|
+
3. Mark task "in_progress" in todos
|
|
290
|
+
4. When code is ready, trigger review with \`{done} bd create "Review: <task>" -t review -p 1 && bd close <id> --reason "Approved"\`
|
|
291
|
+
5. If reviewer requests changes, update code and re-review
|
|
292
|
+
6. Never skip review on non-trivial features
|
|
244
293
|
`;
|
|
245
294
|
let firstAgentStart = true;
|
|
246
295
|
pi.on("before_agent_start", async (event) => {
|
|
247
296
|
if (firstAgentStart) {
|
|
248
297
|
event.systemPrompt += AUTO_TODO_INVOKE_HINT;
|
|
298
|
+
event.systemPrompt += COMMIT_BUILD_CHECKLIST;
|
|
299
|
+
event.systemPrompt += WRITE_REVIEW_HINT;
|
|
249
300
|
firstAgentStart = false;
|
|
250
301
|
}
|
|
251
302
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-harness/capability-registry",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.7",
|
|
4
4
|
"description": "Capability Registry for pi-harness-runtime — tracks model capabilities and enables capability-based routing",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@moocoding/config-capture",
|
|
3
|
+
"version": "0.10.7",
|
|
4
|
+
"description": "Auto-capture API-fetched configuration values to AGENTS.md",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "src/index.ts",
|
|
7
|
+
"types": "src/index.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./src/index.ts",
|
|
11
|
+
"types": "./src/index.ts"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"pi-extension",
|
|
16
|
+
"config",
|
|
17
|
+
"documentation",
|
|
18
|
+
"dns",
|
|
19
|
+
"routes"
|
|
20
|
+
],
|
|
21
|
+
"author": "MooCoding",
|
|
22
|
+
"license": "MIT"
|
|
23
|
+
}
|
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config Capture Extension
|
|
3
|
+
*
|
|
4
|
+
* Automatically detects API responses containing constant configuration values
|
|
5
|
+
* (DNS records, routes, feature flags, etc.) and logs a suggestion to document
|
|
6
|
+
* them to AGENTS.md.
|
|
7
|
+
*
|
|
8
|
+
* Pattern: Like todo-bd-sync, this listens to tool execution end events
|
|
9
|
+
* and logs when constant config is detected. The agent decides whether to
|
|
10
|
+
* document based on context.
|
|
11
|
+
*
|
|
12
|
+
* Usage:
|
|
13
|
+
* import { registerConfigCapture } from "@moocoding/config-capture";
|
|
14
|
+
* registerConfigCapture(pi);
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
// ─── Types ────────────────────────────────────────────────────────────────────
|
|
18
|
+
|
|
19
|
+
export type ConfigType =
|
|
20
|
+
| "dns_records"
|
|
21
|
+
| "routes"
|
|
22
|
+
| "feature_flags"
|
|
23
|
+
| "environment_config"
|
|
24
|
+
| "integration_ids"
|
|
25
|
+
| "webhook_urls"
|
|
26
|
+
| "redirect_rules"
|
|
27
|
+
| "unknown";
|
|
28
|
+
|
|
29
|
+
export interface ConfigDetection {
|
|
30
|
+
detected: boolean;
|
|
31
|
+
configType: ConfigType | null;
|
|
32
|
+
confidence: "high" | "medium" | "low";
|
|
33
|
+
sampleData?: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// ─── Config Type Detection ────────────────────────────────────────────────────
|
|
37
|
+
|
|
38
|
+
const DNS_PATTERNS = [
|
|
39
|
+
"zone_id",
|
|
40
|
+
"zoneId",
|
|
41
|
+
"dns_record",
|
|
42
|
+
"dns-record",
|
|
43
|
+
"cloudflare",
|
|
44
|
+
"name_servers",
|
|
45
|
+
"@",
|
|
46
|
+
"ttl",
|
|
47
|
+
"proxied",
|
|
48
|
+
"record_type",
|
|
49
|
+
" a ",
|
|
50
|
+
"aaaa",
|
|
51
|
+
"cname",
|
|
52
|
+
"txt",
|
|
53
|
+
"mx",
|
|
54
|
+
"ns",
|
|
55
|
+
"spf",
|
|
56
|
+
];
|
|
57
|
+
|
|
58
|
+
const ROUTE_PATTERNS = [
|
|
59
|
+
"routes",
|
|
60
|
+
"endpoints",
|
|
61
|
+
"api_routes",
|
|
62
|
+
"api_rout",
|
|
63
|
+
"path",
|
|
64
|
+
"method",
|
|
65
|
+
" get ",
|
|
66
|
+
" post ",
|
|
67
|
+
" put ",
|
|
68
|
+
" delete ",
|
|
69
|
+
" patch ",
|
|
70
|
+
"/api/",
|
|
71
|
+
"route_path",
|
|
72
|
+
];
|
|
73
|
+
|
|
74
|
+
const FEATURE_FLAG_PATTERNS = [
|
|
75
|
+
"feature_flags",
|
|
76
|
+
"feature-flags",
|
|
77
|
+
"feature_toggle",
|
|
78
|
+
"feature-toggle",
|
|
79
|
+
"enabled",
|
|
80
|
+
"disabled",
|
|
81
|
+
"rollout",
|
|
82
|
+
"variants",
|
|
83
|
+
];
|
|
84
|
+
|
|
85
|
+
const INTEGRATION_PATTERNS = [
|
|
86
|
+
"integration_id",
|
|
87
|
+
"integrationId",
|
|
88
|
+
"webhook_url",
|
|
89
|
+
"webhookUrl",
|
|
90
|
+
"webhook_id",
|
|
91
|
+
"redirect_url",
|
|
92
|
+
"account_id",
|
|
93
|
+
"project_id",
|
|
94
|
+
];
|
|
95
|
+
|
|
96
|
+
// ─── Detection Logic ─────────────────────────────────────────────────────────
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Detect if a tool result contains constant configuration data
|
|
100
|
+
*/
|
|
101
|
+
export function detectConfig(result: unknown): ConfigDetection {
|
|
102
|
+
if (!result || typeof result !== "object") {
|
|
103
|
+
return { detected: false, configType: null, confidence: "low" };
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const resultStr = JSON.stringify(result).toLowerCase();
|
|
107
|
+
const scores: { type: ConfigType; score: number }[] = [
|
|
108
|
+
{ type: "dns_records", score: countMatches(resultStr, DNS_PATTERNS) },
|
|
109
|
+
{ type: "routes", score: countMatches(resultStr, ROUTE_PATTERNS) },
|
|
110
|
+
{ type: "feature_flags", score: countMatches(resultStr, FEATURE_FLAG_PATTERNS) },
|
|
111
|
+
{ type: "integration_ids", score: countMatches(resultStr, INTEGRATION_PATTERNS) },
|
|
112
|
+
];
|
|
113
|
+
|
|
114
|
+
// Sort by score descending
|
|
115
|
+
scores.sort((a, b) => b.score - a.score);
|
|
116
|
+
|
|
117
|
+
const best = scores[0];
|
|
118
|
+
if (best.score < 2) {
|
|
119
|
+
return { detected: false, configType: null, confidence: "low" };
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Check for array of objects (typical config structure)
|
|
123
|
+
const hasArrayOfObjects = detectArrayOfObjects(result);
|
|
124
|
+
|
|
125
|
+
let confidence: "high" | "medium" | "low" = "low";
|
|
126
|
+
if (best.score >= 4 || (best.score >= 2 && hasArrayOfObjects)) {
|
|
127
|
+
confidence = "high";
|
|
128
|
+
} else if (best.score >= 2) {
|
|
129
|
+
confidence = "medium";
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Extract sample data for logging
|
|
133
|
+
const sampleData = extractSampleData(result, best.type);
|
|
134
|
+
|
|
135
|
+
return {
|
|
136
|
+
detected: true,
|
|
137
|
+
configType: best.type,
|
|
138
|
+
confidence,
|
|
139
|
+
sampleData,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function countMatches(text: string, patterns: string[]): number {
|
|
144
|
+
return patterns.filter((p) => text.includes(p.toLowerCase())).length;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function detectArrayOfObjects(result: unknown): boolean {
|
|
148
|
+
if (Array.isArray(result)) {
|
|
149
|
+
return result.some((item) => typeof item === "object" && item !== null);
|
|
150
|
+
}
|
|
151
|
+
if (typeof result === "object" && result !== null) {
|
|
152
|
+
const values = Object.values(result);
|
|
153
|
+
return values.some((v) => Array.isArray(v) && v.length > 0 && typeof v[0] === "object");
|
|
154
|
+
}
|
|
155
|
+
return false;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function extractSampleData(result: unknown, _type: ConfigType): string | undefined {
|
|
159
|
+
if (!Array.isArray(result) || result.length === 0) return undefined;
|
|
160
|
+
|
|
161
|
+
const sample = result[0];
|
|
162
|
+
if (typeof sample !== "object" || sample === null) return undefined;
|
|
163
|
+
|
|
164
|
+
const entries = Object.entries(sample).slice(0, 5);
|
|
165
|
+
if (entries.length === 0) return undefined;
|
|
166
|
+
|
|
167
|
+
const lines = entries.map(([k, v]) => `${k}: ${JSON.stringify(v)}`);
|
|
168
|
+
return lines.join(", ");
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// ─── Privacy Filter ────────────────────────────────────────────────────────────
|
|
172
|
+
|
|
173
|
+
const SENSITIVE_PATTERNS = [
|
|
174
|
+
"token",
|
|
175
|
+
"secret",
|
|
176
|
+
"password",
|
|
177
|
+
"key",
|
|
178
|
+
"credential",
|
|
179
|
+
"auth",
|
|
180
|
+
"api_key",
|
|
181
|
+
"apiKey",
|
|
182
|
+
"bearer",
|
|
183
|
+
"authorization",
|
|
184
|
+
"private_",
|
|
185
|
+
"private-",
|
|
186
|
+
];
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Check if a field name is sensitive (should not be documented)
|
|
190
|
+
*/
|
|
191
|
+
export function isSensitiveField(fieldName: string): boolean {
|
|
192
|
+
const lower = fieldName.toLowerCase();
|
|
193
|
+
return SENSITIVE_PATTERNS.some((p) => lower.includes(p));
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Remove sensitive fields from a config object
|
|
198
|
+
*/
|
|
199
|
+
export function removeSensitiveFields<T extends object>(config: T): Partial<T> {
|
|
200
|
+
const sanitized: Record<string, unknown> = {};
|
|
201
|
+
|
|
202
|
+
for (const [key, value] of Object.entries(config)) {
|
|
203
|
+
if (!isSensitiveField(key)) {
|
|
204
|
+
sanitized[key] = value;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return sanitized as Partial<T>;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// ─── Format Output ────────────────────────────────────────────────────────────
|
|
212
|
+
|
|
213
|
+
export type OutputFormat = "markdown" | "json" | "brief";
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Format detected config for AGENTS.md
|
|
217
|
+
*/
|
|
218
|
+
export function formatForAgentsMd(
|
|
219
|
+
detection: ConfigDetection,
|
|
220
|
+
sampleData?: string,
|
|
221
|
+
): string {
|
|
222
|
+
const lines: string[] = [];
|
|
223
|
+
|
|
224
|
+
switch (detection.configType) {
|
|
225
|
+
case "dns_records":
|
|
226
|
+
lines.push("### DNS Records");
|
|
227
|
+
lines.push("");
|
|
228
|
+
lines.push("| Name | Type | Content | Notes |");
|
|
229
|
+
lines.push("|------|------|---------|-------|");
|
|
230
|
+
lines.push("| ... | ... | ... | ... |");
|
|
231
|
+
lines.push("");
|
|
232
|
+
lines.push("*Source: Auto-captured from API*");
|
|
233
|
+
break;
|
|
234
|
+
|
|
235
|
+
case "routes":
|
|
236
|
+
lines.push("### API Routes");
|
|
237
|
+
lines.push("");
|
|
238
|
+
lines.push("- `GET /api/resource` - Description");
|
|
239
|
+
lines.push("- `POST /api/resource` - Create");
|
|
240
|
+
lines.push("");
|
|
241
|
+
lines.push("*Source: Auto-captured from API*");
|
|
242
|
+
break;
|
|
243
|
+
|
|
244
|
+
case "feature_flags":
|
|
245
|
+
lines.push("### Feature Flags");
|
|
246
|
+
lines.push("");
|
|
247
|
+
lines.push("| Flag | Enabled | Notes |");
|
|
248
|
+
lines.push("|------|---------|-------|");
|
|
249
|
+
lines.push("| flag_name | true/false | ... |");
|
|
250
|
+
lines.push("");
|
|
251
|
+
lines.push("*Source: Auto-captured from API*");
|
|
252
|
+
break;
|
|
253
|
+
|
|
254
|
+
default:
|
|
255
|
+
lines.push("### Configuration");
|
|
256
|
+
lines.push("");
|
|
257
|
+
if (sampleData) {
|
|
258
|
+
lines.push("```");
|
|
259
|
+
lines.push(sampleData);
|
|
260
|
+
lines.push("```");
|
|
261
|
+
}
|
|
262
|
+
lines.push("");
|
|
263
|
+
lines.push("*Source: Auto-captured from API*");
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
return lines.join("\n");
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// ─── Extension Registration ────────────────────────────────────────────────────
|
|
270
|
+
|
|
271
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
272
|
+
|
|
273
|
+
// Type for tool_execution_end event
|
|
274
|
+
interface ToolExecutionEndEvent {
|
|
275
|
+
type: "tool_execution_end";
|
|
276
|
+
toolCallId: string;
|
|
277
|
+
toolName: string;
|
|
278
|
+
result: unknown;
|
|
279
|
+
isError: boolean;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
interface ConfigCaptureConfig {
|
|
283
|
+
/** Enable debug logging */
|
|
284
|
+
debug?: boolean;
|
|
285
|
+
/** Minimum confidence to trigger capture */
|
|
286
|
+
minConfidence?: "high" | "medium" | "low";
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
const DEFAULT_CONFIG = {
|
|
290
|
+
debug: false,
|
|
291
|
+
minConfidence: "medium" as const,
|
|
292
|
+
};
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Register the config-capture extension
|
|
296
|
+
*/
|
|
297
|
+
export function registerConfigCapture(
|
|
298
|
+
pi: ExtensionAPI,
|
|
299
|
+
config: ConfigCaptureConfig = {},
|
|
300
|
+
): void {
|
|
301
|
+
const cfg = { ...DEFAULT_CONFIG, ...config };
|
|
302
|
+
|
|
303
|
+
// Track if we've already suggested documenting this config in this session
|
|
304
|
+
const documentedConfigs = new Set<string>();
|
|
305
|
+
|
|
306
|
+
// Listen to tool execution end
|
|
307
|
+
pi.on("tool_execution_end", (event: ToolExecutionEndEvent) => {
|
|
308
|
+
// Skip errors
|
|
309
|
+
if (event.isError) return;
|
|
310
|
+
|
|
311
|
+
// Skip non-API tools (focus on bash/curl/http calls)
|
|
312
|
+
const apiTools = ["bash", "http_request", "fetch", "curl"];
|
|
313
|
+
if (!apiTools.includes(event.toolName)) return;
|
|
314
|
+
|
|
315
|
+
// Detect config in result
|
|
316
|
+
const detection = detectConfig(event.result);
|
|
317
|
+
|
|
318
|
+
if (!detection.detected) return;
|
|
319
|
+
|
|
320
|
+
// Check confidence threshold
|
|
321
|
+
const confidenceLevels = { low: 0, medium: 1, high: 2 };
|
|
322
|
+
const minLevel = confidenceLevels[cfg.minConfidence!];
|
|
323
|
+
const currentLevel = confidenceLevels[detection.confidence];
|
|
324
|
+
|
|
325
|
+
if (currentLevel < minLevel) return;
|
|
326
|
+
|
|
327
|
+
// Create a unique key for this config type + rough content hash
|
|
328
|
+
const contentStr = JSON.stringify(event.result).slice(0, 100);
|
|
329
|
+
const configKey = `${detection.configType}-${contentStr}`;
|
|
330
|
+
|
|
331
|
+
// Skip if already suggested in this session
|
|
332
|
+
if (documentedConfigs.has(configKey)) return;
|
|
333
|
+
|
|
334
|
+
// Log detection
|
|
335
|
+
if (cfg.debug) {
|
|
336
|
+
console.log(`[config-capture] Detected ${detection.configType} (${detection.confidence})`);
|
|
337
|
+
console.log(`[config-capture] Sample: ${detection.sampleData}`);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// Mark as documented
|
|
341
|
+
documentedConfigs.add(configKey);
|
|
342
|
+
|
|
343
|
+
// Log the suggestion - agent will notice this
|
|
344
|
+
console.log(`[config-capture] Config detected: ${detection.configType}`);
|
|
345
|
+
console.log(`[config-capture] Confidence: ${detection.confidence}`);
|
|
346
|
+
console.log(`[config-capture] Sample: ${detection.sampleData?.slice(0, 200)}`);
|
|
347
|
+
|
|
348
|
+
// Suggest action
|
|
349
|
+
const actionMsg = `[config-capture] Consider documenting this to AGENTS.md section "Discovered Configuration"`;
|
|
350
|
+
console.log(actionMsg);
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
console.log("[config-capture] Started - detecting API config responses");
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// Default export
|
|
357
|
+
export default registerConfigCapture;
|