@turri-dev/cli 0.1.27 → 0.1.28-next.d5f2680

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 (216) hide show
  1. package/README.md +6 -6
  2. package/dist/advisor-chat.d.ts +63 -0
  3. package/dist/advisor-chat.js +290 -0
  4. package/dist/background-skills.d.ts +53 -0
  5. package/dist/background-skills.js +121 -0
  6. package/dist/bedrock-region.d.ts +66 -0
  7. package/dist/bedrock-region.js +144 -0
  8. package/dist/btw.d.ts +1 -1
  9. package/dist/btw.js +1 -1
  10. package/dist/change-plain-cli.js +20 -13
  11. package/dist/chat-idle.d.ts +7 -0
  12. package/dist/chat-idle.js +20 -0
  13. package/dist/chats.d.ts +10 -0
  14. package/dist/chats.js +23 -0
  15. package/dist/cli-options.d.ts +1 -2
  16. package/dist/cli-options.js +2 -7
  17. package/dist/cli.js +11 -3
  18. package/dist/config-command.d.ts +14 -0
  19. package/dist/config-command.js +35 -15
  20. package/dist/config-edit.d.ts +3 -3
  21. package/dist/config-edit.js +16 -12
  22. package/dist/config.d.ts +54 -34
  23. package/dist/config.js +40 -44
  24. package/dist/conform-cli.js +12 -10
  25. package/dist/conformance-switch.d.ts +34 -0
  26. package/dist/conformance-switch.js +108 -0
  27. package/dist/cultivate-cli.js +15 -5
  28. package/dist/drift-cli.js +2 -0
  29. package/dist/extension.d.ts +15 -0
  30. package/dist/extension.js +260 -83
  31. package/dist/host-session.d.ts +26 -0
  32. package/dist/host-session.js +30 -2
  33. package/dist/host.d.ts +5 -2
  34. package/dist/host.js +7 -1
  35. package/dist/init-config.d.ts +1 -1
  36. package/dist/init-config.js +20 -11
  37. package/dist/loop-cli.d.ts +3 -3
  38. package/dist/loop-cli.js +13 -16
  39. package/dist/loop-tools.js +18 -10
  40. package/dist/model-check.d.ts +8 -3
  41. package/dist/model-check.js +13 -8
  42. package/dist/new-project.js +12 -8
  43. package/dist/{validate-cli.js → parse-cli.js} +11 -5
  44. package/dist/parse-tool.d.ts +9 -0
  45. package/dist/parse-tool.js +33 -0
  46. package/dist/pi-launch.js +1 -1
  47. package/dist/plain/check.d.ts +53 -6
  48. package/dist/plain/check.js +217 -24
  49. package/dist/plain/concepts.d.ts +8 -0
  50. package/dist/plain/concepts.js +66 -23
  51. package/dist/plain/cycles.d.ts +21 -0
  52. package/dist/plain/cycles.js +190 -0
  53. package/dist/plain/errors.d.ts +4 -0
  54. package/dist/plain/errors.js +7 -0
  55. package/dist/plain/files.d.ts +18 -1
  56. package/dist/plain/files.js +39 -2
  57. package/dist/plain/graph.d.ts +33 -4
  58. package/dist/plain/graph.js +60 -12
  59. package/dist/plain/highlight.d.ts +3 -2
  60. package/dist/plain/highlight.js +4 -3
  61. package/dist/plain/index.d.ts +8 -5
  62. package/dist/plain/index.js +8 -5
  63. package/dist/plain/liquid.js +1 -6
  64. package/dist/plain/markdown.d.ts +32 -3
  65. package/dist/plain/markdown.js +146 -24
  66. package/dist/plain/module-concepts.js +2 -2
  67. package/dist/plain/parser.d.ts +83 -28
  68. package/dist/plain/parser.js +381 -260
  69. package/dist/plain/plain.tmLanguage.json +29 -3
  70. package/dist/plain/project.d.ts +48 -0
  71. package/dist/plain/project.js +155 -0
  72. package/dist/plain/spec.d.ts +90 -28
  73. package/dist/plain/spec.js +107 -133
  74. package/dist/plain/test-plain-file.d.ts +59 -0
  75. package/dist/plain/test-plain-file.js +232 -0
  76. package/dist/regenerate/activity.d.ts +20 -9
  77. package/dist/regenerate/activity.js +11 -4
  78. package/dist/regenerate/advisor-records.d.ts +93 -0
  79. package/dist/regenerate/advisor-records.js +110 -0
  80. package/dist/regenerate/advisor-runs.d.ts +87 -0
  81. package/dist/regenerate/advisor-runs.js +327 -0
  82. package/dist/regenerate/base-folder.d.ts +68 -0
  83. package/dist/regenerate/base-folder.js +168 -0
  84. package/dist/regenerate/cases.d.ts +9 -6
  85. package/dist/regenerate/cases.js +70 -14
  86. package/dist/regenerate/change-view.d.ts +8 -3
  87. package/dist/regenerate/change-view.js +71 -22
  88. package/dist/regenerate/chunk-plan.d.ts +36 -15
  89. package/dist/regenerate/chunk-plan.js +165 -59
  90. package/dist/regenerate/conform.d.ts +3 -0
  91. package/dist/regenerate/conform.js +6 -5
  92. package/dist/regenerate/conformance-agents.d.ts +18 -39
  93. package/dist/regenerate/conformance-agents.js +60 -88
  94. package/dist/regenerate/conformance.d.ts +23 -13
  95. package/dist/regenerate/conformance.js +119 -82
  96. package/dist/regenerate/diff-view.d.ts +1 -1
  97. package/dist/regenerate/diff-view.js +20 -4
  98. package/dist/regenerate/drift.d.ts +47 -15
  99. package/dist/regenerate/drift.js +101 -30
  100. package/dist/regenerate/jobs.d.ts +2 -2
  101. package/dist/regenerate/jobs.js +1 -1
  102. package/dist/regenerate/ledger.d.ts +19 -0
  103. package/dist/regenerate/loop.d.ts +62 -43
  104. package/dist/regenerate/loop.js +472 -341
  105. package/dist/regenerate/paths.d.ts +4 -0
  106. package/dist/regenerate/paths.js +7 -1
  107. package/dist/regenerate/plain-palette.js +2 -0
  108. package/dist/regenerate/prompt.d.ts +57 -19
  109. package/dist/regenerate/prompt.js +157 -122
  110. package/dist/regenerate/records.d.ts +43 -12
  111. package/dist/regenerate/records.js +102 -88
  112. package/dist/regenerate/regenerate.js +29 -11
  113. package/dist/regenerate/regression.d.ts +4 -4
  114. package/dist/regenerate/regression.js +14 -10
  115. package/dist/regenerate/renames.d.ts +42 -0
  116. package/dist/regenerate/renames.js +185 -0
  117. package/dist/regenerate/requires.d.ts +1 -1
  118. package/dist/regenerate/requires.js +10 -3
  119. package/dist/regenerate/resources.d.ts +5 -3
  120. package/dist/regenerate/resources.js +4 -4
  121. package/dist/regenerate/scripts-being-written.d.ts +19 -0
  122. package/dist/regenerate/scripts-being-written.js +30 -0
  123. package/dist/regenerate/spec-map-view.d.ts +2 -2
  124. package/dist/regenerate/spec-map-view.js +46 -15
  125. package/dist/regenerate/spec-map.d.ts +27 -5
  126. package/dist/regenerate/spec-map.js +92 -60
  127. package/dist/regenerate/spec-steps.d.ts +48 -5
  128. package/dist/regenerate/spec-steps.js +213 -28
  129. package/dist/regenerate/state.d.ts +4 -3
  130. package/dist/regenerate/stop-report.d.ts +1 -1
  131. package/dist/regenerate/stop-report.js +10 -10
  132. package/dist/regenerate/test-advisor.d.ts +101 -0
  133. package/dist/regenerate/test-advisor.js +379 -0
  134. package/dist/regenerate/test-kinds.d.ts +71 -28
  135. package/dist/regenerate/test-kinds.js +110 -63
  136. package/dist/regenerate/test-scripts.d.ts +2 -0
  137. package/dist/regenerate/test-scripts.js +4 -0
  138. package/dist/regenerate/testing-steps.d.ts +41 -0
  139. package/dist/regenerate/testing-steps.js +110 -0
  140. package/dist/regenerate/testing.d.ts +1 -1
  141. package/dist/regenerate/testing.js +5 -4
  142. package/dist/regenerate/unit-review.d.ts +1 -1
  143. package/dist/regenerate/unit-review.js +3 -3
  144. package/dist/regenerate-cli.js +11 -12
  145. package/dist/release-agent.js +4 -0
  146. package/dist/release-cli.js +2 -0
  147. package/dist/release-tools.js +2 -0
  148. package/dist/run-report.d.ts +2 -2
  149. package/dist/run-report.js +4 -3
  150. package/dist/self-invocation.d.ts +1 -1
  151. package/dist/self-invocation.js +1 -1
  152. package/dist/sentinel.js +1 -1
  153. package/dist/setup.d.ts +10 -0
  154. package/dist/setup.js +52 -4
  155. package/dist/skill.d.ts +10 -0
  156. package/dist/skill.js +6 -0
  157. package/dist/skills.js +3 -1
  158. package/dist/spec-tools.js +21 -31
  159. package/dist/test-plain-files.d.ts +41 -0
  160. package/dist/test-plain-files.js +177 -0
  161. package/docs/README.md +3 -1
  162. package/docs/authoring-plain.md +46 -13
  163. package/docs/chats.md +3 -1
  164. package/docs/config.md +20 -15
  165. package/docs/deploy.md +1 -1
  166. package/docs/development.md +2 -1
  167. package/docs/headless.md +15 -18
  168. package/docs/hosting.md +28 -12
  169. package/docs/installation.md +1 -0
  170. package/docs/parser.md +88 -27
  171. package/docs/regenerating.md +87 -52
  172. package/docs/sentinel.md +1 -1
  173. package/docs/skills-and-gates.md +3 -1
  174. package/docs/test-advisor.md +110 -0
  175. package/docs/theming.md +1 -1
  176. package/docs/using.md +17 -15
  177. package/genome/rules/bullet-continuation.md +8 -8
  178. package/genome/rules/concise-specs-examples.md +111 -80
  179. package/genome/rules/concise-specs-integration-examples.md +56 -41
  180. package/genome/rules/concise-specs.md +17 -16
  181. package/genome/rules/definitions.md +5 -5
  182. package/genome/rules/examples/integration-embedded-testing/run_conformance_tests_java.sh +1 -1
  183. package/genome/rules/func-specs.md +69 -74
  184. package/genome/rules/impl-reqs.md +4 -4
  185. package/genome/rules/integration-embedded-testing.md +20 -20
  186. package/genome/rules/integration-embedded.md +31 -31
  187. package/genome/rules/integration-standalone.md +9 -9
  188. package/genome/rules/integrations.md +18 -18
  189. package/genome/rules/linked-resources.md +19 -16
  190. package/genome/rules/module-structure.md +21 -14
  191. package/genome/rules/project-model.md +18 -17
  192. package/genome/rules/required-concepts.md +1 -1
  193. package/genome/rules/requires-modules.md +6 -5
  194. package/genome/rules/semantic-ids.md +49 -0
  195. package/genome/rules/stdlib.md +4 -5
  196. package/genome/rules/test-plain-files.md +130 -0
  197. package/genome/rules/test-reqs.md +8 -8
  198. package/genome/rules/turri-regeneration.md +23 -8
  199. package/genome/skills/analyze-2-func-specs/SKILL.md +36 -21
  200. package/genome/skills/analyze-func-specs/SKILL.md +46 -32
  201. package/genome/skills/break-down-func-spec/SKILL.md +91 -67
  202. package/genome/skills/consolidate-concepts/SKILL.md +10 -10
  203. package/genome/skills/convert-old-syntax/SKILL.md +68 -0
  204. package/genome/skills/convert-old-syntax/references/rubric.md +11 -0
  205. package/genome/skills/debug-specs/SKILL.md +62 -56
  206. package/genome/skills/implement-conformance-testing-script/SKILL.md +19 -15
  207. package/genome/skills/implement-conformance-testing-script/assets/run_conformance_tests_java.sh +2 -2
  208. package/genome/skills/implement-conformance-testing-script/assets/run_conformance_tests_python.sh +2 -2
  209. package/genome/skills/implement-unit-testing-script/SKILL.md +14 -10
  210. package/genome/skills/refactor-module/SKILL.md +35 -35
  211. package/genome/skills/resolve-section-ownership/SKILL.md +9 -9
  212. package/genome/skills/resolve-spec-conflict/SKILL.md +35 -29
  213. package/package.json +7 -6
  214. package/dist/regenerate/choose-conformance.d.ts +0 -32
  215. package/dist/regenerate/choose-conformance.js +0 -117
  216. /package/dist/{validate-cli.d.ts → parse-cli.d.ts} +0 -0
