antigravity-ai-kit 2.1.0 → 3.0.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 (114) hide show
  1. package/.agent/README.md +4 -4
  2. package/.agent/agents/README.md +16 -12
  3. package/.agent/agents/architect.md +1 -0
  4. package/.agent/agents/backend-specialist.md +11 -0
  5. package/.agent/agents/code-reviewer.md +1 -0
  6. package/.agent/agents/database-architect.md +11 -0
  7. package/.agent/agents/devops-engineer.md +11 -0
  8. package/.agent/agents/e2e-runner.md +1 -0
  9. package/.agent/agents/explorer-agent.md +11 -0
  10. package/.agent/agents/frontend-specialist.md +11 -0
  11. package/.agent/agents/mobile-developer.md +11 -0
  12. package/.agent/agents/performance-optimizer.md +11 -0
  13. package/.agent/agents/planner.md +1 -0
  14. package/.agent/agents/refactor-cleaner.md +1 -0
  15. package/.agent/agents/reliability-engineer.md +11 -0
  16. package/.agent/agents/security-reviewer.md +1 -0
  17. package/.agent/agents/sprint-orchestrator.md +10 -0
  18. package/.agent/agents/tdd-guide.md +1 -0
  19. package/.agent/commands/code-review.md +1 -0
  20. package/.agent/commands/debug.md +1 -0
  21. package/.agent/commands/deploy.md +1 -0
  22. package/.agent/commands/help.md +252 -31
  23. package/.agent/commands/plan.md +1 -0
  24. package/.agent/commands/status.md +1 -0
  25. package/.agent/commands/tdd.md +1 -0
  26. package/.agent/contexts/brainstorm.md +26 -0
  27. package/.agent/contexts/debug.md +28 -0
  28. package/.agent/contexts/implement.md +29 -0
  29. package/.agent/contexts/review.md +27 -0
  30. package/.agent/contexts/ship.md +28 -0
  31. package/.agent/engine/identity.json +13 -0
  32. package/.agent/engine/loading-rules.json +23 -1
  33. package/.agent/engine/marketplace-index.json +29 -0
  34. package/.agent/engine/reliability-config.json +14 -0
  35. package/.agent/engine/sdlc-map.json +44 -0
  36. package/.agent/engine/workflow-state.json +28 -2
  37. package/.agent/hooks/hooks.json +27 -25
  38. package/.agent/manifest.json +12 -4
  39. package/.agent/rules.md +2 -1
  40. package/.agent/skills/README.md +10 -5
  41. package/.agent/skills/i18n-localization/SKILL.md +191 -0
  42. package/.agent/skills/mcp-integration/SKILL.md +224 -0
  43. package/.agent/skills/parallel-agents/SKILL.md +1 -1
  44. package/.agent/skills/shell-conventions/SKILL.md +92 -0
  45. package/.agent/skills/ui-ux-pro-max/SKILL.md +557 -0
  46. package/.agent/skills/ui-ux-pro-max/data/charts.csv +26 -0
  47. package/.agent/skills/ui-ux-pro-max/data/colors.csv +97 -0
  48. package/.agent/skills/ui-ux-pro-max/data/icons.csv +101 -0
  49. package/.agent/skills/ui-ux-pro-max/data/landing.csv +31 -0
  50. package/.agent/skills/ui-ux-pro-max/data/products.csv +97 -0
  51. package/.agent/skills/ui-ux-pro-max/data/react-performance.csv +45 -0
  52. package/.agent/skills/ui-ux-pro-max/data/stacks/astro.csv +54 -0
  53. package/.agent/skills/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
  54. package/.agent/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
  55. package/.agent/skills/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
  56. package/.agent/skills/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
  57. package/.agent/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
  58. package/.agent/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
  59. package/.agent/skills/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
  60. package/.agent/skills/ui-ux-pro-max/data/stacks/react.csv +54 -0
  61. package/.agent/skills/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
  62. package/.agent/skills/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
  63. package/.agent/skills/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
  64. package/.agent/skills/ui-ux-pro-max/data/stacks/vue.csv +50 -0
  65. package/.agent/skills/ui-ux-pro-max/data/styles.csv +68 -0
  66. package/.agent/skills/ui-ux-pro-max/data/typography.csv +58 -0
  67. package/.agent/skills/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
  68. package/.agent/skills/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
  69. package/.agent/skills/ui-ux-pro-max/data/web-interface.csv +31 -0
  70. package/.agent/skills/ui-ux-pro-max/scripts/core.py +253 -0
  71. package/.agent/skills/ui-ux-pro-max/scripts/design_system.py +1067 -0
  72. package/.agent/skills/ui-ux-pro-max/scripts/search.py +114 -0
  73. package/.agent/templates/adr-template.md +32 -0
  74. package/.agent/templates/bug-report.md +37 -0
  75. package/.agent/templates/feature-request.md +32 -0
  76. package/.agent/workflows/README.md +92 -78
  77. package/.agent/workflows/brainstorm.md +154 -100
  78. package/.agent/workflows/create.md +142 -75
  79. package/.agent/workflows/debug.md +157 -98
  80. package/.agent/workflows/deploy.md +195 -144
  81. package/.agent/workflows/enhance.md +157 -65
  82. package/.agent/workflows/orchestrate.md +171 -114
  83. package/.agent/workflows/plan.md +147 -72
  84. package/.agent/workflows/preview.md +140 -83
  85. package/.agent/workflows/quality-gate.md +196 -0
  86. package/.agent/workflows/retrospective.md +197 -0
  87. package/.agent/workflows/review.md +188 -0
  88. package/.agent/workflows/status.md +142 -91
  89. package/.agent/workflows/test.md +168 -95
  90. package/.agent/workflows/ui-ux-pro-max.md +181 -127
  91. package/README.md +215 -78
  92. package/bin/ag-kit.js +344 -10
  93. package/lib/agent-registry.js +214 -0
  94. package/lib/agent-reputation.js +351 -0
  95. package/lib/cli-commands.js +235 -0
  96. package/lib/conflict-detector.js +245 -0
  97. package/lib/engineering-manager.js +354 -0
  98. package/lib/error-budget.js +294 -0
  99. package/lib/hook-system.js +252 -0
  100. package/lib/identity.js +245 -0
  101. package/lib/loading-engine.js +208 -0
  102. package/lib/marketplace.js +298 -0
  103. package/lib/plugin-system.js +604 -0
  104. package/lib/security-scanner.js +309 -0
  105. package/lib/self-healing.js +434 -0
  106. package/lib/session-manager.js +261 -0
  107. package/lib/skill-sandbox.js +244 -0
  108. package/lib/task-governance.js +523 -0
  109. package/lib/task-model.js +317 -0
  110. package/lib/updater.js +201 -0
  111. package/lib/verify.js +240 -0
  112. package/lib/workflow-engine.js +353 -0
  113. package/lib/workflow-persistence.js +160 -0
  114. package/package.json +7 -3
