@neotx/core 0.1.0-alpha.22 → 0.1.0-alpha.24
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 +53 -3
- package/dist/index.js +99 -16
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -38,6 +38,7 @@ declare const agentConfigSchema: z.ZodObject<{
|
|
|
38
38
|
name: z.ZodString;
|
|
39
39
|
extends: z.ZodOptional<z.ZodString>;
|
|
40
40
|
description: z.ZodOptional<z.ZodString>;
|
|
41
|
+
version: z.ZodOptional<z.ZodString>;
|
|
41
42
|
model: z.ZodOptional<z.ZodEnum<{
|
|
42
43
|
opus: "opus";
|
|
43
44
|
sonnet: "sonnet";
|
|
@@ -62,7 +63,29 @@ declare const agentConfigSchema: z.ZodObject<{
|
|
|
62
63
|
writable: "writable";
|
|
63
64
|
}>>;
|
|
64
65
|
maxTurns: z.ZodOptional<z.ZodNumber>;
|
|
66
|
+
maxCost: z.ZodOptional<z.ZodNumber>;
|
|
65
67
|
mcpServers: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
68
|
+
agents: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
69
|
+
description: z.ZodString;
|
|
70
|
+
prompt: z.ZodString;
|
|
71
|
+
tools: z.ZodOptional<z.ZodArray<z.ZodEnum<{
|
|
72
|
+
Read: "Read";
|
|
73
|
+
Write: "Write";
|
|
74
|
+
Edit: "Edit";
|
|
75
|
+
Bash: "Bash";
|
|
76
|
+
Glob: "Glob";
|
|
77
|
+
Grep: "Grep";
|
|
78
|
+
Agent: "Agent";
|
|
79
|
+
WebSearch: "WebSearch";
|
|
80
|
+
WebFetch: "WebFetch";
|
|
81
|
+
NotebookEdit: "NotebookEdit";
|
|
82
|
+
}>>>;
|
|
83
|
+
model: z.ZodOptional<z.ZodEnum<{
|
|
84
|
+
opus: "opus";
|
|
85
|
+
sonnet: "sonnet";
|
|
86
|
+
haiku: "haiku";
|
|
87
|
+
}>>;
|
|
88
|
+
}, z.core.$strip>>>;
|
|
66
89
|
}, z.core.$strip>;
|
|
67
90
|
type AgentConfig = z.infer<typeof agentConfigSchema>;
|
|
68
91
|
type AgentModel = z.infer<typeof agentModelSchema>;
|
|
@@ -368,18 +391,31 @@ declare function removeRepoFromGlobalConfig(pathOrName: string): Promise<boolean
|
|
|
368
391
|
*/
|
|
369
392
|
declare function listReposFromGlobalConfig(): Promise<RepoConfig[]>;
|
|
370
393
|
|
|
394
|
+
interface SubagentDefinition {
|
|
395
|
+
description: string;
|
|
396
|
+
prompt: string;
|
|
397
|
+
tools?: string[] | undefined;
|
|
398
|
+
model?: string | undefined;
|
|
399
|
+
}
|
|
371
400
|
interface AgentDefinition {
|
|
372
401
|
description: string;
|
|
373
402
|
prompt: string;
|
|
374
403
|
tools: string[];
|
|
375
404
|
model: string;
|
|
376
405
|
mcpServers?: string[] | undefined;
|
|
406
|
+
agents?: Record<string, SubagentDefinition> | undefined;
|
|
377
407
|
}
|
|
378
408
|
interface ResolvedAgent {
|
|
379
409
|
name: string;
|
|
380
410
|
definition: AgentDefinition;
|
|
381
411
|
sandbox: "writable" | "readonly";
|
|
382
412
|
maxTurns?: number | undefined;
|
|
413
|
+
/**
|
|
414
|
+
* Maximum cost in USD for this agent session.
|
|
415
|
+
* Checked post-session; if session cost >= maxCost, budget_exceeded error is thrown.
|
|
416
|
+
*/
|
|
417
|
+
maxCost?: number | undefined;
|
|
418
|
+
version?: string | undefined;
|
|
383
419
|
source: "built-in" | "custom" | "extended";
|
|
384
420
|
}
|
|
385
421
|
interface PersistedRun {
|
|
@@ -1058,7 +1094,9 @@ interface SessionOptions {
|
|
|
1058
1094
|
env?: Record<string, string>;
|
|
1059
1095
|
initTimeoutMs: number;
|
|
1060
1096
|
maxDurationMs: number;
|
|
1097
|
+
maxTurns?: number | undefined;
|
|
1061
1098
|
resumeSessionId?: string | undefined;
|
|
1099
|
+
agents?: Record<string, unknown> | undefined;
|
|
1062
1100
|
onEvent?: ((event: SessionEvent) => void) | undefined;
|
|
1063
1101
|
}
|
|
1064
1102
|
interface SessionResult {
|
|
@@ -1208,6 +1246,16 @@ type DecisionInput = Omit<Decision, "id" | "createdAt" | "answeredAt" | "answer"
|
|
|
1208
1246
|
* JSONL-backed store for decisions.
|
|
1209
1247
|
* Append-only with in-place updates for answers and expiration.
|
|
1210
1248
|
* Uses an in-memory mutex to serialize write operations.
|
|
1249
|
+
*
|
|
1250
|
+
* Compaction Strategy:
|
|
1251
|
+
* - Threshold-based compaction triggers on either:
|
|
1252
|
+
* 1. Tombstone ratio exceeds 30% of total valid entries (tombstones / (valid decisions + tombstones), excluding malformed lines)
|
|
1253
|
+
* 2. File size exceeds 10MB (prevents unbounded growth)
|
|
1254
|
+
* - Compaction rebuilds the file, filtering out tombstoned entries and preserving active decisions
|
|
1255
|
+
* - In-memory index maintains O(1) lookup without full file scans
|
|
1256
|
+
* - Compaction runs synchronously within the write lock to maintain consistency
|
|
1257
|
+
* - During compaction: all write operations are blocked until compaction completes, preventing race conditions
|
|
1258
|
+
* - Concurrent reads during compaction may return stale data from before compaction started
|
|
1211
1259
|
*/
|
|
1212
1260
|
declare class DecisionStore {
|
|
1213
1261
|
private readonly filePath;
|
|
@@ -1215,6 +1263,8 @@ declare class DecisionStore {
|
|
|
1215
1263
|
private readonly dirCache;
|
|
1216
1264
|
/** Promise-based mutex to serialize write operations */
|
|
1217
1265
|
private writeLock;
|
|
1266
|
+
/** Maximum file size in bytes before validation fails (default: 10MB) */
|
|
1267
|
+
private readonly maxFileSizeBytes;
|
|
1218
1268
|
constructor(filePath: string);
|
|
1219
1269
|
/**
|
|
1220
1270
|
* Acquire the write lock and execute a callback.
|
|
@@ -1314,9 +1364,9 @@ declare const activityEntrySchema: z.ZodObject<{
|
|
|
1314
1364
|
message: "message";
|
|
1315
1365
|
decision: "decision";
|
|
1316
1366
|
tool_use: "tool_use";
|
|
1367
|
+
action: "action";
|
|
1317
1368
|
event: "event";
|
|
1318
1369
|
heartbeat: "heartbeat";
|
|
1319
|
-
action: "action";
|
|
1320
1370
|
warning: "warning";
|
|
1321
1371
|
thinking: "thinking";
|
|
1322
1372
|
plan: "plan";
|
|
@@ -1379,8 +1429,8 @@ declare const activityQueryOptionsSchema: z.ZodObject<{
|
|
|
1379
1429
|
error: "error";
|
|
1380
1430
|
message: "message";
|
|
1381
1431
|
decision: "decision";
|
|
1382
|
-
event: "event";
|
|
1383
1432
|
action: "action";
|
|
1433
|
+
event: "event";
|
|
1384
1434
|
plan: "plan";
|
|
1385
1435
|
dispatch: "dispatch";
|
|
1386
1436
|
}>>;
|
|
@@ -1988,4 +2038,4 @@ declare function testWebhooks(): Promise<WebhookTestResult[]>;
|
|
|
1988
2038
|
|
|
1989
2039
|
declare const VERSION = "0.1.0";
|
|
1990
2040
|
|
|
1991
|
-
export { type ActiveSession, type ActivityEntry, ActivityLog, type ActivityQueryOptions, type AgentConfig, type AgentDefinition, type AgentMessageEvent, type AgentModel, AgentRegistry, type AgentTool, type AgentToolEntry, type AgentToolUseEvent, type AuditLogMiddleware, type BudgetAlertEvent, ConfigStore, type CostEntry, CostJournal, type CostUpdateEvent, type Decision, type DecisionInput, type DecisionOption, DecisionStore, type DispatchInput, type Embedder, EventJournal, EventQueue, type GateWaitingEvent, type GitStrategy, type GlobalConfig, HeartbeatLoop, type HeartbeatLoopOptions, type HookEvent, type InboxMessage, LocalEmbedder, type LoopDetectionMiddleware, type McpServerConfig, type MemoryEntry, type MemoryQuery, type MemoryStats, MemoryStore, type MemoryType, type MemoryWriteInput, type Middleware, type MiddlewareChain, type MiddlewareContext, type MiddlewareContextMap, type MiddlewareEvent, type MiddlewareHandler, type MiddlewareResult, type NeoConfig, type NeoEvent, NeoEventEmitter, Orchestrator, type OrchestratorOptions, type OrchestratorShutdownEvent, type OrchestratorStatus, type ParsedOutput, type PersistedRun, type Priority, type QueueDequeueEvent, type QueueEnqueueEvent, type QueuedEvent, type RecoveryOptions, type RepoConfig, type RepoConfigInput, type ResolvedAgent, type RunContext, type SDKHooks, type SandboxConfig, Semaphore, type SemaphoreCallbacks, type SemaphoreConfig, type SessionCloneInfo, type SessionCompleteEvent, SessionError, type SessionEvent, type SessionExecutionConfig, type SessionExecutionDeps, type SessionExecutionInput, type SessionExecutionResult, SessionExecutor, type SessionFailEvent, type SessionOptions, type SessionResult, type SessionStartEvent, StatusReader, type StepCompleteEvent, type StepResult, type StepStartEvent, SupervisorDaemon, type SupervisorDaemonOptions, type SupervisorDaemonState, type SupervisorDaemonState as SupervisorState, type SupervisorStatus, type TaskResult, VERSION, WebhookDispatcher, type WebhookEntry, type WebhookEntryInput, type WebhookIncomingEvent, WebhookServer, type WebhookTestPayload, type WebhookTestResult, activityEntrySchema, addRepoToGlobalConfig, addWebhook, agentConfigSchema, agentModelSchema, agentSandboxSchema, agentToolEntrySchema, agentToolSchema, appendLogBuffer, auditLog, budgetGuard, buildFullPrompt, buildGitStrategyInstructions, buildMiddlewareChain, buildReportingInstructions, buildSDKHooks, buildSandboxConfig, createBranch, createSessionClone, decisionOptionSchema, decisionSchema, deleteBranch, fetchRemote, getBranchName, getCurrentBranch, getDataDir, getJournalsDir, getRepoRunsDir, getRunDispatchPath, getRunLogPath, getRunsDir, getSupervisorActivityPath, getSupervisorDecisionsPath, getSupervisorDir, getSupervisorEventsPath, getSupervisorInboxPath, getSupervisorLockPath, getSupervisorStatePath, getSupervisorsDir, globalConfigSchema, inboxMessageSchema, isProcessAlive, listReposFromGlobalConfig, listSessionClones, listWebhooks, loadAgentFile, loadConfig, loadGlobalConfig, loadRepoInstructions, loopDetection, matchesFilter, mcpServerConfigSchema, neoConfigSchema, parseOutput, pushBranch, pushSessionBranch, removeRepoFromGlobalConfig, removeSessionClone, removeWebhook, repoConfigSchema, repoOverrideConfigSchema, resolveAgent, runSession, runWithRecovery, supervisorDaemonStateSchema, supervisorDaemonStateSchema as supervisorStateSchema, supervisorStatusSchema, testWebhooks, toRepoSlug, webhookEntrySchema, webhookIncomingEventSchema };
|
|
2041
|
+
export { type ActiveSession, type ActivityEntry, ActivityLog, type ActivityQueryOptions, type AgentConfig, type AgentDefinition, type AgentMessageEvent, type AgentModel, AgentRegistry, type AgentTool, type AgentToolEntry, type AgentToolUseEvent, type AuditLogMiddleware, type BudgetAlertEvent, ConfigStore, type CostEntry, CostJournal, type CostUpdateEvent, type Decision, type DecisionInput, type DecisionOption, DecisionStore, type DispatchInput, type Embedder, EventJournal, EventQueue, type GateWaitingEvent, type GitStrategy, type GlobalConfig, HeartbeatLoop, type HeartbeatLoopOptions, type HookEvent, type InboxMessage, LocalEmbedder, type LoopDetectionMiddleware, type McpServerConfig, type MemoryEntry, type MemoryQuery, type MemoryStats, MemoryStore, type MemoryType, type MemoryWriteInput, type Middleware, type MiddlewareChain, type MiddlewareContext, type MiddlewareContextMap, type MiddlewareEvent, type MiddlewareHandler, type MiddlewareResult, type NeoConfig, type NeoEvent, NeoEventEmitter, Orchestrator, type OrchestratorOptions, type OrchestratorShutdownEvent, type OrchestratorStatus, type ParsedOutput, type PersistedRun, type Priority, type QueueDequeueEvent, type QueueEnqueueEvent, type QueuedEvent, type RecoveryOptions, type RepoConfig, type RepoConfigInput, type ResolvedAgent, type RunContext, type SDKHooks, type SandboxConfig, Semaphore, type SemaphoreCallbacks, type SemaphoreConfig, type SessionCloneInfo, type SessionCompleteEvent, SessionError, type SessionEvent, type SessionExecutionConfig, type SessionExecutionDeps, type SessionExecutionInput, type SessionExecutionResult, SessionExecutor, type SessionFailEvent, type SessionOptions, type SessionResult, type SessionStartEvent, StatusReader, type StepCompleteEvent, type StepResult, type StepStartEvent, type SubagentDefinition, SupervisorDaemon, type SupervisorDaemonOptions, type SupervisorDaemonState, type SupervisorDaemonState as SupervisorState, type SupervisorStatus, type TaskResult, VERSION, WebhookDispatcher, type WebhookEntry, type WebhookEntryInput, type WebhookIncomingEvent, WebhookServer, type WebhookTestPayload, type WebhookTestResult, activityEntrySchema, addRepoToGlobalConfig, addWebhook, agentConfigSchema, agentModelSchema, agentSandboxSchema, agentToolEntrySchema, agentToolSchema, appendLogBuffer, auditLog, budgetGuard, buildFullPrompt, buildGitStrategyInstructions, buildMiddlewareChain, buildReportingInstructions, buildSDKHooks, buildSandboxConfig, createBranch, createSessionClone, decisionOptionSchema, decisionSchema, deleteBranch, fetchRemote, getBranchName, getCurrentBranch, getDataDir, getJournalsDir, getRepoRunsDir, getRunDispatchPath, getRunLogPath, getRunsDir, getSupervisorActivityPath, getSupervisorDecisionsPath, getSupervisorDir, getSupervisorEventsPath, getSupervisorInboxPath, getSupervisorLockPath, getSupervisorStatePath, getSupervisorsDir, globalConfigSchema, inboxMessageSchema, isProcessAlive, listReposFromGlobalConfig, listSessionClones, listWebhooks, loadAgentFile, loadConfig, loadGlobalConfig, loadRepoInstructions, loopDetection, matchesFilter, mcpServerConfigSchema, neoConfigSchema, parseOutput, pushBranch, pushSessionBranch, removeRepoFromGlobalConfig, removeSessionClone, removeWebhook, repoConfigSchema, repoOverrideConfigSchema, resolveAgent, runSession, runWithRecovery, supervisorDaemonStateSchema, supervisorDaemonStateSchema as supervisorStateSchema, supervisorStatusSchema, testWebhooks, toRepoSlug, webhookEntrySchema, webhookIncomingEventSchema };
|
package/dist/index.js
CHANGED
|
@@ -20,17 +20,32 @@ var agentToolSchema = z.enum([
|
|
|
20
20
|
]);
|
|
21
21
|
var agentToolEntrySchema = z.union([agentToolSchema, z.literal("$inherited")]);
|
|
22
22
|
var agentSandboxSchema = z.enum(["writable", "readonly"]);
|
|
23
|
+
var subagentDefinitionSchema = z.object({
|
|
24
|
+
description: z.string(),
|
|
25
|
+
prompt: z.string(),
|
|
26
|
+
tools: z.array(agentToolSchema).optional(),
|
|
27
|
+
model: agentModelSchema.optional()
|
|
28
|
+
});
|
|
23
29
|
var agentConfigSchema = z.object({
|
|
24
30
|
name: z.string(),
|
|
25
31
|
extends: z.string().optional(),
|
|
26
32
|
description: z.string().optional(),
|
|
33
|
+
version: z.string().optional(),
|
|
27
34
|
model: agentModelSchema.optional(),
|
|
28
35
|
tools: z.array(agentToolEntrySchema).optional(),
|
|
29
36
|
prompt: z.string().optional(),
|
|
30
37
|
promptAppend: z.string().optional(),
|
|
31
38
|
sandbox: agentSandboxSchema.optional(),
|
|
32
39
|
maxTurns: z.number().optional(),
|
|
33
|
-
|
|
40
|
+
/**
|
|
41
|
+
* Maximum cost in USD for this agent session.
|
|
42
|
+
* Checked post-session (SDK provides cost only after session ends).
|
|
43
|
+
* If session cost >= maxCost, a budget_exceeded error is thrown.
|
|
44
|
+
* Child agents can override the parent's maxCost.
|
|
45
|
+
*/
|
|
46
|
+
maxCost: z.number().min(0).optional(),
|
|
47
|
+
mcpServers: z.array(z.string()).optional(),
|
|
48
|
+
agents: z.record(z.string(), subagentDefinitionSchema).optional()
|
|
34
49
|
});
|
|
35
50
|
|
|
36
51
|
// src/agents/loader.ts
|
|
@@ -66,6 +81,20 @@ ${issues}`);
|
|
|
66
81
|
);
|
|
67
82
|
}
|
|
68
83
|
}
|
|
84
|
+
if (config.agents) {
|
|
85
|
+
for (const [name, subagent] of Object.entries(config.agents)) {
|
|
86
|
+
if (subagent.prompt.endsWith(".md")) {
|
|
87
|
+
const subagentPromptPath = path.resolve(path.dirname(filePath), subagent.prompt);
|
|
88
|
+
try {
|
|
89
|
+
subagent.prompt = await readFile(subagentPromptPath, "utf-8");
|
|
90
|
+
} catch (err) {
|
|
91
|
+
throw new Error(
|
|
92
|
+
`Subagent "${name}" prompt file not found: ${subagentPromptPath} (referenced in ${filePath}). Error: ${err instanceof Error ? err.message : String(err)}`
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
69
98
|
return config;
|
|
70
99
|
}
|
|
71
100
|
|
|
@@ -91,18 +120,25 @@ function resolveExtendedAgent(config, extendsName, builtIns) {
|
|
|
91
120
|
const tools = mergeTools(config.tools, base.tools);
|
|
92
121
|
const prompt = mergePrompt(config.prompt, config.promptAppend, base.prompt);
|
|
93
122
|
const mcpServers = mergeMcpServerNames(base.mcpServers, config.mcpServers);
|
|
123
|
+
const agents = mergeAgents(
|
|
124
|
+
base.agents,
|
|
125
|
+
config.agents
|
|
126
|
+
);
|
|
94
127
|
const definition = {
|
|
95
128
|
description: config.description ?? base.description ?? "",
|
|
96
129
|
prompt,
|
|
97
130
|
tools,
|
|
98
131
|
model: config.model ?? base.model ?? "sonnet",
|
|
99
|
-
...mcpServers.length > 0 ? { mcpServers } : {}
|
|
132
|
+
...mcpServers.length > 0 ? { mcpServers } : {},
|
|
133
|
+
...agents ? { agents } : {}
|
|
100
134
|
};
|
|
101
135
|
return {
|
|
102
136
|
name: config.name,
|
|
103
137
|
definition,
|
|
104
138
|
sandbox: config.sandbox ?? base.sandbox ?? "readonly",
|
|
105
139
|
...config.maxTurns !== void 0 ? { maxTurns: config.maxTurns } : base.maxTurns !== void 0 ? { maxTurns: base.maxTurns } : {},
|
|
140
|
+
...config.maxCost !== void 0 ? { maxCost: config.maxCost } : base.maxCost !== void 0 ? { maxCost: base.maxCost } : {},
|
|
141
|
+
...config.version !== void 0 ? { version: config.version } : base.version !== void 0 ? { version: base.version } : {},
|
|
106
142
|
source: config.name === extendsName && !config.extends ? "built-in" : "extended"
|
|
107
143
|
};
|
|
108
144
|
}
|
|
@@ -144,13 +180,16 @@ ${config.promptAppend}`;
|
|
|
144
180
|
prompt,
|
|
145
181
|
tools,
|
|
146
182
|
model: config.model,
|
|
147
|
-
...config.mcpServers?.length ? { mcpServers: config.mcpServers } : {}
|
|
183
|
+
...config.mcpServers?.length ? { mcpServers: config.mcpServers } : {},
|
|
184
|
+
...config.agents ? { agents: config.agents } : {}
|
|
148
185
|
};
|
|
149
186
|
return {
|
|
150
187
|
name: config.name,
|
|
151
188
|
definition,
|
|
152
189
|
sandbox: config.sandbox,
|
|
153
190
|
...config.maxTurns !== void 0 ? { maxTurns: config.maxTurns } : {},
|
|
191
|
+
...config.maxCost !== void 0 ? { maxCost: config.maxCost } : {},
|
|
192
|
+
...config.version !== void 0 ? { version: config.version } : {},
|
|
154
193
|
source: "custom"
|
|
155
194
|
};
|
|
156
195
|
}
|
|
@@ -175,6 +214,12 @@ function mergeMcpServerNames(base, override) {
|
|
|
175
214
|
if (!base?.length && !override?.length) return [];
|
|
176
215
|
return [.../* @__PURE__ */ new Set([...base ?? [], ...override ?? []])];
|
|
177
216
|
}
|
|
217
|
+
function mergeAgents(base, override) {
|
|
218
|
+
if (!base && !override) return void 0;
|
|
219
|
+
if (!base) return override;
|
|
220
|
+
if (!override) return base;
|
|
221
|
+
return { ...base, ...override };
|
|
222
|
+
}
|
|
178
223
|
|
|
179
224
|
// src/agents/registry.ts
|
|
180
225
|
var AgentRegistry = class {
|
|
@@ -1996,7 +2041,7 @@ function buildQueryOptions(options) {
|
|
|
1996
2041
|
// Always pass cwd: session clone for writable agents, repo root for readonly.
|
|
1997
2042
|
// Without this, readonly agents default to process.cwd() and may write to main tree.
|
|
1998
2043
|
cwd: sessionPath ?? options.repoPath,
|
|
1999
|
-
|
|
2044
|
+
...options.maxTurns ? { maxTurns: options.maxTurns } : {},
|
|
2000
2045
|
allowedTools: sandboxConfig.allowedTools,
|
|
2001
2046
|
// Workers run detached without a TTY — bypass interactive permission prompts.
|
|
2002
2047
|
// Required pair: permissionMode alone is not enough, SDK also needs the flag.
|
|
@@ -2013,6 +2058,9 @@ function buildQueryOptions(options) {
|
|
|
2013
2058
|
if (options.mcpServers && Object.keys(options.mcpServers).length > 0) {
|
|
2014
2059
|
queryOptions.mcpServers = options.mcpServers;
|
|
2015
2060
|
}
|
|
2061
|
+
if (options.agents && Object.keys(options.agents).length > 0) {
|
|
2062
|
+
queryOptions.agents = options.agents;
|
|
2063
|
+
}
|
|
2016
2064
|
if (options.env && Object.keys(options.env).length > 0) {
|
|
2017
2065
|
queryOptions.env = { ...process.env, ...options.env };
|
|
2018
2066
|
}
|
|
@@ -2241,14 +2289,23 @@ ALWAYS run commands from this directory. NEVER cd to or operate on any other rep
|
|
|
2241
2289
|
sandboxConfig,
|
|
2242
2290
|
hooks,
|
|
2243
2291
|
env: agentEnv,
|
|
2292
|
+
agents: agent.definition.agents,
|
|
2244
2293
|
initTimeoutMs: this.config.initTimeoutMs,
|
|
2245
2294
|
maxDurationMs: this.config.maxDurationMs,
|
|
2246
2295
|
maxRetries: this.config.maxRetries,
|
|
2247
2296
|
backoffBaseMs: this.config.backoffBaseMs,
|
|
2248
2297
|
...sessionPath ? { sessionPath } : {},
|
|
2249
2298
|
...mcpServers ? { mcpServers } : {},
|
|
2250
|
-
...onAttempt ? { onAttempt } : {}
|
|
2299
|
+
...onAttempt ? { onAttempt } : {},
|
|
2300
|
+
...agent.maxTurns ? { maxTurns: agent.maxTurns } : {}
|
|
2251
2301
|
});
|
|
2302
|
+
if (agent.maxCost !== void 0 && sessionResult.costUsd >= agent.maxCost) {
|
|
2303
|
+
throw new SessionError(
|
|
2304
|
+
`Agent session exceeded budget: $${sessionResult.costUsd.toFixed(4)} >= $${agent.maxCost.toFixed(4)} limit`,
|
|
2305
|
+
"budget_exceeded",
|
|
2306
|
+
sessionResult.sessionId
|
|
2307
|
+
);
|
|
2308
|
+
}
|
|
2252
2309
|
const parsed = parseOutput(sessionResult.output);
|
|
2253
2310
|
const result = {
|
|
2254
2311
|
status: "success",
|
|
@@ -3456,9 +3513,20 @@ import { z as z5 } from "zod";
|
|
|
3456
3513
|
|
|
3457
3514
|
// src/supervisor/decisions.ts
|
|
3458
3515
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
3459
|
-
import { appendFile as appendFile4, readFile as readFile6, writeFile as writeFile3 } from "fs/promises";
|
|
3516
|
+
import { appendFile as appendFile4, readFile as readFile6, stat as stat3, writeFile as writeFile3 } from "fs/promises";
|
|
3460
3517
|
import path11 from "path";
|
|
3461
3518
|
import { z as z4 } from "zod";
|
|
3519
|
+
var DecisionFileSizeError = class extends Error {
|
|
3520
|
+
constructor(filePath, fileSizeBytes, maxSizeBytes) {
|
|
3521
|
+
super(
|
|
3522
|
+
`Decision file exceeds maximum size: ${filePath} (${(fileSizeBytes / 1024 / 1024).toFixed(2)}MB > ${(maxSizeBytes / 1024 / 1024).toFixed(2)}MB)`
|
|
3523
|
+
);
|
|
3524
|
+
this.filePath = filePath;
|
|
3525
|
+
this.fileSizeBytes = fileSizeBytes;
|
|
3526
|
+
this.maxSizeBytes = maxSizeBytes;
|
|
3527
|
+
this.name = "DecisionFileSizeError";
|
|
3528
|
+
}
|
|
3529
|
+
};
|
|
3462
3530
|
var decisionOptionSchema = z4.object({
|
|
3463
3531
|
key: z4.string(),
|
|
3464
3532
|
label: z4.string(),
|
|
@@ -3479,12 +3547,20 @@ var decisionSchema = z4.object({
|
|
|
3479
3547
|
answer: z4.string().optional(),
|
|
3480
3548
|
expiredAt: z4.coerce.string().optional()
|
|
3481
3549
|
});
|
|
3550
|
+
var tombstoneSchema = z4.object({
|
|
3551
|
+
action: z4.literal("tombstone"),
|
|
3552
|
+
id: z4.string(),
|
|
3553
|
+
createdAt: z4.coerce.string(),
|
|
3554
|
+
reason: z4.enum(["deleted", "expired", "purged"])
|
|
3555
|
+
});
|
|
3482
3556
|
var DecisionStore = class {
|
|
3483
3557
|
filePath;
|
|
3484
3558
|
dir;
|
|
3485
3559
|
dirCache = /* @__PURE__ */ new Set();
|
|
3486
3560
|
/** Promise-based mutex to serialize write operations */
|
|
3487
3561
|
writeLock = Promise.resolve();
|
|
3562
|
+
/** Maximum file size in bytes before validation fails (default: 10MB) */
|
|
3563
|
+
maxFileSizeBytes = 10 * 1024 * 1024;
|
|
3488
3564
|
constructor(filePath) {
|
|
3489
3565
|
this.filePath = filePath;
|
|
3490
3566
|
this.dir = path11.dirname(filePath);
|
|
@@ -3607,6 +3683,10 @@ var DecisionStore = class {
|
|
|
3607
3683
|
async readAll() {
|
|
3608
3684
|
let content;
|
|
3609
3685
|
try {
|
|
3686
|
+
const stats = await stat3(this.filePath);
|
|
3687
|
+
if (stats.size > this.maxFileSizeBytes) {
|
|
3688
|
+
throw new DecisionFileSizeError(this.filePath, stats.size, this.maxFileSizeBytes);
|
|
3689
|
+
}
|
|
3610
3690
|
content = await readFile6(this.filePath, "utf-8");
|
|
3611
3691
|
} catch (error) {
|
|
3612
3692
|
if (error.code === "ENOENT") {
|
|
@@ -3733,7 +3813,7 @@ var activityQueryOptionsSchema = z5.object({
|
|
|
3733
3813
|
|
|
3734
3814
|
// src/supervisor/activity-log.ts
|
|
3735
3815
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
3736
|
-
import { appendFile as appendFile5, readFile as readFile7, rename, stat as
|
|
3816
|
+
import { appendFile as appendFile5, readFile as readFile7, rename, stat as stat4 } from "fs/promises";
|
|
3737
3817
|
import path12 from "path";
|
|
3738
3818
|
var ACTIVITY_FILE = "activity.jsonl";
|
|
3739
3819
|
var MAX_SIZE_BYTES = 10 * 1024 * 1024;
|
|
@@ -3795,7 +3875,7 @@ var ActivityLog = class {
|
|
|
3795
3875
|
}
|
|
3796
3876
|
async checkRotation() {
|
|
3797
3877
|
try {
|
|
3798
|
-
const stats = await
|
|
3878
|
+
const stats = await stat4(this.filePath);
|
|
3799
3879
|
if (stats.size > MAX_SIZE_BYTES) {
|
|
3800
3880
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
3801
3881
|
const rotatedPath = path12.join(this.dir, `activity-${timestamp}.jsonl`);
|
|
@@ -4113,7 +4193,7 @@ var IdleDetector = class {
|
|
|
4113
4193
|
};
|
|
4114
4194
|
|
|
4115
4195
|
// src/supervisor/log-buffer.ts
|
|
4116
|
-
import { appendFile as appendFile6, readFile as readFile9, stat as
|
|
4196
|
+
import { appendFile as appendFile6, readFile as readFile9, stat as stat5, writeFile as writeFile5 } from "fs/promises";
|
|
4117
4197
|
import path13 from "path";
|
|
4118
4198
|
var LOG_BUFFER_FILE = "log-buffer.jsonl";
|
|
4119
4199
|
var MAX_FILE_BYTES = 1024 * 1024;
|
|
@@ -4247,7 +4327,9 @@ var OPERATING_PRINCIPLES = `### Operating principles
|
|
|
4247
4327
|
- Your user-visible channel is \`neo log\` only; produce concise tool calls (not reasoning/explanations) and avoid wasted tokens.
|
|
4248
4328
|
- You may inspect repositories available via \`neo repos\`, read-only to launch agents.
|
|
4249
4329
|
- Task hygiene is non-negotiable: update task outcomes EVERY heartbeat. A task without a current outcome is a blind spot.
|
|
4250
|
-
- **No duplicate dispatches**: before dispatching a \`developer\` for any finding, ALWAYS check for open or recently merged PRs on the same topic: \`gh pr list --repo <repo> --search "<keywords>" --state open\` and \`--state merged --limit 5\`. If a similar PR exists \u2192 skip and log with \`neo log discovery\`. Dispatching duplicate agents wastes budget and pollutes the PR list
|
|
4330
|
+
- **No duplicate dispatches**: before dispatching a \`developer\` for any finding, ALWAYS check for open or recently merged PRs on the same topic: \`gh pr list --repo <repo> --search "<keywords>" --state open\` and \`--state merged --limit 5\`. If a similar PR exists \u2192 skip and log with \`neo log discovery\`. Dispatching duplicate agents wastes budget and pollutes the PR list.
|
|
4331
|
+
- **Decision routing**: when a pending decision arrives from an agent, answer within 1-2 heartbeats. Route: (1) answer directly if strategic/scope/priority, (2) dispatch scout to investigate if codebase context needed, (3) wait for human if autoDecide is off or genuinely uncertain. Agents are BLOCKED waiting \u2014 stale decisions waste session budget.
|
|
4332
|
+
- **Verify agent output**: always read agent output with \`neo runs <runId>\` before dispatching follow-up work. Route based on agent output contracts documented in SUPERVISOR.md.`;
|
|
4251
4333
|
var COMMANDS = `### Dispatching agents
|
|
4252
4334
|
\`\`\`bash
|
|
4253
4335
|
neo run <agent> --prompt "..." --repo <path> --branch <name> [--priority critical|high|medium|low] [--meta '<json>']
|
|
@@ -4272,7 +4354,7 @@ neo runs <runId> # full run details + agent output (MUST READ
|
|
|
4272
4354
|
neo cost --short [--all] # check budget
|
|
4273
4355
|
\`\`\`
|
|
4274
4356
|
|
|
4275
|
-
\`neo runs <runId>\` returns the agent's full output. **ALWAYS read it when a run completes** \u2014 it contains
|
|
4357
|
+
\`neo runs <runId>\` returns the agent's full output. **ALWAYS read it when a run completes** \u2014 it contains the agent's results that you need to decide next steps per SUPERVISOR.md routing rules.
|
|
4276
4358
|
|
|
4277
4359
|
### Memory
|
|
4278
4360
|
\`\`\`bash
|
|
@@ -4323,8 +4405,9 @@ var HEARTBEAT_RULES = `### Heartbeat lifecycle
|
|
|
4323
4405
|
1. DEDUP FIRST \u2014 check focus for PROCESSED entries. Skip any runId already processed.
|
|
4324
4406
|
2. MONITOR RUNS \u2014 \`neo runs --short\` to check active run status. If a run completed since last HB, read its output with \`neo runs <runId>\` BEFORE doing anything else.
|
|
4325
4407
|
3. PENDING TASKS? \u2014 dispatch the next eligible task from work queue. Do not re-plan.
|
|
4326
|
-
4. EVENTS? \u2014 process run completions, messages, webhooks.
|
|
4408
|
+
4. EVENTS? \u2014 process run completions, messages, webhooks. Read agent output and route per SUPERVISOR.md contracts.
|
|
4327
4409
|
5. FOLLOW-UPS? \u2014 check CI (\`gh pr checks\`), deferred dispatches.
|
|
4410
|
+
5b. DECISIONS? \u2014 check \`neo decision list\` for pending decisions from agents. Route each: answer directly, dispatch scout to investigate, or wait for human. Agents are blocked waiting \u2014 prioritize these.
|
|
4328
4411
|
6. DISPATCH \u2014 route work to agents. Mark tasks \`in_progress\`, add ACTIVE to focus.
|
|
4329
4412
|
7. UPDATE TASKS \u2014 review ALL in_progress/blocked tasks. For each: confirm status matches reality (run still active? PR merged? blocked resolved?). Update outcomes immediately \u2014 do not defer to next heartbeat.
|
|
4330
4413
|
8. SERIALIZE & YIELD \u2014 rewrite focus (see <focus>), log your decisions, and yield. Do not poll.
|
|
@@ -4333,15 +4416,15 @@ var HEARTBEAT_RULES = `### Heartbeat lifecycle
|
|
|
4333
4416
|
<run-monitoring>
|
|
4334
4417
|
Runs are your agents in the field. You MUST actively track them:
|
|
4335
4418
|
- **On dispatch**: include a label in \`--meta\` for identification: \`--meta '{"label":"T6-csv-export","ticketId":"YC-42",...}'\`
|
|
4336
|
-
- **On completion**: ALWAYS run \`neo runs <runId>\` to read the full output.
|
|
4419
|
+
- **On completion**: ALWAYS run \`neo runs <runId>\` to read the full output. This is NOT optional \u2014 you cannot decide next steps without reading the output.
|
|
4337
4420
|
- **On failure**: read the output to understand why. Decide: retry (blocked), abandon, or escalate.
|
|
4338
4421
|
- **Active runs**: check \`neo runs --short --status running\` to verify your runs are still alive. If a run disappeared, investigate.
|
|
4339
4422
|
</run-monitoring>
|
|
4340
4423
|
|
|
4341
4424
|
<multi-task-initiatives>
|
|
4342
|
-
**Branch strategy:** one branch per initiative
|
|
4425
|
+
**Branch strategy:** one branch per initiative. Architect produces a plan; developer executes all tasks on that branch. Independent initiatives CAN run in parallel on different branches.
|
|
4343
4426
|
|
|
4344
|
-
**Dispatch quality:**
|
|
4427
|
+
**Dispatch quality:** when dispatching developer with a plan, include the plan path and any context from completed prior work (PR numbers, APIs added). For direct tasks (no plan), write a detailed \`--prompt\` with acceptance criteria.
|
|
4345
4428
|
|
|
4346
4429
|
**Post-completion:** if agent opened a PR, dispatch \`reviewer\` in parallel with CI (do not wait). Update task outcome with concrete details (PR#, what was done) and update the initiative note.
|
|
4347
4430
|
|
|
@@ -4430,7 +4513,7 @@ function buildMemoryRulesExamples(supervisorDir) {
|
|
|
4430
4513
|
neo memory write --type focus --expires 2h "ACTIVE: 5900a64a developer 'T1' branch:feat/x (cat ${notesDir}/plan-YC-2670-kanban.md)"
|
|
4431
4514
|
neo memory write --type fact --scope /repo "main branch uses protected merges \u2014 agents must create PRs, never push directly"
|
|
4432
4515
|
neo memory write --type fact --scope /repo "pnpm build must pass before push \u2014 CI does not rebuild, run 2g589f34a5a failed without it"
|
|
4433
|
-
neo memory write --type procedure --scope /repo "After architect run:
|
|
4516
|
+
neo memory write --type procedure --scope /repo "After architect run: read plan path from output, dispatch developer with plan per SUPERVISOR.md routing"
|
|
4434
4517
|
neo memory write --type procedure --scope /repo "When developer run fails with ENOSPC: the repo has large fixtures \u2014 use --branch with shallow clone flag"
|
|
4435
4518
|
neo memory write --type feedback --scope /repo "User wants PR descriptions in French even though code is in English"
|
|
4436
4519
|
neo memory write --type task --scope /repo --severity high --category "neo runs 2g589f34a5a" --tags "initiative:auth-v2,depends:mem_xyz" "T1: Auth middleware"
|