@phuetz/code-buddy 1.2.0 → 1.3.1

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 (104) hide show
  1. package/README.md +119 -24
  2. package/dist/agent/autonomous/agentic-coding-contract.d.ts +6 -6
  3. package/dist/agent/base-agent.d.ts +4 -0
  4. package/dist/agent/base-agent.js +6 -0
  5. package/dist/agent/facades/infrastructure-facade.d.ts +9 -2
  6. package/dist/agent/facades/infrastructure-facade.js +15 -6
  7. package/dist/agent/self-improvement/authored-artifact-gate.d.ts +18 -0
  8. package/dist/agent/self-improvement/authored-artifact-gate.js +42 -0
  9. package/dist/agent/self-improvement/authored-tool-runtime.d.ts +27 -0
  10. package/dist/agent/self-improvement/authored-tool-runtime.js +57 -0
  11. package/dist/agent/self-improvement/authored-tool-store.d.ts +24 -0
  12. package/dist/agent/self-improvement/authored-tool-store.js +57 -0
  13. package/dist/agent/self-improvement/llm-tool-proposer.d.ts +41 -0
  14. package/dist/agent/self-improvement/llm-tool-proposer.js +136 -0
  15. package/dist/agent/self-improvement/sandbox-scorer.d.ts +17 -0
  16. package/dist/agent/self-improvement/sandbox-scorer.js +43 -0
  17. package/dist/agent/self-improvement/self-knowledge.d.ts +8 -0
  18. package/dist/agent/self-improvement/self-knowledge.js +24 -0
  19. package/dist/agent/self-improvement/skill-benchmark.d.ts +9 -0
  20. package/dist/agent/self-improvement/skill-benchmark.js +22 -0
  21. package/dist/agent/self-improvement/skill-consolidator.d.ts +71 -0
  22. package/dist/agent/self-improvement/skill-consolidator.js +137 -0
  23. package/dist/agent/self-improvement/skill-engine.d.ts +42 -0
  24. package/dist/agent/self-improvement/skill-engine.js +87 -0
  25. package/dist/agent/self-improvement/skill-gate.d.ts +19 -0
  26. package/dist/agent/self-improvement/skill-gate.js +62 -0
  27. package/dist/agent/self-improvement/skill-mutator.d.ts +74 -0
  28. package/dist/agent/self-improvement/skill-mutator.js +223 -0
  29. package/dist/agent/self-improvement/skill-proposer.d.ts +40 -0
  30. package/dist/agent/self-improvement/skill-proposer.js +82 -0
  31. package/dist/agent/self-improvement/skill-types.d.ts +41 -0
  32. package/dist/agent/self-improvement/skill-types.js +13 -0
  33. package/dist/agent/self-improvement/tool-benchmark.d.ts +10 -0
  34. package/dist/agent/self-improvement/tool-benchmark.js +37 -0
  35. package/dist/agent/self-improvement/tool-engine.d.ts +54 -0
  36. package/dist/agent/self-improvement/tool-engine.js +101 -0
  37. package/dist/agent/self-improvement/tool-gate.d.ts +20 -0
  38. package/dist/agent/self-improvement/tool-gate.js +78 -0
  39. package/dist/agent/self-improvement/tool-proposer.d.ts +31 -0
  40. package/dist/agent/self-improvement/tool-proposer.js +34 -0
  41. package/dist/agent/self-improvement/tool-skill-mutator.d.ts +40 -0
  42. package/dist/agent/self-improvement/tool-skill-mutator.js +79 -0
  43. package/dist/agent/self-improvement/tool-types.d.ts +48 -0
  44. package/dist/agent/self-improvement/tool-types.js +9 -0
  45. package/dist/agent/self-improvement/types.d.ts +3 -1
  46. package/dist/agent/tool-handler.js +3 -0
  47. package/dist/codebuddy/providers/provider-chatgpt-responses.js +6 -1
  48. package/dist/codebuddy/tools.d.ts +7 -0
  49. package/dist/codebuddy/tools.js +40 -0
  50. package/dist/commands/cli/improve-command.js +123 -0
  51. package/dist/commands/enhanced-command-handler.js +1 -1
  52. package/dist/commands/handlers/missing-handlers.d.ts +1 -1
  53. package/dist/commands/handlers/missing-handlers.js +26 -3
  54. package/dist/commands/skills-cli/index.js +123 -0
  55. package/dist/commands/slash/builtin-commands.js +1 -1
  56. package/dist/companion/percepts.js +11 -1
  57. package/dist/context/bootstrap-loader.js +6 -23
  58. package/dist/context/import-directive-parser.d.ts +4 -0
  59. package/dist/context/import-directive-parser.js +51 -6
  60. package/dist/context/instruction-excludes.d.ts +30 -1
  61. package/dist/context/instruction-excludes.js +71 -1
  62. package/dist/context/jit-context.d.ts +8 -10
  63. package/dist/context/jit-context.js +28 -106
  64. package/dist/context/project-context.d.ts +90 -0
  65. package/dist/context/project-context.js +295 -0
  66. package/dist/daemon/autonomous-loop.d.ts +31 -1
  67. package/dist/daemon/autonomous-loop.js +80 -2
  68. package/dist/harness/contract.d.ts +28 -28
  69. package/dist/identity/identity-manager.js +3 -2
  70. package/dist/index.js +17 -1
  71. package/dist/mcp/mcp-resources.js +2 -3
  72. package/dist/sensory/dreaming.d.ts +45 -0
  73. package/dist/sensory/dreaming.js +114 -0
  74. package/dist/sensory/heartbeat-scheduler.d.ts +38 -0
  75. package/dist/sensory/heartbeat-scheduler.js +72 -0
  76. package/dist/sensory/reactions.d.ts +24 -0
  77. package/dist/sensory/reactions.js +31 -0
  78. package/dist/sensory/screen-reaction.d.ts +23 -0
  79. package/dist/sensory/screen-reaction.js +59 -0
  80. package/dist/sensory/sensory-bridge.d.ts +23 -0
  81. package/dist/sensory/sensory-bridge.js +85 -0
  82. package/dist/sensory/sensory-memory.d.ts +20 -0
  83. package/dist/sensory/sensory-memory.js +39 -0
  84. package/dist/sensory/speech-reaction.d.ts +21 -0
  85. package/dist/sensory/speech-reaction.js +83 -0
  86. package/dist/sensory/vision-reaction.d.ts +31 -0
  87. package/dist/sensory/vision-reaction.js +74 -0
  88. package/dist/server/index.js +89 -0
  89. package/dist/services/prompt-builder.d.ts +10 -0
  90. package/dist/services/prompt-builder.js +75 -9
  91. package/dist/skills/parser.js +3 -0
  92. package/dist/skills/skill-importer.d.ts +58 -0
  93. package/dist/skills/skill-importer.js +261 -0
  94. package/dist/skills/skill-sources.d.ts +20 -0
  95. package/dist/skills/skill-sources.js +102 -0
  96. package/dist/skills/types.d.ts +6 -0
  97. package/dist/tools/register-tool-handler.d.ts +25 -0
  98. package/dist/tools/register-tool-handler.js +100 -0
  99. package/dist/tools/registry.d.ts +6 -0
  100. package/dist/tools/registry.js +8 -0
  101. package/dist/utils/init-project.d.ts +7 -0
  102. package/dist/utils/init-project.js +37 -0
  103. package/dist/utils/settings-manager.d.ts +12 -0
  104. package/package.json +2 -2
