@interf/compiler 0.4.0 → 0.5.0

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 (160) hide show
  1. package/README.md +71 -69
  2. package/builtin-workflows/interf/README.md +6 -6
  3. package/builtin-workflows/interf/compile/stages/shape/SKILL.md +7 -7
  4. package/builtin-workflows/interf/compile/stages/structure/SKILL.md +2 -2
  5. package/builtin-workflows/interf/compile/stages/summarize/SKILL.md +1 -1
  6. package/builtin-workflows/interf/{workspace.schema.json → compiled.schema.json} +5 -5
  7. package/builtin-workflows/interf/improve/SKILL.md +3 -3
  8. package/builtin-workflows/interf/use/query/SKILL.md +2 -2
  9. package/builtin-workflows/interf/workflow.json +42 -31
  10. package/dist/commands/check-draft.d.ts +19 -0
  11. package/dist/commands/check-draft.js +110 -0
  12. package/dist/commands/compile-controller.d.ts +4 -4
  13. package/dist/commands/compile-controller.js +117 -81
  14. package/dist/commands/compile.d.ts +5 -5
  15. package/dist/commands/compile.js +61 -62
  16. package/dist/commands/compiled-flow.d.ts +23 -0
  17. package/dist/commands/compiled-flow.js +112 -0
  18. package/dist/commands/create-workflow-wizard.d.ts +3 -3
  19. package/dist/commands/create-workflow-wizard.js +11 -11
  20. package/dist/commands/create.d.ts +2 -2
  21. package/dist/commands/create.js +50 -57
  22. package/dist/commands/default.js +2 -2
  23. package/dist/commands/executor-flow.d.ts +20 -1
  24. package/dist/commands/executor-flow.js +67 -7
  25. package/dist/commands/init.js +242 -289
  26. package/dist/commands/list.js +14 -10
  27. package/dist/commands/reset.js +6 -6
  28. package/dist/commands/source-config-wizard.d.ts +12 -8
  29. package/dist/commands/source-config-wizard.js +356 -119
  30. package/dist/commands/status.js +49 -26
  31. package/dist/commands/test-flow.d.ts +23 -10
  32. package/dist/commands/test-flow.js +278 -58
  33. package/dist/commands/test.d.ts +7 -1
  34. package/dist/commands/test.js +264 -65
  35. package/dist/commands/verify.js +23 -14
  36. package/dist/index.d.ts +7 -7
  37. package/dist/index.js +4 -4
  38. package/dist/lib/agent-args.js +2 -1
  39. package/dist/lib/agent-constants.js +1 -1
  40. package/dist/lib/agent-render.js +4 -4
  41. package/dist/lib/agent-shells.d.ts +8 -8
  42. package/dist/lib/agent-shells.js +231 -142
  43. package/dist/lib/compiled-compile.d.ts +52 -0
  44. package/dist/lib/compiled-compile.js +274 -0
  45. package/dist/lib/compiled-home.d.ts +5 -0
  46. package/dist/lib/compiled-home.js +32 -0
  47. package/dist/lib/compiled-layout.d.ts +2 -0
  48. package/dist/lib/compiled-layout.js +60 -0
  49. package/dist/lib/compiled-paths.d.ts +41 -0
  50. package/dist/lib/compiled-paths.js +111 -0
  51. package/dist/lib/{workspace-raw.d.ts → compiled-raw.d.ts} +8 -7
  52. package/dist/lib/{workspace-raw.js → compiled-raw.js} +16 -14
  53. package/dist/lib/compiled-reset.d.ts +1 -0
  54. package/dist/lib/compiled-reset.js +44 -0
  55. package/dist/lib/compiled-schema.d.ts +27 -0
  56. package/dist/lib/compiled-schema.js +110 -0
  57. package/dist/lib/config.d.ts +0 -1
  58. package/dist/lib/config.js +0 -1
  59. package/dist/lib/discovery.d.ts +1 -1
  60. package/dist/lib/discovery.js +3 -3
  61. package/dist/lib/interf-bootstrap.d.ts +1 -1
  62. package/dist/lib/interf-bootstrap.js +4 -4
  63. package/dist/lib/interf-detect.d.ts +10 -10
  64. package/dist/lib/interf-detect.js +78 -56
  65. package/dist/lib/interf-scaffold.d.ts +2 -2
  66. package/dist/lib/interf-scaffold.js +90 -57
  67. package/dist/lib/interf-workflow-package.d.ts +3 -3
  68. package/dist/lib/interf-workflow-package.js +30 -30
  69. package/dist/lib/interf.d.ts +5 -5
  70. package/dist/lib/interf.js +4 -4
  71. package/dist/lib/local-workflows.d.ts +4 -4
  72. package/dist/lib/local-workflows.js +35 -70
  73. package/dist/lib/obsidian.d.ts +1 -1
  74. package/dist/lib/parse.js +92 -1
  75. package/dist/lib/project-paths.d.ts +13 -0
  76. package/dist/lib/project-paths.js +29 -0
  77. package/dist/lib/runtime-acceptance.d.ts +7 -1
  78. package/dist/lib/runtime-acceptance.js +194 -59
  79. package/dist/lib/runtime-contracts.d.ts +2 -4
  80. package/dist/lib/runtime-contracts.js +17 -161
  81. package/dist/lib/runtime-inventory.d.ts +7 -0
  82. package/dist/lib/runtime-inventory.js +29 -0
  83. package/dist/lib/runtime-paths.js +5 -5
  84. package/dist/lib/runtime-prompt.js +9 -6
  85. package/dist/lib/runtime-reconcile.d.ts +2 -3
  86. package/dist/lib/runtime-reconcile.js +92 -171
  87. package/dist/lib/runtime-runs.js +30 -39
  88. package/dist/lib/runtime-types.d.ts +10 -19
  89. package/dist/lib/runtime.d.ts +2 -2
  90. package/dist/lib/runtime.js +1 -1
  91. package/dist/lib/schema.d.ts +163 -140
  92. package/dist/lib/schema.js +163 -124
  93. package/dist/lib/source-config.d.ts +24 -20
  94. package/dist/lib/source-config.js +154 -116
  95. package/dist/lib/state-artifacts.d.ts +5 -5
  96. package/dist/lib/state-artifacts.js +8 -8
  97. package/dist/lib/state-health.d.ts +4 -4
  98. package/dist/lib/state-health.js +108 -126
  99. package/dist/lib/state-io.d.ts +8 -8
  100. package/dist/lib/state-io.js +77 -50
  101. package/dist/lib/state-paths.js +5 -5
  102. package/dist/lib/state-view.d.ts +4 -4
  103. package/dist/lib/state-view.js +52 -55
  104. package/dist/lib/state.d.ts +5 -5
  105. package/dist/lib/state.js +4 -4
  106. package/dist/lib/summarize-plan.d.ts +3 -2
  107. package/dist/lib/summarize-plan.js +18 -16
  108. package/dist/lib/test-execution.js +9 -9
  109. package/dist/lib/test-matrices.d.ts +3 -3
  110. package/dist/lib/test-matrices.js +6 -6
  111. package/dist/lib/test-paths.d.ts +4 -4
  112. package/dist/lib/test-paths.js +16 -10
  113. package/dist/lib/test-sandbox.d.ts +1 -1
  114. package/dist/lib/test-sandbox.js +38 -31
  115. package/dist/lib/test-targets.d.ts +2 -2
  116. package/dist/lib/test-targets.js +11 -11
  117. package/dist/lib/test-types.d.ts +1 -1
  118. package/dist/lib/test.d.ts +1 -1
  119. package/dist/lib/test.js +1 -1
  120. package/dist/lib/util.d.ts +2 -0
  121. package/dist/lib/util.js +14 -1
  122. package/dist/lib/validate-compiled.d.ts +27 -0
  123. package/dist/lib/validate-compiled.js +236 -0
  124. package/dist/lib/validate-helpers.d.ts +0 -8
  125. package/dist/lib/validate-helpers.js +0 -30
  126. package/dist/lib/validate.d.ts +4 -4
  127. package/dist/lib/validate.js +49 -15
  128. package/dist/lib/workflow-abi.d.ts +37 -46
  129. package/dist/lib/workflow-abi.js +51 -76
  130. package/dist/lib/workflow-definitions.d.ts +11 -11
  131. package/dist/lib/workflow-definitions.js +36 -53
  132. package/dist/lib/workflow-helpers.d.ts +2 -3
  133. package/dist/lib/workflow-helpers.js +9 -13
  134. package/dist/lib/workflow-improvement.d.ts +3 -3
  135. package/dist/lib/workflow-improvement.js +48 -48
  136. package/dist/lib/workflow-review-paths.d.ts +3 -3
  137. package/dist/lib/workflow-review-paths.js +11 -11
  138. package/dist/lib/workflow-stage-runner.d.ts +1 -1
  139. package/dist/lib/workflow-stage-runner.js +8 -8
  140. package/dist/lib/workflows.d.ts +9 -9
  141. package/dist/lib/workflows.js +15 -17
  142. package/package.json +10 -9
  143. package/dist/commands/workspace-flow.d.ts +0 -23
  144. package/dist/commands/workspace-flow.js +0 -109
  145. package/dist/lib/registry.d.ts +0 -16
  146. package/dist/lib/registry.js +0 -65
  147. package/dist/lib/validate-workspace.d.ts +0 -121
  148. package/dist/lib/validate-workspace.js +0 -407
  149. package/dist/lib/workspace-compile.d.ts +0 -54
  150. package/dist/lib/workspace-compile.js +0 -476
  151. package/dist/lib/workspace-home.d.ts +0 -5
  152. package/dist/lib/workspace-home.js +0 -32
  153. package/dist/lib/workspace-layout.d.ts +0 -2
  154. package/dist/lib/workspace-layout.js +0 -60
  155. package/dist/lib/workspace-paths.d.ts +0 -41
  156. package/dist/lib/workspace-paths.js +0 -107
  157. package/dist/lib/workspace-reset.d.ts +0 -1
  158. package/dist/lib/workspace-reset.js +0 -43
  159. package/dist/lib/workspace-schema.d.ts +0 -17
  160. package/dist/lib/workspace-schema.js +0 -74
