@bolloon/bolloon-agent 0.1.13 → 0.1.14

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.
Files changed (52) hide show
  1. package/dist/agents/pi-sdk.js +185 -0
  2. package/dist/agents/shell-guard.js +354 -0
  3. package/dist/agents/shell-tool.js +83 -0
  4. package/dist/agents/skill-loader.js +174 -0
  5. package/dist/bollharness-integration/context-chain-router.js +3 -3
  6. package/dist/bollharness-integration/context-router.js +1 -1
  7. package/dist/heartbeat/Watchdog.js +7 -5
  8. package/dist/heartbeat/index.js +1 -0
  9. package/dist/heartbeat/self-improve-bus.js +85 -0
  10. package/dist/pi-ecosystem-judgment/index.js +1 -2
  11. package/dist/utils/auto-update.js +44 -12
  12. package/dist/web/client.js +839 -103
  13. package/dist/web/components/p2p/P2PModal.js +188 -0
  14. package/dist/web/components/p2p/index.js +264 -226
  15. package/dist/web/components/p2p/p2p-modal.js +657 -0
  16. package/dist/web/components/p2p/p2p-tools.js +248 -0
  17. package/dist/web/index.html +88 -8
  18. package/dist/web/server.js +2360 -0
  19. package/dist/web/style.css +506 -9
  20. package/package.json +2 -2
  21. package/scripts/build-cli.js +11 -1
  22. package/src/agents/pi-sdk.ts +196 -0
  23. package/src/agents/shell-guard.ts +417 -0
  24. package/src/agents/shell-tool.ts +103 -0
  25. package/src/agents/skill-loader.ts +202 -0
  26. package/src/bollharness-integration/context-chain-router.ts +3 -3
  27. package/src/bollharness-integration/context-router.ts +1 -1
  28. package/src/heartbeat/Watchdog.ts +7 -5
  29. package/src/heartbeat/index.ts +1 -0
  30. package/src/heartbeat/self-improve-bus.ts +110 -0
  31. package/src/types.d.ts +12 -0
  32. package/src/utils/auto-update.ts +45 -14
  33. package/src/web/client.js +839 -103
  34. package/src/web/index.html +88 -8
  35. package/src/web/server.ts +427 -101
  36. package/src/web/style.css +506 -9
  37. package/dist/bollharness-integration/bollharness-integration/context-router-judgment.d.ts +0 -48
  38. package/dist/bollharness-integration/bollharness-integration/context-router-judgment.js +0 -261
  39. package/dist/bollharness-integration/bollharness-integration/context-router.d.ts +0 -110
  40. package/dist/bollharness-integration/bollharness-integration/context-router.js +0 -542
  41. package/dist/bollharness-integration/bollharness-integration/gate-state-machine.d.ts +0 -87
  42. package/dist/bollharness-integration/bollharness-integration/gate-state-machine.js +0 -231
  43. package/dist/bollharness-integration/bollharness-integration/gate-transition-hooks.d.ts +0 -30
  44. package/dist/bollharness-integration/bollharness-integration/gate-transition-hooks.js +0 -91
  45. package/dist/bollharness-integration/bollharness-integration/guard-checker.d.ts +0 -105
  46. package/dist/bollharness-integration/bollharness-integration/guard-checker.js +0 -353
  47. package/dist/bollharness-integration/bollharness-integration/index.d.ts +0 -66
  48. package/dist/bollharness-integration/bollharness-integration/index.js +0 -32
  49. package/dist/bollharness-integration/bollharness-integration/integration.d.ts +0 -219
  50. package/dist/bollharness-integration/bollharness-integration/integration.js +0 -420
  51. package/dist/bollharness-integration/bollharness-integration/skill-adapter.d.ts +0 -151
  52. package/dist/bollharness-integration/bollharness-integration/skill-adapter.js +0 -518
