@treeseed/sdk 0.8.7 → 0.8.9

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 (37) hide show
  1. package/dist/capacity.d.ts +120 -1
  2. package/dist/capacity.js +371 -2
  3. package/dist/control-plane-client.d.ts +1 -1
  4. package/dist/d1-store.d.ts +5 -5
  5. package/dist/d1-store.js +24 -24
  6. package/dist/db/d1.d.ts +102 -0
  7. package/dist/db/node-sqlite.d.ts +102 -0
  8. package/dist/db/schema.d.ts +204 -0
  9. package/dist/db/schema.js +9 -0
  10. package/dist/index.d.ts +5 -5
  11. package/dist/index.js +33 -23
  12. package/dist/market-client.d.ts +32 -0
  13. package/dist/market-client.js +48 -0
  14. package/dist/operations/services/config-runtime.js +57 -20
  15. package/dist/operations/services/d1-migration.js +10 -2
  16. package/dist/operations/services/github-automation.js +1 -1
  17. package/dist/operations/services/hosting-audit.d.ts +2 -1
  18. package/dist/operations/services/hosting-audit.js +18 -9
  19. package/dist/operations/services/hub-provider-launch.d.ts +3 -3
  20. package/dist/operations/services/hub-provider-launch.js +16 -16
  21. package/dist/operations/services/{knowledge-coop-packaging.d.ts → market-packaging.d.ts} +13 -13
  22. package/dist/operations/services/{knowledge-coop-packaging.js → market-packaging.js} +10 -10
  23. package/dist/operations/services/project-platform.d.ts +32 -0
  24. package/dist/operations/services/project-platform.js +91 -1
  25. package/dist/platform/contracts.d.ts +53 -31
  26. package/dist/platform/utils/site-config-schema.js +120 -52
  27. package/dist/{knowledge-coop.d.ts → project-workflow.d.ts} +15 -15
  28. package/dist/{knowledge-coop.js → project-workflow.js} +15 -15
  29. package/dist/reconcile/builtin-adapters.js +95 -11
  30. package/dist/scripts/tenant-d1-migrate-local.js +1 -0
  31. package/dist/sdk-types.d.ts +5 -4
  32. package/dist/sdk.d.ts +1 -1
  33. package/dist/stores/{knowledge-coop-store.d.ts → project-workflow-store.d.ts} +3 -3
  34. package/dist/stores/{knowledge-coop-store.js → project-workflow-store.js} +4 -4
  35. package/dist/workflow/operations.js +6 -6
  36. package/dist/workflow-state.js +2 -2
  37. package/package.json +1 -1
@@ -1,4 +1,4 @@
1
- import type { CapacityEstimateConfidence, CapacityGrant, CapacityPlan, CapacityProviderLane, CapacityReservation, TaskEstimateProfile } from './sdk-types.ts';
1
+ import type { CapacityEstimateConfidence, CapacityGrant, CapacityPlan, CapacityProvider, CapacityProviderLane, CapacityReservation, CreateCapacityReservationRequest, CreateCapacityRoutingDecisionRequest, RecordCapacityUsageRequest, TaskEstimateProfile } from './sdk-types.ts';
2
2
  import type { AgentProviderProfile } from './types/agents.ts';
3
3
  export type ProcessingEnvironment = 'local' | 'staging' | 'prod';