@@ -1,12 +1,84 @@
1
+ import { existsSync, readdirSync, statSync } from "node:fs";
2
+ import { join } from "node:path";
1
3
  import * as p from "@clack/prompts";
2
- import { workspaceMaxAttempts, workspaceMaxLoops } from "../lib/source-config.js";
4
+ import { compiledMaxAttempts, compiledMaxLoops, resolveSourceDatasetPath, } from "../lib/source-config.js";
3
5
  import { slugify } from "../lib/util.js";
4
- export const DEFAULT_WORKSPACE_NAME = "my-workspace";
5
- export const DEFAULT_WORKSPACE_CHECK_QUESTION_PLACEHOLDER = "A question you can already verify from this dataset";
6
- export const DEFAULT_WORKSPACE_CHECK_ANSWER_PLACEHOLDER = "The expected answer in plain English";
7
- export const DEFAULT_WORKSPACE_ABOUT_PLACEHOLDER = "Focused workspace for the dataset questions that matter most here.";
6
+ import { resolveOrConfigureLocalExecutor } from "./executor-flow.js";
7
+ import { draftTruthChecks } from "./check-draft.js";
8
+ export const DEFAULT_COMPILED_NAME = "dataset1";
9
+ export const DEFAULT_COMPILED_CHECK_QUESTION_PLACEHOLDER = "A question you can already verify from this dataset";
10
+ export const DEFAULT_COMPILED_CHECK_ANSWER_PLACEHOLDER = "The expected answer in plain English";
11
+ export const DEFAULT_COMPILED_ABOUT_PLACEHOLDER = "Example: forward-demand metrics, board-prep questions, or chart reads from this dataset.";
12
+ export const DEFAULT_DATASET_PATH_PLACEHOLDER = "./dataset1";
8
13
  export const DEFAULT_COMPILE_RETRY_ATTEMPTS = 1;
