@neotx/core 0.1.0-alpha.19 → 0.1.0-alpha.20
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/dist/index.d.ts +7 -0
- package/dist/index.js +198 -82
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -149,6 +149,9 @@ declare const globalConfigSchema: z.ZodObject<{
|
|
|
149
149
|
compactionIntervalMs: z.ZodDefault<z.ZodNumber>;
|
|
150
150
|
eventTimeoutMs: z.ZodDefault<z.ZodNumber>;
|
|
151
151
|
instructions: z.ZodOptional<z.ZodString>;
|
|
152
|
+
idleSkipMax: z.ZodDefault<z.ZodNumber>;
|
|
153
|
+
activeWorkSkipMax: z.ZodDefault<z.ZodNumber>;
|
|
154
|
+
autoDecide: z.ZodDefault<z.ZodBoolean>;
|
|
152
155
|
}, z.core.$strip>>;
|
|
153
156
|
memory: z.ZodDefault<z.ZodObject<{
|
|
154
157
|
embeddings: z.ZodDefault<z.ZodBoolean>;
|
|
@@ -220,6 +223,9 @@ declare const neoConfigSchema: z.ZodObject<{
|
|
|
220
223
|
compactionIntervalMs: z.ZodDefault<z.ZodNumber>;
|
|
221
224
|
eventTimeoutMs: z.ZodDefault<z.ZodNumber>;
|
|
222
225
|
instructions: z.ZodOptional<z.ZodString>;
|
|
226
|
+
idleSkipMax: z.ZodDefault<z.ZodNumber>;
|
|
227
|
+
activeWorkSkipMax: z.ZodDefault<z.ZodNumber>;
|
|
228
|
+
autoDecide: z.ZodDefault<z.ZodBoolean>;
|
|
223
229
|
}, z.core.$strip>>;
|
|
224
230
|
memory: z.ZodDefault<z.ZodObject<{
|
|
225
231
|
embeddings: z.ZodDefault<z.ZodBoolean>;
|
|
@@ -1635,6 +1641,7 @@ declare class HeartbeatLoop {
|
|
|
1635
1641
|
private checkBudgetExceeded;
|
|
1636
1642
|
/**
|
|
1637
1643
|
* Handle skip logic for idle and active-work scenarios.
|
|
1644
|
+
* Uses IdleDetector to make skip decisions based on context.
|
|
1638
1645
|
*/
|
|
1639
1646
|
private handleSkipLogic;
|
|
1640
1647
|
/**
|
package/dist/index.js
CHANGED
|
@@ -518,7 +518,13 @@ var supervisorConfigSchema = z2.object({
|
|
|
518
518
|
compactionIntervalMs: z2.number().default(36e5),
|
|
519
519
|
/** Safety timeout for waitForWork (ms) */
|
|
520
520
|
eventTimeoutMs: z2.number().default(3e5),
|
|
521
|
-
instructions: z2.string().optional()
|
|
521
|
+
instructions: z2.string().optional(),
|
|
522
|
+
/** Max consecutive idle loop iterations before supervisor pauses polling */
|
|
523
|
+
idleSkipMax: z2.number().default(20),
|
|
524
|
+
/** Max consecutive active-work loop iterations before supervisor yields */
|
|
525
|
+
activeWorkSkipMax: z2.number().default(3),
|
|
526
|
+
/** When true, supervisor answers pending decisions autonomously instead of waiting for human input */
|
|
527
|
+
autoDecide: z2.boolean().default(false)
|
|
522
528
|
}).default({
|
|
523
529
|
port: 7777,
|
|
524
530
|
heartbeatTimeoutMs: 3e5,
|
|
@@ -527,7 +533,10 @@ var supervisorConfigSchema = z2.object({
|
|
|
527
533
|
dailyCapUsd: 50,
|
|
528
534
|
consolidationIntervalMs: 3e5,
|
|
529
535
|
compactionIntervalMs: 36e5,
|
|
530
|
-
eventTimeoutMs: 3e5
|
|
536
|
+
eventTimeoutMs: 3e5,
|
|
537
|
+
idleSkipMax: 20,
|
|
538
|
+
activeWorkSkipMax: 3,
|
|
539
|
+
autoDecide: false
|
|
531
540
|
});
|
|
532
541
|
var globalConfigSchema = z2.object({
|
|
533
542
|
repos: z2.array(repoConfigSchema).default([]),
|
|
@@ -598,7 +607,10 @@ var defaultConfig = {
|
|
|
598
607
|
dailyCapUsd: 50,
|
|
599
608
|
consolidationIntervalMs: 3e5,
|
|
600
609
|
compactionIntervalMs: 36e5,
|
|
601
|
-
eventTimeoutMs: 3e5
|
|
610
|
+
eventTimeoutMs: 3e5,
|
|
611
|
+
idleSkipMax: 20,
|
|
612
|
+
activeWorkSkipMax: 3,
|
|
613
|
+
autoDecide: false
|
|
602
614
|
},
|
|
603
615
|
memory: { embeddings: true }
|
|
604
616
|
};
|
|
@@ -3811,6 +3823,57 @@ import { readdir as readdir4, readFile as readFile11, writeFile as writeFile6 }
|
|
|
3811
3823
|
import { homedir as homedir4 } from "os";
|
|
3812
3824
|
import path14 from "path";
|
|
3813
3825
|
|
|
3826
|
+
// src/supervisor/idle-detector.ts
|
|
3827
|
+
import { z as z6 } from "zod";
|
|
3828
|
+
var idleDetectorConfigSchema = z6.object({
|
|
3829
|
+
idleSkipMax: z6.number(),
|
|
3830
|
+
activeWorkSkipMax: z6.number()
|
|
3831
|
+
});
|
|
3832
|
+
var idleContextSchema = z6.object({
|
|
3833
|
+
eventCount: z6.number(),
|
|
3834
|
+
activeRuns: z6.number(),
|
|
3835
|
+
hasPendingConsolidation: z6.boolean(),
|
|
3836
|
+
hasExpiredDecisions: z6.boolean(),
|
|
3837
|
+
timeSinceLastHeartbeatMs: z6.number(),
|
|
3838
|
+
idleSkipCount: z6.number(),
|
|
3839
|
+
activeWorkSkipCount: z6.number()
|
|
3840
|
+
});
|
|
3841
|
+
var skipResultSchema = z6.object({
|
|
3842
|
+
shouldSkip: z6.boolean(),
|
|
3843
|
+
reason: z6.string()
|
|
3844
|
+
});
|
|
3845
|
+
var IdleDetector = class {
|
|
3846
|
+
config;
|
|
3847
|
+
constructor(config) {
|
|
3848
|
+
this.config = config;
|
|
3849
|
+
}
|
|
3850
|
+
/**
|
|
3851
|
+
* Evaluate whether the current heartbeat should be skipped.
|
|
3852
|
+
* @returns SkipResult with shouldSkip flag and reason
|
|
3853
|
+
*/
|
|
3854
|
+
shouldSkip(context) {
|
|
3855
|
+
if (context.eventCount > 0) {
|
|
3856
|
+
return { shouldSkip: false, reason: "events pending" };
|
|
3857
|
+
}
|
|
3858
|
+
if (context.hasPendingConsolidation) {
|
|
3859
|
+
return { shouldSkip: false, reason: "pending consolidation" };
|
|
3860
|
+
}
|
|
3861
|
+
if (context.hasExpiredDecisions) {
|
|
3862
|
+
return { shouldSkip: false, reason: "expired decisions" };
|
|
3863
|
+
}
|
|
3864
|
+
if (context.activeRuns > 0) {
|
|
3865
|
+
if (context.activeWorkSkipCount >= this.config.activeWorkSkipMax) {
|
|
3866
|
+
return { shouldSkip: false, reason: "active work skip threshold exceeded" };
|
|
3867
|
+
}
|
|
3868
|
+
return { shouldSkip: true, reason: "active runs, within threshold" };
|
|
3869
|
+
}
|
|
3870
|
+
if (context.idleSkipCount >= this.config.idleSkipMax) {
|
|
3871
|
+
return { shouldSkip: false, reason: "idle skip threshold exceeded" };
|
|
3872
|
+
}
|
|
3873
|
+
return { shouldSkip: true, reason: "idle, within threshold" };
|
|
3874
|
+
}
|
|
3875
|
+
};
|
|
3876
|
+
|
|
3814
3877
|
// src/supervisor/log-buffer.ts
|
|
3815
3878
|
import { appendFile as appendFile6, readFile as readFile10, stat as stat2, writeFile as writeFile5 } from "fs/promises";
|
|
3816
3879
|
import path13 from "path";
|
|
@@ -4140,7 +4203,7 @@ ${lines}
|
|
|
4140
4203
|
}
|
|
4141
4204
|
return "<focus>\n(empty \u2014 use neo memory write --type focus to set working context)\n</focus>";
|
|
4142
4205
|
}
|
|
4143
|
-
function buildPendingDecisionsSection(decisions) {
|
|
4206
|
+
function buildPendingDecisionsSection(decisions, autoDecide = false) {
|
|
4144
4207
|
if (!decisions || decisions.length === 0) {
|
|
4145
4208
|
return "";
|
|
4146
4209
|
}
|
|
@@ -4159,13 +4222,22 @@ function buildPendingDecisionsSection(decisions) {
|
|
|
4159
4222
|
lines.push(` Context: ${d.context}`);
|
|
4160
4223
|
}
|
|
4161
4224
|
}
|
|
4162
|
-
|
|
4163
|
-
|
|
4225
|
+
const instruction = autoDecide ? `You are in **autoDecide** mode \u2014 answer each pending decision yourself based on available context, project knowledge, and best engineering judgment.
|
|
4226
|
+
|
|
4227
|
+
\`\`\`bash
|
|
4228
|
+
neo decision answer <decision_id> <answer>
|
|
4229
|
+
\`\`\`
|
|
4230
|
+
|
|
4231
|
+
For each decision: analyze the options, consider the project context and risk, then answer decisively. Prefer safe, incremental choices when uncertain. Log your reasoning before answering.
|
|
4164
4232
|
|
|
4165
|
-
To answer a decision, emit a \`decision:answer\` event:
|
|
4233
|
+
**Merge authority:** In autoDecide mode you MAY merge branches when the PR is ready (CI green, reviews approved). Use \`gh pr merge\` with the appropriate merge strategy.` : `To answer a decision, emit a \`decision:answer\` event:
|
|
4166
4234
|
\`\`\`bash
|
|
4167
4235
|
neo event emit decision:answer --data '{"id":"<decision_id>","answer":"<option_key>"}'
|
|
4168
4236
|
\`\`\``;
|
|
4237
|
+
return `Pending decisions (${decisions.length}):
|
|
4238
|
+
${lines.join("\n")}
|
|
4239
|
+
|
|
4240
|
+
${instruction}`;
|
|
4169
4241
|
}
|
|
4170
4242
|
function buildAnsweredDecisionsSection(decisions) {
|
|
4171
4243
|
if (!decisions || decisions.length === 0) {
|
|
@@ -4193,7 +4265,7 @@ ${opts.activeRuns.map((r) => `- ${r}`).join("\n")}`);
|
|
|
4193
4265
|
if (recentActions) {
|
|
4194
4266
|
parts.push(recentActions);
|
|
4195
4267
|
}
|
|
4196
|
-
const pendingDecisions = buildPendingDecisionsSection(opts.pendingDecisions);
|
|
4268
|
+
const pendingDecisions = buildPendingDecisionsSection(opts.pendingDecisions, opts.autoDecide);
|
|
4197
4269
|
if (pendingDecisions) {
|
|
4198
4270
|
parts.push(pendingDecisions);
|
|
4199
4271
|
}
|
|
@@ -4519,7 +4591,28 @@ Nothing to do. Run \`neo log discovery "idle"\` and yield. Do not produce any ot
|
|
|
4519
4591
|
}
|
|
4520
4592
|
const repoList = opts.repos.map((r) => `- ${r.path} (branch: ${r.defaultBranch})`).join("\n");
|
|
4521
4593
|
if (hasPendingDecisions) {
|
|
4522
|
-
const pendingSection = buildPendingDecisionsSection(opts.pendingDecisions);
|
|
4594
|
+
const pendingSection = buildPendingDecisionsSection(opts.pendingDecisions, opts.autoDecide);
|
|
4595
|
+
if (opts.autoDecide) {
|
|
4596
|
+
return `${buildRoleSection(opts.heartbeatCount)}
|
|
4597
|
+
|
|
4598
|
+
<context>
|
|
4599
|
+
No events. No active runs. No pending tasks.
|
|
4600
|
+
${budgetLine}
|
|
4601
|
+
|
|
4602
|
+
${pendingSection}
|
|
4603
|
+
|
|
4604
|
+
Repositories:
|
|
4605
|
+
${repoList}
|
|
4606
|
+
</context>
|
|
4607
|
+
|
|
4608
|
+
<reference>
|
|
4609
|
+
${getCommandsSection(opts.heartbeatCount)}
|
|
4610
|
+
</reference>
|
|
4611
|
+
|
|
4612
|
+
<directive>
|
|
4613
|
+
Idle \u2014 but there are pending decisions to resolve. You are in **autoDecide** mode: answer each pending decision now using your best engineering judgment, then yield. You MAY merge branches when PRs are ready (CI green, reviews approved).
|
|
4614
|
+
</directive>`;
|
|
4615
|
+
}
|
|
4523
4616
|
return `${buildRoleSection(opts.heartbeatCount)}
|
|
4524
4617
|
|
|
4525
4618
|
<context>
|
|
@@ -4638,50 +4731,50 @@ neo memory forget <stale-id>
|
|
|
4638
4731
|
}
|
|
4639
4732
|
|
|
4640
4733
|
// src/supervisor/webhookEvents.ts
|
|
4641
|
-
import { z as
|
|
4642
|
-
var supervisorStartedEventSchema =
|
|
4643
|
-
type:
|
|
4644
|
-
supervisorId:
|
|
4645
|
-
startedAt:
|
|
4734
|
+
import { z as z7 } from "zod";
|
|
4735
|
+
var supervisorStartedEventSchema = z7.object({
|
|
4736
|
+
type: z7.literal("supervisor_started"),
|
|
4737
|
+
supervisorId: z7.string(),
|
|
4738
|
+
startedAt: z7.string().datetime()
|
|
4646
4739
|
});
|
|
4647
|
-
var heartbeatEventSchema =
|
|
4648
|
-
type:
|
|
4649
|
-
supervisorId:
|
|
4650
|
-
heartbeatNumber:
|
|
4651
|
-
timestamp:
|
|
4652
|
-
runsActive:
|
|
4653
|
-
budget:
|
|
4654
|
-
todayUsd:
|
|
4655
|
-
limitUsd:
|
|
4740
|
+
var heartbeatEventSchema = z7.object({
|
|
4741
|
+
type: z7.literal("heartbeat"),
|
|
4742
|
+
supervisorId: z7.string(),
|
|
4743
|
+
heartbeatNumber: z7.number().int().min(0),
|
|
4744
|
+
timestamp: z7.string().datetime(),
|
|
4745
|
+
runsActive: z7.number().int().min(0),
|
|
4746
|
+
budget: z7.object({
|
|
4747
|
+
todayUsd: z7.number().min(0),
|
|
4748
|
+
limitUsd: z7.number().min(0)
|
|
4656
4749
|
})
|
|
4657
4750
|
});
|
|
4658
|
-
var runDispatchedEventSchema =
|
|
4659
|
-
type:
|
|
4660
|
-
supervisorId:
|
|
4661
|
-
runId:
|
|
4662
|
-
agent:
|
|
4663
|
-
repo:
|
|
4664
|
-
branch:
|
|
4665
|
-
prompt:
|
|
4751
|
+
var runDispatchedEventSchema = z7.object({
|
|
4752
|
+
type: z7.literal("run_dispatched"),
|
|
4753
|
+
supervisorId: z7.string(),
|
|
4754
|
+
runId: z7.string(),
|
|
4755
|
+
agent: z7.string(),
|
|
4756
|
+
repo: z7.string(),
|
|
4757
|
+
branch: z7.string(),
|
|
4758
|
+
prompt: z7.string().max(500)
|
|
4666
4759
|
// truncated
|
|
4667
4760
|
});
|
|
4668
|
-
var runCompletedEventSchema =
|
|
4669
|
-
type:
|
|
4670
|
-
supervisorId:
|
|
4671
|
-
runId:
|
|
4672
|
-
status:
|
|
4673
|
-
output:
|
|
4761
|
+
var runCompletedEventSchema = z7.object({
|
|
4762
|
+
type: z7.literal("run_completed"),
|
|
4763
|
+
supervisorId: z7.string(),
|
|
4764
|
+
runId: z7.string(),
|
|
4765
|
+
status: z7.enum(["completed", "failed", "cancelled"]),
|
|
4766
|
+
output: z7.string().max(1e3).optional(),
|
|
4674
4767
|
// truncated
|
|
4675
|
-
costUsd:
|
|
4676
|
-
durationMs:
|
|
4768
|
+
costUsd: z7.number().min(0),
|
|
4769
|
+
durationMs: z7.number().int().min(0)
|
|
4677
4770
|
});
|
|
4678
|
-
var supervisorStoppedEventSchema =
|
|
4679
|
-
type:
|
|
4680
|
-
supervisorId:
|
|
4681
|
-
stoppedAt:
|
|
4682
|
-
reason:
|
|
4771
|
+
var supervisorStoppedEventSchema = z7.object({
|
|
4772
|
+
type: z7.literal("supervisor_stopped"),
|
|
4773
|
+
supervisorId: z7.string(),
|
|
4774
|
+
stoppedAt: z7.string().datetime(),
|
|
4775
|
+
reason: z7.enum(["shutdown", "budget_exceeded", "error", "manual"])
|
|
4683
4776
|
});
|
|
4684
|
-
var supervisorWebhookEventSchema =
|
|
4777
|
+
var supervisorWebhookEventSchema = z7.discriminatedUnion("type", [
|
|
4685
4778
|
supervisorStartedEventSchema,
|
|
4686
4779
|
heartbeatEventSchema,
|
|
4687
4780
|
runDispatchedEventSchema,
|
|
@@ -4690,8 +4783,6 @@ var supervisorWebhookEventSchema = z6.discriminatedUnion("type", [
|
|
|
4690
4783
|
]);
|
|
4691
4784
|
|
|
4692
4785
|
// src/supervisor/heartbeat.ts
|
|
4693
|
-
var DEFAULT_IDLE_SKIP_MAX = 20;
|
|
4694
|
-
var DEFAULT_ACTIVE_WORK_SKIP_MAX = 3;
|
|
4695
4786
|
var DEFAULT_CONSOLIDATION_INTERVAL = 5;
|
|
4696
4787
|
function shouldConsolidate(heartbeatCount, lastConsolidationHeartbeat, consolidationInterval, hasPendingEntries) {
|
|
4697
4788
|
const since = heartbeatCount - lastConsolidationHeartbeat;
|
|
@@ -4856,13 +4947,18 @@ var HeartbeatLoop = class {
|
|
|
4856
4947
|
const activeRuns = await this.getActiveRuns();
|
|
4857
4948
|
const decisionStore = this.getDecisionStore();
|
|
4858
4949
|
await this.processDecisionAnswers(rawEvents, decisionStore);
|
|
4859
|
-
await decisionStore.expire();
|
|
4860
|
-
const
|
|
4861
|
-
|
|
4950
|
+
const expiredDecisions = await decisionStore.expire();
|
|
4951
|
+
const hasExpiredDecisions = expiredDecisions.length > 0;
|
|
4952
|
+
const pendingDecisions = this.config.supervisor.autoDecide ? await decisionStore.pending() : [];
|
|
4953
|
+
const answeredDecisions = this.config.supervisor.autoDecide ? await decisionStore.answered(state?.lastHeartbeat) : [];
|
|
4954
|
+
const unconsolidatedEntries = await readUnconsolidated(this.supervisorDir);
|
|
4955
|
+
const hasPendingConsolidation = unconsolidatedEntries.length > 0;
|
|
4862
4956
|
const skipResult = await this.handleSkipLogic({
|
|
4863
4957
|
state,
|
|
4864
4958
|
totalEventCount,
|
|
4865
|
-
activeRuns
|
|
4959
|
+
activeRuns,
|
|
4960
|
+
hasPendingConsolidation,
|
|
4961
|
+
hasExpiredDecisions
|
|
4866
4962
|
});
|
|
4867
4963
|
if (skipResult.shouldSkip) return;
|
|
4868
4964
|
if (skipResult.resetCounters) {
|
|
@@ -4877,6 +4973,8 @@ var HeartbeatLoop = class {
|
|
|
4877
4973
|
isCompaction: modeResult.isCompaction,
|
|
4878
4974
|
isConsolidation: modeResult.isConsolidation,
|
|
4879
4975
|
activeRuns,
|
|
4976
|
+
pendingDecisions,
|
|
4977
|
+
answeredDecisions,
|
|
4880
4978
|
lastHeartbeat: state?.lastHeartbeat,
|
|
4881
4979
|
lastConsolidationTimestamp: modeResult.lastConsolidationTs
|
|
4882
4980
|
});
|
|
@@ -4972,35 +5070,50 @@ var HeartbeatLoop = class {
|
|
|
4972
5070
|
}
|
|
4973
5071
|
/**
|
|
4974
5072
|
* Handle skip logic for idle and active-work scenarios.
|
|
5073
|
+
* Uses IdleDetector to make skip decisions based on context.
|
|
4975
5074
|
*/
|
|
4976
5075
|
async handleSkipLogic(opts) {
|
|
4977
|
-
const { state, totalEventCount, activeRuns } = opts;
|
|
5076
|
+
const { state, totalEventCount, activeRuns, hasPendingConsolidation, hasExpiredDecisions } = opts;
|
|
4978
5077
|
const idleSkipCount = state?.idleSkipCount ?? 0;
|
|
4979
5078
|
const activeWorkSkipCount = state?.activeWorkSkipCount ?? 0;
|
|
4980
5079
|
const hasActiveWork = activeRuns.length > 0;
|
|
4981
|
-
|
|
5080
|
+
const lastHeartbeatMs = state?.lastHeartbeat ? new Date(state.lastHeartbeat).getTime() : Date.now();
|
|
5081
|
+
const timeSinceLastHeartbeatMs = Date.now() - lastHeartbeatMs;
|
|
5082
|
+
const context = {
|
|
5083
|
+
eventCount: totalEventCount,
|
|
5084
|
+
activeRuns: activeRuns.length,
|
|
5085
|
+
hasPendingConsolidation,
|
|
5086
|
+
hasExpiredDecisions,
|
|
5087
|
+
timeSinceLastHeartbeatMs,
|
|
5088
|
+
idleSkipCount,
|
|
5089
|
+
activeWorkSkipCount
|
|
5090
|
+
};
|
|
5091
|
+
const detector = new IdleDetector({
|
|
5092
|
+
idleSkipMax: this.config.supervisor.idleSkipMax,
|
|
5093
|
+
activeWorkSkipMax: this.config.supervisor.activeWorkSkipMax
|
|
5094
|
+
});
|
|
5095
|
+
const result = detector.shouldSkip(context);
|
|
5096
|
+
if (result.shouldSkip) {
|
|
4982
5097
|
if (hasActiveWork) {
|
|
4983
|
-
|
|
4984
|
-
|
|
4985
|
-
|
|
4986
|
-
|
|
4987
|
-
|
|
4988
|
-
|
|
4989
|
-
|
|
4990
|
-
|
|
4991
|
-
);
|
|
4992
|
-
return { shouldSkip: true, resetCounters: false };
|
|
4993
|
-
}
|
|
5098
|
+
await this.updateState({
|
|
5099
|
+
activeWorkSkipCount: activeWorkSkipCount + 1,
|
|
5100
|
+
idleSkipCount: 0
|
|
5101
|
+
});
|
|
5102
|
+
await this.activityLog.log(
|
|
5103
|
+
"heartbeat",
|
|
5104
|
+
`Active-work skip #${activeWorkSkipCount + 1}/${this.config.supervisor.activeWorkSkipMax} \u2014 ${result.reason}`
|
|
5105
|
+
);
|
|
4994
5106
|
} else {
|
|
4995
|
-
|
|
4996
|
-
|
|
4997
|
-
|
|
4998
|
-
|
|
4999
|
-
|
|
5000
|
-
|
|
5001
|
-
|
|
5002
|
-
|
|
5107
|
+
await this.updateState({
|
|
5108
|
+
idleSkipCount: idleSkipCount + 1,
|
|
5109
|
+
activeWorkSkipCount: 0
|
|
5110
|
+
});
|
|
5111
|
+
await this.activityLog.log(
|
|
5112
|
+
"heartbeat",
|
|
5113
|
+
`Idle skip #${idleSkipCount + 1}/${this.config.supervisor.idleSkipMax} \u2014 ${result.reason}`
|
|
5114
|
+
);
|
|
5003
5115
|
}
|
|
5116
|
+
return { shouldSkip: true, resetCounters: false };
|
|
5004
5117
|
}
|
|
5005
5118
|
const needsReset = idleSkipCount > 0 || activeWorkSkipCount > 0;
|
|
5006
5119
|
return { shouldSkip: false, resetCounters: needsReset };
|
|
@@ -5075,7 +5188,10 @@ var HeartbeatLoop = class {
|
|
|
5075
5188
|
customInstructions: this.customInstructions,
|
|
5076
5189
|
supervisorDir: this.supervisorDir,
|
|
5077
5190
|
memories,
|
|
5078
|
-
recentActions
|
|
5191
|
+
recentActions,
|
|
5192
|
+
pendingDecisions: opts.pendingDecisions,
|
|
5193
|
+
answeredDecisions: opts.answeredDecisions,
|
|
5194
|
+
autoDecide: this.config.supervisor.autoDecide
|
|
5079
5195
|
};
|
|
5080
5196
|
if (opts.isCompaction) {
|
|
5081
5197
|
return {
|
|
@@ -5899,16 +6015,16 @@ import path17 from "path";
|
|
|
5899
6015
|
import { existsSync as existsSync10 } from "fs";
|
|
5900
6016
|
import { mkdir as mkdir8, readFile as readFile15, writeFile as writeFile9 } from "fs/promises";
|
|
5901
6017
|
import path18 from "path";
|
|
5902
|
-
import { z as
|
|
5903
|
-
var webhookEntrySchema =
|
|
5904
|
-
url:
|
|
5905
|
-
events:
|
|
5906
|
-
secret:
|
|
5907
|
-
timeoutMs:
|
|
5908
|
-
createdAt:
|
|
6018
|
+
import { z as z8 } from "zod";
|
|
6019
|
+
var webhookEntrySchema = z8.object({
|
|
6020
|
+
url: z8.string().url(),
|
|
6021
|
+
events: z8.array(z8.string()).optional(),
|
|
6022
|
+
secret: z8.string().optional(),
|
|
6023
|
+
timeoutMs: z8.number().default(5e3),
|
|
6024
|
+
createdAt: z8.string().default(() => (/* @__PURE__ */ new Date()).toISOString())
|
|
5909
6025
|
});
|
|
5910
|
-
var webhooksConfigSchema =
|
|
5911
|
-
webhooks:
|
|
6026
|
+
var webhooksConfigSchema = z8.object({
|
|
6027
|
+
webhooks: z8.array(webhookEntrySchema).default([])
|
|
5912
6028
|
});
|
|
5913
6029
|
function getWebhooksConfigPath() {
|
|
5914
6030
|
return path18.join(getDataDir(), "webhooks.json");
|