{"version":3,"file":"spawn-budget.d.ts","sourceRoot":"","sources":["../../../../src/runs/shared/spawn-budget.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,eAAe,EAEpB,KAAK,mBAAmB,EACxB,KAAK,aAAa,EAClB,MAAM,uBAAuB,CAAC;AAwB/B,wBAAgB,sBAAsB,CACrC,KAAK,EAAE,aAAa,EACpB,MAAM,EAAE,eAAe,EACvB,SAAS,GAAE,MAAM,GAAG,IAA6B,GAC/C,mBAAmB,CAcrB;AAED,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,mBAAmB,GAAG,MAAM,CAG9E;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,mBAAmB,GAAG,MAAM,CAEvE;AAED,wBAAgB,oBAAoB,CACnC,KAAK,EAAE,aAAa,EACpB,MAAM,EAAE,eAAe,EACvB,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,SAAS,EAAE,MAAM,GACf;IAAE,QAAQ,EAAE,mBAAmB,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAOnD;AAED,wBAAgB,kBAAkB,CACjC,KAAK,EAAE,aAAa,EACpB,MAAM,EAAE,eAAe,EACvB,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,SAAS,EAAE,MAAM,GACf;IAAE,QAAQ,EAAE,mBAAmB,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAKnD;AAED,wBAAgB,yBAAyB,CACxC,KAAK,EAAE,aAAa,EACpB,MAAM,EAAE,eAAe,EACvB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GAChB;IAAE,QAAQ,EAAE,mBAAmB,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAkBnD;AAED,wBAAgB,gBAAgB,CAC/B,KAAK,EAAE,aAAa,EACpB,MAAM,EAAE,eAAe,EACvB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,GAAG,SAAa,GACd;IAAE,QAAQ,EAAE,mBAAmB,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAkBnD","sourcesContent":["import {\n\ttype ExtensionConfig,\n\tresolveMaxSubagentSpawnsPerSession,\n\ttype SpawnBudgetSnapshot,\n\ttype SubagentState,\n} from \"../../shared/types.ts\";\n\nconst MAX_GRANT_HISTORY = 20;\n\nfunction sessionState(state: SubagentState, config: ExtensionConfig, sessionId: string | null) {\n\tlet counters = state.subagentSpawns;\n\tif (!counters || counters.sessionId !== sessionId) {\n\t\tcounters = {\n\t\t\tsessionId,\n\t\t\tcount: 0,\n\t\t\tconfiguredLimit: resolveMaxSubagentSpawnsPerSession(config.maxSubagentSpawnsPerSession) ?? null,\n\t\t\tgranted: 0,\n\t\t\tgrantHistory: [],\n\t\t};\n\t\tstate.subagentSpawns = counters;\n\t}\n\tif (counters.configuredLimit === undefined) {\n\t\tcounters.configuredLimit = resolveMaxSubagentSpawnsPerSession(config.maxSubagentSpawnsPerSession) ?? null;\n\t}\n\tcounters.granted ??= 0;\n\tcounters.grantHistory ??= [];\n\treturn counters;\n}\n\nexport function getSpawnBudgetSnapshot(\n\tstate: SubagentState,\n\tconfig: ExtensionConfig,\n\tsessionId: string | null = state.currentSessionId,\n): SpawnBudgetSnapshot {\n\tconst counters = sessionState(state, config, sessionId);\n\tconst configuredLimit = counters.configuredLimit ?? null;\n\tconst granted = configuredLimit === null ? 0 : (counters.granted ?? 0);\n\tconst limit = configuredLimit === null ? null : configuredLimit + granted;\n\treturn {\n\t\tused: counters.count,\n\t\tconfiguredLimit,\n\t\tgranted,\n\t\tlimit,\n\t\tremaining: limit === null ? null : Math.max(0, limit - counters.count),\n\t\tgrantRemaining: configuredLimit === null ? null : Math.max(0, configuredLimit - granted),\n\t\tgrantHistory: [...(counters.grantHistory ?? [])],\n\t};\n}\n\nexport function formatSpawnBudgetSummary(snapshot: SpawnBudgetSnapshot): string {\n\tif (snapshot.limit === null) return \"unlimited\";\n\treturn `${snapshot.used}/${snapshot.limit} used, ${snapshot.remaining} remaining (configured ${snapshot.configuredLimit}; granted ${snapshot.granted}; grant allowance ${snapshot.grantRemaining})`;\n}\n\nexport function formatSpawnBudget(snapshot: SpawnBudgetSnapshot): string {\n\treturn `Spawn budget: ${formatSpawnBudgetSummary(snapshot)}`;\n}\n\nexport function preflightSpawnBudget(\n\tstate: SubagentState,\n\tconfig: ExtensionConfig,\n\tsessionId: string | null,\n\trequested: number,\n): { snapshot: SpawnBudgetSnapshot; error?: string } {\n\tconst snapshot = getSpawnBudgetSnapshot(state, config, sessionId);\n\tif (requested <= 0 || snapshot.limit === null || requested <= (snapshot.remaining ?? 0)) return { snapshot };\n\treturn {\n\t\tsnapshot,\n\t\terror: `Subagent spawn limit reached for this session (${snapshot.used}/${snapshot.limit} used, ${requested} requested). ${snapshot.remaining} remaining; the declared run cannot fit, so no children were started. Grant budget explicitly from the root interactive session or start a new session.`,\n\t};\n}\n\nexport function reserveSpawnBudget(\n\tstate: SubagentState,\n\tconfig: ExtensionConfig,\n\tsessionId: string | null,\n\trequested: number,\n): { snapshot: SpawnBudgetSnapshot; error?: string } {\n\tconst checked = preflightSpawnBudget(state, config, sessionId, requested);\n\tif (checked.error || requested <= 0 || checked.snapshot.limit === null) return checked;\n\tstate.subagentSpawns!.count += requested;\n\treturn { snapshot: getSpawnBudgetSnapshot(state, config, sessionId) };\n}\n\nexport function preflightSpawnBudgetGrant(\n\tstate: SubagentState,\n\tconfig: ExtensionConfig,\n\tsessionId: string,\n\tadditional: number,\n): { snapshot: SpawnBudgetSnapshot; error?: string } {\n\tconst snapshot = getSpawnBudgetSnapshot(state, config, sessionId);\n\tif (!Number.isInteger(additional) || additional <= 0) {\n\t\treturn { snapshot, error: \"action='grant-spawn-budget' requires additional to be a positive integer.\" };\n\t}\n\tif (snapshot.configuredLimit === null || snapshot.limit === null) {\n\t\treturn {\n\t\t\tsnapshot,\n\t\t\terror: \"The current session has no configured spawn cap, so it does not need a budget grant.\",\n\t\t};\n\t}\n\tif (additional > (snapshot.grantRemaining ?? 0)) {\n\t\treturn {\n\t\t\tsnapshot,\n\t\t\terror: `Spawn budget grant rejected: ${additional} requested but only ${snapshot.grantRemaining} of the original configured limit remains grantable.`,\n\t\t};\n\t}\n\treturn { snapshot };\n}\n\nexport function grantSpawnBudget(\n\tstate: SubagentState,\n\tconfig: ExtensionConfig,\n\tsessionId: string,\n\tadditional: number,\n\tnow = Date.now(),\n): { snapshot: SpawnBudgetSnapshot; error?: string } {\n\tconst checked = preflightSpawnBudgetGrant(state, config, sessionId, additional);\n\tif (checked.error) return checked;\n\tconst before = checked.snapshot;\n\tif (before.limit === null) {\n\t\treturn {\n\t\t\tsnapshot: before,\n\t\t\terror: \"The current session has no configured spawn cap, so it does not need a budget grant.\",\n\t\t};\n\t}\n\tconst counters = state.subagentSpawns!;\n\tcounters.granted = (counters.granted ?? 0) + additional;\n\tconst limit = before.limit + additional;\n\tcounters.grantHistory = [\n\t\t...(counters.grantHistory ?? []),\n\t\t{ sessionId, amount: additional, grantedAt: now, previousLimit: before.limit, limit },\n\t].slice(-MAX_GRANT_HISTORY);\n\treturn { snapshot: getSpawnBudgetSnapshot(state, config, sessionId) };\n}\n"]}