9
14
  export const DEFAULT_SELF_IMPROVING_LOOPS = 3;
15
+ function normalizeOptionalPromptText(value) {
16
+ if (typeof value !== "string")
17
+ return undefined;
18
+ const normalized = value.trim();
19
+ return normalized.length > 0 ? normalized : undefined;
20
+ }
21
+ function findSingleDatasetFolderCandidate(cwd) {
22
+ const ignoredEntries = new Set([
23
+ ".DS_Store",
24
+ ".git",
25
+ ".interf",
26
+ "interf",
27
+ "interf.json",
28
+ "node_modules",
29
+ ]);
30
+ let rootEntries = [];
31
+ try {
32
+ rootEntries = readdirSync(cwd);
33
+ }
34
+ catch {
35
+ return null;
36
+ }
37
+ const visibleEntries = rootEntries.filter((entry) => !ignoredEntries.has(entry));
38
+ const visibleFiles = [];
39
+ const visibleDirectories = [];
40
+ for (const entry of visibleEntries) {
41
+ try {
42
+ const entryPath = join(cwd, entry);
43
+ if (statSync(entryPath).isDirectory()) {
44
+ visibleDirectories.push(entry);
45
+ }
46
+ else {
47
+ visibleFiles.push(entry);
48
+ }
49
+ }
50
+ catch {
51
+ // ignore unreadable entries
52
+ }
53
+ }
54
+ if (visibleFiles.length > 0 || visibleDirectories.length !== 1) {
55
+ return null;
56
+ }
57
+ return `./${visibleDirectories[0]}`;
58
+ }
59
+ export function defaultDatasetPathForPrompt(name, introStyle, cwd = process.cwd()) {
60
+ const namedFolderPath = join(cwd, name);
61
+ if (existsSync(namedFolderPath)) {
62
+ try {
63
+ if (statSync(namedFolderPath).isDirectory()) {
64
+ return `./${name}`;
65
+ }
66
+ }
67
+ catch {
68
+ // fall through
69
+ }
70
+ }
71
+ if (introStyle === "first") {
72
+ return findSingleDatasetFolderCandidate(cwd) ?? ".";
73
+ }
74
+ return `./${name}`;
75
+ }
76
+ export function datasetAboutPromptMessage(introStyle) {
77
+ if (introStyle === "edit") {
78
+ return "What should this dataset stay accurate about?";
79
+ }
80
+ return "What should this dataset be accurate about?";
81
+ }
10
82
  function formatAttemptLabel(count, noun) {
11
83
  return `${count} ${noun}${count === 1 ? "" : "s"}`;
12
84
  }