4
4
  export interface CapacityProviderRegistration {
@@ -62,6 +62,111 @@ export interface CapacityLaneScore {
62
62
  costPenalty: number;
63
63
  reasons: string[];
64
64
  }
65
+ export interface CapacityTaskEstimate {
66
+ taskSignature: string;
67
+ confidence: CapacityEstimateConfidence;
68
+ estimatedCreditsP50: number;
69
+ estimatedCreditsP90: number;
70
+ reservedCredits: number;
71
+ }
72
+ export interface TeamCapacitySummary {
73
+ teamId: string;
74
+ monthlyCredits: number | null;
75
+ monthlyUsedCredits: number;
76
+ monthlyRemainingCredits: number | null;
77
+ dailyCredits: number | null;
78
+ dailyUsedCredits: number;
79
+ dailyReservedCredits: number;
80
+ dailyRemainingCredits: number | null;
81
+ providerCount: number;
82
+ activeProviderCount: number;
83
+ degradedProviderCount: number;
84
+ grantCount: number;
85
+ blockedTaskCount: number;
86
+ approvalRequiredCount: number;
87
+ }
88
+ export interface ProjectCapacitySummary extends TeamCapacitySummary {
89
+ projectId: string;
90
+ environment: ProcessingEnvironment;
91
+ readiness: 'ready' | 'waiting_for_budget' | 'waiting_for_provider' | 'paused_by_policy' | 'needs_approval';
92
+ reasons: string[];
93
+ }
94
+ export interface RouteAndReserveInput {
95
+ plan: CapacityPlan;
96
+ estimate: CapacityTaskEstimate;
97
+ taskId?: string | null;
98
+ workDayId?: string | null;
99
+ taskKind?: string | null;
100
+ requiredCapabilities?: string[];
101
+ modelClass?: string | null;
102
+ priorityClass?: string | null;
103
+ allowDegradedProviders?: boolean;
104
+ repositoryMutation?: boolean;
105
+ production?: boolean;
106
+ selectedModel?: string | null;
107
+ source?: string;
108
+ metadata?: Record<string, unknown>;
109
+ }
110
+ export type RouteAndReserveBlockCode = 'no_capacity_provider' | 'no_capacity_grant' | 'no_eligible_lane' | 'insufficient_budget' | 'approval_required';
111
+ export interface RouteAndReserveCandidate {
112
+ providerId: string;
113
+ laneId: string;
114
+ grantId: string;
115
+ remainingCredits: number | null;
116
+ score: CapacityLaneScore;
117
+ eligible: boolean;
118
+ reasons: string[];
119
+ }
120
+ export type RouteAndReserveResult = {
121
+ ok: true;
122
+ provider: CapacityProvider;
123
+ lane: CapacityProviderLane;
124
+ grant: CapacityGrant;
125
+ estimate: CapacityTaskEstimate;
126
+ remainingCreditsBefore: number | null;
127
+ reservation: CreateCapacityReservationRequest;
128
+ routingDecision: CreateCapacityRoutingDecisionRequest;
129
+ ledgerEntry: RecordCapacityUsageRequest;
130
+ capacityMetadata: {
131
+ providerId: string;
132
+ laneId: string;
133
+ grantId: string;
134
+ reservationId: string | null;
135
+ routingDecisionId: string | null;
136
+ estimatedCreditsP50: number;
137
+ estimatedCreditsP90: number;
138
+ reservedCredits: number;
139
+ };
140
+ candidates: RouteAndReserveCandidate[];
141
+ } | {
142
+ ok: false;
143
+ code: RouteAndReserveBlockCode;
144
+ reason: string;
145
+ estimate: CapacityTaskEstimate;
146
+ candidates: RouteAndReserveCandidate[];
147
+ };
148
+ export interface CapacitySettlementInput {
149
+ reservation: CapacityReservation;
150
+ actualCredits: number;
151
+ actualProviderUnits?: number | null;
152
+ actualUsd?: number | null;
153
+ teamId?: string | null;
154
+ projectId?: string | null;
155
+ workDayId?: string | null;
156
+ taskId?: string | null;
157
+ source?: string;
158
+ metadata?: Record<string, unknown>;
159
+ }
160
+ export interface CapacitySettlement {
161
+ reservationId: string;
162
+ state: 'consumed' | 'overran_pending_approval';
163
+ consumeEntry: RecordCapacityUsageRequest;
164
+ releaseEntry: RecordCapacityUsageRequest | null;
165
+ overrunEntry: RecordCapacityUsageRequest | null;
166
+ consumedCredits: number;
167
+ releasedCredits: number;
168
+ overrunCredits: number;
169
+ }
65
170
  export declare function reserveCreditsForEstimate(input: CapacityEstimateInput): {
66
171
  taskSignature: string;
67
172
  confidence: CapacityEstimateConfidence;
@@ -78,9 +183,23 @@ export declare function summarizeCapacityPlan(plan: CapacityPlan): {
78
183
  laneCount: number;
79
184
  grantCount: number;
80
185
  };
186
+ export declare function summarizeTeamCapacityPlan(plan: CapacityPlan): TeamCapacitySummary;
187
+ export declare function summarizeProjectCapacityPlan(plan: CapacityPlan, options?: {
188
+ workPolicyEnabled?: boolean | null;
189
+ approvalRequiredCount?: number;
190
+ blockedTaskCount?: number;
191
+ }): ProjectCapacitySummary;
81
192
  export declare function scoreCapacityLane(input: CapacityLaneCandidate): CapacityLaneScore;
82
193
  export declare function selectBestCapacityLane(candidates: CapacityLaneCandidate[]): {
83
194
  selected: CapacityLaneScore;
84
195
  scores: CapacityLaneScore[];
85
196
  };
86
197
  export declare function reservationHasCapacity(reservation: CapacityReservation): boolean;
198
+ export declare function createReservationReleaseEntry(input: {
199
+ reservation: CapacityReservation;
200
+ credits?: number | null;
201
+ source?: string;
202
+ metadata?: Record<string, unknown>;
203
+ }): RecordCapacityUsageRequest;
204
+ export declare function settleCapacityActuals(input: CapacitySettlementInput): CapacitySettlement;
205
+ export declare function routeAndReserveCapacity(input: RouteAndReserveInput): RouteAndReserveResult;
package/dist/capacity.js CHANGED
@@ -6,6 +6,97 @@ function scarcityPenalty(level) {
6
6
  if (level === "medium") return 15;
7
7
  return 0;
8
8
  }
9
+ function metadataStatus(value) {
10
+ const status = value?.status;
11
+ return typeof status === "string" ? status : null;
12
+ }
13
+ function stringArray(value) {
14
+ return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
15
+ }
16
+ function booleanValue(value) {
17
+ return typeof value === "boolean" ? value : null;
18
+ }
19
+ function numberValue(value) {
20
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
21
+ }
22
+ function reservationDebit(reservation) {
23
+ if (reservation.state === "released" || reservation.state === "expired" || reservation.state === "cancelled") {
24
+ return 0;
25
+ }
26
+ if (reservation.state === "consumed" || reservation.state === "failed") {
27
+ return Math.max(0, reservation.consumedCredits);
28
+ }
29
+ return Math.max(reservation.reservedCredits, reservation.consumedCredits, 0);
30
+ }
31
+ function activeReservationDebit(reservation) {
32
+ if (reservation.state === "reserved" || reservation.state === "consuming") {
33
+ return Math.max(reservation.reservedCredits, reservation.consumedCredits, 0);
34
+ }
35
+ if (reservation.state === "consumed" || reservation.state === "failed") {
36
+ return Math.max(reservation.consumedCredits, 0);
37
+ }
38
+ return 0;
39
+ }
40
+ function grantMatchesReservation(grant, reservation) {
41
+ if (grant.teamId !== reservation.teamId) return false;
42
+ if (grant.capacityProviderId !== reservation.capacityProviderId) return false;
43
+ if (grant.laneId && grant.laneId !== reservation.laneId) return false;
44
+ if (grant.projectId && grant.projectId !== reservation.projectId) return false;
45
+ return true;
46
+ }
47
+ function grantRemainingCredits(plan, grant) {
48
+ const limit = grant.dailyCreditLimit ?? grant.monthlyCreditLimit;
49
+ if (limit === null || limit === void 0) return null;
50
+ const debits = plan.activeReservations.filter((reservation) => grantMatchesReservation(grant, reservation)).reduce((total, reservation) => total + reservationDebit(reservation), 0);
51
+ return Math.max(0, Number(limit) - debits);
52
+ }
53
+ function providerIsEligible(provider, input) {
54
+ if (provider.status === "active") return true;
55
+ if (provider.status === "degraded" && input.allowDegradedProviders) return true;
56
+ return false;
57
+ }
58
+ function grantIsEligible(grant, input) {
59
+ if (grant.state !== "active") return false;
60
+ if (grant.teamId !== input.plan.teamId) return false;
61
+ if (grant.environment && grant.environment !== input.plan.environment) return false;
62
+ if (grant.projectId && grant.projectId !== input.plan.projectId) return false;
63
+ return true;
64
+ }
65
+ function lanePolicyReasons(lane, input) {
66
+ const reasons = [];
67
+ const laneStatus = metadataStatus(lane.metadata);
68
+ if (laneStatus && laneStatus !== "active") reasons.push(`lane_status:${laneStatus}`);
69
+ const policy = lane.routingPolicy ?? {};
70
+ const taskKinds = stringArray(policy.taskKinds);
71
+ const taskKind = input.taskKind ?? input.estimate.taskSignature;
72
+ if (taskKinds.length > 0 && !taskKinds.includes(taskKind)) reasons.push("task_kind_mismatch");
73
+ const requiredCapabilities = stringArray(policy.requiredCapabilities);
74
+ const missingCapabilities = (input.requiredCapabilities ?? []).filter((capability) => !requiredCapabilities.includes(capability));
75
+ if (requiredCapabilities.length > 0 && missingCapabilities.length > 0) {
76
+ reasons.push("capability_mismatch");
77
+ }
78
+ const allowedEnvironments = stringArray(policy.allowedEnvironments);
79
+ if (allowedEnvironments.length > 0 && !allowedEnvironments.includes(input.plan.environment)) {
80
+ reasons.push("environment_mismatch");
81
+ }
82
+ const maxCreditsPerTask = numberValue(policy.maxCreditsPerTask);
83
+ if (maxCreditsPerTask !== null && input.estimate.reservedCredits > maxCreditsPerTask) {
84
+ reasons.push("task_credit_limit_exceeded");
85
+ }
86
+ const approvalThreshold = numberValue(policy.requiresApprovalAboveCredits);
87
+ if (approvalThreshold !== null && input.estimate.reservedCredits > approvalThreshold) {
88
+ reasons.push("approval_required");
89
+ }
90
+ const repositoryMutationAllowed = booleanValue(policy.repositoryMutationAllowed);
91
+ if (input.repositoryMutation && repositoryMutationAllowed === false) {
92
+ reasons.push("repository_mutation_not_allowed");
93
+ }
94
+ const productionAllowed = booleanValue(policy.productionAllowed);
95
+ if (input.production && productionAllowed === false) {
96
+ reasons.push("production_not_allowed");
97
+ }
98
+ return reasons;
99
+ }
9
100
  function reserveCreditsForEstimate(input) {
10
101
  const profileP50 = finiteNumber(input.profile?.creditsP50);
11
102
  const profileP90 = finiteNumber(input.profile?.creditsP90);
@@ -26,7 +117,7 @@ function reserveCreditsForEstimate(input) {
26
117
  };
27
118
  }
28
119
  function summarizeCapacityPlan(plan) {
29
- const reservedCredits = plan.activeReservations.filter((reservation) => reservation.state === "reserved").reduce((total, reservation) => total + reservation.reservedCredits, 0);
120
+ const reservedCredits = plan.activeReservations.filter((reservation) => reservation.state === "reserved" || reservation.state === "consuming").reduce((total, reservation) => total + reservation.reservedCredits, 0);
30
121
  const consumedCredits = plan.activeReservations.reduce((total, reservation) => total + reservation.consumedCredits, 0);
31
122
  const grantedDailyCredits = plan.grants.filter((grant) => grant.state === "active").reduce((total, grant) => total + (grant.dailyCreditLimit ?? 0), 0);
32
123
  return {
@@ -39,6 +130,55 @@ function summarizeCapacityPlan(plan) {
39
130
  grantCount: plan.grants.length
40
131
  };
41
132
  }
133
+ function summarizeTeamCapacityPlan(plan) {
134
+ const dailyCredits = plan.grants.filter((grant) => grant.state === "active").reduce((total, grant) => total + (grant.dailyCreditLimit ?? 0), 0);
135
+ const monthlyCredits = plan.grants.filter((grant) => grant.state === "active").reduce((total, grant) => total + (grant.monthlyCreditLimit ?? 0), 0);
136
+ const dailyReservedCredits = plan.activeReservations.reduce((total, reservation) => total + activeReservationDebit(reservation), 0);
137
+ const dailyUsedCredits = plan.activeReservations.reduce((total, reservation) => total + Math.max(0, reservation.consumedCredits), 0);
138
+ return {
139
+ teamId: plan.teamId,
140
+ monthlyCredits: monthlyCredits > 0 ? monthlyCredits : null,
141
+ monthlyUsedCredits: dailyUsedCredits,
142
+ monthlyRemainingCredits: monthlyCredits > 0 ? Math.max(0, monthlyCredits - dailyUsedCredits) : null,
143
+ dailyCredits: dailyCredits > 0 ? dailyCredits : null,
144
+ dailyUsedCredits,
145
+ dailyReservedCredits,
146
+ dailyRemainingCredits: dailyCredits > 0 ? Math.max(0, dailyCredits - dailyReservedCredits - dailyUsedCredits) : null,
147
+ providerCount: plan.providers.length,
148
+ activeProviderCount: plan.providers.filter((provider) => provider.status === "active").length,
149
+ degradedProviderCount: plan.providers.filter((provider) => provider.status === "degraded").length,
150
+ grantCount: plan.grants.length,
151
+ blockedTaskCount: 0,
152
+ approvalRequiredCount: 0
153
+ };
154
+ }
155
+ function summarizeProjectCapacityPlan(plan, options = {}) {
156
+ const summary = summarizeTeamCapacityPlan(plan);
157
+ const reasons = [];
158
+ let readiness = "ready";
159
+ if (options.workPolicyEnabled === false) {
160
+ readiness = "paused_by_policy";
161
+ reasons.push("work_policy_disabled");
162
+ } else if (summary.activeProviderCount <= 0) {
163
+ readiness = "waiting_for_provider";
164
+ reasons.push("no_active_provider");
165
+ } else if (summary.dailyRemainingCredits !== null && summary.dailyRemainingCredits <= 0) {
166
+ readiness = "waiting_for_budget";
167
+ reasons.push("daily_budget_exhausted");
168
+ } else if ((options.approvalRequiredCount ?? 0) > 0) {
169
+ readiness = "needs_approval";
170
+ reasons.push("approval_required");
171
+ }
172
+ return {
173
+ ...summary,
174
+ projectId: plan.projectId,
175
+ environment: plan.environment,
176
+ readiness,
177
+ reasons,
178
+ blockedTaskCount: options.blockedTaskCount ?? summary.blockedTaskCount,
179
+ approvalRequiredCount: options.approvalRequiredCount ?? summary.approvalRequiredCount
180
+ };
181
+ }
42
182
  function scoreCapacityLane(input) {
43
183
  const reasons = [];
44
184
  let agentFit = 0;
@@ -91,10 +231,239 @@ function selectBestCapacityLane(candidates) {
91
231
  function reservationHasCapacity(reservation) {
92
232
  return reservation.state === "reserved" && reservation.reservedCredits > reservation.consumedCredits;
93
233
  }
234
+ function createReservationReleaseEntry(input) {
235
+ const credits = Math.max(0, Number(input.credits ?? input.reservation.reservedCredits - input.reservation.consumedCredits));
236
+ return {
237
+ capacityProviderId: input.reservation.capacityProviderId,
238
+ laneId: input.reservation.laneId,
239
+ reservationId: input.reservation.id,
240
+ teamId: input.reservation.teamId,
241
+ projectId: input.reservation.projectId,
242
+ workDayId: input.reservation.workDayId,
243
+ taskId: input.reservation.taskId,
244
+ phase: "reservation_released",
245
+ credits: -credits,
246
+ source: input.source ?? "capacity_coordinator",
247
+ metadata: input.metadata ?? {}
248
+ };
249
+ }
250
+ function settleCapacityActuals(input) {
251
+ const consumedCredits = Math.max(0, Number(input.actualCredits ?? 0));
252
+ const releasedCredits = Math.max(0, input.reservation.reservedCredits - consumedCredits);
253
+ const overrunCredits = Math.max(0, consumedCredits - input.reservation.reservedCredits);
254
+ const base = {
255
+ capacityProviderId: input.reservation.capacityProviderId,
256
+ laneId: input.reservation.laneId,
257
+ reservationId: input.reservation.id,
258
+ teamId: input.teamId ?? input.reservation.teamId,
259
+ projectId: input.projectId ?? input.reservation.projectId,
260
+ workDayId: input.workDayId ?? input.reservation.workDayId,
261
+ taskId: input.taskId ?? input.reservation.taskId,
262
+ source: input.source ?? "capacity_coordinator",
263
+ metadata: input.metadata ?? {}
264
+ };
265
+ const consumeEntry = {
266
+ ...base,
267
+ phase: "task_completed_actual_settlement",
268
+ credits: consumedCredits,
269
+ providerUnits: input.actualProviderUnits ?? null,
270
+ usd: input.actualUsd ?? null
271
+ };
272
+ const releaseEntry = releasedCredits > 0 ? {
273
+ ...base,
274
+ phase: "reservation_released",
275
+ credits: -releasedCredits
276
+ } : null;
277
+ const overrunEntry = overrunCredits > 0 ? {
278
+ ...base,
279
+ phase: "overrun_hold",
280
+ credits: overrunCredits
281
+ } : null;
282
+ return {
283
+ reservationId: input.reservation.id,
284
+ state: overrunCredits > 0 ? "overran_pending_approval" : "consumed",
285
+ consumeEntry,
286
+ releaseEntry,
287
+ overrunEntry,
288
+ consumedCredits,
289
+ releasedCredits,
290
+ overrunCredits
291
+ };
292
+ }
293
+ function routeAndReserveCapacity(input) {
294
+ const providers = input.plan.providers.filter((provider2) => providerIsEligible(provider2, input));
295
+ const grants = input.plan.grants.filter((grant2) => grantIsEligible(grant2, input));
296
+ const candidates = [];
297
+ for (const grant2 of grants) {
298
+ const provider2 = providers.find((candidate) => candidate.id === grant2.capacityProviderId);
299
+ if (!provider2) continue;
300
+ const lanes = input.plan.lanes.filter(
301
+ (lane2) => lane2.capacityProviderId === provider2.id && (!grant2.laneId || grant2.laneId === lane2.id)
302
+ );
303
+ for (const lane2 of lanes) {
304
+ const reasons = lanePolicyReasons(lane2, input);
305
+ const remainingCredits = grantRemainingCredits(input.plan, grant2);
306
+ if (remainingCredits !== null && remainingCredits < input.estimate.reservedCredits && (grant2.overflowPolicy === "deny" || grant2.overflowPolicy === "hard_grant")) {
307
+ reasons.push("insufficient_budget");
308
+ }
309
+ if (remainingCredits !== null && remainingCredits < input.estimate.reservedCredits && grant2.overflowPolicy === "approval_required") {
310
+ reasons.push("approval_required");
311
+ }
312
+ const score = scoreCapacityLane({
313
+ lane: lane2,
314
+ grant: grant2,
315
+ remainingCredits,
316
+ taskKind: input.taskKind ?? input.estimate.taskSignature,
317
+ requiredCapabilities: input.requiredCapabilities,
318
+ modelClass: input.modelClass ?? null
319
+ });
320
+ candidates.push({
321
+ providerId: provider2.id,
322
+ laneId: lane2.id,
323
+ grantId: grant2.id,
324
+ remainingCredits,
325
+ score,
326
+ eligible: reasons.length === 0,
327
+ reasons
328
+ });
329
+ }
330
+ }
331
+ if (input.plan.providers.length === 0 || providers.length === 0) {
332
+ return {
333
+ ok: false,
334
+ code: "no_capacity_provider",
335
+ reason: "No active helper capacity provider is available.",
336
+ estimate: input.estimate,
337
+ candidates
338
+ };
339
+ }
340
+ if (grants.length === 0) {
341
+ return {
342
+ ok: false,
343
+ code: "no_capacity_grant",
344
+ reason: "No active capacity grant is available for this team, project, and environment.",
345
+ estimate: input.estimate,
346
+ candidates
347
+ };
348
+ }
349
+ const eligible = candidates.filter((candidate) => candidate.eligible).sort((left, right) => right.score.score - left.score.score || left.laneId.localeCompare(right.laneId));
350
+ const selected = eligible[0] ?? null;
351
+ if (!selected) {
352
+ const hasApprovalBlock = candidates.some((candidate) => candidate.reasons.includes("approval_required"));
353
+ const hasBudgetBlock = candidates.some((candidate) => candidate.reasons.includes("insufficient_budget"));
354
+ return {
355
+ ok: false,
356
+ code: hasApprovalBlock ? "approval_required" : hasBudgetBlock ? "insufficient_budget" : "no_eligible_lane",
357
+ reason: hasApprovalBlock ? "The requested helper task needs approval before capacity can be reserved." : hasBudgetBlock ? "The requested helper task is above the remaining approved budget." : "No provider lane matches the task policy and capability requirements.",
358
+ estimate: input.estimate,
359
+ candidates
360
+ };
361
+ }
362
+ const provider = providers.find((candidate) => candidate.id === selected.providerId);
363
+ const lane = input.plan.lanes.find((candidate) => candidate.id === selected.laneId);
364
+ const grant = grants.find((candidate) => candidate.id === selected.grantId);
365
+ if (!provider || !lane || !grant) {
366
+ return {
367
+ ok: false,
368
+ code: "no_eligible_lane",
369
+ reason: "The selected capacity lane could not be resolved.",
370
+ estimate: input.estimate,
371
+ candidates
372
+ };
373
+ }
374
+ const candidatePayload = candidates.map((candidate) => ({
375
+ providerId: candidate.providerId,
376
+ laneId: candidate.laneId,
377
+ grantId: candidate.grantId,
378
+ remainingCredits: candidate.remainingCredits,
379
+ eligible: candidate.eligible,
380
+ reasons: candidate.reasons,
381
+ score: candidate.score.score
382
+ }));
383
+ const scorePayload = Object.fromEntries(candidates.map((candidate) => [candidate.laneId, candidate.score]));
384
+ const reservation = {
385
+ capacityProviderId: provider.id,
386
+ laneId: lane.id,
387
+ teamId: input.plan.teamId,
388
+ projectId: input.plan.projectId,
389
+ workDayId: input.workDayId ?? null,
390
+ taskId: input.taskId ?? null,
391
+ state: "reserved",
392
+ reservedCredits: input.estimate.reservedCredits,
393
+ metadata: {
394
+ ...input.metadata ?? {},
395
+ grantId: grant.id,
396
+ taskSignature: input.estimate.taskSignature,
397
+ estimatedCreditsP50: input.estimate.estimatedCreditsP50,
398
+ estimatedCreditsP90: input.estimate.estimatedCreditsP90
399
+ }
400
+ };
401
+ const routingDecision = {
402
+ taskId: input.taskId ?? null,
403
+ workDayId: input.workDayId ?? null,
404
+ projectId: input.plan.projectId,
405
+ selectedProviderId: provider.id,
406
+ selectedLaneId: lane.id,
407
+ selectedModel: input.selectedModel ?? null,
408
+ decision: "selected",
409
+ reason: selected.score.reasons.length > 0 ? selected.score.reasons.join(",") : "best_eligible_lane",
410
+ candidates: candidatePayload,
411
+ scores: scorePayload,
412
+ metadata: {
413
+ ...input.metadata ?? {},
414
+ grantId: grant.id,
415
+ remainingCreditsBefore: selected.remainingCredits,
416
+ reservedCredits: input.estimate.reservedCredits
417
+ }
418
+ };
419
+ const ledgerEntry = {
420
+ capacityProviderId: provider.id,
421
+ laneId: lane.id,
422
+ teamId: input.plan.teamId,
423
+ projectId: input.plan.projectId,
424
+ workDayId: input.workDayId ?? null,
425
+ taskId: input.taskId ?? null,
426
+ phase: "reservation_created",
427
+ credits: input.estimate.reservedCredits,
428
+ source: input.source ?? "capacity_coordinator",
429
+ metadata: {
430
+ ...input.metadata ?? {},
431
+ grantId: grant.id,
432
+ taskSignature: input.estimate.taskSignature
433
+ }
434
+ };
435
+ return {
436
+ ok: true,
437
+ provider,
438
+ lane,
439
+ grant,
440
+ estimate: input.estimate,
441
+ remainingCreditsBefore: selected.remainingCredits,
442
+ reservation,
443
+ routingDecision,
444
+ ledgerEntry,
445
+ capacityMetadata: {
446
+ providerId: provider.id,
447
+ laneId: lane.id,
448
+ grantId: grant.id,
449
+ reservationId: reservation.id ?? null,
450
+ routingDecisionId: routingDecision.id ?? null,
451
+ estimatedCreditsP50: input.estimate.estimatedCreditsP50,
452
+ estimatedCreditsP90: input.estimate.estimatedCreditsP90,
453
+ reservedCredits: input.estimate.reservedCredits
454
+ },
455
+ candidates
456
+ };
457
+ }
94
458
  export {
459
+ createReservationReleaseEntry,
95
460
  reservationHasCapacity,
96
461
  reserveCreditsForEstimate,
462
+ routeAndReserveCapacity,
97
463
  scoreCapacityLane,
98
464
  selectBestCapacityLane,
99
- summarizeCapacityPlan
465
+ settleCapacityActuals,
466
+ summarizeCapacityPlan,
467
+ summarizeProjectCapacityPlan,
468
+ summarizeTeamCapacityPlan
100
469
  };
@@ -1,5 +1,5 @@
1
1
  import type { AgentPool, AgentPoolRegistration, AgentPoolScaleDecision, ApprovalRequest, CapacityGrant, CapacityPlan, CapacityProvider, CapacityProviderLane, CapacityReservation, CapacityRoutingDecision, CatalogArtifactVersion, CatalogItem, CatalogItemFilters, CreateApprovalRequestRequest, CreateCapacityReservationRequest, CreateCapacityRoutingDecisionRequest, CreateProjectDeploymentRequest, CreateTaskEstimateRequest, CreateTaskUsageActualRequest, PriorityOverride, PrioritySnapshot, ProjectConnection, ProjectDeployment, ProjectEnvironment, ProjectEnvironmentName, ProjectHosting, ProjectInfrastructureResource, ProjectWorkdaySummary, RecordAgentPoolRegistrationRequest, RecordCapacityUsageRequest, RepositoryClaim, RunnerScaleDecision, ScaleDecision, SdkCreateWorkdayRequest, SdkRecordRepositoryClaimRequest, SdkRecordRunnerScaleDecisionRequest, SdkRecordWorkerRunnerRequest, TeamStorageLocator, TeamWebHost, TaskEstimate, UpsertAgentPoolRequest, UpsertCapacityGrantRequest, UpsertCapacityProviderLaneRequest, UpsertCapacityProviderRequest, UpsertCatalogArtifactVersionRequest, UpsertCatalogItemRequest, UpsertProjectEnvironmentRequest, UpsertProjectHostingRequest, UpsertProjectInfrastructureResourceRequest, UpsertTeamStorageLocatorRequest, UpsertTeamWebHostRequest, WorkdayPolicy, WorkdayRequest, WorkerRunner, SdkPriorityOverrideRequest, SdkUpsertWorkPolicyRequest } from './sdk-types.ts';
2
- import type { AgentMessageRecord, AgentStatusRecord, DirectBoardItemSummary, InboxItem, LaunchProjectRequest, LaunchProjectResult, ProjectOverviewSummary, ReleaseDetail, ReleaseSummary, SharePackageStatus, TeamHomeSummary, TeamMemberSummary, WorkstreamDetail, WorkstreamSummary } from './knowledge-coop.ts';
2
+ import type { AgentMessageRecord, AgentStatusRecord, DirectBoardItemSummary, InboxItem, LaunchProjectRequest, LaunchProjectResult, ProjectOverviewSummary, ReleaseDetail, ReleaseSummary, SharePackageStatus, TeamHomeSummary, TeamMemberSummary, WorkstreamDetail, WorkstreamSummary } from './project-workflow.ts';
3
3
  export interface ControlPlaneClientOptions {
4
4
  baseUrl: string;
5
5
  accessToken?: string | null;
@@ -1,6 +1,6 @@
1
1
  import type { ContentLeaseRecord } from './types/agents.ts';
2
2
  import type { D1DatabaseLike } from './types/cloudflare.ts';
3
- import type { ReleaseDetail, ReleaseSummary, SharePackageStatus, WorkstreamDetail, WorkstreamEvent, WorkstreamSummary } from './knowledge-coop.ts';
3
+ import type { ReleaseDetail, ReleaseSummary, SharePackageStatus, WorkstreamDetail, WorkstreamEvent, WorkstreamSummary } from './project-workflow.ts';
4
4
  import type { SdkAppendTaskEventRequest, SdkAckMessageRequest, SdkClaimMessageRequest, SdkClaimTaskRequest, SdkCloseWorkDayRequest, SdkCompleteTaskRequest, SdkCreateReportRequest, SdkCreateMessageRequest, SdkCreatePrioritySnapshotRequest, SdkCreateTaskRequest, SdkCursorEntity, SdkCursorRequest, SdkFailTaskRequest, SdkFollowRequest, SdkGetRequest, SdkGetCursorRequest, SdkLeaseEntity, SdkLeaseReleaseRequest, SdkManagerContextPayload, SdkMessageEntity, SdkMutationRequest, SdkPickRequest, SdkPickResult, SdkPriorityOverrideRequest, SdkClaimWorkdayManagerLeaseRequest, SdkCreateWorkdayRequest, SdkRecordRepositoryClaimRequest, SdkRecordRunnerScaleDecisionRequest, SdkRecordWorkerRunnerRequest, SdkRecordRunRequest, SdkRecordScaleDecisionRequest, SdkRecordTaskCreditsRequest, SdkReleaseWorkdayManagerLeaseRequest, SdkReportEntity, SdkRunEntity, SdkSearchRequest, SdkStartWorkDayRequest, SdkSubscriptionEntity, SdkTaskEntity, SdkTaskSearchRequest, SdkUpsertWorkPolicyRequest, SdkTaskProgressRequest, SdkUpdateWorkDayGraphRequest, SdkUpdateRequest, SdkWorkDayEntity, RepositoryClaim, RunnerScaleDecision, ScaleDecision, TaskCreditLedgerEntry, WorkdayManagerLease, WorkdayPolicy, WorkdayRequest, WorkerRunner, PrioritySnapshot } from './sdk-types.ts';
5
5
  import { type LeaseClaimInput } from './stores/lease-store.ts';
6
6
  export interface TryClaimContentLeaseInput extends LeaseClaimInput {
@@ -91,7 +91,7 @@ export declare class MemoryAgentDatabase implements AgentDatabase {
91
91
  private readonly prioritySnapshots;
92
92
  private readonly taskCreditLedger;
93
93
  private readonly scaleDecisions;
94
- private readonly knowledgeCoop;
94
+ private readonly projectWorkflow;
95
95
  private messageId;
96
96
  constructor(seed?: {
97
97
  subscriptions?: SdkSubscriptionEntity[];
@@ -235,7 +235,7 @@ export declare class CloudflareD1AgentDatabase implements AgentDatabase {
235
235
  private readonly cursors;
236
236
  private readonly leases;
237
237
  private readonly operational;
238
- private readonly knowledgeCoop;
238
+ private readonly projectWorkflow;
239
239
  constructor(db: D1DatabaseLike);
240
240
  get(request: SdkGetRequest): Promise<Record<string, unknown> | null>;
241
241
  search(request: SdkSearchRequest): Promise<Record<string, unknown>[]>;
@@ -318,11 +318,11 @@ export declare class CloudflareD1AgentDatabase implements AgentDatabase {
318
318
  projectId: string;
319
319
  title: string;
320
320
  summary: string | null;
321
- state: import("./knowledge-coop.ts").WorkstreamState;
321
+ state: import("./project-workflow.ts").WorkstreamState;
322
322
  branchName: string | null;
323
323
  branchRef: string | null;
324
324
  owner: string | null;
325
- linkedItems: import("./knowledge-coop.ts").LinkedProjectRecordRef[];
325
+ linkedItems: import("./project-workflow.ts").LinkedProjectRecordRef[];
326
326
  verificationStatus: "completed" | "failed" | "waiting" | null;
327
327
  verificationSummary: string | null;
328
328
  lastSaveAt: string | null;