@@ -21,7 +21,6 @@ const ROLE_ABOUT = {
21
21
  default: "every role not named",
22
22
  chat: "the conversation - as harness-model, which it wins over",
23
23
  sentinel: "the sentinel: checks every finished pulse and tests the release",
24
- chooser: "chooses what gets conformance tests under turri regenerate",
25
24
  planner: "cuts the work into pulses",
26
25
  diagnosis: "looks into a pulse that failed for good",
27
26
  release: "the release agent",
@@ -33,6 +32,7 @@ const ROLE_ABOUT = {
33
32
  judge: "judges a failing conformance run - as judge-model, which it wins over",
34
33
  arbiter: "weighs a second review",
35
34
  debugger: "a fresh look at unit tests that keep failing the same way",
35
+ advisor: "the test advisor: whether a new or changed functional spec needs scenarios",
36
36
  };
37
37
  /** Every setting, in the order the list shows them. */
38
38
  export function settings(rules = []) {
@@ -60,13 +60,15 @@ export function settings(rules = []) {
60
60
  { key: "coding-model", about: "the model that writes the code", kind: "model", unset: "harness-model", effect: "next-pulse" },
61
61
  { key: "judge-model", about: "the judge and the test review of a conformance run", kind: "model", unset: "coding-model", effect: "next-pulse" },
62
62
  { key: "module", about: "the .plain file turri regenerate builds when none is named", kind: "path", unset: "the folder's .plain files", effect: "next-regenerate", projectOnly: true },
63
- { key: "conformance-tests", about: "which functional specs get conformance tests", kind: "choice", options: ["all", "chosen", "module", "false"], unset: "all, where a module has test reqs", effect: "next-plan" },
64
- { key: "conformance-budget", about: "under conformance-tests: chosen or module, how many may be chosen - a count or a share", kind: "budget", options: ["10%", "30%", "50%", "5", "10"], unset: "no limit", effect: "next-plan" },
65
63
  { key: "review", about: "whether the code and its tests are reviewed once they pass", kind: "boolean", unset: "true", effect: "next-pulse" },
66
64
  { key: "mutation-testing", about: "whether the coding agent and the reviewer can put a bug in the code for one test run (can_it_fail)", kind: "boolean", unset: "true", effect: "next-pulse" },
67
65
  { key: "allow-to-stop-jobs", about: "whether turri stops a running pulse the ***plain has moved on from", kind: "boolean", unset: "true", effect: "now" },
68
66
  { key: "release-after-pulse", about: "whether every pulse that lands code releases it", kind: "boolean", unset: "false", effect: "next-landing" },
69
67
  { key: "sentinel", about: "whether a chat of its own checks every finished pulse, tests the release, and tells you what is wrong - ask: you are asked before it first opens", kind: "choice", options: ["ask", "true", "false"], unset: "ask", effect: "next-landing" },
68
+ { key: "test-advisor", about: "whether turri checks each new or changed functional spec with no scenarios in the background, to see whether it needs scenarios - on a yes, the chat writes them", kind: "boolean", unset: "true", effect: "now" },
69
+ { key: "conformance-tests", about: "whether functional specs' scenarios are written and conformance tested - false: none, the test advisor and conform off", kind: "boolean", unset: "false", effect: "now" },
70
+ { key: "test-dir", about: "the folder of the test plain files, a folder per module in it, by path from the project root", kind: "path", unset: "tests", effect: "now" },
71
+ { key: "base-folder", about: "a folder a codebase that requires no other module starts from, by path from the project root - code to build on, files to use, copied in once", kind: "path", unset: "none: it starts empty", effect: "next-pulse" },
70
72
  { key: "unittests-script", about: "the unit testing script, by path from the project root", kind: "path", unset: "the one run_unittests*.sh found", effect: "next-test-run" },
71
73
  { key: "conformance-tests-script", about: "the conformance testing script, by path from the project root", kind: "path", unset: "the one run_conformance_tests*.sh found", effect: "next-test-run" },
72
74
  { key: "prepare-environment-script", about: "run on the build before every conformance testing script run, by path from the project root - optional", kind: "path", unset: "the one prepare_environment*.sh found, else none", effect: "next-test-run" },
@@ -128,14 +130,6 @@ export function parseValue(setting, typed, known) {
128
130
  return { error: `${setting.key} is a whole number of at least ${setting.min ?? 0}.` };
129
131
  return { value: number };
130
132
  }
131
- case "budget": {
132
- if (/^\d+$/.test(text))
133
- return { value: Number(text) };
134
- const share = /^(\d+(?:\.\d+)?)\s*%$/.exec(text);
135
- if (share !== null && Number(share[1]) <= 100)
136
- return { value: `${share[1]}%` };
137
- return { error: `${setting.key} is a count, such as 5, or a share, such as 30%.` };
138
- }
139
133
  case "model": {
140
134
  const { model, thinking } = splitModelSpec(text);
141
135
  const colon = text.lastIndexOf(":");
@@ -351,7 +345,7 @@ export function writeSetting(dir, key, value) {
351
345
  writeFileSync(join(dir, CONFIG_FILE), text);
352
346
  return text;
353
347
  }
354
- /** The files a path setting is offered: the testing scripts in the root and test_scripts/, or the .plain files of the folder. */
348
+ /** The files a path setting is offered: the testing scripts in the root and test_scripts/, the .plain files of the folder, or - the test folder - its folders. */
355
349
  export function pathOptions(dir, key) {
356
350
  const list = (folder, test) => {
357
351
  try {
@@ -365,6 +359,16 @@ export function pathOptions(dir, key) {
365
359
  };
366
360
  if (key === "module")
367
361
  return list("", (name) => name.endsWith(".plain")).sort();
362
+ if (key === "test-dir" || key === "base-folder") {
363
+ const own = key === "test-dir" ? ["tests"] : [];
364
+ try {
365
+ const folders = readdirSync(dir).filter((name) => !name.startsWith(".") && name !== "plain_modules" && name !== "node_modules" && statSync(join(dir, name)).isDirectory());
366
+ return [...new Set([...own, ...folders])].sort();
367
+ }
368
+ catch {
369
+ return own;
370
+ }
371
+ }
368
372
  const prefix = key === "unittests-script" ? "run_unittests" : key === "conformance-tests-script" ? "run_conformance_tests" : "prepare_environment";
369
373
  const script = (name) => name.startsWith(prefix) && /\.(sh|ps1)$/.test(name);
370
374
  return [...list("", script), ...list("test_scripts", script)].sort();
package/dist/config.d.ts CHANGED
@@ -5,6 +5,9 @@
5
5
  *
6
6
  * ```yaml
7
7
  * module: prism_cli.plain # what `turri regenerate` builds by default
8
+ * conformance-tests: false # whether scenarios are written and conformance tested - false: none, the test advisor off (default: false)
9
+ * test-dir: tests # where the test plain files are, a folder per module: tests/<module>/ (default: tests)
10
+ * base-folder: existing-app # a codebase that requires none starts as a copy of it - code to build on, assets to use
8
11
  * harness-model: # the model you chat with in `turri`
9
12
  * model: anthropic/claude-opus-5-5
10
13
  * thinking: high
@@ -13,12 +16,11 @@
13
16
  * thinking: medium
14
17
  * judge-model: # the judge and the test review (default: coding-model)
15
18
  * model: google/gemini-3.1-pro
16
- * conformance-tests: chosen # all, chosen (those with acceptance tests, and those the chooser picks after each pulse), module (the chooser picks, and plans, once the module is regenerated) or false (default: false)
17
- * conformance-budget: 30% # under chosen or module: how many functional specs a module may have chosen, beside those with acceptance tests - a count or a share (default: no limit)
18
19
  * review: false # review the code and its tests once they pass (default: true)
19
20
  * mutation-testing: false # give the coding agent and the reviewer can_it_fail (default: true)
20
21
  * allow-to-stop-jobs: false # stop a running job the spec moved on from (default: true)
21
22
  * release-after-pulse: true # release what each pulse lands, as its last stage, before the next pulse (default: false)
23
+ * test-advisor: false # check each new or changed functional spec with no scenarios for whether it needs them - on a yes, the chat writes them (default: true)
22
24
  * sentinel: true # a chat of its own every finished pulse goes to, which tests the release and tells you what is wrong: true, false, or ask - the person asked before it first opens in a session (default: ask)
23
25
  * rules-off: [integrations] # ***plain rules to leave out of the prompts, by name (default: none)
24
26
  * unittests-script: test_scripts/run_unittests.sh # the testing scripts - see test-scripts.ts
@@ -126,9 +128,10 @@ export interface ModelChoice {
126
128
  /**
127
129
  * The agents turri starts, by what they do - each can be given its own model, thinking and turn limit (`models:`).
128
130
  * The code fixer of a conformance run and the repair agent are coding agents; the unit-test and conformance arbiters
129
- * are both `arbiter`.
131
+ * are both `arbiter`. The test advisor's calls - classifying a functional spec, its probes, its readers, its verifier -
132
+ * are `advisor`.
130
133
  */
131
- export declare const AGENT_ROLES: readonly ["chat", "sentinel", "chooser", "planner", "diagnosis", "release", "coding", "conformance", "explorer", "reviewer", "test-reviewer", "judge", "arbiter", "debugger"];
134
+ export declare const AGENT_ROLES: readonly ["chat", "sentinel", "planner", "diagnosis", "release", "coding", "conformance", "explorer", "reviewer", "test-reviewer", "judge", "arbiter", "debugger", "advisor"];
132
135
  export type AgentRole = (typeof AGENT_ROLES)[number];
133
136
  /**
134
137
  * How hard each role thinks when nothing names a level - not the config's `models:`, nor a `:level` on the model it is
@@ -165,6 +168,12 @@ export declare function projectModels(config: Pick<ProjectConfig, "harnessModel"
165
168
  coding?: ModelChoice;
166
169
  judge?: ModelChoice;
167
170
  };
171
+ /**
172
+ * What a skill run from the command line runs on: the project's harness model, as a skill in the chat runs on the
173
+ * chat's - or its coding model, for a skill that names it (`metadata.model: coding`) - undefined, and pi's default,
174
+ * when the project names none.
175
+ */
176
+ export declare function skillModel(root: string, role?: "harness" | "coding"): string | undefined;
168
177
  /**
169
178
  * What the config itself says a role runs on - its own entry, the legacy key that names it (judge-model for the judge
170
179
  * and the test review), then `default` (the chat's side: the chat's model instead) - or nothing when it says nothing
@@ -172,6 +181,11 @@ export declare function projectModels(config: Pick<ProjectConfig, "harnessModel"
172
181
  * The coding role always runs on what it is given: its config is already in it (projectModels).
173
182
  */
174
183
  export declare function roleModel(config: Pick<ProjectConfig, "harnessModel" | "judgeModel" | "models">, role: AgentRole): ModelChoice | undefined;
184
+ /**
185
+ * What the test advisor's calls run on: `models.advisor` - else `default` - and without either the coding
186
+ * model alone, thinking as the role has it (ROLE_THINKING). Undefined when the config names no model at all.
187
+ */
188
+ export declare function advisorModel(config: ProjectConfig): string | undefined;
175
189
  /** How long each turn of a role's agents may take, in milliseconds: its own, `default`'s, `turn-limit:`'s - or undefined, the harness's default. */
176
190
  export declare function roleTurnLimitMs(config: Pick<ProjectConfig, "models" | "turnLimit">, role: AgentRole | undefined): number | undefined;
177
191
  /** `sentinel:` - on, off, or `ask`: on once the person says so, asked before it first opens in a session. */
@@ -188,24 +202,6 @@ export interface ProjectConfig {
188
202
  * the code, the tests or the spec is wrong, and the test review. Unset: the coding model.
189
203
  */
190
204
  judgeModel?: ModelChoice;
191
- /**
192
- * Whether conformance tests are written and run, and for what. true (`all`): every functional spec the code is built
193
- * from. "chosen": the ones with acceptance tests, and those the chooser picks from what each code pulse regenerated, as
194
- * the pulse ends. "module": the same, but the chooser is asked once, when the whole module is regenerated - what to test,
195
- * and in which pulses. Under both, those the person asks for with conform too, and a choice is kept once its tests land.
196
- * false: none, unless the person asks. Unset: none, as with false.
197
- */
198
- conformanceTests?: boolean | "chosen" | "module";
199
- /**
200
- * Under `conformance-tests: chosen`: how many of a module's functional specs may be chosen for conformance tests, beside
201
- * those with acceptance tests - a count, or a share of the module's functional specs (rounded up, at least one).
202
- * Every choice for the module counts, whenever it was made; the person's own conform is not limited. Unset: no limit.
203
- */
204
- conformanceBudget?: {
205
- count: number;
206
- } | {
207
- share: number;
208
- };
209
205
  /**
210
206
  * Whether the code and its unit tests - and the conformance tests - are reviewed once they pass: two reviews at
211
207
  * most, the second weighed by the arbiter. false: the work goes on once its tests pass. Unset: false.
@@ -234,6 +230,30 @@ export interface ProjectConfig {
234
230
  * asked, before it first opens in a session, whether to start it. Unset: ask.
235
231
  */
236
232
  sentinel?: SentinelSetting;
233
+ /**
234
+ * Whether the test advisor starts by itself: in the chat and a host, each new or changed functional spec with no
235
+ * scenarios is classified in the background, and on a yes the chat writes its scenarios (docs/test-advisor.md). false
236
+ * turns off only that: the chat's evaluate_tests still works, and asked for scenarios, the chat writes them as before.
237
+ * Unset: true.
238
+ */
239
+ testAdvisor?: boolean;
240
+ /**
241
+ * The folder of the test plain files, from the project's folder: a functional spec's scenarios are in its test plain
242
+ * file in `<test-dir>/<module>/`. Unset: `tests`.
243
+ */
244
+ testDir?: string;
245
+ /**
246
+ * Whether functional specs' scenarios are written and conformance tested (conformance-switch.ts). False: none - no
247
+ * conformance pulse, no conformance testing script, the test advisor and the chat's conform and evaluate_tests off; the
248
+ * test plain files there are kept, and not tested. The person asking for tests, or agreeing to the chat's offer, turns it
249
+ * on. Unset: false.
250
+ */
251
+ conformanceTests?: boolean;
252
+ /**
253
+ * A folder, from the project's folder, that a codebase requiring no other module starts from - a copy of it, once,
254
+ * before its first pulse: code to build on, files to use (src/regenerate/base-folder.ts). Unset: it starts empty.
255
+ */
256
+ baseFolder?: string;
237
257
  /** Path from the root to the unit testing script. */
238
258
  unittestsScript?: string;
239
259
  /** Path from the root to the conformance testing script. */
@@ -303,13 +323,15 @@ export declare const CONFIG_KEYS: {
303
323
  readonly harnessModel: "harness-model";
304
324
  readonly codingModel: "coding-model";
305
325
  readonly judgeModel: "judge-model";
306
- readonly conformanceTests: "conformance-tests";
307
- readonly conformanceBudget: "conformance-budget";
308
326
  readonly review: "review";
309
327
  readonly mutationTesting: "mutation-testing";
310
328
  readonly allowToStopJobs: "allow-to-stop-jobs";
311
329
  readonly releaseAfterPulse: "release-after-pulse";
312
330
  readonly sentinel: "sentinel";
331
+ readonly testAdvisor: "test-advisor";
332
+ readonly testDir: "test-dir";
333
+ readonly conformanceTests: "conformance-tests";
334
+ readonly baseFolder: "base-folder";
313
335
  readonly unittestsScript: "unittests-script";
314
336
  readonly conformanceTestsScript: "conformance-tests-script";
315
337
  readonly prepareEnvironmentScript: "prepare-environment-script";
@@ -327,12 +349,6 @@ export declare const CONFIG_KEYS: {
327
349
  readonly models: "models";
328
350
  readonly turnLimit: "turn-limit";
329
351
  };
330
- /** Whether `conformance-tests:` turns the conformance tests on: all (true), chosen or module. Not set, they are off, as with false. */
331
- export declare function conformanceSwitchedOn(setting: ProjectConfig["conformanceTests"]): boolean;
332
- /** When the chooser decides which functional specs get conformance tests: after each code pulse, once the module is regenerated, or never - every one, or none. */
333
- export declare function choosingWhen(setting: ProjectConfig["conformanceTests"]): "pulse" | "module" | undefined;
334
- /** How many functional specs a module of `count` may have chosen under a budget: the count, or the share rounded up - at least one. */
335
- export declare function budgetFor(budget: NonNullable<ProjectConfig["conformanceBudget"]>, count: number): number;
336
352
  /**
337
353
  * The project's config - with a stack's over it, when one is named - or nothing of it when there is no file or it does
338
354
  * not parse.
@@ -340,12 +356,12 @@ export declare function budgetFor(budget: NonNullable<ProjectConfig["conformance
340
356
  export declare function readProjectConfig(root: string, stack?: string): ProjectConfig;
341
357
  /**
342
358
  * What a command's own options say of the config's keys - `turri regenerate --harness-model`, `--coding-model`,
343
- * `--judge-model`, `--conformance-tests`, `--review`, `--mutation-testing` - read as if the file had them: each takes its key's value, and
359
+ * `--judge-model`, `--review`, `--mutation-testing` - read as if the file had them: each takes its key's value, and
344
360
  * every key keeps its place in the order, so a run is the same as one with them in config.turri.yaml - a `models:`
345
361
  * entry still winning over `harness-model`, `coding-model` or `judge-model`. A headless run needs no config file
346
362
  * edited. Never set in the conversation.
347
363
  */
348
- type RunOverrides = Partial<Pick<ProjectConfig, "harnessModel" | "codingModel" | "judgeModel" | "conformanceTests" | "review" | "mutationTesting">>;
364
+ type RunOverrides = Partial<Pick<ProjectConfig, "harnessModel" | "codingModel" | "judgeModel" | "review" | "mutationTesting">>;
349
365
  /** Megabytes of package caches a project keeps when `cache-keep:` does not say. */
350
366
  export declare const DEFAULT_CACHE_KEEP_MB = 4096;
351
367
  /**
@@ -355,10 +371,14 @@ export declare const DEFAULT_CACHE_KEEP_MB = 4096;
355
371
  export declare function debugMode(project: string): boolean;
356
372
  /** Read a command's options as the config's keys for the rest of this process. */
357
373
  export declare function overrideConfig(overrides: RunOverrides): void;
358
- /** `--conformance-tests <value>`: the config's own values - all (or true), chosen, module, false. Undefined for anything else. */
359
- export declare function conformanceOption(value: string): ProjectConfig["conformanceTests"] | undefined;
360
374
  /** `--review <value>`, `--mutation-testing <value>`: the config's own, true or false. Undefined for anything else. */
361
375
  export declare function booleanOption(value: string): boolean | undefined;
376
+ /** Where the test plain files are when `test-dir:` does not say. */
377
+ export declare const DEFAULT_TEST_DIR = "tests";
378
+ /** The folder of a module's project's test plain files: `test-dir:` - its stack's over the project's - from the project's folder. */
379
+ export declare function testDirOf(plainFile: string): string;
362
380
  /** The config a spec is built with: its project's, with its module's stack over it (`stackForModule`). */
363
381
  export declare function configForSpec(plainFile: string): ProjectConfig;
382
+ /** One config file, read, or nothing of it when it is not there or does not parse. */
383
+ export declare function readConfigFile(path: string): ProjectConfig;
364
384
  export {};
package/dist/config.js CHANGED
@@ -11,6 +11,9 @@ import { projectDirOf } from "./regenerate/paths.js";
11
11
  *
12
12
  * ```yaml
13
13
  * module: prism_cli.plain # what `turri regenerate` builds by default
14
+ * conformance-tests: false # whether scenarios are written and conformance tested - false: none, the test advisor off (default: false)
15
+ * test-dir: tests # where the test plain files are, a folder per module: tests/<module>/ (default: tests)
16
+ * base-folder: existing-app # a codebase that requires none starts as a copy of it - code to build on, assets to use
14
17
  * harness-model: # the model you chat with in `turri`
15
18
  * model: anthropic/claude-opus-5-5
16
19
  * thinking: high
@@ -19,12 +22,11 @@ import { projectDirOf } from "./regenerate/paths.js";
19
22
  * thinking: medium
20
23
  * judge-model: # the judge and the test review (default: coding-model)
21
24
  * model: google/gemini-3.1-pro
22
- * conformance-tests: chosen # all, chosen (those with acceptance tests, and those the chooser picks after each pulse), module (the chooser picks, and plans, once the module is regenerated) or false (default: false)
23
- * conformance-budget: 30% # under chosen or module: how many functional specs a module may have chosen, beside those with acceptance tests - a count or a share (default: no limit)
24
25
  * review: false # review the code and its tests once they pass (default: true)
25
26
  * mutation-testing: false # give the coding agent and the reviewer can_it_fail (default: true)
26
27
  * allow-to-stop-jobs: false # stop a running job the spec moved on from (default: true)
27
28
  * release-after-pulse: true # release what each pulse lands, as its last stage, before the next pulse (default: false)
29
+ * test-advisor: false # check each new or changed functional spec with no scenarios for whether it needs them - on a yes, the chat writes them (default: true)
28
30
  * sentinel: true # a chat of its own every finished pulse goes to, which tests the release and tells you what is wrong: true, false, or ask - the person asked before it first opens in a session (default: ask)
29
31
  * rules-off: [integrations] # ***plain rules to leave out of the prompts, by name (default: none)
30
32
  * unittests-script: test_scripts/run_unittests.sh # the testing scripts - see test-scripts.ts
@@ -214,9 +216,10 @@ export const THINKING_LEVELS = ["off", "minimal", "low", "medium", "high", "xhig
214
216
  /**
215
217
  * The agents turri starts, by what they do - each can be given its own model, thinking and turn limit (`models:`).
216
218
  * The code fixer of a conformance run and the repair agent are coding agents; the unit-test and conformance arbiters
217
- * are both `arbiter`.
219
+ * are both `arbiter`. The test advisor's calls - classifying a functional spec, its probes, its readers, its verifier -
220
+ * are `advisor`.
218
221
  */
219
- export const AGENT_ROLES = ["chat", "sentinel", "chooser", "planner", "diagnosis", "release", "coding", "conformance", "explorer", "reviewer", "test-reviewer", "judge", "arbiter", "debugger"];
222
+ export const AGENT_ROLES = ["chat", "sentinel", "planner", "diagnosis", "release", "coding", "conformance", "explorer", "reviewer", "test-reviewer", "judge", "arbiter", "debugger", "advisor"];
220
223
  /**
221
224
  * How hard each role thinks when nothing names a level - not the config's `models:`, nor a `:level` on the model it is
222
225
  * given. The agents that do the work - write the code and the tests, explore, release - think little: they work from a
@@ -228,19 +231,19 @@ export const ROLE_THINKING = {
228
231
  conformance: "low",
229
232
  explorer: "low",
230
233
  release: "low",
234
+ advisor: "low",
231
235
  reviewer: "medium",
232
236
  "test-reviewer": "medium",
233
237
  judge: "medium",
234
238
  arbiter: "medium",
235
239
  debugger: "medium",
236
240
  planner: "medium",
237
- chooser: "medium",
238
241
  diagnosis: "medium",
239
242
  };
240
243
  /** The roles on the conversation's side: without their own entry they take the chat's model, not `default`. */
241
244
  // The release is not: it follows steps - a script, a start command - and runs on the coding model, thinking low. Nor
242
245
  // is the diagnosis: a post-mortem of a job that failed, read by the person - it runs on the coding model, thinking medium.
243
- const CHAT_SIDE = ["chat", "sentinel", "chooser", "planner"];
246
+ const CHAT_SIDE = ["chat", "sentinel", "planner"];
244
247
  function isThinkingLevel(value) {
245
248
  return typeof value === "string" && THINKING_LEVELS.includes(value);
246
249
  }
@@ -295,6 +298,14 @@ export function projectModels(config) {
295
298
  const codingModel = coding?.model !== undefined ? { model: coding.model } : undefined;
296
299
  return { harness, coding, judge: inheritModel(choiceOf(models.judge), inheritModel(config.judgeModel, inheritModel(choiceOf(models.default), codingModel))) };
297
300
  }
301
+ /**
302
+ * What a skill run from the command line runs on: the project's harness model, as a skill in the chat runs on the
303
+ * chat's - or its coding model, for a skill that names it (`metadata.model: coding`) - undefined, and pi's default,
304
+ * when the project names none.
305
+ */
306
+ export function skillModel(root, role = "harness") {
307
+ return modelSpec(projectModels(readProjectConfig(root, stackOf(root)))[role]);
308
+ }
298
309
  /** A role entry's model and thinking alone. */
299
310
  function choiceOf(entry) {
300
311
  if (entry === undefined || (entry.model === undefined && entry.thinking === undefined))
@@ -320,6 +331,14 @@ export function roleModel(config, role) {
320
331
  const legacy = role === "judge" || role === "test-reviewer" ? config.judgeModel : undefined;
321
332
  return inheritModel(own, inheritModel(legacy, choiceOf(models.default)));
322
333
  }
334
+ /**
335
+ * What the test advisor's calls run on: `models.advisor` - else `default` - and without either the coding
336
+ * model alone, thinking as the role has it (ROLE_THINKING). Undefined when the config names no model at all.
337
+ */
338
+ export function advisorModel(config) {
339
+ const coding = projectModels(config).coding?.model;
340
+ return modelSpec(inheritModel(roleModel(config, "advisor"), coding !== undefined ? { model: coding } : undefined));
341
+ }
323
342
  /** How long each turn of a role's agents may take, in milliseconds: its own, `default`'s, `turn-limit:`'s - or undefined, the harness's default. */
324
343
  export function roleTurnLimitMs(config, role) {
325
344
  const models = config.models ?? {};
@@ -377,13 +396,15 @@ export const CONFIG_KEYS = {
377
396
  harnessModel: "harness-model",
378
397
  codingModel: "coding-model",
379
398
  judgeModel: "judge-model",
380
- conformanceTests: "conformance-tests",
381
- conformanceBudget: "conformance-budget",
382
399
  review: "review",
383
400
  mutationTesting: "mutation-testing",
384
401
  allowToStopJobs: "allow-to-stop-jobs",
385
402
  releaseAfterPulse: "release-after-pulse",
386
403
  sentinel: "sentinel",
404
+ testAdvisor: "test-advisor",
405
+ testDir: "test-dir",
406
+ conformanceTests: "conformance-tests",
407
+ baseFolder: "base-folder",
387
408
  unittestsScript: "unittests-script",
388
409
  conformanceTestsScript: "conformance-tests-script",
389
410
  prepareEnvironmentScript: "prepare-environment-script",
@@ -404,34 +425,6 @@ export const CONFIG_KEYS = {
404
425
  function whatScriptsRunOn(value) {
405
426
  return value === "copy" || value === "in-place" ? value : undefined;
406
427
  }
407
- /** `conformance-tests:` - true or all, chosen, module, false. Anything else is not read. */
408
- function conformanceSetting(value) {
409
- if (typeof value === "boolean")
410
- return value;
411
- const word = typeof value === "string" ? value.trim().toLowerCase() : undefined;
412
- return word === "all" ? true : word === "chosen" ? "chosen" : word === "module" ? "module" : word === "false" ? false : word === "true" ? true : undefined;
413
- }
414
- /** Whether `conformance-tests:` turns the conformance tests on: all (true), chosen or module. Not set, they are off, as with false. */
415
- export function conformanceSwitchedOn(setting) {
416
- return setting === true || setting === "chosen" || setting === "module";
417
- }
418
- /** When the chooser decides which functional specs get conformance tests: after each code pulse, once the module is regenerated, or never - every one, or none. */
419
- export function choosingWhen(setting) {
420
- return setting === "chosen" ? "pulse" : setting === "module" ? "module" : undefined;
421
- }
422
- /** `conformance-budget:` - a whole number, or a share such as `30%`. Anything else is not read. */
423
- function budgetSetting(value) {
424
- if (typeof value === "number" && Number.isInteger(value) && value >= 0)
425
- return { count: value };
426
- const share = typeof value === "string" ? /^\s*(\d+(?:\.\d+)?)\s*%\s*$/.exec(value) : null;
427
- if (share !== null && Number(share[1]) <= 100)
428
- return { share: Number(share[1]) / 100 };
429
- return undefined;
430
- }
431
- /** How many functional specs a module of `count` may have chosen under a budget: the count, or the share rounded up - at least one. */
432
- export function budgetFor(budget, count) {
433
- return "count" in budget ? budget.count : Math.max(1, Math.ceil(budget.share * count));
434
- }
435
428
  function text(value) {
436
429
  return typeof value === "string" && value.trim() !== "" ? value.trim() : undefined;
437
430
  }
@@ -483,10 +476,6 @@ export function debugMode(project) {
483
476
  export function overrideConfig(overrides) {
484
477
  runOverrides = { ...overrides };
485
478
  }
486
- /** `--conformance-tests <value>`: the config's own values - all (or true), chosen, module, false. Undefined for anything else. */
487
- export function conformanceOption(value) {
488
- return conformanceSetting(value);
489
- }
490
479
  /** `--review <value>`, `--mutation-testing <value>`: the config's own, true or false. Undefined for anything else. */
491
480
  export function booleanOption(value) {
492
481
  const word = value.trim().toLowerCase();
@@ -530,13 +519,19 @@ function agentEnvSetting(value) {
530
519
  function withoutUndefined(config) {
531
520
  return Object.fromEntries(Object.entries(config).filter(([, value]) => value !== undefined));
532
521
  }
522
+ /** Where the test plain files are when `test-dir:` does not say. */
523
+ export const DEFAULT_TEST_DIR = "tests";
524
+ /** The folder of a module's project's test plain files: `test-dir:` - its stack's over the project's - from the project's folder. */
525
+ export function testDirOf(plainFile) {
526
+ return resolve(projectDirOf(resolve(plainFile)), configForSpec(plainFile).testDir ?? DEFAULT_TEST_DIR);
527
+ }
533
528
  /** The config a spec is built with: its project's, with its module's stack over it (`stackForModule`). */
534
529
  export function configForSpec(plainFile) {
535
530
  const root = projectDirOf(resolve(plainFile));
536
531
  return readProjectConfig(root, stackForModule(plainFile));
537
532
  }
538
533
  /** One config file, read, or nothing of it when it is not there or does not parse. */
539
- function readConfigFile(path) {
534
+ export function readConfigFile(path) {
540
535
  let parsed;
541
536
  try {
542
537
  if (!statSync(path).isFile())
@@ -549,19 +544,20 @@ function readConfigFile(path) {
549
544
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed))
550
545
  return {};
551
546
  const raw = Object.fromEntries(Object.entries(parsed).map(([key, value]) => [key.replace(/_/g, "-"), value]));
552
- const conformance = raw[CONFIG_KEYS.conformanceTests];
553
547
  return {
554
548
  module: text(raw[CONFIG_KEYS.module]),
555
549
  harnessModel: modelChoice(raw[CONFIG_KEYS.harnessModel]),
556
550
  codingModel: modelChoice(raw[CONFIG_KEYS.codingModel]) ?? modelChoice(raw.model),
557
551
  judgeModel: modelChoice(raw[CONFIG_KEYS.judgeModel]),
558
- conformanceTests: conformanceSetting(conformance),
559
- conformanceBudget: budgetSetting(raw[CONFIG_KEYS.conformanceBudget]),
560
552
  review: typeof raw[CONFIG_KEYS.review] === "boolean" ? raw[CONFIG_KEYS.review] : undefined,
561
553
  mutationTesting: typeof raw[CONFIG_KEYS.mutationTesting] === "boolean" ? raw[CONFIG_KEYS.mutationTesting] : undefined,
562
554
  allowToStopJobs: typeof raw[CONFIG_KEYS.allowToStopJobs] === "boolean" ? raw[CONFIG_KEYS.allowToStopJobs] : undefined,
563
555
  releaseAfterPulse: typeof raw[CONFIG_KEYS.releaseAfterPulse] === "boolean" ? raw[CONFIG_KEYS.releaseAfterPulse] : undefined,
564
556
  sentinel: typeof raw[CONFIG_KEYS.sentinel] === "boolean" || raw[CONFIG_KEYS.sentinel] === "ask" ? raw[CONFIG_KEYS.sentinel] : undefined,
557
+ testAdvisor: typeof raw[CONFIG_KEYS.testAdvisor] === "boolean" ? raw[CONFIG_KEYS.testAdvisor] : undefined,
558
+ testDir: text(raw[CONFIG_KEYS.testDir]),
559
+ conformanceTests: typeof raw[CONFIG_KEYS.conformanceTests] === "boolean" ? raw[CONFIG_KEYS.conformanceTests] : undefined,
560
+ baseFolder: text(raw[CONFIG_KEYS.baseFolder]),
565
561
  unittestsScript: text(raw[CONFIG_KEYS.unittestsScript]),
566
562
  conformanceTestsScript: text(raw[CONFIG_KEYS.conformanceTestsScript]),
567
563
  prepareEnvironmentScript: text(raw[CONFIG_KEYS.prepareEnvironmentScript]),
@@ -1,23 +1,25 @@
1
1
  import { parseArgs } from "./cli-options.js";
2
2
  import { headlessOptions, runLoop } from "./loop-cli.js";
3
- const USAGE = `usage: turri conform <file.plain> [frid ...] [options]
3
+ const USAGE = `usage: turri conform <file.plain> [module:func-id ...] [options]
4
4
 
5
- Writes and runs the black-box conformance tests of a module's functional specs - those named, or
6
- every one - on the code as it is built, as the chat's conform does, whatever the config's
7
- conformance-tests says: from the spec's test reqs and acceptance tests, with the whole suite the
8
- module inherits, a failure fixed in the test or the code, whichever is wrong. Every functional spec
9
- tested goes in one pulse, as far as the size guardrail lets.
5
+ Writes and runs the black-box conformance tests of a module's functional specs - those named, each
6
+ as module:func-id, or every one with scenarios - on the code as it is built, as the chat's conform does:
7
+ exactly their conformance and acceptance scenarios, following the spec's test reqs, with the whole suite
8
+ the module inherits, a failure fixed in the test or the code, whichever is wrong. A functional spec with
9
+ no scenarios is refused: write them first. So is a module with no test reqs, or no conformance testing
10
+ script for its stack: the refusal names the next step. Every functional spec tested goes in one pulse,
11
+ as far as the size guardrail lets.
10
12
 
11
13
  --one-by-one a pulse a functional spec instead
12
- --harness-model <p/id> config.turri.yaml's harness-model for this run: the planner, the conformance chooser, a diagnosis
14
+ --harness-model <p/id> config.turri.yaml's harness-model for this run: the planner, a diagnosis
13
15
  --coding-model <p/id> its coding-model, --model too: the agents that build
14
16
  --judge-model <p/id> its judge-model: the judge and the test review
15
17
  --review <true|false> its review: whether the code and its tests are reviewed once they pass
16
18
  --build-dir <dir> as the run ends, export the code there (see turri regenerate --help)
17
19
  --report <file.json> write a report of the run there (see turri regenerate --help)`;
18
20
  const { positional, options } = parseArgs(process.argv.slice(2), ["--one-by-one"], USAGE, ["--build-dir", "--report", "--harness-model", "--judge-model", "--review"]);
19
- const { report, buildDir } = headlessOptions(options, false);
20
- const [plainFile, ...frids] = positional;
21
+ const { report, buildDir } = headlessOptions(options);
22
+ const [plainFile, ...funcIds] = positional;
21
23
  if (plainFile === undefined) {
22
24
  console.error(USAGE);
23
25
  process.exit(1);
@@ -28,7 +30,7 @@ runLoop({
28
30
  ...(report !== undefined ? { report } : {}),
29
31
  command: ["conform", ...process.argv.slice(2)],
30
32
  ask: (loop) => loop.conformance(plainFile, {
31
- ...(frids.length > 0 ? { frids } : {}),
33
+ ...(funcIds.length > 0 ? { funcIds } : {}),
32
34
  ...(options["one-by-one"] !== undefined ? { separately: true } : {}),
33
35
  }),
34
36
  }).catch((error) => {
@@ -0,0 +1,34 @@
1
+ import { type ToolDefinition } from "@earendil-works/pi-coding-agent";
2
+ /**
3
+ * Whether a project's functional specs are conformance tested: `conformance-tests:` in its config, a stack's own over the
4
+ * project's, false when unset. Off, nothing of conformance testing runs - no conformance pulse, no conformance testing
5
+ * script, the test advisor and the chat's conform and evaluate_tests off; the test plain files there are kept, and not
6
+ * tested. The chat always knows it, and how they are turned on: the person asking for tests, or agreeing to the chat's
7
+ * offer of them, turns them on - for this session and the next, written into the config.
8
+ */
9
+ /** The chat's tools that run conformance testing: there while the tests are on. */
10
+ export declare const CONFORMANCE_TOOLS: string[];
11
+ /** The chat's tool that turns them on: there while they are off. */
12
+ export declare const TURN_ON_TOOL = "turn_on_conformance_tests";
13
+ /** Whether a module's functional specs are conformance tested: its stack's `conformance-tests:` over the project's. */
14
+ export declare function conformanceTestsOn(plainFile: string): boolean;
15
+ /** Whether the project conformance tests anything: its own config, or a stack's - for the chat's tools, which are the project's. */
16
+ export declare function conformanceTestsOnIn(project: string): boolean;
17
+ /**
18
+ * Turn conformance testing on: `conformance-tests: true` written where the module's value comes from - its stack's file
19
+ * when that names the key, else config.turri.yaml - and in effect at once. Says which file.
20
+ */
21
+ export declare function turnOnConformanceTests(project: string, plainFile?: string): string;
22
+ /**
23
+ * What the chat is told of conformance testing, every turn: what it is, whether it is on here, and - off - how it is
24
+ * turned on, and that it may offer it.
25
+ */
26
+ export declare function conformanceBlock(on: boolean): string;
27
+ /**
28
+ * turn_on_conformance_tests: the chat turns conformance testing on, the person having asked for it or agreed to it.
29
+ * `turnOn` is the session's (extension.ts `turnOnConformance`): the setting written, every chat's tools switched - the
30
+ * file written, from the project.
31
+ */
32
+ export declare function turnOnConformanceTestsTool(options: {
33
+ turnOn: (plainFile?: string) => string;
34
+ }): ToolDefinition;