@@ -20,14 +92,13 @@ export function resolveCompileLoopMode(maxAttempts, maxLoops) {
20
92
  export function describeCompileLoopSelection(options) {
21
93
  const mode = resolveCompileLoopMode(options.maxAttempts, options.maxLoops);
22
94
  if (mode === "once") {
23
- return "Run a single compile attempt without workflow edits.";
95
+ return "Compile once.";
24
96
  }
25
97
  if (mode === "retry") {
26
- return `Retry the same workflow up to ${formatAttemptLabel(options.maxAttempts ?? DEFAULT_COMPILE_RETRY_ATTEMPTS, "attempt")}.`;
98
+ return "Compile retries are enabled for this dataset.";
27
99
  }
28
- const attempts = options.maxAttempts ?? DEFAULT_COMPILE_RETRY_ATTEMPTS;
29
100
  const loops = options.maxLoops ?? DEFAULT_SELF_IMPROVING_LOOPS;
30
- return `Run ${formatAttemptLabel(attempts, "attempt")} per workflow variation and allow up to ${formatAttemptLabel(loops, "self-improving workflow loop")}.`;
101
+ return `Self-improving loops are enabled for this dataset (${formatAttemptLabel(loops, "workflow revision")}).`;
31
102
  }
32
103
  export async function promptCheckCases(options) {
33
104
  p.log.info(options.heading);
@@ -66,33 +137,189 @@ export async function promptCheckCases(options) {
66
137
  return cases;
67
138
  }
68
139
  }
69
- async function promptWorkspaceChecks(options) {
140
+ function printDraftTruthChecks(checks) {
141
+ console.log();
142
+ p.log.info(`Draft truth checks: ${checks.length}`);
143
+ for (const [index, check] of checks.entries()) {
144
+ console.log(` ${index + 1}. ${check.question}`);
145
+ console.log(` Expected: ${check.answer ?? ""}`);
146
+ }
147
+ }
148
+ async function promptDraftTruthChecks(options) {
149
+ let resolvedDatasetPath;
150
+ try {
151
+ const datasetConfig = {
152
+ path: options.datasetPath,
153
+ };
154
+ resolvedDatasetPath = resolveSourceDatasetPath(options.projectPath, datasetConfig);
155
+ }
156
+ catch (error) {
157
+ p.log.error(error instanceof Error ? error.message : String(error));
158
+ return "manual";
159
+ }
160
+ const resolved = await resolveOrConfigureLocalExecutor({
161
+ preflight: true,
162
+ purpose: "draft",
163
+ });
164
+ if (!resolved.executor) {
165
+ if (resolved.cancelled)
166
+ return null;
167
+ p.log.error(resolved.error ?? "No local agent detected for truth-check drafting.");
168
+ const fallback = await p.select({
169
+ message: "How do you want to continue?",
170
+ options: [
171
+ {
172
+ value: "manual",
173
+ label: "Add truth checks manually",
174
+ hint: "Write the questions and expected answers yourself",
175
+ },
176
+ {
177
+ value: "skip",
178
+ label: "Skip for now",
179
+ hint: "Save this dataset without truth checks",
180
+ },
181
+ ],
182
+ });
183
+ if (p.isCancel(fallback))
184
+ return null;
185
+ return fallback === "manual" ? "manual" : [];
186
+ }
187
+ while (true) {
188
+ p.log.info("Drafting truth checks from the dataset files.");
189
+ const drafted = await draftTruthChecks({
190
+ datasetName: options.datasetName,
191
+ datasetPath: resolvedDatasetPath,
192
+ about: options.about,
193
+ executor: resolved.executor,
194
+ targetCount: 4,
195
+ });
196
+ if (!drafted.checks) {
197
+ p.log.error(drafted.error ?? "Could not draft truth checks from this dataset.");
198
+ const retryMode = await p.select({
199
+ message: "How do you want to continue?",
200
+ options: [
201
+ {
202
+ value: "retry",
203
+ label: "Try auto-create again",
204
+ hint: "Run the same local agent again on the dataset folder",
205
+ },
206
+ {
207
+ value: "manual",
208
+ label: "Add truth checks manually",
209
+ hint: "Write the checks yourself instead",
210
+ },
211
+ {
212
+ value: "skip",
213
+ label: "Skip for now",
214
+ hint: "Save this dataset without truth checks",
215
+ },
216
+ ],
217
+ });
218
+ if (p.isCancel(retryMode))
219
+ return null;
220
+ if (retryMode === "retry")
221
+ continue;
222
+ return retryMode === "manual" ? "manual" : [];
223
+ }
224
+ printDraftTruthChecks(drafted.checks);
225
+ const nextStep = await p.select({
226
+ message: "Use these truth checks?",
227
+ options: [
228
+ {
229
+ value: "use",
230
+ label: "Use this draft (Recommended)",
231
+ hint: "Save these checks and edit them later if needed",
232
+ },
233
+ {
234
+ value: "retry",
235
+ label: "Draft again",
236
+ hint: "Run the same local agent again on the dataset folder",
237
+ },
238
+ {
239
+ value: "manual",
240
+ label: "Add them manually instead",
241
+ hint: "Discard this draft and write the checks yourself",
242
+ },
243
+ {
244
+ value: "skip",
245
+ label: "Skip for now",
246
+ hint: "Save this dataset without truth checks",
247
+ },
248
+ ],
249
+ });
250
+ if (p.isCancel(nextStep))
251
+ return null;
252
+ if (nextStep === "retry")
253
+ continue;
254
+ if (nextStep === "manual")
255
+ return "manual";
256
+ if (nextStep === "skip")
257
+ return [];
258
+ return drafted.checks;
259
+ }
260
+ }
261
+ async function promptCompiledChecks(options) {
70
262
  if (!options.initialChecks?.length) {
71
263
  if (options.initialAbout) {
72
- p.log.info(`Focus: ${options.initialAbout}`);
264
+ p.log.info(`About: ${options.initialAbout}`);
73
265
  }
74
- p.log.info("Truth checks define what should hold for this dataset.");
75
- p.log.info("Each truth check is a question plus the expected correct answer.");
76
- p.log.info("Start with simple facts, comparisons, or conclusions you can verify in the source material.");
77
- const addNow = await p.confirm({
78
- message: "Add a few truth checks for this dataset now? (Recommended)",
79
- initialValue: true,
266
+ p.log.info("Truth checks are the questions this dataset should already answer correctly.");
267
+ const mode = await p.select({
268
+ message: "How do you want to create them?",
269
+ options: [
270
+ {
271
+ value: "draft",
272
+ label: "Auto-create a draft (Recommended)",
273
+ hint: "Let a local agent draft a few clear, verifiable checks from this dataset",
274
+ },
275
+ {
276
+ value: "manual",
277
+ label: "Add them manually",
278
+ hint: "Write the questions and expected answers yourself",
279
+ },
280
+ {
281
+ value: "skip",
282
+ label: "Skip for now",
283
+ hint: "You can save the dataset first and add checks later",
284
+ },
285
+ ],
80
286
  });
81
- if (p.isCancel(addNow))
287
+ if (p.isCancel(mode))
82
288
  return null;
83
- if (!addNow)
289
+ if (mode === "skip")
84
290
  return [];
291
+ if (mode === "draft") {
292
+ const drafted = await promptDraftTruthChecks({
293
+ projectPath: options.projectPath,
294
+ datasetName: options.datasetName,
295
+ datasetPath: options.datasetPath,
296
+ about: options.initialAbout,
297
+ });
298
+ if (drafted === null)
299
+ return null;
300
+ if (drafted === "manual") {
301
+ return promptCheckCases({
302
+ heading: "Truth checks",
303
+ questionMessage: "Question 1?",
304
+ questionPlaceholder: DEFAULT_COMPILED_CHECK_QUESTION_PLACEHOLDER,
305
+ answerMessage: "Expected answer 1?",
306
+ answerPlaceholder: DEFAULT_COMPILED_CHECK_ANSWER_PLACEHOLDER,
307
+ addAnotherMessage: "Add another question?",
308
+ });
309
+ }
310
+ return drafted;
311
+ }
85
312
  return promptCheckCases({
86
313
  heading: "Truth checks",
87
314
  questionMessage: "Question 1?",
88
- questionPlaceholder: DEFAULT_WORKSPACE_CHECK_QUESTION_PLACEHOLDER,
315
+ questionPlaceholder: DEFAULT_COMPILED_CHECK_QUESTION_PLACEHOLDER,
89
316
  answerMessage: "Expected answer 1?",
90
- answerPlaceholder: DEFAULT_WORKSPACE_CHECK_ANSWER_PLACEHOLDER,
317
+ answerPlaceholder: DEFAULT_COMPILED_CHECK_ANSWER_PLACEHOLDER,
91
318
  addAnotherMessage: "Add another question?",
92
319
  });
93
320
  }
94
321
  if (options.initialAbout) {
95
- p.log.info(`Focus: ${options.initialAbout}`);
322
+ p.log.info(`About: ${options.initialAbout}`);
96
323
  }
97
324
  p.log.info(`Current truth checks: ${options.initialChecks.length}`);
98
325
  const mode = await p.select({
@@ -113,10 +340,15 @@ async function promptWorkspaceChecks(options) {
113
340
  label: "Replace all",
114
341
  hint: "Rewrite the truth checks from scratch",
115
342
  },
343
+ {
344
+ value: "redraft",
345
+ label: "Replace with auto-created draft",
346
+ hint: "Let a local agent rewrite the checks from the dataset files",
347
+ },
116
348
  {
117
349
  value: "clear",
118
350
  label: "Clear them for now",
119
- hint: "Keep this workspace without saved truth checks",
351
+ hint: "Keep this dataset without saved truth checks",
120
352
  },
121
353
  ],
122
354
  });
@@ -128,16 +360,37 @@ async function promptWorkspaceChecks(options) {
128
360
  if (mode === "clear") {
129
361
  return [];
130
362
  }
363
+ if (mode === "redraft") {
364
+ const drafted = await promptDraftTruthChecks({
365
+ projectPath: options.projectPath,
366
+ datasetName: options.datasetName,
367
+ datasetPath: options.datasetPath,
368
+ about: options.initialAbout,
369
+ });
370
+ if (drafted === null)
371
+ return null;
372
+ if (drafted === "manual") {
373
+ return promptCheckCases({
374
+ heading: "Replace truth checks",
375
+ questionMessage: "Question 1?",
376
+ questionPlaceholder: DEFAULT_COMPILED_CHECK_QUESTION_PLACEHOLDER,
377
+ answerMessage: "Expected answer 1?",
378
+ answerPlaceholder: DEFAULT_COMPILED_CHECK_ANSWER_PLACEHOLDER,
379
+ addAnotherMessage: "Add another question?",
380
+ });
381
+ }
382
+ return drafted;
383
+ }
131
384
  const nextChecks = await promptCheckCases({
132
385
  heading: mode === "add" ? "Add more truth checks" : "Replace truth checks",
133
386
  questionMessage: mode === "add"
134
387
  ? `Question ${options.initialChecks.length + 1}?`
135
388
  : "Question 1?",
136
- questionPlaceholder: DEFAULT_WORKSPACE_CHECK_QUESTION_PLACEHOLDER,
389
+ questionPlaceholder: DEFAULT_COMPILED_CHECK_QUESTION_PLACEHOLDER,
137
390
  answerMessage: mode === "add"
138
391
  ? `Expected answer ${options.initialChecks.length + 1}?`
139
392
  : "Expected answer 1?",
140
- answerPlaceholder: DEFAULT_WORKSPACE_CHECK_ANSWER_PLACEHOLDER,
393
+ answerPlaceholder: DEFAULT_COMPILED_CHECK_ANSWER_PLACEHOLDER,
141
394
  addAnotherMessage: "Add another question?",
142
395
  startIndex: mode === "add" ? options.initialChecks.length + 1 : 1,
143
396
  });
@@ -145,24 +398,6 @@ async function promptWorkspaceChecks(options) {
145
398
  return null;
146
399
  return mode === "add" ? [...options.initialChecks, ...nextChecks] : nextChecks;
147
400
  }
148
- async function promptRetryAttempts(options) {
149
- const minimum = options.minimum ?? 1;
150
- const maxAttempts = await p.text({
151
- message: options.message,
152
- placeholder: String(Math.max(minimum, DEFAULT_COMPILE_RETRY_ATTEMPTS)),
153
- initialValue: String(Math.max(options.initialMaxAttempts ?? DEFAULT_COMPILE_RETRY_ATTEMPTS, minimum)),
154
- validate: (value) => {
155
- const parsed = Number.parseInt(value.trim(), 10);
156
- if (!Number.isInteger(parsed) || parsed < minimum || parsed > 5) {
157
- return `Enter a whole number from ${minimum} to 5`;
158
- }
159
- return undefined;
160
- },
161
- });
162
- if (p.isCancel(maxAttempts))
163
- return null;
164
- return workspaceMaxAttempts(Number.parseInt(String(maxAttempts).trim(), 10)) ?? DEFAULT_COMPILE_RETRY_ATTEMPTS;
165
- }
166
401
  async function promptSelfImprovingLoops(options) {
167
402
  const maxLoops = await p.text({
168
403
  message: options.message,
@@ -178,13 +413,14 @@ async function promptSelfImprovingLoops(options) {
178
413
  });
179
414
  if (p.isCancel(maxLoops))
180
415
  return null;
181
- return workspaceMaxLoops(Number.parseInt(String(maxLoops).trim(), 10)) ?? DEFAULT_SELF_IMPROVING_LOOPS;
416
+ return compiledMaxLoops(Number.parseInt(String(maxLoops).trim(), 10)) ?? DEFAULT_SELF_IMPROVING_LOOPS;
182
417
  }
183
418
  export async function promptCompileLoopSelection(options) {
184
419
  if (!options.hasChecks) {
185
420
  return {};
186
421
  }
187
422
  const currentMode = resolveCompileLoopMode(options.initialMaxAttempts, options.initialMaxLoops);
423
+ const currentPromptMode = currentMode === "self-improving" ? "self-improving" : "once";
188
424
  const recommendedMode = options.recommendedMode ?? "self-improving";
189
425
  const includeCompileOnce = options.includeCompileOnce !== false;
190
426
  const hasSavedPolicy = typeof options.initialMaxAttempts === "number" ||
@@ -199,37 +435,35 @@ export async function promptCompileLoopSelection(options) {
199
435
  const optionsByMode = {
200
436
  once: {
201
437
  value: "once",
202
- label: "Single attempt",
203
- hint: "No retries or workflow edits",
204
- },
205
- retry: {
206
- value: "retry",
207
- label: "Retry the same workflow",
208
- hint: `Run compile + test up to ${formatAttemptLabel(Math.max(options.initialMaxAttempts ?? 2, 2), "attempt")}`,
438
+ label: "Compile once",
439
+ hint: "Build the compiled dataset once with the selected workflow",
209
440
  },
210
441
  "self-improving": {
211
442
  value: "self-improving",
212
443
  label: recommendedMode === "self-improving"
213
444
  ? "Self-improving loops (Recommended)"
214
445
  : "Self-improving loops",
215
- hint: `Retry each variation, then edit the workflow and retest up to ${options.initialMaxLoops ?? DEFAULT_SELF_IMPROVING_LOOPS} loop${(options.initialMaxLoops ?? DEFAULT_SELF_IMPROVING_LOOPS) === 1 ? "" : "s"}`,
446
+ hint: `Let Interf revise the workflow and retry up to ${options.initialMaxLoops ?? DEFAULT_SELF_IMPROVING_LOOPS} time${(options.initialMaxLoops ?? DEFAULT_SELF_IMPROVING_LOOPS) === 1 ? "" : "s"}`,
447
+ },
448
+ retry: {
449
+ value: "retry",
450
+ label: "Compile once",
451
+ hint: "Build the compiled dataset once with the selected workflow",
216
452
  },
217
453
  };
218
454
  const orderedModes = (hasSavedPolicy
219
455
  ? [
220
- currentMode,
221
- ...(recommendedMode !== currentMode ? [recommendedMode] : []),
222
- "retry",
456
+ currentPromptMode,
457
+ ...(recommendedMode !== currentPromptMode ? [recommendedMode] : []),
223
458
  "once",
224
459
  ]
225
460
  : [
226
461
  recommendedMode,
227
- "retry",
228
462
  "once",
229
463
  ]).filter((mode, index, list) => list.indexOf(mode) === index)
230
464
  .filter((mode) => includeCompileOnce || mode !== "once");
231
465
  const selectedMode = await p.select({
232
- message: options.message ?? "How should this workspace compile?",
466
+ message: options.message ?? "How should this dataset compile?",
233
467
  options: orderedModes.map((mode) => optionsByMode[mode]),
234
468
  });
235
469
  if (p.isCancel(selectedMode))
@@ -237,57 +471,42 @@ export async function promptCompileLoopSelection(options) {
237
471
  if (selectedMode === "once") {
238
472
  return {};
239
473
  }
240
- const maxAttempts = await promptRetryAttempts({
241
- initialMaxAttempts: options.initialMaxAttempts ?? DEFAULT_COMPILE_RETRY_ATTEMPTS,
242
- minimum: selectedMode === "retry" ? 2 : 1,
243
- message: selectedMode === "retry"
244
- ? "Maximum compile attempts for the same workflow?"
245
- : "Attempts per workflow variation?",
246
- });
247
- if (maxAttempts === null)
248
- return null;
249
- if (selectedMode === "retry") {
250
- return {
251
- max_attempts: maxAttempts,
252
- };
253
- }
254
474
  const maxLoops = await promptSelfImprovingLoops({
255
475
  initialMaxLoops: options.initialMaxLoops ?? DEFAULT_SELF_IMPROVING_LOOPS,
256
- message: "Maximum self-improving workflow loops?",
476
+ message: "How many workflow revisions should Interf try?",
257
477
  });
258
478
  if (maxLoops === null)
259
479
  return null;
260
480
  return {
261
- max_attempts: maxAttempts,
481
+ max_attempts: compiledMaxAttempts(DEFAULT_COMPILE_RETRY_ATTEMPTS) ?? DEFAULT_COMPILE_RETRY_ATTEMPTS,
262
482
  max_loops: maxLoops,
263
483
  };
264
484
  }
265
- export async function promptSingleWorkspaceConfig(options = {}) {
485
+ export async function promptSingleCompiledConfig(options = {}) {
266
486
  const initial = options.initial;
267
487
  const introStyle = options.introStyle ?? "first";
268
- const collectChecksFirst = introStyle === "first" && options.skipNamePrompt && !options.fixedName;
269
488
  if (introStyle === "first") {
270
- p.log.info("Set a few truth checks you already know should hold for this dataset.");
271
- p.log.info("Add an optional focus only if you want this workspace especially good at one job on the dataset.");
489
+ p.log.info("Pick the dataset folder you want to measure.");
490
+ p.log.info("Then say what this dataset should be accurate about and save a few truth checks you can verify.");
272
491
  }
273
492
  else if (introStyle === "additional") {
274
- p.log.info("Add another workspace only if this dataset needs a separate focus or a separate set of truth checks.");
493
+ p.log.info("Add another dataset only if this project needs a separate folder or set of truth checks.");
275
494
  }
276
495
  const fixedName = options.fixedName ? slugify(String(options.fixedName)) : undefined;
277
496
  if (options.fixedName && !fixedName) {
278
- p.log.error("Current workspace folder name needs letters, numbers, or dashes.");
497
+ p.log.error("Current dataset id needs letters, numbers, or dashes.");
279
498
  return null;
280
499
  }
281
- let name = fixedName ?? (options.skipNamePrompt ? slugify(String(initial?.name ?? DEFAULT_WORKSPACE_NAME)) : undefined);
500
+ let name = fixedName ?? (options.skipNamePrompt ? slugify(String(initial?.name ?? DEFAULT_COMPILED_NAME)) : undefined);
282
501
  if (name) {
283
502
  if (options.fixedName) {
284
- p.log.info(`Editing truth checks for workspace "${name}".`);
503
+ p.log.info(`Editing truth checks for dataset "${name}".`);
285
504
  }
286
505
  }
287
506
  else {
288
- const suggestedName = initial?.name ?? slugify(String(initial?.about ?? "")) ?? DEFAULT_WORKSPACE_NAME;
507
+ const suggestedName = initial?.name ?? slugify(String(initial?.about ?? "")) ?? DEFAULT_COMPILED_NAME;
289
508
  const rawName = await p.text({
290
- message: "Workspace name?",
509
+ message: "Dataset id?",
291
510
  placeholder: suggestedName,
292
511
  initialValue: suggestedName,
293
512
  validate: (value) => (value.trim().length === 0 ? "Name is required" : undefined),
@@ -296,60 +515,78 @@ export async function promptSingleWorkspaceConfig(options = {}) {
296
515
  return null;
297
516
  name = slugify(String(rawName));
298
517
  if (!name) {
299
- p.log.error("Workspace name needs letters, numbers, or dashes.");
518
+ p.log.error("Dataset id needs letters, numbers, or dashes.");
300
519
  return null;
301
520
  }
302
521
  if (name !== rawName) {
303
- p.log.info(`Workspace name: ${name}`);
522
+ p.log.info(`Dataset id: ${name}`);
304
523
  }
305
524
  }
306
- let about = initial?.about ?? "";
307
- let checks = null;
525
+ let about = normalizeOptionalPromptText(initial?.about);
526
+ const defaultDatasetPath = initial?.path ?? defaultDatasetPathForPrompt(name, introStyle, options.projectPath ?? process.cwd());
527
+ const datasetPath = await p.text({
528
+ message: "Dataset folder?",
529
+ placeholder: DEFAULT_DATASET_PATH_PLACEHOLDER,
530
+ initialValue: defaultDatasetPath,
531
+ validate: (value) => {
532
+ const normalized = value.trim();
533
+ if (normalized.length === 0)
534
+ return "Dataset folder is required";
535
+ try {
536
+ resolveSourceDatasetPath(options.projectPath ?? process.cwd(), { path: normalized });
537
+ return undefined;
538
+ }
539
+ catch (error) {
540
+ return error instanceof Error ? error.message : String(error);
541
+ }
542
+ },
543
+ });
544
+ if (p.isCancel(datasetPath))
545
+ return null;
546
+ const normalizedDatasetPath = String(datasetPath).trim();
308
547
  let compileLoopSelection = {
309
548
  ...(typeof initial?.max_attempts === "number" ? { max_attempts: initial.max_attempts } : {}),
310
549
  ...(typeof initial?.max_loops === "number" ? { max_loops: initial.max_loops } : {}),
311
550
  };
312
- if (collectChecksFirst) {
313
- checks = await promptWorkspaceChecks({
314
- initialChecks: initial?.checks,
315
- });
316
- if (checks === null)
317
- return null;
318
- }
319
551
  if (!(options.skipAboutPrompt && initial?.about)) {
320
- about = await p.text({
321
- message: "Optional focus for this workspace?",
322
- placeholder: DEFAULT_WORKSPACE_ABOUT_PLACEHOLDER,
323
- initialValue: initial?.about,
552
+ const aboutInput = await p.text({
553
+ message: datasetAboutPromptMessage(introStyle),
554
+ placeholder: DEFAULT_COMPILED_ABOUT_PLACEHOLDER,
555
+ initialValue: about ?? "",
324
556
  });
325
- if (p.isCancel(about))
557
+ if (p.isCancel(aboutInput))
326
558
  return null;
559
+ about = normalizeOptionalPromptText(aboutInput);
327
560
  }
328
- if (!checks) {
329
- checks = await promptWorkspaceChecks({
330
- initialAbout: String(about).trim(),
331
- initialChecks: initial?.checks,
561
+ const checks = await promptCompiledChecks({
562
+ projectPath: options.projectPath ?? process.cwd(),
563
+ datasetName: name,
564
+ datasetPath: normalizedDatasetPath,
565
+ initialAbout: about,
566
+ initialChecks: initial?.checks,
567
+ });
568
+ if (checks === null)
569
+ return null;
570
+ if (introStyle === "edit") {
571
+ compileLoopSelection = await promptCompileLoopSelection({
572
+ initialMaxAttempts: initial?.max_attempts,
573
+ initialMaxLoops: initial?.max_loops,
574
+ hasChecks: checks.length > 0,
575
+ intro: [
576
+ ...(options.selectedWorkflowLabel
577
+ ? [`Workflow: ${options.selectedWorkflowLabel}`]
578
+ : []),
579
+ "Compile mode",
580
+ "Choose whether this dataset should compile once or keep revising the workflow until it passes the same truth checks.",
581
+ ],
332
582
  });
333
- if (checks === null)
583
+ if (compileLoopSelection === null)
334
584
  return null;
335
585
  }
336
- compileLoopSelection = await promptCompileLoopSelection({
337
- initialMaxAttempts: initial?.max_attempts,
338
- initialMaxLoops: initial?.max_loops,
339
- hasChecks: checks.length > 0,
340
- intro: [
341
- ...(options.selectedWorkflowLabel
342
- ? [`Workflow: ${options.selectedWorkflowLabel}`]
343
- : []),
344
- "Compile mode",
345
- "Choose whether this workspace should compile once, retry the same workflow, or run self-improving loops that edit the workflow and retest it on the same truth checks.",
346
- ],
347
- });
348
- if (compileLoopSelection === null)
349
- return null;
350
586
  return {
351
587
  name,
352
- ...(String(about).trim().length > 0 ? { about: String(about).trim() } : {}),
588
+ path: normalizedDatasetPath,
589
+ ...(about ? { about } : {}),
353
590
  ...(typeof compileLoopSelection.max_attempts === "number"
354
591
  ? { max_attempts: compileLoopSelection.max_attempts }
355
592
  : {}),