@@ -23,6 +23,45 @@
23
23
  import { chooseAutonomousModel, } from '../agent/model-tier.js';
24
24
  import { beginFleetWork, isFleetSaturated } from '../fleet/fleet-load.js';
25
25
  import { DEFAULT_COLAB_GOAL_MAX_TURNS } from './colab-goal.js';
26
+ /**
27
+ * Default idle self-improvement: author tools for any seed scenario NOT yet in the
28
+ * evolutionary archive (so it stops once the seed benchmark is covered, and the
29
+ * bound persists across restarts). Auto-apply; gated by the caller on idle +
30
+ * CODEBUDDY_SELF_IMPROVE + cooldown.
31
+ */
32
+ async function defaultSelfImproveHook() {
33
+ const { EvolutionaryArchive } = await import('../agent/self-improvement/evolutionary-archive.js');
34
+ const archived = new Set(new EvolutionaryArchive().list().map((e) => e.targetScenarioId));
35
+ // Tools first.
36
+ const { ToolImprovementEngine } = await import('../agent/self-improvement/tool-engine.js');
37
+ const { LlmToolProposer } = await import('../agent/self-improvement/llm-tool-proposer.js');
38
+ const { SEED_TOOL_SCENARIOS } = await import('../agent/self-improvement/tool-benchmark.js');
39
+ const uncoveredTools = SEED_TOOL_SCENARIOS.filter((s) => !archived.has(s.id));
40
+ if (uncoveredTools.length > 0) {
41
+ const r = await new ToolImprovementEngine({
42
+ scenarios: uncoveredTools,
43
+ proposer: new LlmToolProposer(),
44
+ autonomy: 'auto-apply',
45
+ }).runCycle();
46
+ if (r.applied)
47
+ return { applied: true, detail: `authored tool ${r.gate?.appliedRef}` };
48
+ }
49
+ // Then skills.
50
+ const { SkillImprovementEngine } = await import('../agent/self-improvement/skill-engine.js');
51
+ const { LlmSkillProposer } = await import('../agent/self-improvement/skill-proposer.js');
52
+ const { SEED_SKILL_SCENARIOS } = await import('../agent/self-improvement/skill-benchmark.js');
53
+ const uncoveredSkills = SEED_SKILL_SCENARIOS.filter((s) => !archived.has(s.id));
54
+ if (uncoveredSkills.length > 0) {
55
+ const r = await new SkillImprovementEngine({
56
+ scenarios: uncoveredSkills,
57
+ proposer: new LlmSkillProposer(),
58
+ autonomy: 'auto-apply',
59
+ }).runCycle();
60
+ if (r.applied)
61
+ return { applied: true, detail: `authored skill ${r.gate?.appliedRef}` };
62
+ }
63
+ return { applied: false, detail: 'all seed tool + skill scenarios already covered (or no proposal)' };
64
+ }
26
65
  function resolveGoalMaxTurns(raw) {
27
66
  return typeof raw === 'number' && Number.isSafeInteger(raw) && raw > 0
28
67
  ? raw
@@ -45,6 +84,10 @@ export class FleetAutonomousLoop {
45
84
  */
46
85
  failures = new Map();
47
86
  goalJudge;
87
+ selfImprove;
88
+ selfImproveCooldownMs;
89
+ now;
90
+ lastSelfImproveAt = Number.NEGATIVE_INFINITY;
48
91
  constructor(config) {
49
92
  this.store = config.store;
50
93
  this.tierConfig = config.tierConfig;
@@ -52,6 +95,40 @@ export class FleetAutonomousLoop {
52
95
  this.policy = config.policy ?? {};
53
96
  this.enabled = config.enabled ?? (() => true);
54
97
  this.goalJudge = config.goalJudge;
98
+ this.selfImprove = config.selfImprove ?? defaultSelfImproveHook;
99
+ this.selfImproveCooldownMs = config.selfImproveCooldownMs ?? 15 * 60 * 1000;
100
+ this.now = config.now ?? (() => Date.now());
101
+ }
102
+ /**
103
+ * Idle hook: when the queue is empty and self-improvement is opted in, run one
104
+ * bounded, cooldown-gated improvement cycle instead of sitting fully idle.
105
+ * Double-gated (idle + CODEBUDDY_SELF_IMPROVE) and bounded (cooldown + the
106
+ * engine no-ops once seed scenarios are covered). Never throws.
107
+ */
108
+ async maybeSelfImprove() {
109
+ if (process.env.CODEBUDDY_SELF_IMPROVE !== 'true') {
110
+ this.store.updatePresence({ status: 'idle', currentTask: null });
111
+ return { outcome: 'idle' };
112
+ }
113
+ const now = this.now();
114
+ if (now - this.lastSelfImproveAt < this.selfImproveCooldownMs) {
115
+ this.store.updatePresence({ status: 'idle', currentTask: null });
116
+ return { outcome: 'idle', detail: 'self-improve on cooldown' };
117
+ }
118
+ this.lastSelfImproveAt = now;
119
+ this.store.updatePresence({ status: 'active', currentTask: 'self-improvement' });
120
+ const doneLoad = beginFleetWork('autonomy.task');
121
+ try {
122
+ const r = await this.selfImprove();
123
+ return { outcome: r.applied ? 'self_improved' : 'idle', detail: r.detail };
124
+ }
125
+ catch (err) {
126
+ return { outcome: 'idle', detail: `self-improve error: ${err instanceof Error ? err.message : String(err)}` };
127
+ }
128
+ finally {
129
+ doneLoad();
130
+ this.store.updatePresence({ status: 'idle', currentTask: null });
131
+ }
55
132
  }
56
133
  /** Run a single autonomous tick. Never throws — failures are logged + reported. */
57
134
  async tick() {
@@ -71,8 +148,9 @@ export class FleetAutonomousLoop {
71
148
  this.store.updatePresence({ status: 'active' });
72
149
  const next = this.store.nextClaimable();
73
150
  if (!next) {
74
- this.store.updatePresence({ status: 'idle', currentTask: null });
75
- return { outcome: 'idle' };
151
+ // No real work — use the idle moment for one bounded self-improvement
152
+ // cycle (opt-in + cooldown), otherwise sit idle.
153
+ return this.maybeSelfImprove();
76
154
  }
77
155
  // Claim. If another agent won the race between read and claim, treat it as
78
156
  // idle for this tick rather than crashing.
@@ -139,6 +139,7 @@ export declare const runSchema: z.ZodObject<{
139
139
  }, "strict", z.ZodTypeAny, {
140
140
  status: "cancelled" | "running" | "completed" | "failed" | "queued" | "waiting_approval";
141
141
  id: string;
142
+ schemaVersion: 1;
142
143
  objective: string;
143
144
  kind: "run";
144
145
  actor: {
@@ -146,7 +147,6 @@ export declare const runSchema: z.ZodObject<{
146
147
  id: string;
147
148
  provider?: string | undefined;
148
149
  };
149
- schemaVersion: 1;
150
150
  startedAt: number;
151
151
  metadata?: {
152
152
  tags: string[];
@@ -169,6 +169,7 @@ export declare const runSchema: z.ZodObject<{
169
169
  }, {
170
170
  status: "cancelled" | "running" | "completed" | "failed" | "queued" | "waiting_approval";
171
171
  id: string;
172
+ schemaVersion: 1;
172
173
  objective: string;
173
174
  kind: "run";
174
175
  actor: {
@@ -176,7 +177,6 @@ export declare const runSchema: z.ZodObject<{
176
177
  id: string;
177
178
  provider?: string | undefined;
178
179
  };
179
- schemaVersion: 1;
180
180
  startedAt: number;
181
181
  metadata?: {
182
182
  sessionId?: string | undefined;
@@ -245,8 +245,8 @@ export declare const proofSchema: z.ZodObject<{
245
245
  id: string;
246
246
  summary: string;
247
247
  createdAt: number;
248
- kind: "proof";
249
248
  schemaVersion: 1;
249
+ kind: "proof";
250
250
  runId: string;
251
251
  producedBy: {
252
252
  type: "agent" | "human";
@@ -259,8 +259,8 @@ export declare const proofSchema: z.ZodObject<{
259
259
  id: string;
260
260
  summary: string;
261
261
  createdAt: number;
262
- kind: "proof";
263
262
  schemaVersion: 1;
263
+ kind: "proof";
264
264
  runId: string;
265
265
  producedBy: {
266
266
  type: "agent" | "human";
@@ -283,17 +283,17 @@ export declare const sensitiveActionSchema: z.ZodObject<{
283
283
  name: string;
284
284
  id: string;
285
285
  scope: string[];
286
+ schemaVersion: 1;
286
287
  kind: "sensitive-action";
287
288
  requires: "autonomous" | "dry-run-required" | "approval-required";
288
- schemaVersion: 1;
289
289
  riskLevel: "low" | "medium" | "high";
290
290
  defaultDryRun: boolean;
291
291
  }, {
292
292
  name: string;
293
293
  id: string;
294
+ schemaVersion: 1;
294
295
  kind: "sensitive-action";
295
296
  requires: "autonomous" | "dry-run-required" | "approval-required";
296
- schemaVersion: 1;
297
297
  riskLevel: "low" | "medium" | "high";
298
298
  scope?: string[] | undefined;
299
299
  defaultDryRun?: boolean | undefined;
@@ -364,6 +364,7 @@ export declare const workflowSchema: z.ZodObject<{
364
364
  id: string;
365
365
  version: number;
366
366
  summary: string;
367
+ schemaVersion: 1;
367
368
  kind: "workflow";
368
369
  nodes: {
369
370
  id: string;
@@ -371,7 +372,6 @@ export declare const workflowSchema: z.ZodObject<{
371
372
  canvasKind: "action" | "trigger" | "logic";
372
373
  role?: "edit" | "analysis" | "handoff" | "approval" | "verification" | "gate" | undefined;
373
374
  }[];
374
- schemaVersion: 1;
375
375
  edges: {
376
376
  source: string;
377
377
  target: string;
@@ -381,6 +381,7 @@ export declare const workflowSchema: z.ZodObject<{
381
381
  id: string;
382
382
  version: number;
383
383
  summary: string;
384
+ schemaVersion: 1;
384
385
  kind: "workflow";
385
386
  nodes: {
386
387
  id: string;
@@ -388,7 +389,6 @@ export declare const workflowSchema: z.ZodObject<{
388
389
  canvasKind: "action" | "trigger" | "logic";
389
390
  role?: "edit" | "analysis" | "handoff" | "approval" | "verification" | "gate" | undefined;
390
391
  }[];
391
- schemaVersion: 1;
392
392
  edges?: {
393
393
  source: string;
394
394
  target: string;
@@ -413,8 +413,8 @@ export declare const approvalSchema: z.ZodObject<{
413
413
  id: string;
414
414
  target: string;
415
415
  decision: "rejected" | "approved";
416
- kind: "approval";
417
416
  schemaVersion: 1;
417
+ kind: "approval";
418
418
  reviewer: string;
419
419
  decidedAt: number;
420
420
  scope?: string | undefined;
@@ -425,8 +425,8 @@ export declare const approvalSchema: z.ZodObject<{
425
425
  id: string;
426
426
  target: string;
427
427
  decision: "rejected" | "approved";
428
- kind: "approval";
429
428
  schemaVersion: 1;
429
+ kind: "approval";
430
430
  reviewer: string;
431
431
  decidedAt: number;
432
432
  scope?: string | undefined;
@@ -453,17 +453,17 @@ export declare const lessonSchema: z.ZodObject<{
453
453
  tags: string[];
454
454
  createdAt: number;
455
455
  policy: "none" | "lessons" | "handoff";
456
+ schemaVersion: 1;
456
457
  kind: "lesson";
457
458
  tier: "technical" | "experience";
458
- schemaVersion: 1;
459
459
  sourceRunId: string;
460
460
  }, {
461
461
  content: string;
462
462
  id: string;
463
463
  createdAt: number;
464
+ schemaVersion: 1;
464
465
  kind: "lesson";
465
466
  tier: "technical" | "experience";
466
- schemaVersion: 1;
467
467
  sourceRunId: string;
468
468
  tags?: string[] | undefined;
469
469
  policy?: "none" | "lessons" | "handoff" | undefined;
@@ -483,8 +483,8 @@ export declare const capabilitySchema: z.ZodObject<{
483
483
  level: "read" | "sensitive" | "reversible-write";
484
484
  id: string;
485
485
  policy: "autonomous" | "dry-run-required" | "approval-required";
486
- kind: "capability";
487
486
  schemaVersion: 1;
487
+ kind: "capability";
488
488
  fleetPolicy: "none" | "read-only-help" | "delegated-slices";
489
489
  description?: string | undefined;
490
490
  }, {
@@ -492,8 +492,8 @@ export declare const capabilitySchema: z.ZodObject<{
492
492
  level: "read" | "sensitive" | "reversible-write";
493
493
  id: string;
494
494
  policy: "autonomous" | "dry-run-required" | "approval-required";
495
- kind: "capability";
496
495
  schemaVersion: 1;
496
+ kind: "capability";
497
497
  description?: string | undefined;
498
498
  fleetPolicy?: "none" | "read-only-help" | "delegated-slices" | undefined;
499
499
  }>;
@@ -567,6 +567,7 @@ export declare const harnessArtifactSchema: z.ZodDiscriminatedUnion<"kind", [z.Z
567
567
  }, "strict", z.ZodTypeAny, {
568
568
  status: "cancelled" | "running" | "completed" | "failed" | "queued" | "waiting_approval";
569
569
  id: string;
570
+ schemaVersion: 1;
570
571
  objective: string;
571
572
  kind: "run";
572
573
  actor: {
@@ -574,7 +575,6 @@ export declare const harnessArtifactSchema: z.ZodDiscriminatedUnion<"kind", [z.Z
574
575
  id: string;
575
576
  provider?: string | undefined;
576
577
  };
577
- schemaVersion: 1;
578
578
  startedAt: number;
579
579
  metadata?: {
580
580
  tags: string[];
@@ -597,6 +597,7 @@ export declare const harnessArtifactSchema: z.ZodDiscriminatedUnion<"kind", [z.Z
597
597
  }, {
598
598
  status: "cancelled" | "running" | "completed" | "failed" | "queued" | "waiting_approval";
599
599
  id: string;
600
+ schemaVersion: 1;
600
601
  objective: string;
601
602
  kind: "run";
602
603
  actor: {
@@ -604,7 +605,6 @@ export declare const harnessArtifactSchema: z.ZodDiscriminatedUnion<"kind", [z.Z
604
605
  id: string;
605
606
  provider?: string | undefined;
606
607
  };
607
- schemaVersion: 1;
608
608
  startedAt: number;
609
609
  metadata?: {
610
610
  sessionId?: string | undefined;
@@ -651,8 +651,8 @@ export declare const harnessArtifactSchema: z.ZodDiscriminatedUnion<"kind", [z.Z
651
651
  id: string;
652
652
  summary: string;
653
653
  createdAt: number;
654
- kind: "proof";
655
654
  schemaVersion: 1;
655
+ kind: "proof";
656
656
  runId: string;
657
657
  producedBy: {
658
658
  type: "agent" | "human";
@@ -665,8 +665,8 @@ export declare const harnessArtifactSchema: z.ZodDiscriminatedUnion<"kind", [z.Z
665
665
  id: string;
666
666
  summary: string;
667
667
  createdAt: number;
668
- kind: "proof";
669
668
  schemaVersion: 1;
669
+ kind: "proof";
670
670
  runId: string;
671
671
  producedBy: {
672
672
  type: "agent" | "human";
@@ -687,17 +687,17 @@ export declare const harnessArtifactSchema: z.ZodDiscriminatedUnion<"kind", [z.Z
687
687
  name: string;
688
688
  id: string;
689
689
  scope: string[];
690
+ schemaVersion: 1;
690
691
  kind: "sensitive-action";
691
692
  requires: "autonomous" | "dry-run-required" | "approval-required";
692
- schemaVersion: 1;
693
693
  riskLevel: "low" | "medium" | "high";
694
694
  defaultDryRun: boolean;
695
695
  }, {
696
696
  name: string;
697
697
  id: string;
698
+ schemaVersion: 1;
698
699
  kind: "sensitive-action";
699
700
  requires: "autonomous" | "dry-run-required" | "approval-required";
700
- schemaVersion: 1;
701
701
  riskLevel: "low" | "medium" | "high";
702
702
  scope?: string[] | undefined;
703
703
  defaultDryRun?: boolean | undefined;
@@ -738,6 +738,7 @@ export declare const harnessArtifactSchema: z.ZodDiscriminatedUnion<"kind", [z.Z
738
738
  id: string;
739
739
  version: number;
740
740
  summary: string;
741
+ schemaVersion: 1;
741
742
  kind: "workflow";
742
743
  nodes: {
743
744
  id: string;
@@ -745,7 +746,6 @@ export declare const harnessArtifactSchema: z.ZodDiscriminatedUnion<"kind", [z.Z
745
746
  canvasKind: "action" | "trigger" | "logic";
746
747
  role?: "edit" | "analysis" | "handoff" | "approval" | "verification" | "gate" | undefined;
747
748
  }[];
748
- schemaVersion: 1;
749
749
  edges: {
750
750
  source: string;
751
751
  target: string;
@@ -755,6 +755,7 @@ export declare const harnessArtifactSchema: z.ZodDiscriminatedUnion<"kind", [z.Z
755
755
  id: string;
756
756
  version: number;
757
757
  summary: string;
758
+ schemaVersion: 1;
758
759
  kind: "workflow";
759
760
  nodes: {
760
761
  id: string;
@@ -762,7 +763,6 @@ export declare const harnessArtifactSchema: z.ZodDiscriminatedUnion<"kind", [z.Z
762
763
  canvasKind: "action" | "trigger" | "logic";
763
764
  role?: "edit" | "analysis" | "handoff" | "approval" | "verification" | "gate" | undefined;
764
765
  }[];
765
- schemaVersion: 1;
766
766
  edges?: {
767
767
  source: string;
768
768
  target: string;
@@ -785,8 +785,8 @@ export declare const harnessArtifactSchema: z.ZodDiscriminatedUnion<"kind", [z.Z
785
785
  id: string;
786
786
  target: string;
787
787
  decision: "rejected" | "approved";
788
- kind: "approval";
789
788
  schemaVersion: 1;
789
+ kind: "approval";
790
790
  reviewer: string;
791
791
  decidedAt: number;
792
792
  scope?: string | undefined;
@@ -797,8 +797,8 @@ export declare const harnessArtifactSchema: z.ZodDiscriminatedUnion<"kind", [z.Z
797
797
  id: string;
798
798
  target: string;
799
799
  decision: "rejected" | "approved";
800
- kind: "approval";
801
800
  schemaVersion: 1;
801
+ kind: "approval";
802
802
  reviewer: string;
803
803
  decidedAt: number;
804
804
  scope?: string | undefined;
@@ -820,17 +820,17 @@ export declare const harnessArtifactSchema: z.ZodDiscriminatedUnion<"kind", [z.Z
820
820
  tags: string[];
821
821
  createdAt: number;
822
822
  policy: "none" | "lessons" | "handoff";
823
+ schemaVersion: 1;
823
824
  kind: "lesson";
824
825
  tier: "technical" | "experience";
825
- schemaVersion: 1;
826
826
  sourceRunId: string;
827
827
  }, {
828
828
  content: string;
829
829
  id: string;
830
830
  createdAt: number;
831
+ schemaVersion: 1;
831
832
  kind: "lesson";
832
833
  tier: "technical" | "experience";
833
- schemaVersion: 1;
834
834
  sourceRunId: string;
835
835
  tags?: string[] | undefined;
836
836
  policy?: "none" | "lessons" | "handoff" | undefined;
@@ -848,8 +848,8 @@ export declare const harnessArtifactSchema: z.ZodDiscriminatedUnion<"kind", [z.Z
848
848
  level: "read" | "sensitive" | "reversible-write";
849
849
  id: string;
850
850
  policy: "autonomous" | "dry-run-required" | "approval-required";
851
- kind: "capability";
852
851
  schemaVersion: 1;
852
+ kind: "capability";
853
853
  fleetPolicy: "none" | "read-only-help" | "delegated-slices";
854
854
  description?: string | undefined;
855
855
  }, {
@@ -857,8 +857,8 @@ export declare const harnessArtifactSchema: z.ZodDiscriminatedUnion<"kind", [z.Z
857
857
  level: "read" | "sensitive" | "reversible-write";
858
858
  id: string;
859
859
  policy: "autonomous" | "dry-run-required" | "approval-required";
860
- kind: "capability";
861
860
  schemaVersion: 1;
861
+ kind: "capability";
862
862
  description?: string | undefined;
863
863
  fleetPolicy?: "none" | "read-only-help" | "delegated-slices" | undefined;
864
864
  }>]>;
@@ -16,13 +16,14 @@ import { logger } from '../utils/logger.js';
16
16
  // ============================================================================
17
17
  // Defaults
18
18
  // ============================================================================
19
+ // AGENTS.md and INSTRUCTIONS.md are intentionally NOT here — they are owned by
20
+ // the unified project-context loader (src/context/project-context.ts). Identity
21
+ // covers only the soul/identity tier.
19
22
  const DEFAULT_IDENTITY_FILES = [
20
23
  'SOUL.md',
21
24
  'USER.md',
22
- 'AGENTS.md',
23
25
  'TOOLS.md',
24
26
  'IDENTITY.md',
25
- 'INSTRUCTIONS.md',
26
27
  'BOOT.md',
27
28
  'BOOTSTRAP.md',
28
29
  'HEARTBEAT.md',
package/dist/index.js CHANGED
@@ -825,7 +825,11 @@ async function applyCustomAgentToolFilter(agentConfig) {
825
825
  async function processPromptHeadless(prompt, apiKey, baseURL, model, maxToolRounds, selfHealEnabled = true, outputFormat = 'json', outputSchemaPath, agentName) {
826
826
  const previousDisableMCP = process.env.CODEBUDDY_DISABLE_MCP;
827
827
  const previousHeadless = process.env.CODEBUDDY_HEADLESS;
828
- process.env.CODEBUDDY_DISABLE_MCP = 'true';
828
+ // Headless defaults MCP OFF (startup cost / determinism), but respect an
829
+ // explicit opt-in so `CODEBUDDY_DISABLE_MCP=false buddy -p …` can use MCP
830
+ // servers (e.g. the Code Explorer / gitnexus bridge, or the benchmark's
831
+ // "with graph" condition). Mirrors the opt-in pattern in goal-cli.ts.
832
+ process.env.CODEBUDDY_DISABLE_MCP = process.env.CODEBUDDY_DISABLE_MCP ?? 'true';
829
833
  process.env.CODEBUDDY_HEADLESS = 'true';
830
834
  try {
831
835
  const customAgentConfig = await loadCustomAgentForCli(agentName, false);
@@ -834,6 +838,18 @@ async function processPromptHeadless(prompt, apiKey, baseURL, model, maxToolRoun
834
838
  const agent = new CodeBuddyAgent(apiKey, baseURL, modelToUse, maxToolRounds);
835
839
  await applyActiveLlmFailover(agent);
836
840
  await agent.systemPromptReady;
841
+ // When MCP is opted in for this headless run, wait for the servers to finish
842
+ // connecting so their tools (e.g. the Code Explorer / gitnexus bridge) are
843
+ // registered before the first turn — otherwise the one-shot turn races init
844
+ // and the agent never sees the MCP tools.
845
+ if (process.env.CODEBUDDY_DISABLE_MCP !== 'true') {
846
+ try {
847
+ await agent.getMCPReady();
848
+ }
849
+ catch (e) {
850
+ logger.debug('MCP readiness wait failed (continuing without MCP tools)', { error: String(e) });
851
+ }
852
+ }
837
853
  if (customAgentConfig?.systemPrompt) {
838
854
  agent.setSystemPrompt(customAgentConfig.systemPrompt);
839
855
  }
@@ -17,9 +17,8 @@ export function registerResources(server) {
17
17
  mimeType: 'text/markdown',
18
18
  }, async () => {
19
19
  try {
20
- const { loadContext, formatContextForPrompt } = await import('../context/context-files.js');
21
- const context = await loadContext(process.cwd());
22
- let text = formatContextForPrompt(context);
20
+ const { resolveProjectContext } = await import('../context/project-context.js');
21
+ let text = resolveProjectContext({ cwd: process.cwd() }).text;
23
22
  // Append git status
24
23
  try {
25
24
  const { execSync } = await import('child_process');
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Dreaming — heartbeat-paced memory consolidation. Every N beats, the short-term
3
+ * sensory buffer is drained and consolidated into a compact "dream" summary
4
+ * (counts by kind, salient events, time window, average load) appended to a
5
+ * long-term dream journal. The heartbeat-paced analogue of OpenClaw's dreaming
6
+ * (short-term recall → consolidated long-term memory).
7
+ *
8
+ * @module sensory/dreaming
9
+ */
10
+ import type { Perception } from './reactions.js';
11
+ export interface DreamSummary {
12
+ dreamedAt: number;
13
+ windowStartMs: number | null;
14
+ windowEndMs: number | null;
15
+ total: number;
16
+ /** "audio/speech_start" → count, "vital/heartbeat" → count, … */
17
+ byKind: Record<string, number>;
18
+ salient: Array<{
19
+ modality?: string;
20
+ kind?: string;
21
+ salience?: number;
22
+ tsMs?: number;
23
+ }>;
24
+ avgLoad: number | null;
25
+ }
26
+ /** Pure consolidation: summarize a window of perceptions into a dream. */
27
+ export declare function consolidate(perceptions: Perception[], now: number): DreamSummary;
28
+ export interface DreamingOptions {
29
+ cwd?: string;
30
+ now?: number;
31
+ /** Injectable promotion (tests); defaults to promoteSalientDream. */
32
+ promote?: (summary: DreamSummary) => Promise<void>;
33
+ }
34
+ /**
35
+ * One dreaming pass: drain the short-term buffer, consolidate, append to the
36
+ * dream journal, and promote a SALIENT dream into long-term persistent memory.
37
+ * Returns the summary, or null if there was nothing to consolidate.
38
+ */
39
+ export declare function runDreamingPass(options?: DreamingOptions): Promise<DreamSummary | null>;
40
+ /**
41
+ * Promote a salient dream into Code Buddy's persistent memory under a STABLE key
42
+ * (`dream:recent`) so repeated promotions UPDATE rather than accumulate (stays
43
+ * within the memory char budget). Never throws.
44
+ */
45
+ export declare function promoteSalientDream(summary: DreamSummary): Promise<void>;
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Dreaming — heartbeat-paced memory consolidation. Every N beats, the short-term
3
+ * sensory buffer is drained and consolidated into a compact "dream" summary
4
+ * (counts by kind, salient events, time window, average load) appended to a
5
+ * long-term dream journal. The heartbeat-paced analogue of OpenClaw's dreaming
6
+ * (short-term recall → consolidated long-term memory).
7
+ *
8
+ * @module sensory/dreaming
9
+ */
10
+ import { appendFile, mkdir, stat, rename } from 'fs/promises';
11
+ import path from 'path';
12
+ import { getSensoryMemory } from './sensory-memory.js';
13
+ import { logger } from '../utils/logger.js';
14
+ const SALIENT_THRESHOLD = 128;
15
+ /** Pure consolidation: summarize a window of perceptions into a dream. */
16
+ export function consolidate(perceptions, now) {
17
+ const byKind = {};
18
+ const salient = [];
19
+ let loadSum = 0;
20
+ let loadN = 0;
21
+ let minTs = null;
22
+ let maxTs = null;
23
+ for (const p of perceptions) {
24
+ const key = `${p.modality}/${p.kind}`;
25
+ byKind[key] = (byKind[key] ?? 0) + 1;
26
+ if ((p.salience ?? 0) >= SALIENT_THRESHOLD) {
27
+ salient.push({ modality: p.modality, kind: p.kind, salience: p.salience, tsMs: p.tsMs });
28
+ }
29
+ const load = p.payload?.load1;
30
+ if (typeof load === 'number') {
31
+ loadSum += load;
32
+ loadN += 1;
33
+ }
34
+ // Window on the ingest wall-clock (consistent across senses), not the
35
+ // sense-relative tsMs (frame-relative for audio vs unix for vital).
36
+ if (typeof p.receivedAt === 'number') {
37
+ minTs = minTs === null ? p.receivedAt : Math.min(minTs, p.receivedAt);
38
+ maxTs = maxTs === null ? p.receivedAt : Math.max(maxTs, p.receivedAt);
39
+ }
40
+ }
41
+ return {
42
+ dreamedAt: now,
43
+ windowStartMs: minTs,
44
+ windowEndMs: maxTs,
45
+ total: perceptions.length,
46
+ byKind,
47
+ salient: salient.slice(0, 20),
48
+ avgLoad: loadN > 0 ? loadSum / loadN : null,
49
+ };
50
+ }
51
+ /**
52
+ * One dreaming pass: drain the short-term buffer, consolidate, append to the
53
+ * dream journal, and promote a SALIENT dream into long-term persistent memory.
54
+ * Returns the summary, or null if there was nothing to consolidate.
55
+ */
56
+ export async function runDreamingPass(options = {}) {
57
+ const perceptions = getSensoryMemory().drain();
58
+ if (perceptions.length === 0)
59
+ return null;
60
+ const summary = consolidate(perceptions, options.now ?? Date.now());
61
+ try {
62
+ const dir = path.join(options.cwd ?? process.cwd(), '.codebuddy', 'companion');
63
+ await mkdir(dir, { recursive: true });
64
+ const file = path.join(dir, 'dreams.jsonl');
65
+ // Rotate when large (the disk-guard lesson): keep one .1 backup, never grow unbounded.
66
+ try {
67
+ const info = await stat(file);
68
+ if (info.size > 512 * 1024)
69
+ await rename(file, `${file}.1`);
70
+ }
71
+ catch {
72
+ /* no file yet */
73
+ }
74
+ await appendFile(file, `${JSON.stringify(summary)}\n`, 'utf8');
75
+ }
76
+ catch (err) {
77
+ logger.warn(`[dreaming] could not persist dream: ${err instanceof Error ? err.message : String(err)}`);
78
+ }
79
+ // Deep consolidation — salient dreams become long-term memory the agent reads.
80
+ if (summary.salient.length > 0) {
81
+ await (options.promote ?? promoteSalientDream)(summary);
82
+ }
83
+ logger.info(`[dreaming] consolidated ${summary.total} perception(s) → ${Object.keys(summary.byKind).length} kind(s), ${summary.salient.length} salient, avg load ${summary.avgLoad ?? '?'}`);
84
+ return summary;
85
+ }
86
+ /**
87
+ * Promote a salient dream into Code Buddy's persistent memory under a STABLE key
88
+ * (`dream:recent`) so repeated promotions UPDATE rather than accumulate (stays
89
+ * within the memory char budget). Never throws.
90
+ */
91
+ export async function promoteSalientDream(summary) {
92
+ try {
93
+ const { getMemoryManager } = await import('../memory/persistent-memory.js');
94
+ const manager = getMemoryManager();
95
+ await manager.initialize();
96
+ // Cap the kinds string (a daemon could emit many distinct kinds → an
97
+ // oversized write that the memory char-limit would reject).
98
+ const kindEntries = Object.entries(summary.byKind).sort((a, b) => b[1] - a[1]);
99
+ const kinds = kindEntries
100
+ .slice(0, 12)
101
+ .map(([k, n]) => `${k}×${n}`)
102
+ .join(', ') + (kindEntries.length > 12 ? `, +${kindEntries.length - 12} more` : '');
103
+ const top = summary.salient
104
+ .slice(0, 5)
105
+ .map((s) => `${s.modality}/${s.kind}`)
106
+ .join(', ');
107
+ const value = `Recent salient perception: ${summary.total} events (${kinds}); salient: ${top}; avg load ${summary.avgLoad ?? '?'}.`;
108
+ await manager.remember('dream:recent', value, { scope: 'project', category: 'context', tags: ['dream', 'sensory'] });
109
+ }
110
+ catch (err) {
111
+ logger.warn(`[dreaming] could not promote dream to memory: ${err instanceof Error ? err.message : String(err)}`);
112
+ }
113
+ }
114
+ //# sourceMappingURL=dreaming.js.map