ralphctl 0.4.2 → 0.4.3

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.
@@ -2,27 +2,18 @@
2
2
  import {
3
3
  PromptCancelledError,
4
4
  addCheckScriptToRepository,
5
- escapableSelect
6
- } from "./chunk-D2YGPLIV.mjs";
5
+ escapableSelect,
6
+ getAllConfigSchemaEntries,
7
+ getConfigDefaultValue,
8
+ parseConfigValue
9
+ } from "./chunk-TDBEEHTS.mjs";
7
10
  import {
8
11
  editorInput
9
- } from "./chunk-7JLZQICD.mjs";
12
+ } from "./chunk-MDE6KPJQ.mjs";
10
13
  import {
11
- addProjectRepo,
12
- getProject,
13
- getProjectById,
14
- getRepoById,
15
- listProjects,
16
- removeProject,
17
- removeProjectRepo,
18
- resolveRepoPath
19
- } from "./chunk-NUYQK5MN.mjs";
20
- import {
21
- SignalParser,
22
14
  addTask,
23
15
  areAllTasksDone,
24
16
  branchExists,
25
- buildTicketRefinePrompt,
26
17
  createIdeatePipeline,
27
18
  createPlanPipeline,
28
19
  createRefinePipeline,
@@ -40,19 +31,23 @@ import {
40
31
  isGlabAvailable,
41
32
  listTasks,
42
33
  parseRequirementsFile,
43
- processLifecycleAdapter,
44
- providerDisplayName,
45
34
  removeTask,
46
35
  renderParsedTasksTable,
47
36
  reorderByDependencies,
48
37
  reorderTask,
49
- resolveProvider,
50
38
  runAiSession,
51
39
  saveTasks,
52
40
  updateTask,
53
41
  updateTaskStatus,
54
42
  validateImportTasks
55
- } from "./chunk-TKPTT2UG.mjs";
43
+ } from "./chunk-LCY32RW4.mjs";
44
+ import {
45
+ SignalParser,
46
+ buildTicketRefinePrompt,
47
+ processLifecycleAdapter,
48
+ providerDisplayName,
49
+ resolveProvider
50
+ } from "./chunk-2FT37OZX.mjs";
56
51
  import {
57
52
  fetchIssueFromUrl,
58
53
  formatIssueContext,
@@ -63,7 +58,7 @@ import {
63
58
  removeTicket,
64
59
  truncate,
65
60
  updateTicket
66
- } from "./chunk-JOQO4HMM.mjs";
61
+ } from "./chunk-EGUFQNRB.mjs";
67
62
  import {
68
63
  EXIT_ERROR,
69
64
  exitWithCode
@@ -72,33 +67,33 @@ import {
72
67
  getPrompt,
73
68
  getSharedDeps
74
69
  } from "./chunk-747KW2RW.mjs";
70
+ import {
71
+ addProjectRepo,
72
+ getProject,
73
+ getProjectById,
74
+ getRepoById,
75
+ listProjects,
76
+ removeProject,
77
+ removeProjectRepo,
78
+ resolveRepoPath
79
+ } from "./chunk-LDSG7G2T.mjs";
75
80
  import {
76
81
  activateSprint,
77
82
  assertSprintStatus,
78
83
  closeSprint,
79
84
  createSprint,
80
85
  deleteSprint,
81
- getAiProvider,
82
- getConfig,
83
- getCurrentSprint,
84
86
  getCurrentSprintOrThrow,
85
- getEditor,
86
- getEvaluationIterations,
87
87
  getProgress,
88
88
  getSprint,
89
89
  listSprints,
90
90
  logProgress,
91
91
  logSprintBaselines,
92
92
  resolveSprintId,
93
- saveConfig,
94
93
  saveSprint,
95
- setAiProvider,
96
- setCurrentSprint,
97
- setEditor,
98
- setEvaluationIterations,
99
94
  summarizeProgressForContext,
100
95
  withFileLock
101
- } from "./chunk-YCDUVPRT.mjs";
96
+ } from "./chunk-RQGD5WS6.mjs";
102
97
  import {
103
98
  DETAIL_LABEL_WIDTH,
104
99
  badge,
@@ -111,6 +106,11 @@ import {
111
106
  fieldMultiline,
112
107
  formatSprintStatus,
113
108
  formatTaskStatus,
109
+ getAiProvider,
110
+ getConfig,
111
+ getCurrentSprint,
112
+ getEditor,
113
+ getEvaluationIterations,
114
114
  getQuoteForContext,
115
115
  horizontalLine,
116
116
  icons,
@@ -123,6 +123,11 @@ import {
123
123
  progressBar,
124
124
  renderCard,
125
125
  renderTable,
126
+ saveConfig,
127
+ setAiProvider,
128
+ setCurrentSprint,
129
+ setEditor,
130
+ setEvaluationIterations,
126
131
  showEmpty,
127
132
  showError,
128
133
  showNextStep,
@@ -133,13 +138,14 @@ import {
133
138
  showWarning,
134
139
  success,
135
140
  terminalBell
136
- } from "./chunk-FKMKOWLA.mjs";
141
+ } from "./chunk-WZTY77GY.mjs";
137
142
  import {
138
143
  ensureError,
139
144
  unwrapOrThrow,
140
145
  wrapAsync
141
146
  } from "./chunk-IWXBJD2D.mjs";
142
147
  import {
148
+ CURRENT_ONBOARDING_VERSION,
143
149
  ImportTasksSchema,
144
150
  RequirementStatusSchema,
145
151
  SprintSchema,
@@ -162,7 +168,7 @@ import {
162
168
  getTasksFilePath,
163
169
  readValidatedJson,
164
170
  validateProjectPath
165
- } from "./chunk-CTP2A436.mjs";
171
+ } from "./chunk-D2HWXEHH.mjs";
166
172
  import {
167
173
  NoCurrentSprintError,
168
174
  ProjectNotFoundError,
@@ -170,14 +176,13 @@ import {
170
176
  SprintStatusError,
171
177
  StorageError,
172
178
  TaskNotFoundError,
173
- TicketNotFoundError,
174
- ValidationError
179
+ TicketNotFoundError
175
180
  } from "./chunk-57UWLHRH.mjs";
176
181
 
177
182
  // package.json
178
183
  var package_default = {
179
184
  name: "ralphctl",
180
- version: "0.4.2",
185
+ version: "0.4.3",
181
186
  description: "Agent harness for long-running AI coding tasks \u2014 orchestrates Claude Code & GitHub Copilot across repositories",
182
187
  homepage: "https://github.com/lukas-grigis/ralphctl",
183
188
  type: "module",
@@ -245,8 +250,8 @@ var package_default = {
245
250
  "@types/node": "^25.6.0",
246
251
  "@types/react": "^19.2.14",
247
252
  "@types/tabtab": "^3.0.4",
248
- "@vitest/coverage-v8": "^4.1.4",
249
- eslint: "^10.2.0",
253
+ "@vitest/coverage-v8": "^4.1.5",
254
+ eslint: "^10.2.1",
250
255
  "eslint-config-prettier": "^10.1.8",
251
256
  globals: "^17.5.0",
252
257
  husky: "^9.1.7",
@@ -256,11 +261,11 @@ var package_default = {
256
261
  tsup: "^8.5.1",
257
262
  tsx: "^4.21.0",
258
263
  typescript: "^5.9.3",
259
- "typescript-eslint": "^8.58.2",
260
- vitest: "^4.1.4"
264
+ "typescript-eslint": "^8.59.0",
265
+ vitest: "^4.1.5"
261
266
  },
262
267
  "lint-staged": {
263
- "*.ts": [
268
+ "*.{ts,tsx}": [
264
269
  "eslint --cache --fix",
265
270
  "prettier --write"
266
271
  ],
@@ -1897,7 +1902,7 @@ async function selectProject(message = "Select project:") {
1897
1902
  default: true
1898
1903
  });
1899
1904
  if (create) {
1900
- const { projectAddCommand } = await import("./add-GX7P7XTT.mjs");
1905
+ const { projectAddCommand } = await import("./add-ZZYL4BSF.mjs");
1901
1906
  await projectAddCommand({ interactive: true });
1902
1907
  const updated = await listProjects();
1903
1908
  if (updated.length === 0) return null;
@@ -1932,7 +1937,7 @@ async function selectSprint(message = "Select sprint:", filter) {
1932
1937
  default: true
1933
1938
  });
1934
1939
  if (create) {
1935
- const { sprintCreateCommand } = await import("./create-7WFSCMP4.mjs");
1940
+ const { sprintCreateCommand } = await import("./create-PQK6KKRD.mjs");
1936
1941
  await sprintCreateCommand({ interactive: true });
1937
1942
  const updated = await listSprints();
1938
1943
  const refiltered = filter ? updated.filter((s) => filter.includes(s.status)) : updated;
@@ -1967,7 +1972,7 @@ async function selectTicket(message = "Select ticket:", filter) {
1967
1972
  default: true
1968
1973
  });
1969
1974
  if (create) {
1970
- const { ticketAddCommand } = await import("./add-CIM72NE3.mjs");
1975
+ const { ticketAddCommand } = await import("./add-MG26JWBP.mjs");
1971
1976
  await ticketAddCommand({ interactive: true });
1972
1977
  const updated = await listTickets();
1973
1978
  const refiltered = filter ? updated.filter(filter) : updated;
@@ -4615,136 +4620,6 @@ async function progressShowCommand() {
4615
4620
  console.log(content);
4616
4621
  }
4617
4622
 
4618
- // src/integration/config/schema-provider.ts
4619
- import { Result as Result6 } from "typescript-result";
4620
-
4621
- // src/domain/config-schema.ts
4622
- var ConfigSchemaDefinition = {
4623
- currentSprint: {
4624
- key: "currentSprint",
4625
- label: "Current Sprint",
4626
- type: "string",
4627
- default: null,
4628
- description: "Currently active sprint ID (set by `sprint start`, cleared on `sprint close`)",
4629
- validation: (val) => val === null || typeof val === "string" && val.length > 0,
4630
- scope: "global"
4631
- },
4632
- aiProvider: {
4633
- key: "aiProvider",
4634
- label: "AI Provider",
4635
- type: "enum",
4636
- enum: ["claude", "copilot"],
4637
- default: null,
4638
- description: "AI provider for task execution (Claude Code or GitHub Copilot CLI)",
4639
- validation: (val) => val === null || typeof val === "string" && ["claude", "copilot"].includes(val),
4640
- scope: "global"
4641
- },
4642
- evaluationIterations: {
4643
- key: "evaluationIterations",
4644
- label: "Evaluation Iterations",
4645
- type: "integer",
4646
- min: 0,
4647
- max: 10,
4648
- default: 1,
4649
- description: "Number of fix-attempt iterations after initial evaluation; 0 = disabled. Higher values allow more refinement rounds.",
4650
- validation: (val) => typeof val === "number" && Number.isInteger(val) && val >= 0 && val <= 10,
4651
- scope: "sprint"
4652
- }
4653
- // Phase 2+ additions can be added here as single schema entries
4654
- // maxTaskTurns: { ... },
4655
- // checkScriptTimeout: { ... },
4656
- };
4657
- function getSchemaEntry(key) {
4658
- return ConfigSchemaDefinition[key];
4659
- }
4660
- function getAllSchemaEntries() {
4661
- return Object.values(ConfigSchemaDefinition);
4662
- }
4663
- function getDefaultValue(key) {
4664
- return ConfigSchemaDefinition[key].default;
4665
- }
4666
-
4667
- // src/integration/config/schema-provider.ts
4668
- function getAllConfigSchemaEntries() {
4669
- return getAllSchemaEntries();
4670
- }
4671
- function getConfigSchemaEntry(key) {
4672
- return getSchemaEntry(key);
4673
- }
4674
- function getConfigDefaultValue(key) {
4675
- return getDefaultValue(key);
4676
- }
4677
- function validateConfigValue(key, value) {
4678
- if (!(key in ConfigSchemaDefinition)) {
4679
- return Result6.error(new ValidationError(`Unknown config key: ${key}`, key));
4680
- }
4681
- const schemaKey = key;
4682
- const entry = getConfigSchemaEntry(schemaKey);
4683
- if (!entry.validation(value)) {
4684
- let errorMsg = `Invalid value for ${key}`;
4685
- if (entry.type === "enum" && entry.enum) {
4686
- errorMsg += `: must be one of ${entry.enum.join(", ")}`;
4687
- } else if (entry.type === "integer" || entry.type === "number") {
4688
- const constraints = [];
4689
- if (entry.min !== void 0) constraints.push(`min: ${String(entry.min)}`);
4690
- if (entry.max !== void 0) constraints.push(`max: ${String(entry.max)}`);
4691
- if (constraints.length > 0) errorMsg += ` (${constraints.join(", ")})`;
4692
- }
4693
- return Result6.error(new ValidationError(errorMsg, key));
4694
- }
4695
- return Result6.ok(value);
4696
- }
4697
- function parseConfigValue(key, stringValue) {
4698
- if (!(key in ConfigSchemaDefinition)) {
4699
- return Result6.error(new ValidationError(`Unknown config key: ${key}`, key));
4700
- }
4701
- const schemaKey = key;
4702
- const entry = getConfigSchemaEntry(schemaKey);
4703
- let parsedValue;
4704
- try {
4705
- switch (entry.type) {
4706
- case "string":
4707
- parsedValue = stringValue === "null" ? null : stringValue;
4708
- break;
4709
- case "integer":
4710
- parsedValue = stringValue === "null" ? null : Number.parseInt(stringValue, 10);
4711
- if (Number.isNaN(parsedValue)) {
4712
- return Result6.error(new ValidationError(`Expected integer for ${key}, got ${stringValue}`, key));
4713
- }
4714
- break;
4715
- case "number":
4716
- parsedValue = stringValue === "null" ? null : Number.parseFloat(stringValue);
4717
- if (Number.isNaN(parsedValue)) {
4718
- return Result6.error(new ValidationError(`Expected number for ${key}, got ${stringValue}`, key));
4719
- }
4720
- break;
4721
- case "boolean":
4722
- if (stringValue.toLowerCase() === "true" || stringValue === "1") {
4723
- parsedValue = true;
4724
- } else if (stringValue.toLowerCase() === "false" || stringValue === "0") {
4725
- parsedValue = false;
4726
- } else if (stringValue === "null") {
4727
- parsedValue = null;
4728
- } else {
4729
- return Result6.error(new ValidationError(`Expected boolean for ${key}, got ${stringValue}`, key));
4730
- }
4731
- break;
4732
- case "enum":
4733
- if (stringValue === "null") {
4734
- parsedValue = null;
4735
- } else {
4736
- parsedValue = stringValue;
4737
- }
4738
- break;
4739
- }
4740
- } catch (err) {
4741
- return Result6.error(
4742
- new ValidationError(`Failed to parse ${key}: ${err instanceof Error ? err.message : String(err)}`, key)
4743
- );
4744
- }
4745
- return validateConfigValue(key, parsedValue);
4746
- }
4747
-
4748
4623
  // src/integration/cli/commands/config/config.ts
4749
4624
  var KEY_ALIASES = {
4750
4625
  provider: "aiProvider"
@@ -4820,7 +4695,7 @@ async function configShowCommand() {
4820
4695
  }
4821
4696
 
4822
4697
  // src/integration/cli/commands/doctor/doctor.ts
4823
- import { access as access2, constants } from "fs/promises";
4698
+ import { access as access2, constants, readFile as readFile4 } from "fs/promises";
4824
4699
  import { join as join5 } from "path";
4825
4700
  import { spawnSync as spawnSync2 } from "child_process";
4826
4701
  var REQUIRED_NODE_MAJOR = 24;
@@ -4935,6 +4810,90 @@ async function checkProjectPaths() {
4935
4810
  }
4936
4811
  return { name: "Project paths", status: "fail", detail: issues.join("; ") };
4937
4812
  }
4813
+ function providerInstructionsRelPath(provider) {
4814
+ if (provider === "claude") return "CLAUDE.md";
4815
+ return ".github/copilot-instructions.md";
4816
+ }
4817
+ async function checkRepoOnboarding() {
4818
+ const projects = await listProjects();
4819
+ const config = await getConfig();
4820
+ const provider = config.aiProvider;
4821
+ const results = [];
4822
+ for (const project of projects) {
4823
+ for (const repo of project.repositories) {
4824
+ const name = `Onboarding \u2014 ${project.name}/${repo.name}`;
4825
+ if (!provider) {
4826
+ results.push({
4827
+ name,
4828
+ status: "skip",
4829
+ detail: "configure an AI provider to use onboarding"
4830
+ });
4831
+ continue;
4832
+ }
4833
+ const relPath = providerInstructionsRelPath(provider);
4834
+ const instructionsPath = join5(repo.path, relPath);
4835
+ const hasInstructions = await fileExists(instructionsPath);
4836
+ const ver = repo.onboardingVersion;
4837
+ if (ver == null) {
4838
+ if (hasInstructions) {
4839
+ results.push({
4840
+ name,
4841
+ status: "pass",
4842
+ detail: `authored ${relPath} (not harness-managed)`
4843
+ });
4844
+ } else {
4845
+ results.push({
4846
+ name,
4847
+ status: "skip",
4848
+ detail: `never onboarded \u2014 run \`ralphctl project onboard ${project.name} --repo ${repo.name}\``
4849
+ });
4850
+ }
4851
+ continue;
4852
+ }
4853
+ if (!hasInstructions) {
4854
+ results.push({
4855
+ name,
4856
+ status: "warn",
4857
+ detail: `onboardingVersion set but ${relPath} missing \u2014 re-run \`ralphctl project onboard\``
4858
+ });
4859
+ continue;
4860
+ }
4861
+ if (ver < CURRENT_ONBOARDING_VERSION) {
4862
+ results.push({
4863
+ name,
4864
+ status: "warn",
4865
+ detail: `onboarding v${String(ver)} < v${String(CURRENT_ONBOARDING_VERSION)} \u2014 re-run to refresh`
4866
+ });
4867
+ continue;
4868
+ }
4869
+ if (ver > CURRENT_ONBOARDING_VERSION) {
4870
+ results.push({
4871
+ name,
4872
+ status: "warn",
4873
+ detail: `onboarding v${String(ver)} > v${String(CURRENT_ONBOARDING_VERSION)} \u2014 repo onboarded by a newer ralphctl version \u2014 upgrade the CLI to manage it cleanly`
4874
+ });
4875
+ continue;
4876
+ }
4877
+ let body;
4878
+ try {
4879
+ body = await readFile4(instructionsPath, "utf-8");
4880
+ } catch {
4881
+ results.push({ name, status: "warn", detail: `${relPath} unreadable \u2014 re-run \`ralphctl project onboard\`` });
4882
+ continue;
4883
+ }
4884
+ if (body.includes("LOW-CONFIDENCE:")) {
4885
+ results.push({
4886
+ name,
4887
+ status: "warn",
4888
+ detail: "low-confidence sections detected \u2014 re-run interactively to review"
4889
+ });
4890
+ continue;
4891
+ }
4892
+ results.push({ name, status: "pass", detail: `onboarding v${String(ver)}` });
4893
+ }
4894
+ }
4895
+ return results;
4896
+ }
4938
4897
  async function checkEvaluationConfig() {
4939
4898
  const config = await getConfig();
4940
4899
  if (config.evaluationIterations == null) {
@@ -4950,6 +4909,17 @@ async function checkEvaluationConfig() {
4950
4909
  detail: `evaluationIterations: ${String(config.evaluationIterations)}`
4951
4910
  };
4952
4911
  }
4912
+ async function checkAiCheckScriptDiscovery() {
4913
+ const config = await getConfig();
4914
+ if (config.aiCheckScriptDiscovery === false) {
4915
+ return {
4916
+ name: "AI check-script discovery",
4917
+ status: "warn",
4918
+ detail: "disabled \u2014 `project add` will skip the AI fallback for unrecognized ecosystems (re-enable: ralphctl config set aiCheckScriptDiscovery true)"
4919
+ };
4920
+ }
4921
+ return null;
4922
+ }
4953
4923
  async function checkConfigSchemaValidation() {
4954
4924
  const config = await getConfig();
4955
4925
  const entries = getAllConfigSchemaEntries();
@@ -4999,9 +4969,14 @@ async function doctorCommand() {
4999
4969
  checkProjectPaths(),
5000
4970
  checkCurrentSprint(),
5001
4971
  checkEvaluationConfig(),
4972
+ checkAiCheckScriptDiscovery(),
5002
4973
  checkConfigSchemaValidation()
5003
4974
  ]);
5004
- results.push(...asyncResults);
4975
+ for (const r of asyncResults) {
4976
+ if (r !== null) results.push(r);
4977
+ }
4978
+ const onboardingResults = await checkRepoOnboarding();
4979
+ results.push(...onboardingResults);
5005
4980
  for (const result of results) {
5006
4981
  if (result.status === "pass") {
5007
4982
  log.success(`${result.name}${result.detail ? colors.muted(` \u2014 ${result.detail}`) : ""}`);
@@ -5225,9 +5200,6 @@ export {
5225
5200
  loadDashboardData,
5226
5201
  getNextAction,
5227
5202
  showDashboard,
5228
- getAllSchemaEntries,
5229
- validateConfigValue,
5230
- parseConfigValue,
5231
5203
  configSetCommand,
5232
5204
  configShowCommand,
5233
5205
  checkNodeVersion,
@@ -5237,6 +5209,7 @@ export {
5237
5209
  checkGlabInstalled,
5238
5210
  checkDataDirectory,
5239
5211
  checkProjectPaths,
5212
+ checkRepoOnboarding,
5240
5213
  checkEvaluationConfig,
5241
5214
  checkConfigSchemaValidation,
5242
5215
  checkCurrentSprint,
@@ -1,4 +1,14 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ unwrapOrThrow
4
+ } from "./chunk-IWXBJD2D.mjs";
5
+ import {
6
+ ConfigSchema,
7
+ fileExists,
8
+ getConfigPath,
9
+ readValidatedJson,
10
+ writeValidatedJson
11
+ } from "./chunk-D2HWXEHH.mjs";
2
12
 
3
13
  // src/integration/ui/theme/theme.ts
4
14
  import { bold, cyan, gray, green, red, yellow } from "colorette";
@@ -467,6 +477,60 @@ function renderTable(columns, rows, options = {}) {
467
477
  return result.join("\n");
468
478
  }
469
479
 
480
+ // src/integration/persistence/config.ts
481
+ var DEFAULT_EVALUATION_ITERATIONS = 1;
482
+ var DEFAULT_CONFIG = {
483
+ currentSprint: null,
484
+ aiProvider: null,
485
+ editor: null
486
+ };
487
+ async function getConfig() {
488
+ const configPath = getConfigPath();
489
+ if (!await fileExists(configPath)) {
490
+ return DEFAULT_CONFIG;
491
+ }
492
+ return unwrapOrThrow(await readValidatedJson(configPath, ConfigSchema));
493
+ }
494
+ async function saveConfig(config) {
495
+ unwrapOrThrow(await writeValidatedJson(getConfigPath(), config, ConfigSchema));
496
+ }
497
+ async function getCurrentSprint() {
498
+ const config = await getConfig();
499
+ return config.currentSprint;
500
+ }
501
+ async function setCurrentSprint(sprintId) {
502
+ const config = await getConfig();
503
+ config.currentSprint = sprintId;
504
+ await saveConfig(config);
505
+ }
506
+ async function getAiProvider() {
507
+ const config = await getConfig();
508
+ return config.aiProvider ?? null;
509
+ }
510
+ async function setAiProvider(provider) {
511
+ const config = await getConfig();
512
+ config.aiProvider = provider;
513
+ await saveConfig(config);
514
+ }
515
+ async function getEditor() {
516
+ const config = await getConfig();
517
+ return config.editor ?? null;
518
+ }
519
+ async function setEditor(editor) {
520
+ const config = await getConfig();
521
+ config.editor = editor;
522
+ await saveConfig(config);
523
+ }
524
+ async function getEvaluationIterations() {
525
+ const config = await getConfig();
526
+ return config.evaluationIterations ?? DEFAULT_EVALUATION_ITERATIONS;
527
+ }
528
+ async function setEvaluationIterations(iterations) {
529
+ const config = await getConfig();
530
+ config.evaluationIterations = iterations;
531
+ await saveConfig(config);
532
+ }
533
+
470
534
  export {
471
535
  emoji,
472
536
  colors,
@@ -504,5 +568,15 @@ export {
504
568
  horizontalLine,
505
569
  renderCard,
506
570
  progressBar,
507
- renderTable
571
+ renderTable,
572
+ getConfig,
573
+ saveConfig,
574
+ getCurrentSprint,
575
+ setCurrentSprint,
576
+ getAiProvider,
577
+ setAiProvider,
578
+ getEditor,
579
+ setEditor,
580
+ getEvaluationIterations,
581
+ setEvaluationIterations
508
582
  };