@@ -1,518 +0,0 @@
1
- /**
2
- * Skill Adapter - Bridge between Bollharness skills and Bolloon's SkillRegistry
3
- *
4
- * Loads skills from src/bollharness/.claude/skills/ and adapts them for Bolloon.
5
- *
6
- * Skill structure (from bollharness):
7
- * - arch: Project architect (architecture decisions, boundary freezing)
8
- * - lead: Development workflow commander (fail-closed state machine)
9
- * - task-arch: Task decomposition
10
- * - harness-eng: Engineering execution
11
- * - harness-dev: Development execution
12
- * - harness-eng-test: Engineering testing
13
- * - harness-ops: Operations and truth maintenance
14
- * - harness-bridge: Bridge agent coordination
15
- * - crystal-learn: Failure pattern extraction
16
- * - bug-triage: Bug classification
17
- * - bug-pipeline: Bug fix pipeline
18
- * - guardian-fixer: Issue-to-fix workflow
19
- * - plan-lock: Plan freezing
20
- * - skill-discovery: Skill discovery and recommendation
21
- * - toolkit: Toolkit management
22
- */
23
- import { SkillRegistry } from '@bolloon/constraint-runtime';
24
- import * as fs from 'fs';
25
- import * as path from 'path';
26
- export const BOLLHARNESS_SKILLS_DIR = path.join('src', 'bollharness', '.claude', 'skills');
27
- function parseYamlFrontmatter(content) {
28
- const match = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
29
- if (!match) {
30
- return { metadata: { name: '', description: '', status: 'active', tier: 'entry' }, body: content };
31
- }
32
- const yamlStr = match[1];
33
- const body = match[2];
34
- const metadata = {};
35
- for (const line of yamlStr.split('\n')) {
36
- const colonIndex = line.indexOf(':');
37
- if (colonIndex === -1)
38
- continue;
39
- const key = line.slice(0, colonIndex).trim();
40
- let value = line.slice(colonIndex + 1).trim();
41
- if (value === 'true')
42
- value = true;
43
- else if (value === 'false')
44
- value = false;
45
- else if (!isNaN(Number(value)) && value !== '')
46
- value = Number(value);
47
- metadata[key] = value;
48
- }
49
- return {
50
- metadata: metadata,
51
- body,
52
- };
53
- }
54
- function loadHarnessSkill(skillPath) {
55
- try {
56
- const skillDir = path.dirname(skillPath);
57
- const skillName = path.basename(skillDir);
58
- const content = fs.readFileSync(skillPath, 'utf-8');
59
- const { metadata } = parseYamlFrontmatter(content);
60
- metadata.name = skillName;
61
- return metadata;
62
- }
63
- catch {
64
- return null;
65
- }
66
- }
67
- function loadAllHarnessSkills() {
68
- const skills = [];
69
- if (!fs.existsSync(BOLLHARNESS_SKILLS_DIR)) {
70
- console.warn(`[SkillAdapter] Bollharness skills dir not found: ${BOLLHARNESS_SKILLS_DIR}`);
71
- return skills;
72
- }
73
- const entries = fs.readdirSync(BOLLHARNESS_SKILLS_DIR, { withFileTypes: true });
74
- for (const entry of entries) {
75
- if (!entry.isDirectory())
76
- continue;
77
- const skillPath = path.join(BOLLHARNESS_SKILLS_DIR, entry.name, 'SKILL.md');
78
- if (fs.existsSync(skillPath)) {
79
- const metadata = loadHarnessSkill(skillPath);
80
- if (metadata) {
81
- skills.push(metadata);
82
- }
83
- }
84
- }
85
- return skills;
86
- }
87
- /**
88
- * Base skill class for bollharness-compatible skills
89
- */
90
- export class BaseSkill {
91
- log(message, level = 'info') {
92
- const prefix = level === 'error' ? '❌' : level === 'warn' ? '⚠️' : 'ℹ️';
93
- console.log(`${prefix} [${this.name}] ${message}`);
94
- }
95
- formatOutput(output) {
96
- return JSON.stringify(output, null, 2);
97
- }
98
- }
99
- /**
100
- * Architecture Skill - Project architect for architecture decisions
101
- */
102
- export class ArchSkill extends BaseSkill {
103
- name = 'arch';
104
- description = 'Project architect. Responsible for architecture decisions, scheme comparison, and boundary freezing.';
105
- async execute(params) {
106
- const task = params.task || params.description;
107
- this.log('Analyzing architecture task');
108
- // Extract essence
109
- const essence = this.extractEssence(task);
110
- // Find tensions
111
- const tensions = this.identifyTensions(task);
112
- // Compare alternatives
113
- const alternatives = this.compareAlternatives(task);
114
- // Identify boundaries to freeze
115
- const boundaries = this.identifyBoundaries(task);
116
- return this.formatOutput({
117
- essence,
118
- tensions,
119
- alternatives,
120
- boundaries,
121
- recommendation: this.makeRecommendation(task, alternatives),
122
- });
123
- }
124
- extractEssence(task) {
125
- // Simplified essence extraction
126
- return `The core challenge is: ${task}`;
127
- }
128
- identifyTensions(task) {
129
- return [
130
- 'Simplicity vs Flexibility',
131
- 'Performance vs Maintainability',
132
- 'Coupling vs Cohesion',
133
- ];
134
- }
135
- compareAlternatives(task) {
136
- return [
137
- {
138
- name: 'Option A: Direct Implementation',
139
- tradeoffs: ['Fast to implement', 'May not scale'],
140
- recommendation: 'Suitable for MVP',
141
- },
142
- {
143
- name: 'Option B: Abstraction Layer',
144
- tradeoffs: ['More upfront work', 'Better for extension'],
145
- recommendation: 'Suitable for long-term',
146
- },
147
- ];
148
- }
149
- identifyBoundaries(task) {
150
- return [
151
- 'API contract boundaries',
152
- 'Data format boundaries',
153
- 'Capability boundaries',
154
- ];
155
- }
156
- makeRecommendation(task, alternatives) {
157
- return alternatives[1]?.recommendation || 'Consider abstraction layer for long-term maintainability';
158
- }
159
- }
160
- /**
161
- * Lead Skill - Development workflow commander (fail-closed state machine)
162
- */
163
- export class LeadSkill extends BaseSkill {
164
- name = 'lead';
165
- description = 'Development workflow commander. Fail-closed state machine from idea to production code.';
166
- currentGate = 0;
167
- async execute(params) {
168
- const action = params.action;
169
- this.log('Processing lead action');
170
- switch (action) {
171
- case 'get_gate':
172
- return this.getGatePack();
173
- case 'transition':
174
- return this.handleTransition(params);
175
- case 'classify':
176
- return this.classifyChange(params);
177
- default:
178
- return this.getGatePack();
179
- }
180
- }
181
- getGatePack() {
182
- const gates = [
183
- { gate: 0, name: 'Problem Lock', required: 'Problem statement + Change Classification' },
184
- { gate: 1, name: 'Architecture Design', required: 'ADR draft + Consumer list' },
185
- { gate: 2, name: 'Architecture Review', required: 'Review report (PASS/BLOCK)' },
186
- { gate: 3, name: 'Plan', required: 'PLAN document + Coverage matrix' },
187
- { gate: 4, name: 'Plan Review', required: 'Review report + plan-lock' },
188
- { gate: 5, name: 'Task Architecture', required: 'WP split + TASK.md' },
189
- { gate: 6, name: 'Task Review', required: 'Review report (PASS/BLOCK)' },
190
- { gate: 7, name: 'Execution', required: 'Code + LOG.md' },
191
- { gate: 8, name: 'Final Review', required: 'Review report + Acceptance' },
192
- ];
193
- const current = gates[this.currentGate];
194
- return this.formatOutput({
195
- current_gate: this.currentGate,
196
- gate_name: current.name,
197
- entry_satisfied: true,
198
- blockers: [],
199
- required_artifact: current.required,
200
- required_next_skill: 'arch',
201
- available_actions: ['get_gate', 'transition', 'classify'],
202
- });
203
- }
204
- handleTransition(params) {
205
- const reviewResult = params.reviewResult;
206
- // Check if review gate needs PASS
207
- if (this.currentGate === 2 || this.currentGate === 4 || this.currentGate === 6 || this.currentGate === 8) {
208
- if (!reviewResult || reviewResult.verdict !== 'PASS') {
209
- return this.formatOutput({
210
- transition: 'BLOCKED',
211
- reason: 'Review gate requires PASS verdict from independent reviewer',
212
- current_gate: this.currentGate,
213
- });
214
- }
215
- }
216
- this.currentGate = Math.min(8, this.currentGate + 1);
217
- return this.formatOutput({
218
- transition: 'SUCCESS',
219
- from_gate: this.currentGate - 1,
220
- to_gate: this.currentGate,
221
- gate_pack: this.getGatePack(),
222
- });
223
- }
224
- classifyChange(params) {
225
- const description = params.description || '';
226
- // Simplified classification
227
- const isPolicy = description.includes('policy') || description.includes('boundary');
228
- const isContract = description.includes('API') || description.includes('contract') || description.includes('schema');
229
- const isImplementation = !isPolicy && !isContract;
230
- return this.formatOutput({
231
- classification: isPolicy ? 'policy' : isContract ? 'contract' : 'implementation',
232
- description,
233
- minimum_gate_path: isPolicy ? '0→8 (full)' : isContract ? '0→8 (full + consumers)' : '0→7 (fast track eligible)',
234
- fast_track_eligible: isImplementation,
235
- });
236
- }
237
- }
238
- /**
239
- * Task Architecture Skill - Task decomposition
240
- */
241
- export class TaskArchSkill extends BaseSkill {
242
- name = 'task-arch';
243
- description = 'Task decomposition. Breaks down PLAN into parallelizable work packages (WP).';
244
- async execute(params) {
245
- const plan = params.plan;
246
- this.log('Decomposing plan into work packages');
247
- // Extract work packages
248
- const workPackages = this.extractWorkPackages(plan);
249
- // Identify seams
250
- const seams = this.identifySeams(workPackages);
251
- // Identify integration points
252
- const integration = this.identifyIntegration(workPackages);
253
- return this.formatOutput({
254
- work_packages: workPackages,
255
- seams,
256
- integration,
257
- seam_owners: this.assignSeamOwners(seams),
258
- });
259
- }
260
- extractWorkPackages(plan) {
261
- // Simplified WP extraction
262
- return [
263
- { id: 'WP-1', description: 'Core implementation', files: ['src/agents/*.ts'] },
264
- { id: 'WP-2', description: 'Network layer', files: ['src/network/*.ts'] },
265
- { id: 'WP-3', description: 'Testing', files: ['src/test/*.ts'] },
266
- ];
267
- }
268
- identifySeams(packages) {
269
- return [
270
- { from: 'WP-1', to: 'WP-2', interface: 'P2PNetwork interface' },
271
- { from: 'WP-1', to: 'WP-3', interface: 'Test fixtures' },
272
- ];
273
- }
274
- identifyIntegration(packages) {
275
- return ['Integration test at WP-1/WP-2 boundary'];
276
- }
277
- assignSeamOwners(seams) {
278
- const owners = {};
279
- for (const seam of seams) {
280
- owners[`${seam.from}/${seam.to}`] = 'integration-owner';
281
- }
282
- return owners;
283
- }
284
- }
285
- /**
286
- * Harness Engineering Skill - Engineering execution
287
- */
288
- export class HarnessEngSkill extends BaseSkill {
289
- name = 'harness-eng';
290
- description = 'Engineering execution. Implements code according to PLAN.';
291
- async execute(params) {
292
- const workPackage = params.workPackage;
293
- const plan = params.plan;
294
- this.log(`Executing work package: ${workPackage}`);
295
- // Verify prerequisites
296
- const prereqs = this.checkPrerequisites(workPackage);
297
- // Execute implementation
298
- const steps = this.planImplementation(workPackage, plan);
299
- // Log execution
300
- const log = this.createExecutionLog(steps);
301
- return this.formatOutput({
302
- work_package: workPackage,
303
- prerequisites: prereqs,
304
- steps,
305
- log,
306
- status: prereqs.met ? 'ready' : 'blocked',
307
- });
308
- }
309
- checkPrerequisites(workPackage) {
310
- // Simplified check
311
- return { met: true, missing: [] };
312
- }
313
- planImplementation(workPackage, plan) {
314
- return [
315
- 'Step 1: Implement core logic',
316
- 'Step 2: Add error handling',
317
- 'Step 3: Write unit tests',
318
- 'Step 4: Update documentation',
319
- ];
320
- }
321
- createExecutionLog(steps) {
322
- return `# Execution Log\n\n${steps.map((s, i) => `${i + 1}. ${s}`).join('\n')}`;
323
- }
324
- }
325
- /**
326
- * Harness Engineering Test Skill - Test strategy and execution
327
- * Ported from src/bollharness/.claude/skills/harness-eng-test/SKILL.md
328
- */
329
- export class HarnessEngTestSkill extends BaseSkill {
330
- name = 'harness-eng-test';
331
- description = 'Testing engineering specialist. Test strategy, test case design, test execution and quality verification. Scheduled by lead at Gate 8.';
332
- async execute(params) {
333
- const action = params.action;
334
- const plan = params.plan;
335
- const frozen = params.frozen;
336
- this.log('Executing test engineering');
337
- if (action === 'strategy') {
338
- return this.createTestStrategy(plan);
339
- }
340
- if (action === 'cases') {
341
- return this.createTestCases(plan);
342
- }
343
- if (action === 'execute') {
344
- return this.executeTests();
345
- }
346
- return this.formatOutput({
347
- skill: this.name,
348
- description: this.description,
349
- available_actions: ['strategy', 'cases', 'execute'],
350
- gate_8_only: true,
351
- truth_policy: [
352
- 'Tests must be independent from implementation',
353
- 'Test coverage does not equal test quality',
354
- 'Report test results honestly',
355
- ],
356
- });
357
- }
358
- createTestStrategy(plan) {
359
- const layers = [
360
- { layer: 'Unit tests', target: 'Fast feedback', tool: 'vitest' },
361
- { layer: 'Integration tests', target: 'Module interfaces', tool: 'supertest' },
362
- { layer: 'E2E tests', target: 'User journeys', tool: 'playwright' },
363
- ];
364
- return this.formatOutput({
365
- test_strategy: layers,
366
- coverage_target: plan.includes('API') ? 'contract-focused' : 'function-focused',
367
- fast_track_eligible: false,
368
- });
369
- }
370
- createTestCases(plan) {
371
- return this.formatOutput({
372
- test_cases: [
373
- { id: 'TC-1', description: 'Core functionality', priority: 'P0' },
374
- { id: 'TC-2', description: 'Edge cases', priority: 'P1' },
375
- { id: 'TC-3', description: 'Error handling', priority: 'P1' },
376
- ],
377
- requirements: plan,
378
- });
379
- }
380
- executeTests() {
381
- return this.formatOutput({
382
- execution_report: {
383
- status: 'NOT_EXECUTED',
384
- message: 'Test execution requires bollharness environment',
385
- },
386
- truth_policy: [
387
- '"collect passed" ≠ "tests passed"',
388
- 'Failure is failure, do not downgrade',
389
- 'BLOCKED must be explicitly marked',
390
- ],
391
- });
392
- }
393
- }
394
- /**
395
- * Crystal Learn Skill - Failure pattern extraction
396
- */
397
- export class CrystalLearnSkill extends BaseSkill {
398
- name = 'crystal-learn';
399
- description = 'Extracts failure patterns and maintains invariants.';
400
- async execute(params) {
401
- const task = params.task;
402
- this.log('Extracting failure patterns');
403
- // Identify failure modes
404
- const failures = this.identifyFailures(task);
405
- // Extract patterns
406
- const patterns = this.extractPatterns(failures);
407
- // Generate invariants
408
- const invariants = this.generateInvariants(patterns);
409
- return this.formatOutput({
410
- failure_modes: failures,
411
- patterns,
412
- invariants,
413
- });
414
- }
415
- identifyFailures(task) {
416
- return [
417
- 'Truth source split',
418
- 'Verification decay',
419
- 'Orphaned seams',
420
- ];
421
- }
422
- extractPatterns(failures) {
423
- return failures.map(f => ({
424
- pattern: f,
425
- prevention: `Implement guard to prevent ${f}`,
426
- }));
427
- }
428
- generateInvariants(patterns) {
429
- return patterns.map(p => `INV: ${p.pattern} must not occur`);
430
- }
431
- }
432
- /**
433
- * Skill Adapter - Registers all bollharness skills with Bolloon's SkillRegistry
434
- */
435
- export class SkillAdapter {
436
- registry;
437
- harnessSkills = [];
438
- constructor() {
439
- this.registry = new SkillRegistry();
440
- this.registerSkills();
441
- }
442
- registerSkills() {
443
- // Load harness skills from src/bollharness/.claude/skills/
444
- this.harnessSkills = loadAllHarnessSkills();
445
- this.log(`Loaded ${this.harnessSkills.length} skills from bollharness`);
446
- // Register adapted skills for skills not yet fully adapted
447
- const adaptedSkills = [
448
- new ArchSkill(),
449
- new LeadSkill(),
450
- new TaskArchSkill(),
451
- new HarnessEngSkill(),
452
- new HarnessEngTestSkill(),
453
- new CrystalLearnSkill(),
454
- ];
455
- for (const skill of adaptedSkills) {
456
- try {
457
- this.registry.register(skill);
458
- this.log(`Registered adapted skill: ${skill.name}`);
459
- }
460
- catch (error) {
461
- this.log(`Failed to register ${skill.name}: ${error}`, 'error');
462
- }
463
- }
464
- // Register harness-native skills (metadata only, execution delegated)
465
- for (const harnessMeta of this.harnessSkills) {
466
- const adaptedNames = adaptedSkills.map(s => s.name);
467
- if (!adaptedNames.includes(harnessMeta.name)) {
468
- try {
469
- const proxySkill = createHarnessProxySkill(harnessMeta);
470
- this.registry.register(proxySkill);
471
- this.log(`Registered harness proxy skill: ${harnessMeta.name}`);
472
- }
473
- catch (error) {
474
- this.log(`Failed to register harness skill ${harnessMeta.name}: ${error}`, 'error');
475
- }
476
- }
477
- }
478
- }
479
- getRegistry() {
480
- return this.registry;
481
- }
482
- getSkill(name) {
483
- return this.registry.get(name);
484
- }
485
- listSkills() {
486
- return this.registry.list();
487
- }
488
- listHarnessSkills() {
489
- return this.harnessSkills;
490
- }
491
- async executeSkill(name, params) {
492
- return this.registry.execute(name, params);
493
- }
494
- log(message, level = 'info') {
495
- const prefix = level === 'error' ? '❌' : level === 'warn' ? '⚠️' : 'ℹ️';
496
- console.log(`${prefix} [SkillAdapter] ${message}`);
497
- }
498
- }
499
- function createHarnessProxySkill(meta) {
500
- return {
501
- name: meta.name,
502
- description: meta.description,
503
- async execute(params) {
504
- return JSON.stringify({
505
- skill: meta.name,
506
- description: meta.description,
507
- tier: meta.tier,
508
- status: meta.status,
509
- outputs: meta.outputs || [],
510
- message: `Harness skill '${meta.name}' requires bollharness environment for full execution`,
511
- params_received: params,
512
- }, null, 2);
513
- },
514
- };
515
- }
516
- export const createSkillAdapter = () => {
517
- return new SkillAdapter();
518
- };