@@ -0,0 +1,245 @@
1
+ /**
2
+ * Antigravity AI Kit — Developer Identity System
3
+ *
4
+ * Local identity management for multi-developer scenarios.
5
+ * Auto-detects from git config with manual registration fallback.
6
+ *
7
+ * @module lib/identity
8
+ * @author Emre Dursun
9
+ * @since v3.0.0
10
+ */
11
+
12
+ 'use strict';
13
+
14
+ const fs = require('fs');
15
+ const path = require('path');
16
+ const crypto = require('crypto');
17
+ const { execSync } = require('child_process');
18
+
19
+ const AGENT_DIR = '.agent';
20
+ const ENGINE_DIR = 'engine';
21
+ const IDENTITY_FILE = 'identity.json';
22
+
23
+ /** @type {readonly string[]} */
24
+ const VALID_ROLES = ['owner', 'contributor', 'reviewer'];
25
+
26
+ /**
27
+ * @typedef {object} Identity
28
+ * @property {string} id - Deterministic developer ID (SHA-256 truncated)
29
+ * @property {string} name - Developer name
30
+ * @property {string} email - Developer email
31
+ * @property {string} role - Developer role
32
+ * @property {string} registeredAt - ISO timestamp
33
+ * @property {string} lastActiveAt - ISO timestamp
34
+ */
35
+
36
+ /**
37
+ * Resolves the identity file path.
38
+ *
39
+ * @param {string} projectRoot - Root directory of the project
40
+ * @returns {string} Absolute path to identity.json
41
+ */
42
+ function resolveIdentityPath(projectRoot) {
43
+ return path.join(projectRoot, AGENT_DIR, ENGINE_DIR, IDENTITY_FILE);
44
+ }
45
+
46
+ /**
47
+ * Generates a deterministic developer ID from email.
48
+ *
49
+ * @param {string} email - Developer email
50
+ * @returns {string} 12-char hex ID
51
+ */
52
+ function generateDeveloperId(email) {
53
+ return crypto
54
+ .createHash('sha256')
55
+ .update(email.toLowerCase().trim())
56
+ .digest('hex')
57
+ .slice(0, 12);
58
+ }
59
+
60
+ /**
61
+ * Loads the identity registry from disk.
62
+ *
63
+ * @param {string} projectRoot - Root directory of the project
64
+ * @returns {{ developers: Identity[], activeId: string | null }}
65
+ */
66
+ function loadIdentityRegistry(projectRoot) {
67
+ const identityPath = resolveIdentityPath(projectRoot);
68
+
69
+ if (!fs.existsSync(identityPath)) {
70
+ return { developers: [], activeId: null };
71
+ }
72
+
73
+ try {
74
+ return JSON.parse(fs.readFileSync(identityPath, 'utf-8'));
75
+ } catch {
76
+ return { developers: [], activeId: null };
77
+ }
78
+ }
79
+
80
+ /**
81
+ * Writes the identity registry to disk atomically.
82
+ *
83
+ * @param {string} projectRoot - Root directory of the project
84
+ * @param {object} registry - Registry data
85
+ * @returns {void}
86
+ */
87
+ function writeIdentityRegistry(projectRoot, registry) {
88
+ const identityPath = resolveIdentityPath(projectRoot);
89
+ const tempPath = `${identityPath}.tmp`;
90
+ const dir = path.dirname(identityPath);
91
+
92
+ if (!fs.existsSync(dir)) {
93
+ fs.mkdirSync(dir, { recursive: true });
94
+ }
95
+
96
+ fs.writeFileSync(tempPath, JSON.stringify(registry, null, 2) + '\n', 'utf-8');
97
+ fs.renameSync(tempPath, identityPath);
98
+ }
99
+
100
+ /**
101
+ * Auto-detects developer identity from git config.
102
+ *
103
+ * @returns {{ name: string, email: string } | null}
104
+ */
105
+ function detectFromGit() {
106
+ try {
107
+ const name = execSync('git config user.name', { encoding: 'utf-8' }).trim();
108
+ const email = execSync('git config user.email', { encoding: 'utf-8' }).trim();
109
+
110
+ if (name && email) {
111
+ return { name, email };
112
+ }
113
+ return null;
114
+ } catch {
115
+ return null;
116
+ }
117
+ }
118
+
119
+ /**
120
+ * Registers a new developer identity.
121
+ *
122
+ * @param {string} projectRoot - Root directory of the project
123
+ * @param {object} params - Identity parameters
124
+ * @param {string} params.name - Developer name
125
+ * @param {string} params.email - Developer email
126
+ * @param {string} [params.role] - Developer role (default: 'contributor')
127
+ * @returns {{ success: boolean, identity: Identity, isNew: boolean }}
128
+ */
129
+ function registerIdentity(projectRoot, { name, email, role }) {
130
+ const registry = loadIdentityRegistry(projectRoot);
131
+ const developerId = generateDeveloperId(email);
132
+ const now = new Date().toISOString();
133
+ const identityRole = role && VALID_ROLES.includes(role) ? role : 'contributor';
134
+
135
+ // Check if already registered
136
+ const existingIndex = registry.developers.findIndex((d) => d.id === developerId);
137
+
138
+ if (existingIndex !== -1) {
139
+ // Update last active
140
+ registry.developers[existingIndex].lastActiveAt = now;
141
+ registry.developers[existingIndex].name = name;
142
+ registry.activeId = developerId;
143
+ writeIdentityRegistry(projectRoot, registry);
144
+ return { success: true, identity: registry.developers[existingIndex], isNew: false };
145
+ }
146
+
147
+ /** @type {Identity} */
148
+ const identity = {
149
+ id: developerId,
150
+ name,
151
+ email: email.toLowerCase().trim(),
152
+ role: identityRole,
153
+ registeredAt: now,
154
+ lastActiveAt: now,
155
+ };
156
+
157
+ registry.developers.push(identity);
158
+
159
+ // First developer becomes owner automatically
160
+ if (registry.developers.length === 1) {
161
+ identity.role = 'owner';
162
+ }
163
+
164
+ registry.activeId = developerId;
165
+ writeIdentityRegistry(projectRoot, registry);
166
+
167
+ return { success: true, identity, isNew: true };
168
+ }
169
+
170
+ /**
171
+ * Gets the current active developer identity.
172
+ * Auto-detects and registers from git if no identity exists.
173
+ *
174
+ * @param {string} projectRoot - Root directory of the project
175
+ * @returns {Identity | null}
176
+ */
177
+ function getCurrentIdentity(projectRoot) {
178
+ const registry = loadIdentityRegistry(projectRoot);
179
+
180
+ if (registry.activeId) {
181
+ const identity = registry.developers.find((d) => d.id === registry.activeId);
182
+ if (identity) {
183
+ return identity;
184
+ }
185
+ }
186
+
187
+ // Auto-detect from git
188
+ const gitInfo = detectFromGit();
189
+ if (gitInfo) {
190
+ const result = registerIdentity(projectRoot, { name: gitInfo.name, email: gitInfo.email });
191
+ return result.identity;
192
+ }
193
+
194
+ return null;
195
+ }
196
+
197
+ /**
198
+ * Validates an identity exists and is properly formed.
199
+ *
200
+ * @param {string} developerId - Developer ID to validate
201
+ * @param {string} projectRoot - Root directory of the project
202
+ * @returns {{ valid: boolean, errors: string[] }}
203
+ */
204
+ function validateIdentity(developerId, projectRoot) {
205
+ const registry = loadIdentityRegistry(projectRoot);
206
+ /** @type {string[]} */
207
+ const errors = [];
208
+
209
+ const identity = registry.developers.find((d) => d.id === developerId);
210
+
211
+ if (!identity) {
212
+ return { valid: false, errors: [`Identity not found: ${developerId}`] };
213
+ }
214
+
215
+ if (!identity.name || identity.name.trim().length === 0) {
216
+ errors.push('Identity missing name');
217
+ }
218
+ if (!identity.email || !identity.email.includes('@')) {
219
+ errors.push('Identity missing valid email');
220
+ }
221
+ if (!VALID_ROLES.includes(identity.role)) {
222
+ errors.push(`Invalid role: ${identity.role}`);
223
+ }
224
+
225
+ return { valid: errors.length === 0, errors };
226
+ }
227
+
228
+ /**
229
+ * Lists all registered developer identities.
230
+ *
231
+ * @param {string} projectRoot - Root directory of the project
232
+ * @returns {{ developers: Identity[], activeId: string | null }}
233
+ */
234
+ function listIdentities(projectRoot) {
235
+ return loadIdentityRegistry(projectRoot);
236
+ }
237
+
238
+ module.exports = {
239
+ registerIdentity,
240
+ getCurrentIdentity,
241
+ validateIdentity,
242
+ listIdentities,
243
+ generateDeveloperId,
244
+ detectFromGit,
245
+ };
@@ -0,0 +1,208 @@
1
+ /**
2
+ * Antigravity AI Kit — Loading Rules Engine
3
+ *
4
+ * Runtime implementation of loading-rules.json keyword matching
5
+ * and context budget enforcement.
6
+ *
7
+ * @module lib/loading-engine
8
+ * @author Emre Dursun
9
+ * @since v3.0.0
10
+ */
11
+
12
+ 'use strict';
13
+
14
+ const fs = require('fs');
15
+ const path = require('path');
16
+
17
+ const AGENT_DIR = '.agent';
18
+ const ENGINE_DIR = 'engine';
19
+ const LOADING_RULES_FILE = 'loading-rules.json';
20
+
21
+ /**
22
+ * @typedef {object} LoadPlan
23
+ * @property {string[]} agents - Agents to load
24
+ * @property {string[]} skills - Skills to load
25
+ * @property {string[]} warnings - Budget or resolution warnings
26
+ * @property {object} budgetUsage - Context budget usage stats
27
+ * @property {number} budgetUsage.agentsUsed - Number of agents selected
28
+ * @property {number} budgetUsage.agentsMax - Maximum allowed
29
+ * @property {number} budgetUsage.skillsUsed - Number of skills selected
30
+ * @property {number} budgetUsage.skillsMax - Maximum allowed
31
+ * @property {string[]} matchedDomains - Which domains matched
32
+ */
33
+
34
+ /**
35
+ * Loads and parses loading-rules.json.
36
+ *
37
+ * @param {string} projectRoot - Root directory of the project
38
+ * @returns {object} Parsed loading rules
39
+ */
40
+ function loadRules(projectRoot) {
41
+ const rulesPath = path.join(projectRoot, AGENT_DIR, ENGINE_DIR, LOADING_RULES_FILE);
42
+
43
+ if (!fs.existsSync(rulesPath)) {
44
+ throw new Error(`Loading rules not found: ${rulesPath}`);
45
+ }
46
+
47
+ return JSON.parse(fs.readFileSync(rulesPath, 'utf-8'));
48
+ }
49
+
50
+ /**
51
+ * Matches a task description against domain keywords.
52
+ *
53
+ * @param {string} taskDescription - Human-readable task text
54
+ * @param {string} projectRoot - Root directory of the project
55
+ * @returns {{ matchedDomains: string[], agents: string[], skills: string[] }}
56
+ */
57
+ function resolveForTask(taskDescription, projectRoot) {
58
+ const rules = loadRules(projectRoot);
59
+ const domainRules = rules.domainRules || [];
60
+ const lowerTask = taskDescription.toLowerCase();
61
+
62
+ /** @type {Set<string>} */
63
+ const agents = new Set();
64
+ /** @type {Set<string>} */
65
+ const skills = new Set();
66
+ /** @type {string[]} */
67
+ const matchedDomains = [];
68
+
69
+ for (const rule of domainRules) {
70
+ const hasMatch = (rule.keywords || []).some((keyword) => lowerTask.includes(keyword.toLowerCase()));
71
+
72
+ if (hasMatch) {
73
+ matchedDomains.push(rule.domain);
74
+
75
+ for (const agent of (rule.loadAgents || [])) {
76
+ agents.add(agent);
77
+ }
78
+ for (const skill of (rule.loadSkills || [])) {
79
+ skills.add(skill);
80
+ }
81
+ }
82
+ }
83
+
84
+ return {
85
+ matchedDomains,
86
+ agents: [...agents],
87
+ skills: [...skills],
88
+ };
89
+ }
90
+
91
+ /**
92
+ * Resolves agents and skills for a named workflow using workflow bindings.
93
+ *
94
+ * @param {string} workflowName - Name of the workflow
95
+ * @param {string} projectRoot - Root directory of the project
96
+ * @returns {{ agents: string[], skills: string[], bindingType: string }}
97
+ */
98
+ function resolveForWorkflow(workflowName, projectRoot) {
99
+ const rules = loadRules(projectRoot);
100
+ const bindings = rules.workflowBindings || [];
101
+ const match = bindings.find((b) => b.workflow === workflowName);
102
+
103
+ if (!match) {
104
+ return { agents: [], skills: [], bindingType: 'none' };
105
+ }
106
+
107
+ return {
108
+ agents: match.loadAgents || [],
109
+ skills: match.loadSkills || [],
110
+ bindingType: match.bindingType || 'inferred',
111
+ };
112
+ }
113
+
114
+ /**
115
+ * Enforces context budget limits by trimming agents and skills.
116
+ *
117
+ * @param {string[]} agents - Candidate agents
118
+ * @param {string[]} skills - Candidate skills
119
+ * @param {string} projectRoot - Root directory of the project
120
+ * @returns {{ agents: string[], skills: string[], trimmed: boolean, warnings: string[] }}
121
+ */
122
+ function enforceContextBudget(agents, skills, projectRoot) {
123
+ const rules = loadRules(projectRoot);
124
+ const budget = rules.contextBudget || {};
125
+ const maxAgents = budget.maxAgentsPerSession || 4;
126
+ const maxSkills = budget.maxSkillsPerSession || 6;
127
+ const warningThreshold = (budget.warningThresholdPercent || 80) / 100;
128
+
129
+ /** @type {string[]} */
130
+ const warnings = [];
131
+ let trimmed = false;
132
+
133
+ let finalAgents = [...agents];
134
+ let finalSkills = [...skills];
135
+
136
+ if (finalAgents.length > maxAgents) {
137
+ warnings.push(`Agent budget exceeded: ${finalAgents.length}/${maxAgents} — trimmed to ${maxAgents}`);
138
+ finalAgents = finalAgents.slice(0, maxAgents);
139
+ trimmed = true;
140
+ } else if (finalAgents.length >= maxAgents * warningThreshold) {
141
+ warnings.push(`Agent budget near limit: ${finalAgents.length}/${maxAgents} (${Math.round(finalAgents.length / maxAgents * 100)}%)`);
142
+ }
143
+
144
+ if (finalSkills.length > maxSkills) {
145
+ warnings.push(`Skill budget exceeded: ${finalSkills.length}/${maxSkills} — trimmed to ${maxSkills}`);
146
+ finalSkills = finalSkills.slice(0, maxSkills);
147
+ trimmed = true;
148
+ } else if (finalSkills.length >= maxSkills * warningThreshold) {
149
+ warnings.push(`Skill budget near limit: ${finalSkills.length}/${maxSkills} (${Math.round(finalSkills.length / maxSkills * 100)}%)`);
150
+ }
151
+
152
+ return { agents: finalAgents, skills: finalSkills, trimmed, warnings };
153
+ }
154
+
155
+ /**
156
+ * Full resolution: combines domain matching, workflow binding, and budget enforcement.
157
+ *
158
+ * @param {string} taskDescription - Task text for domain matching
159
+ * @param {string} [workflowName] - Optional workflow name for binding resolution
160
+ * @param {string} projectRoot - Root directory of the project
161
+ * @returns {LoadPlan}
162
+ */
163
+ function getLoadPlan(taskDescription, workflowName, projectRoot) {
164
+ const rules = loadRules(projectRoot);
165
+ const budget = rules.contextBudget || {};
166
+
167
+ // Step 1: Domain keyword matching
168
+ const taskResolution = resolveForTask(taskDescription, projectRoot);
169
+
170
+ // Step 2: Workflow bindings (if workflow specified)
171
+ /** @type {Set<string>} */
172
+ const allAgents = new Set(taskResolution.agents);
173
+ /** @type {Set<string>} */
174
+ const allSkills = new Set(taskResolution.skills);
175
+
176
+ if (workflowName) {
177
+ const wfResolution = resolveForWorkflow(workflowName, projectRoot);
178
+ for (const agent of wfResolution.agents) {
179
+ allAgents.add(agent);
180
+ }
181
+ for (const skill of wfResolution.skills) {
182
+ allSkills.add(skill);
183
+ }
184
+ }
185
+
186
+ // Step 3: Budget enforcement
187
+ const budgetResult = enforceContextBudget([...allAgents], [...allSkills], projectRoot);
188
+
189
+ return {
190
+ agents: budgetResult.agents,
191
+ skills: budgetResult.skills,
192
+ warnings: budgetResult.warnings,
193
+ budgetUsage: {
194
+ agentsUsed: budgetResult.agents.length,
195
+ agentsMax: budget.maxAgentsPerSession || 4,
196
+ skillsUsed: budgetResult.skills.length,
197
+ skillsMax: budget.maxSkillsPerSession || 6,
198
+ },
199
+ matchedDomains: taskResolution.matchedDomains,
200
+ };
201
+ }
202
+
203
+ module.exports = {
204
+ resolveForTask,
205
+ resolveForWorkflow,
206
+ enforceContextBudget,
207
+ getLoadPlan,
208
+ };