pi-harness-runtime 1.1.150 → 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 +24 -0
- 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,383 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for the agent-policy package
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, it, beforeEach, afterEach, expect } from "bun:test";
|
|
6
|
+
import { existsSync, mkdirSync, writeFileSync, rmSync } from "node:fs";
|
|
7
|
+
import { join } from "node:path";
|
|
8
|
+
import { PolicyLoader } from "../src/policy-loader.js";
|
|
9
|
+
import { PolicyStore, resetPolicyStore, getPolicyStore } from "../src/policy-store.js";
|
|
10
|
+
import { renderSystemContract, parseSections, createCleanEnvelope, createDegradedEnvelope } from "../src/policy-renderer.js";
|
|
11
|
+
import { classifyToolCall } from "../src/types.js";
|
|
12
|
+
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
// Test Fixtures
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
|
|
17
|
+
const TEST_DIR = "/tmp/agent-policy-test";
|
|
18
|
+
|
|
19
|
+
function setupTestDir() {
|
|
20
|
+
rmSync(TEST_DIR, { force: true, recursive: true });
|
|
21
|
+
mkdirSync(TEST_DIR, { recursive: true });
|
|
22
|
+
mkdirSync(join(TEST_DIR, "src"), { recursive: true });
|
|
23
|
+
mkdirSync(join(TEST_DIR, "packages/test"), { recursive: true });
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function teardownTestDir() {
|
|
27
|
+
rmSync(TEST_DIR, { force: true, recursive: true });
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function createTestFile(relativePath: string, content: string) {
|
|
31
|
+
const fullPath = join(TEST_DIR, relativePath);
|
|
32
|
+
writeFileSync(fullPath, content, "utf8");
|
|
33
|
+
return fullPath;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
// PolicyLoader Tests
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
|
|
40
|
+
describe("PolicyLoader", () => {
|
|
41
|
+
let loader: PolicyLoader;
|
|
42
|
+
let harnessPath: string;
|
|
43
|
+
|
|
44
|
+
beforeEach(() => {
|
|
45
|
+
setupTestDir();
|
|
46
|
+
harnessPath = createTestFile("AGENTS.md", `# Test Harness Rules
|
|
47
|
+
|
|
48
|
+
## Mandatory Rules
|
|
49
|
+
|
|
50
|
+
- Follow these rules
|
|
51
|
+
- Always do X
|
|
52
|
+
|
|
53
|
+
## Advisory
|
|
54
|
+
|
|
55
|
+
- Consider doing Y
|
|
56
|
+
`);
|
|
57
|
+
loader = new PolicyLoader({
|
|
58
|
+
harnessRulesPath: new URL(`file://${harnessPath}`),
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
afterEach(() => {
|
|
63
|
+
teardownTestDir();
|
|
64
|
+
loader = undefined as any;
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it("should load harness rules", async () => {
|
|
68
|
+
const manifest = await loader.load(TEST_DIR);
|
|
69
|
+
|
|
70
|
+
expect(manifest.revision).toBeTruthy();
|
|
71
|
+
expect(manifest.projectRoot).toBe(TEST_DIR);
|
|
72
|
+
expect(manifest.sources.length).toBeGreaterThan(0);
|
|
73
|
+
expect(manifest.coverage).toBe("complete");
|
|
74
|
+
|
|
75
|
+
// Check mandatory sources
|
|
76
|
+
const mandatory = manifest.sources.filter(s => s.priority === "mandatory");
|
|
77
|
+
expect(mandatory.length).toBeGreaterThan(0);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it("should compute deterministic revision", async () => {
|
|
81
|
+
const manifest1 = await loader.load(TEST_DIR);
|
|
82
|
+
const manifest2 = await loader.load(TEST_DIR);
|
|
83
|
+
|
|
84
|
+
expect(manifest1.revision).toBe(manifest2.revision);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it("should detect rule changes", async () => {
|
|
88
|
+
const manifest1 = await loader.load(TEST_DIR);
|
|
89
|
+
|
|
90
|
+
// Modify the harness rules
|
|
91
|
+
createTestFile("AGENTS.md", `# Modified Rules
|
|
92
|
+
|
|
93
|
+
## Changed
|
|
94
|
+
|
|
95
|
+
- Different content
|
|
96
|
+
`);
|
|
97
|
+
|
|
98
|
+
// Invalidate cache
|
|
99
|
+
loader.invalidateCache(TEST_DIR);
|
|
100
|
+
|
|
101
|
+
const manifest2 = await loader.load(TEST_DIR);
|
|
102
|
+
|
|
103
|
+
expect(manifest1.revision).not.toBe(manifest2.revision);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it("should load project rules when present", async () => {
|
|
107
|
+
createTestFile("RULES.md", `# Project Rules
|
|
108
|
+
|
|
109
|
+
This is a project rule file.
|
|
110
|
+
`);
|
|
111
|
+
|
|
112
|
+
const manifest = await loader.load(TEST_DIR);
|
|
113
|
+
|
|
114
|
+
expect(manifest.sources.length).toBeGreaterThanOrEqual(2);
|
|
115
|
+
expect(manifest.trust).toBeTruthy();
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it("should handle degraded coverage on missing files", async () => {
|
|
119
|
+
const emptyLoader = new PolicyLoader({
|
|
120
|
+
harnessRulesPath: new URL("file:///nonexistent/path/AGENTS.md"),
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
await expect(emptyLoader.load(TEST_DIR)).rejects.toThrow();
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it("should infer scope from target path", async () => {
|
|
127
|
+
const manifest = await loader.loadForTarget(TEST_DIR, join(TEST_DIR, "src/file.ts"));
|
|
128
|
+
|
|
129
|
+
expect(manifest).toBeTruthy();
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
// ---------------------------------------------------------------------------
|
|
134
|
+
// PolicyStore Tests
|
|
135
|
+
// ---------------------------------------------------------------------------
|
|
136
|
+
|
|
137
|
+
describe("PolicyStore", () => {
|
|
138
|
+
let store: PolicyStore;
|
|
139
|
+
|
|
140
|
+
beforeEach(() => {
|
|
141
|
+
resetPolicyStore();
|
|
142
|
+
store = getPolicyStore();
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
afterEach(() => {
|
|
146
|
+
store.invalidateAll();
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
function createTestManifest(revision = "test-rev-1") {
|
|
150
|
+
return {
|
|
151
|
+
revision,
|
|
152
|
+
projectRoot: TEST_DIR,
|
|
153
|
+
trust: "trusted" as const,
|
|
154
|
+
coverage: "complete" as const,
|
|
155
|
+
sources: [{
|
|
156
|
+
path: "/test/AGENTS.md",
|
|
157
|
+
scope: "",
|
|
158
|
+
priority: "mandatory" as const,
|
|
159
|
+
sha256: "abc123",
|
|
160
|
+
bytes: 100,
|
|
161
|
+
harnessOwned: true,
|
|
162
|
+
}],
|
|
163
|
+
loadedAt: Date.now(),
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
it("should record and retrieve receipt", () => {
|
|
168
|
+
const manifest = createTestManifest();
|
|
169
|
+
const sessionId = "test-session-1";
|
|
170
|
+
|
|
171
|
+
const receipt = store.noteDelivered(sessionId, manifest, "system_prompt");
|
|
172
|
+
|
|
173
|
+
expect(receipt.sessionId).toBe(sessionId);
|
|
174
|
+
expect(receipt.revision).toBe(manifest.revision);
|
|
175
|
+
expect(receipt.deliveryMethod).toBe("system_prompt");
|
|
176
|
+
|
|
177
|
+
const retrieved = store.getReceipt(sessionId, TEST_DIR);
|
|
178
|
+
expect(retrieved).not.toBeNull();
|
|
179
|
+
expect(retrieved?.revision).toBe(manifest.revision);
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
it("should validate receipt against manifest", () => {
|
|
183
|
+
const manifest = createTestManifest();
|
|
184
|
+
const sessionId = "test-session-2";
|
|
185
|
+
|
|
186
|
+
store.noteDelivered(sessionId, manifest, "system_prompt");
|
|
187
|
+
|
|
188
|
+
const valid = store.validateReceipt(sessionId, manifest);
|
|
189
|
+
expect(valid.valid).toBe(true);
|
|
190
|
+
|
|
191
|
+
const wrongManifest = createTestManifest("different-revision");
|
|
192
|
+
const invalid = store.validateReceipt(sessionId, wrongManifest);
|
|
193
|
+
expect(invalid.valid).toBe(false);
|
|
194
|
+
expect(invalid.reason).toContain("does not match");
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it("should check receipt validity", () => {
|
|
198
|
+
const manifest = createTestManifest();
|
|
199
|
+
const sessionId = "test-session-3";
|
|
200
|
+
|
|
201
|
+
// No receipt yet
|
|
202
|
+
expect(store.hasValidReceipt(sessionId, manifest)).toBe(false);
|
|
203
|
+
|
|
204
|
+
// Add receipt
|
|
205
|
+
store.noteDelivered(sessionId, manifest, "system_prompt");
|
|
206
|
+
expect(store.hasValidReceipt(sessionId, manifest)).toBe(true);
|
|
207
|
+
|
|
208
|
+
// Different revision
|
|
209
|
+
const wrongManifest = createTestManifest("other-rev");
|
|
210
|
+
expect(store.hasValidReceipt(sessionId, wrongManifest)).toBe(false);
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
it("should invalidate on revision change", () => {
|
|
214
|
+
const manifest1 = createTestManifest("rev-1");
|
|
215
|
+
const manifest2 = createTestManifest("rev-2");
|
|
216
|
+
const sessionId = "test-session-4";
|
|
217
|
+
|
|
218
|
+
store.noteDelivered(sessionId, manifest1, "system_prompt");
|
|
219
|
+
expect(store.hasValidReceipt(sessionId, manifest1)).toBe(true);
|
|
220
|
+
|
|
221
|
+
// New revision - old receipt should not cover it
|
|
222
|
+
expect(store.hasValidReceipt(sessionId, manifest2)).toBe(false);
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
it("should clear session receipts", () => {
|
|
226
|
+
const manifest = createTestManifest();
|
|
227
|
+
const sessionId = "test-session-5";
|
|
228
|
+
|
|
229
|
+
store.noteDelivered(sessionId, manifest, "system_prompt");
|
|
230
|
+
expect(store.getReceipt(sessionId, TEST_DIR)).not.toBeNull();
|
|
231
|
+
|
|
232
|
+
store.clearSession(sessionId);
|
|
233
|
+
expect(store.getReceipt(sessionId, TEST_DIR)).toBeNull();
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
it("should track statistics", () => {
|
|
237
|
+
const manifest = createTestManifest();
|
|
238
|
+
|
|
239
|
+
store.noteDelivered("session-1", manifest, "system_prompt");
|
|
240
|
+
store.noteDelivered("session-2", manifest, "tool");
|
|
241
|
+
|
|
242
|
+
const stats = store.getStats();
|
|
243
|
+
expect(stats.totalReceipts).toBe(2);
|
|
244
|
+
expect(stats.sessionsTracked).toBe(2);
|
|
245
|
+
});
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
// ---------------------------------------------------------------------------
|
|
249
|
+
// PolicyRenderer Tests
|
|
250
|
+
// ---------------------------------------------------------------------------
|
|
251
|
+
|
|
252
|
+
describe("PolicyRenderer", () => {
|
|
253
|
+
function createTestManifest() {
|
|
254
|
+
return {
|
|
255
|
+
revision: "abc123",
|
|
256
|
+
projectRoot: TEST_DIR,
|
|
257
|
+
trust: "trusted" as const,
|
|
258
|
+
coverage: "complete" as const,
|
|
259
|
+
sources: [{
|
|
260
|
+
path: "/test/AGENTS.md",
|
|
261
|
+
scope: "",
|
|
262
|
+
priority: "mandatory" as const,
|
|
263
|
+
sha256: "abc123",
|
|
264
|
+
bytes: 100,
|
|
265
|
+
harnessOwned: true,
|
|
266
|
+
}],
|
|
267
|
+
loadedAt: Date.now(),
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
it("should render system contract", () => {
|
|
272
|
+
const manifest = createTestManifest();
|
|
273
|
+
const contract = renderSystemContract(manifest);
|
|
274
|
+
|
|
275
|
+
expect(contract).toContain("PI-HARNESS POLICY");
|
|
276
|
+
expect(contract).toContain(manifest.revision);
|
|
277
|
+
expect(contract).toContain("Mandatory:");
|
|
278
|
+
expect(contract).toContain("harness_rules");
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
it("should include coverage in contract", () => {
|
|
282
|
+
const manifest = {
|
|
283
|
+
...createTestManifest(),
|
|
284
|
+
coverage: "partial" as const,
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
const contract = renderSystemContract(manifest);
|
|
288
|
+
expect(contract).toContain("coverage=partial");
|
|
289
|
+
expect(contract).toContain("WARNING");
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
it("should include trust warning for untrusted projects", () => {
|
|
293
|
+
const manifest = {
|
|
294
|
+
...createTestManifest(),
|
|
295
|
+
trust: "untrusted" as const,
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
const contract = renderSystemContract(manifest);
|
|
299
|
+
expect(contract).toContain("not trusted");
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
it("should parse markdown sections", () => {
|
|
303
|
+
const content = `# Header 1
|
|
304
|
+
|
|
305
|
+
Some content here.
|
|
306
|
+
|
|
307
|
+
## Header 2
|
|
308
|
+
|
|
309
|
+
More content.
|
|
310
|
+
`;
|
|
311
|
+
|
|
312
|
+
const sections = parseSections(content, "/test/AGENTS.md", "", "mandatory");
|
|
313
|
+
|
|
314
|
+
expect(sections.length).toBe(2);
|
|
315
|
+
expect(sections[0].title).toBe("Header 1");
|
|
316
|
+
expect(sections[0].content).toContain("Some content here");
|
|
317
|
+
expect(sections[1].title).toBe("Header 2");
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
it("should create clean envelope", () => {
|
|
321
|
+
const envelope = createCleanEnvelope();
|
|
322
|
+
|
|
323
|
+
expect(envelope.verdict).toBe("clean");
|
|
324
|
+
expect(envelope.findings).toHaveLength(0);
|
|
325
|
+
expect(envelope.nextAction).toBe("continue");
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
it("should create degraded envelope", () => {
|
|
329
|
+
const envelope = createDegradedEnvelope("LSP timeout");
|
|
330
|
+
|
|
331
|
+
expect(envelope.verdict).toBe("degraded");
|
|
332
|
+
expect(envelope.summary).toContain("LSP timeout");
|
|
333
|
+
expect(envelope.nextAction).toBe("run_full");
|
|
334
|
+
});
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
// ---------------------------------------------------------------------------
|
|
338
|
+
// Tool Classification Tests
|
|
339
|
+
// ---------------------------------------------------------------------------
|
|
340
|
+
|
|
341
|
+
describe("Tool Classifier", () => {
|
|
342
|
+
it("should classify write as mutating", () => {
|
|
343
|
+
const cap = classifyToolCall("write", { path: "/test/file.ts", content: "" });
|
|
344
|
+
expect(cap.mutatesProject).toBe(true);
|
|
345
|
+
expect(cap.releasesProject).toBe(false);
|
|
346
|
+
expect(cap.confidence).toBe("high");
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
it("should classify edit as mutating", () => {
|
|
350
|
+
const cap = classifyToolCall("edit", { path: "/test/file.ts" });
|
|
351
|
+
expect(cap.mutatesProject).toBe(true);
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
it("should classify read as non-mutating", () => {
|
|
355
|
+
const cap = classifyToolCall("read", { path: "/test/file.ts" });
|
|
356
|
+
expect(cap.mutatesProject).toBe(false);
|
|
357
|
+
expect(cap.releasesProject).toBe(false);
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
it("should classify bash git commands as releasing", () => {
|
|
361
|
+
const cap = classifyToolCall("bash", { command: "git commit -m 'test'" });
|
|
362
|
+
expect(cap.mutatesProject).toBe(true);
|
|
363
|
+
expect(cap.releasesProject).toBe(true);
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
it("should classify subagent as child delegation", () => {
|
|
367
|
+
const cap = classifyToolCall("subagent", { agent: "test", task: "do something" });
|
|
368
|
+
expect(cap.isChildDelegation).toBe(true);
|
|
369
|
+
expect(cap.mutatesProject).toBe(true);
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
it("should classify harness_rules as non-mutating", () => {
|
|
373
|
+
const cap = classifyToolCall("harness_rules", { action: "manifest" });
|
|
374
|
+
expect(cap.mutatesProject).toBe(false);
|
|
375
|
+
expect(cap.releasesProject).toBe(false);
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
it("should conservatively classify unknown tools", () => {
|
|
379
|
+
const cap = classifyToolCall("unknown_tool", {});
|
|
380
|
+
expect(cap.mutatesProject).toBe(true); // Conservative
|
|
381
|
+
expect(cap.confidence).toBe("low");
|
|
382
|
+
});
|
|
383
|
+
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-harness/capability-registry",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.152",
|
|
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",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAiD/C;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAuBlE;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC/B,KAAK,EAAE,MAAM,EAAE,EACf,aAAa,SAAI,GACf,YAAY,EAAE,CAWhB;AAqED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAMxD;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAC9B,IAAI,EAAE,MAAM,GACV,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,
|
|
1
|
+
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAiD/C;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAuBlE;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC/B,KAAK,EAAE,MAAM,EAAE,EACf,aAAa,SAAI,GACf,YAAY,EAAE,CAWhB;AAqED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAMxD;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAC9B,IAAI,EAAE,MAAM,GACV,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAoDvC"}
|
|
@@ -135,11 +135,46 @@ export function extractCodeBlocks(text) {
|
|
|
135
135
|
* "mixed" if both, "unknown" otherwise.
|
|
136
136
|
*/
|
|
137
137
|
export function classifyMessage(text) {
|
|
138
|
+
// Skip empty or very short messages
|
|
139
|
+
if (!text || text.trim().length < 20)
|
|
140
|
+
return "unknown";
|
|
141
|
+
// Skip guardian review / risk assessment JSON responses
|
|
142
|
+
// These have fields like "risk_level", "outcome", "user_authorization"
|
|
143
|
+
if (/^\s*\{[^}]*"risk_level"[\s\S]*"outcome"[\s\S]*\}\.?\s*$/.test(text.trim())) {
|
|
144
|
+
return "unknown";
|
|
145
|
+
}
|
|
146
|
+
// Skip pure JSON responses (generic check)
|
|
147
|
+
if (/^\s*\{[^}]+\}\s*$/.test(text.trim()) && text.includes(":")) {
|
|
148
|
+
const firstChar = text.trim()[0];
|
|
149
|
+
if (firstChar === "{" || firstChar === "[") {
|
|
150
|
+
return "unknown";
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
// Skip messages that look like system status updates
|
|
154
|
+
if (/^(Ready|Error|Failed|Processing|Thinking|In progress)/i.test(text.trim())) {
|
|
155
|
+
return "unknown";
|
|
156
|
+
}
|
|
157
|
+
// Skip guardian/system prompts (not real user requests)
|
|
158
|
+
if (/^The following is the (Codex )?agent history/i.test(text.trim()) ||
|
|
159
|
+
/^Codex agent history/i.test(text.trim()) ||
|
|
160
|
+
/^Additional context from (the )?agent/i.test(text.trim()) ||
|
|
161
|
+
/^Your task is to/i.test(text.trim()) ||
|
|
162
|
+
/^You are judging/i.test(text.trim())) {
|
|
163
|
+
return "unknown";
|
|
164
|
+
}
|
|
165
|
+
// Check for markdown headings (strong indicator of planning)
|
|
166
|
+
const headingCount = (text.match(/^#{1,3}\s+/gm) || []).length;
|
|
167
|
+
const bulletCount = (text.match(/^[\s]*[-*+]\s+/gm) || []).length;
|
|
168
|
+
const numberedCount = (text.match(/^[\s]*\d+\.\s+/gm) || []).length;
|
|
138
169
|
const codeBlocks = extractCodeBlocks(text);
|
|
139
170
|
const codeCharCount = codeBlocks.join("").replace(/\s/g, "").length;
|
|
140
171
|
const nonCodeCharCount = text
|
|
141
172
|
.replace(/```[\s\S]*?```/g, "")
|
|
142
173
|
.replace(/\s/g, "").length;
|
|
174
|
+
// If has headings/bullets and no/minimal code, likely a plan
|
|
175
|
+
if ((headingCount >= 2 || bulletCount >= 3 || numberedCount >= 2) && codeCharCount < 100) {
|
|
176
|
+
return "plan";
|
|
177
|
+
}
|
|
143
178
|
if (codeCharCount === 0 && nonCodeCharCount > 0)
|
|
144
179
|
return "plan";
|
|
145
180
|
if (nonCodeCharCount === 0 && codeCharCount > 0)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parser.js","sourceRoot":"","sources":["../../src/parser.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"parser.js","sourceRoot":"","sources":["../../src/parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA+CH,8EAA8E;AAC9E,gDAAgD;AAChD,8EAA8E;AAE9E;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC5C,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;QAAE,OAAO,IAAI,CAAC;IAE9B,IAAI,GAAa,CAAC;IAClB,IAAI,CAAC;QACJ,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAa,CAAC;IACpC,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,IAAI,CAAC;IACb,CAAC;IAED,kEAAkE;IAClE,IAAI,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACrB,MAAM,GAAG,GAAG,qBAAqB,CAAC,GAAG,CAAC,CAAC;QACvC,IAAI,GAAG;YAAE,OAAO,GAAG,CAAC;IACrB,CAAC;IAED,6CAA6C;IAC7C,IAAI,cAAc,CAAC,GAAG,CAAC,EAAE,CAAC;QACzB,MAAM,GAAG,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC;QAClC,IAAI,GAAG;YAAE,OAAO,GAAG,CAAC;IACrB,CAAC;IAED,OAAO,IAAI,CAAC;AACb,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,gBAAgB,CAC/B,KAAe,EACf,aAAa,GAAG,CAAC;IAEjB,MAAM,QAAQ,GAAmB,EAAE,CAAC;IACpC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QAC1B,MAAM,GAAG,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;QACnC,IAAI,GAAG,IAAI,GAAG,CAAC,OAAO,GAAG,aAAa,EAAE,CAAC;YACxC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACpB,CAAC;IACF,CAAC;IACD,gDAAgD;IAChD,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC;IAC/C,OAAO,QAAQ,CAAC;AACjB,CAAC;AAED,8EAA8E;AAC9E,cAAc;AACd,8EAA8E;AAE9E,SAAS,UAAU,CAAC,GAAa;IAChC,OAAO,GAAG,CAAC,IAAI,KAAK,WAAW,CAAC;AACjC,CAAC;AAED,SAAS,cAAc,CAAC,GAAa;IACpC,OAAO,GAAG,CAAC,IAAI,KAAK,eAAe,CAAC;AACrC,CAAC;AAED,8EAA8E;AAC9E,+BAA+B;AAC/B,8EAA8E;AAE9E,SAAS,qBAAqB,CAAC,GAAgB;IAC9C,MAAM,CAAC,GAAG,GAAG,CAAC,OAA0B,CAAC;IACzC,IAAI,CAAC,CAAC,IAAI,KAAK,gBAAgB;QAAE,OAAO,IAAI,CAAC;IAC7C,IAAI,CAAC,CAAC,IAAI,EAAE,IAAI,KAAK,cAAc;QAAE,OAAO,IAAI,CAAC;IAEjD,kCAAkC;IAClC,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,OAAO,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,IAAI,EAAE,EAAE,CAAC;QAC5C,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;YAC7C,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC1B,CAAC;IACF,CAAC;IAED,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAEpC,OAAO;QACN,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,SAAS,EAAE,GAAG,CAAC,SAAS;QACxB,IAAI,EAAE,WAAW;QACjB,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;QACtB,QAAQ,EAAE,KAAK;KACf,CAAC;AACH,CAAC;AAED,SAAS,gBAAgB,CAAC,GAAoB;IAC7C,MAAM,CAAC,GAAG,GAAG,CAAC,OAAO,CAAC;IACtB,IAAI,CAAC,CAAC,IAAI,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IACtC,IAAI,CAAC,CAAC,IAAI,KAAK,MAAM;QAAE,OAAO,IAAI,CAAC;IAEnC,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,OAAO,IAAI,CAAC,CAAC,OAAO,IAAI,EAAE,EAAE,CAAC;QACvC,IAAI,OAAO,CAAC,IAAI,KAAK,YAAY,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;YACnD,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC1B,CAAC;IACF,CAAC;IAED,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAEpC,OAAO;QACN,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,SAAS,EAAE,GAAG,CAAC,SAAS;QACxB,IAAI,EAAE,MAAM;QACZ,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;QACtB,QAAQ,EAAE,KAAK;KACf,CAAC;AACH,CAAC;AAED,8EAA8E;AAC9E,4BAA4B;AAC5B,8EAA8E;AAE9E;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC7C,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,2BAA2B,CAAC,EAAE,CAAC;QAChE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IACrC,CAAC;IACD,OAAO,MAAM,CAAC;AACf,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAC9B,IAAY;IAEZ,oCAAoC;IACpC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,EAAE;QAAE,OAAO,SAAS,CAAC;IAEvD,wDAAwD;IACxD,uEAAuE;IACvE,IAAI,yDAAyD,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;QACjF,OAAO,SAAS,CAAC;IAClB,CAAC;IAED,2CAA2C;IAC3C,IAAI,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACjE,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QACjC,IAAI,SAAS,KAAK,GAAG,IAAI,SAAS,KAAK,GAAG,EAAE,CAAC;YAC5C,OAAO,SAAS,CAAC;QAClB,CAAC;IACF,CAAC;IAED,qDAAqD;IACrD,IAAI,wDAAwD,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;QAChF,OAAO,SAAS,CAAC;IAClB,CAAC;IAED,wDAAwD;IACxD,IAAI,+CAA+C,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QACjE,uBAAuB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QACzC,wCAAwC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QAC1D,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QACrC,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;QAC3C,OAAO,SAAS,CAAC;IAClB,CAAC;IAED,6DAA6D;IAC7D,MAAM,YAAY,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC;IAC/D,MAAM,WAAW,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC;IAClE,MAAM,aAAa,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC;IAEpE,MAAM,UAAU,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC;IAC3C,MAAM,aAAa,GAAG,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC;IACpE,MAAM,gBAAgB,GAAG,IAAI;SAC3B,OAAO,CAAC,iBAAiB,EAAE,EAAE,CAAC;SAC9B,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC;IAE5B,6DAA6D;IAC7D,IAAI,CAAC,YAAY,IAAI,CAAC,IAAI,WAAW,IAAI,CAAC,IAAI,aAAa,IAAI,CAAC,CAAC,IAAI,aAAa,GAAG,GAAG,EAAE,CAAC;QAC1F,OAAO,MAAM,CAAC;IACf,CAAC;IAED,IAAI,aAAa,KAAK,CAAC,IAAI,gBAAgB,GAAG,CAAC;QAAE,OAAO,MAAM,CAAC;IAC/D,IAAI,gBAAgB,KAAK,CAAC,IAAI,aAAa,GAAG,CAAC;QAAE,OAAO,MAAM,CAAC;IAC/D,IAAI,aAAa,GAAG,CAAC,IAAI,gBAAgB,GAAG,CAAC;QAAE,OAAO,OAAO,CAAC;IAC9D,OAAO,SAAS,CAAC;AAClB,CAAC"}
|
|
@@ -197,12 +197,53 @@ export function extractCodeBlocks(text: string): string[] {
|
|
|
197
197
|
export function classifyMessage(
|
|
198
198
|
text: string,
|
|
199
199
|
): "plan" | "code" | "mixed" | "unknown" {
|
|
200
|
+
// Skip empty or very short messages
|
|
201
|
+
if (!text || text.trim().length < 20) return "unknown";
|
|
202
|
+
|
|
203
|
+
// Skip guardian review / risk assessment JSON responses
|
|
204
|
+
// These have fields like "risk_level", "outcome", "user_authorization"
|
|
205
|
+
if (/^\s*\{[^}]*"risk_level"[\s\S]*"outcome"[\s\S]*\}\.?\s*$/.test(text.trim())) {
|
|
206
|
+
return "unknown";
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Skip pure JSON responses (generic check)
|
|
210
|
+
if (/^\s*\{[^}]+\}\s*$/.test(text.trim()) && text.includes(":")) {
|
|
211
|
+
const firstChar = text.trim()[0];
|
|
212
|
+
if (firstChar === "{" || firstChar === "[") {
|
|
213
|
+
return "unknown";
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Skip messages that look like system status updates
|
|
218
|
+
if (/^(Ready|Error|Failed|Processing|Thinking|In progress)/i.test(text.trim())) {
|
|
219
|
+
return "unknown";
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Skip guardian/system prompts (not real user requests)
|
|
223
|
+
if (/^The following is the (Codex )?agent history/i.test(text.trim()) ||
|
|
224
|
+
/^Codex agent history/i.test(text.trim()) ||
|
|
225
|
+
/^Additional context from (the )?agent/i.test(text.trim()) ||
|
|
226
|
+
/^Your task is to/i.test(text.trim()) ||
|
|
227
|
+
/^You are judging/i.test(text.trim())) {
|
|
228
|
+
return "unknown";
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Check for markdown headings (strong indicator of planning)
|
|
232
|
+
const headingCount = (text.match(/^#{1,3}\s+/gm) || []).length;
|
|
233
|
+
const bulletCount = (text.match(/^[\s]*[-*+]\s+/gm) || []).length;
|
|
234
|
+
const numberedCount = (text.match(/^[\s]*\d+\.\s+/gm) || []).length;
|
|
235
|
+
|
|
200
236
|
const codeBlocks = extractCodeBlocks(text);
|
|
201
237
|
const codeCharCount = codeBlocks.join("").replace(/\s/g, "").length;
|
|
202
238
|
const nonCodeCharCount = text
|
|
203
239
|
.replace(/```[\s\S]*?```/g, "")
|
|
204
240
|
.replace(/\s/g, "").length;
|
|
205
241
|
|
|
242
|
+
// If has headings/bullets and no/minimal code, likely a plan
|
|
243
|
+
if ((headingCount >= 2 || bulletCount >= 3 || numberedCount >= 2) && codeCharCount < 100) {
|
|
244
|
+
return "plan";
|
|
245
|
+
}
|
|
246
|
+
|
|
206
247
|
if (codeCharCount === 0 && nonCodeCharCount > 0) return "plan";
|
|
207
248
|
if (nonCodeCharCount === 0 && codeCharCount > 0) return "code";
|
|
208
249
|
if (codeCharCount > 0 && nonCodeCharCount > 0) return "mixed";
|