@interf/compiler 0.5.1 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/README.md +126 -187
  2. package/builtin-workflows/interf/README.md +22 -10
  3. package/builtin-workflows/interf/compile/stages/shape/SKILL.md +6 -3
  4. package/builtin-workflows/interf/compile/stages/structure/SKILL.md +3 -0
  5. package/builtin-workflows/interf/compile/stages/summarize/SKILL.md +18 -2
  6. package/builtin-workflows/interf/improve/SKILL.md +2 -2
  7. package/builtin-workflows/interf/workflow.json +18 -4
  8. package/builtin-workflows/interf/{compiled.schema.json → workflow.schema.json} +9 -2
  9. package/dist/commands/check-draft.js +3 -3
  10. package/dist/commands/compile-controller.js +6 -13
  11. package/dist/commands/compile.d.ts +19 -1
  12. package/dist/commands/compile.js +98 -28
  13. package/dist/commands/create-workflow-wizard.d.ts +20 -2
  14. package/dist/commands/create-workflow-wizard.js +163 -27
  15. package/dist/commands/create.d.ts +1 -1
  16. package/dist/commands/create.js +67 -60
  17. package/dist/commands/dataset-selection.d.ts +6 -0
  18. package/dist/commands/dataset-selection.js +11 -0
  19. package/dist/commands/default.js +3 -3
  20. package/dist/commands/doctor.js +8 -8
  21. package/dist/commands/executor-flow.d.ts +1 -1
  22. package/dist/commands/executor-flow.js +5 -2
  23. package/dist/commands/init.d.ts +5 -0
  24. package/dist/commands/init.js +56 -48
  25. package/dist/commands/list.js +6 -3
  26. package/dist/commands/reset.js +1 -1
  27. package/dist/commands/source-config-wizard.d.ts +2 -2
  28. package/dist/commands/source-config-wizard.js +50 -17
  29. package/dist/commands/test.d.ts +0 -6
  30. package/dist/commands/test.js +9 -17
  31. package/dist/index.d.ts +1 -1
  32. package/dist/index.js +1 -1
  33. package/dist/lib/agent-args.d.ts +1 -0
  34. package/dist/lib/agent-args.js +10 -0
  35. package/dist/lib/agent-execution.js +2 -1
  36. package/dist/lib/agent-preflight.js +2 -1
  37. package/dist/lib/agent-shells.d.ts +26 -1
  38. package/dist/lib/agent-shells.js +213 -39
  39. package/dist/lib/agents.d.ts +1 -1
  40. package/dist/lib/agents.js +1 -1
  41. package/dist/lib/builtin-compiled-workflow.d.ts +6 -97
  42. package/dist/lib/builtin-compiled-workflow.js +66 -125
  43. package/dist/lib/compiled-compile.d.ts +0 -4
  44. package/dist/lib/compiled-compile.js +9 -28
  45. package/dist/lib/compiled-paths.d.ts +1 -0
  46. package/dist/lib/compiled-paths.js +3 -0
  47. package/dist/lib/compiled-reset.d.ts +1 -0
  48. package/dist/lib/compiled-reset.js +42 -14
  49. package/dist/lib/compiled-schema.d.ts +9 -5
  50. package/dist/lib/compiled-schema.js +45 -14
  51. package/dist/lib/discovery.d.ts +1 -1
  52. package/dist/lib/discovery.js +2 -2
  53. package/dist/lib/executors.d.ts +1 -1
  54. package/dist/lib/executors.js +2 -2
  55. package/dist/lib/interf-scaffold.js +4 -11
  56. package/dist/lib/interf-workflow-package.d.ts +8 -3
  57. package/dist/lib/interf-workflow-package.js +128 -62
  58. package/dist/lib/local-workflows.d.ts +4 -3
  59. package/dist/lib/local-workflows.js +126 -103
  60. package/dist/lib/runtime-acceptance.js +15 -3
  61. package/dist/lib/runtime-contracts.js +3 -2
  62. package/dist/lib/runtime-paths.d.ts +1 -0
  63. package/dist/lib/runtime-paths.js +4 -1
  64. package/dist/lib/runtime-prompt.js +3 -1
  65. package/dist/lib/runtime-reconcile.js +88 -51
  66. package/dist/lib/runtime-runs.js +27 -15
  67. package/dist/lib/runtime.d.ts +1 -1
  68. package/dist/lib/runtime.js +1 -1
  69. package/dist/lib/schema.d.ts +71 -14
  70. package/dist/lib/schema.js +15 -12
  71. package/dist/lib/state-view.js +6 -6
  72. package/dist/lib/state.d.ts +1 -0
  73. package/dist/lib/state.js +7 -0
  74. package/dist/lib/test-execution.js +2 -2
  75. package/dist/lib/validate-compiled.js +9 -6
  76. package/dist/lib/validate.d.ts +3 -1
  77. package/dist/lib/validate.js +4 -11
  78. package/dist/lib/workflow-authoring.d.ts +26 -0
  79. package/dist/lib/workflow-authoring.js +119 -0
  80. package/dist/lib/workflow-definitions.d.ts +11 -1
  81. package/dist/lib/workflow-definitions.js +12 -15
  82. package/dist/lib/workflow-edit-session.d.ts +16 -0
  83. package/dist/lib/workflow-edit-session.js +57 -0
  84. package/dist/lib/workflow-edit-utils.d.ts +10 -0
  85. package/dist/lib/workflow-edit-utils.js +39 -0
  86. package/dist/lib/workflow-improvement.js +30 -217
  87. package/dist/lib/workflow-stage-policy.d.ts +5 -0
  88. package/dist/lib/workflow-stage-policy.js +31 -0
  89. package/package.json +4 -5
  90. package/dist/lib/obsidian.d.ts +0 -1
  91. package/dist/lib/obsidian.js +0 -15
  92. package/dist/lib/summarize-plan.d.ts +0 -17
  93. package/dist/lib/summarize-plan.js +0 -120
@@ -1,11 +1,12 @@
1
1
  {
2
- "kind": "compiled-schema",
2
+ "kind": "workflow-schema",
3
3
  "version": 1,
4
4
  "target_type": "compiled",
5
- "label": "Interf Compiler (Recommended) compiled dataset schema",
5
+ "label": "Interf built-in workflow schema",
6
6
  "zones": [
7
7
  {
8
8
  "id": "raw",
9
+ "role": "input",
9
10
  "path": "raw",
10
11
  "kind": "directory",
11
12
  "required": true,
@@ -14,6 +15,7 @@
14
15
  },
15
16
  {
16
17
  "id": "summaries",
18
+ "role": "working",
17
19
  "path": "summaries",
18
20
  "kind": "directory",
19
21
  "required": true,
@@ -24,6 +26,7 @@
24
26
  },
25
27
  {
26
28
  "id": "knowledge-entities",
29
+ "role": "output",
27
30
  "path": "knowledge/entities",
28
31
  "kind": "directory",
29
32
  "required": true,
@@ -34,6 +37,7 @@
34
37
  },
35
38
  {
36
39
  "id": "knowledge-claims",
40
+ "role": "output",
37
41
  "path": "knowledge/claims",
38
42
  "kind": "directory",
39
43
  "required": true,
@@ -44,6 +48,7 @@
44
48
  },
45
49
  {
46
50
  "id": "knowledge-indexes",
51
+ "role": "output",
47
52
  "path": "knowledge/indexes",
48
53
  "kind": "directory",
49
54
  "required": true,
@@ -55,6 +60,7 @@
55
60
  },
56
61
  {
57
62
  "id": "home",
63
+ "role": "output",
58
64
  "path": "home.md",
59
65
  "kind": "file",
60
66
  "required": true,
@@ -65,6 +71,7 @@
65
71
  },
66
72
  {
67
73
  "id": "runtime",
74
+ "role": "runtime",
68
75
  "path": ".interf/runtime",
69
76
  "kind": "runtime",
70
77
  "required": true,
@@ -12,18 +12,18 @@ export function buildTruthCheckDraftPrompt(options) {
12
12
  const taskLines = normalizedAbout
13
13
  ? [
14
14
  `Primary task: ${normalizedAbout}`,
15
- "Draft checks that directly measure whether a local agent would be accurate on that task.",
15
+ "Draft checks that directly measure whether a local agent can answer the key questions from the data behind that task.",
16
16
  "Prefer checks that would make a human confident the dataset is useful for that exact job.",
17
17
  ]
18
18
  : [
19
19
  "No primary task was provided.",
20
- "Prefer broad, representative checks that reflect the most useful questions this dataset should answer.",
20
+ "Prefer broad, representative checks that reflect the most useful questions a human would verify from this dataset.",
21
21
  ];
22
22
  return [
23
23
  "You are drafting Interf truth checks for a local dataset.",
24
24
  "Read the files in this folder and draft a small set of checks that a human can verify from the source material.",
25
25
  "Do not ask follow-up questions.",
26
- "Keep the checks concrete, explicit, and useful for measuring agent accuracy on this dataset.",
26
+ "Keep the checks concrete, explicit, and useful for measuring whether an agent can reason correctly over the data in this dataset.",
27
27
  "",
28
28
  `Dataset id: ${options.datasetName}`,
29
29
  `Dataset folder: ${options.datasetPath}`,
@@ -3,12 +3,13 @@ import { tmpdir } from "node:os";
3
3
  import { dirname, join } from "node:path";
4
4
  import chalk from "chalk";
5
5
  import { readInterfConfig } from "../lib/interf.js";
6
- import { resetCompiledGeneratedState } from "../lib/compiled-reset.js";
6
+ import { clearCompiledRuntimeDerivedArtifacts, resetCompiledGeneratedState, } from "../lib/compiled-reset.js";
7
7
  import { formatActiveCompiledWorkflowStageStep, resolveRequiredCompiledWorkflowFromConfig, } from "../lib/workflow-definitions.js";
8
8
  import { resolveDatasetCompileMaxAttempts, resolveDatasetCompileMaxLoops, } from "../lib/source-config.js";
9
9
  import { runWorkflowImprovementLoop } from "../lib/workflow-improvement.js";
10
10
  import { stageExecutionShellsRoot, workflowPackagePathForCompiled, } from "../lib/compiled-paths.js";
11
11
  import { readCompiledSchemaFile } from "../lib/compiled-schema.js";
12
+ import { initializeCompiledRuntimeState } from "../lib/state.js";
12
13
  import { compileCompiledWithReporter } from "./compiled-flow.js";
13
14
  import { printSavedTestOutcome, questionPassRate, runSavedCompiledTest, } from "./test-flow.js";
14
15
  function printCompileFailure(compiledPath, failedStage) {
@@ -19,14 +20,6 @@ function printCompileFailure(compiledPath, failedStage) {
19
20
  function testScore(outcome) {
20
21
  return (outcome.result.passedCases * 1000) + outcome.result.passedChecks;
21
22
  }
22
- const BEST_VARIATION_RUNTIME_RESTORE_PATHS = [
23
- ".interf/runtime/state.json",
24
- ".interf/runtime/health.json",
25
- ".interf/runtime/view-spec.json",
26
- ".interf/runtime/inventory.json",
27
- ".interf/runtime/run.json",
28
- ".interf/runtime/raw-snapshot.json",
29
- ];
30
23
  function bestVariationRestorePaths(compiledPath) {
31
24
  const schema = readCompiledSchemaFile(workflowPackagePathForCompiled(compiledPath));
32
25
  const zonePaths = (schema?.zones ?? [])
@@ -39,10 +32,8 @@ function bestVariationRestorePaths(compiledPath) {
39
32
  ".codex",
40
33
  ".agents",
41
34
  ".cursor",
42
- ".obsidian",
43
35
  ".interf/interf.json",
44
36
  ".interf/workflow",
45
- ...BEST_VARIATION_RUNTIME_RESTORE_PATHS,
46
37
  ...zonePaths,
47
38
  ];
48
39
  }
@@ -71,6 +62,8 @@ function restoreCompiledBestState(snapshotPath, compiledPath) {
71
62
  rmSync(join(compiledPath, relativePath), { recursive: true, force: true });
72
63
  copyRelativePathIfPresent(snapshotPath, compiledPath, relativePath);
73
64
  }
65
+ clearCompiledRuntimeDerivedArtifacts(compiledPath);
66
+ initializeCompiledRuntimeState(compiledPath);
74
67
  }
75
68
  async function runWorkflowVariation(options) {
76
69
  let bestOutcome = null;
@@ -267,14 +260,14 @@ export async function runConfiguredCompiledCompile(options) {
267
260
  else if (loopEnabled) {
268
261
  if (maxAttempts > 1) {
269
262
  console.log(chalk.dim(` Retry mode: up to ${maxAttempts} compile attempts.`));
270
- console.log(chalk.dim(" Interf Compiler will rerun the same workflow variation, test the compiled dataset, and stop early if it passes."));
263
+ console.log(chalk.dim(" Interf will rerun the same workflow variation, test the compiled dataset, and stop early if it passes."));
271
264
  }
272
265
  else {
273
266
  console.log(chalk.dim(" Compile mode: 1 attempt per workflow variation."));
274
267
  }
275
268
  if (maxLoops != null) {
276
269
  console.log(chalk.dim(` Self-improving loops: up to ${maxLoops} workflow edits after retries fail.`));
277
- console.log(chalk.dim(" Interf Compiler will review failed runs, edit the workflow package, and test new workflow variations."));
270
+ console.log(chalk.dim(" Interf will review failed runs, edit the workflow, and test new workflow variations."));
278
271
  }
279
272
  }
280
273
  if (!loopEnabled || checks.length === 0) {
@@ -1,8 +1,26 @@
1
+ import * as p from "@clack/prompts";
2
+ import { detectInterf } from "../lib/interf.js";
1
3
  import type { SourceDatasetConfig } from "../lib/schema.js";
2
4
  import type { CommandModule } from "yargs";
5
+ import { chooseCompiledConfigToBuild, ensureCompiledFromConfig } from "./compiled-flow.js";
6
+ import { resolveOrConfigureLocalExecutor } from "./executor-flow.js";
7
+ import { runConfiguredCompiledCompile } from "./compile-controller.js";
3
8
  export { runConfiguredCompiledCompile } from "./compile-controller.js";
4
9
  export declare const compileCommand: CommandModule;
5
- export declare function runCompileCommand(argv?: Record<string, unknown>): Promise<void>;
10
+ interface CompileCommandDeps {
11
+ chooseCompiledConfigToBuild: typeof chooseCompiledConfigToBuild;
12
+ confirm: typeof p.confirm;
13
+ detectInterf: typeof detectInterf;
14
+ ensureCompiledFromConfig: typeof ensureCompiledFromConfig;
15
+ resolveInteractiveCompileLoopOverrides: typeof resolveInteractiveCompileLoopOverrides;
16
+ resolveOrConfigureLocalExecutor: typeof resolveOrConfigureLocalExecutor;
17
+ runConfiguredCompiledCompile: typeof runConfiguredCompiledCompile;
18
+ }
19
+ export interface CompileCommandResult {
20
+ compiledPath: string;
21
+ testedDuringCompile: boolean;
22
+ }
23
+ export declare function runCompileCommand(argv?: Record<string, unknown>, deps?: Partial<CompileCommandDeps>): Promise<CompileCommandResult | null>;
6
24
  export declare function resolveInteractiveCompileLoopOverrides(options: {
7
25
  compiledPath: string;
8
26
  compiledConfig: SourceDatasetConfig | null;
@@ -1,16 +1,17 @@
1
1
  import chalk from "chalk";
2
2
  import * as p from "@clack/prompts";
3
3
  import { detectInterf, readInterfConfig, resolveSourceControlPath, } from "../lib/interf.js";
4
- import { sourceDatasetConfigFromInterfConfig, } from "../lib/source-config.js";
4
+ import { sourceDatasetConfigFromInterfConfig, resolveDatasetCompileMaxAttempts, resolveDatasetCompileMaxLoops, } from "../lib/source-config.js";
5
5
  import { addExecutionProfileOptions, executionProfileFromArgv, } from "../lib/execution-profile.js";
6
6
  import { chooseCompiledConfigToBuild, ensureCompiledFromConfig, } from "./compiled-flow.js";
7
+ import { resolveConfiguredDatasetSelection } from "./dataset-selection.js";
7
8
  import { promptCompileLoopSelection, } from "./source-config-wizard.js";
8
9
  import { resolveOrConfigureLocalExecutor } from "./executor-flow.js";
9
10
  import { runConfiguredCompiledCompile } from "./compile-controller.js";
10
11
  export { runConfiguredCompiledCompile } from "./compile-controller.js";
11
12
  export const compileCommand = {
12
13
  command: "compile",
13
- describe: "Build the compiled dataset for the selected dataset",
14
+ describe: "Build a compiled dataset and optionally run retry or self-improving compile loops",
14
15
  builder: (yargs) => addExecutionProfileOptions(yargs).option("max-attempts", {
15
16
  type: "number",
16
17
  describe: "Retry compile + test for the same workflow until the dataset passes or reaches this total attempt limit",
@@ -26,48 +27,105 @@ export const compileCommand = {
26
27
  await runCompileCommand(argv);
27
28
  },
28
29
  };
29
- export async function runCompileCommand(argv = {}) {
30
+ const defaultCompileCommandDeps = {
31
+ chooseCompiledConfigToBuild,
32
+ confirm: p.confirm,
33
+ detectInterf,
34
+ ensureCompiledFromConfig,
35
+ resolveInteractiveCompileLoopOverrides,
36
+ resolveOrConfigureLocalExecutor,
37
+ runConfiguredCompiledCompile,
38
+ };
39
+ function readHintedSourcePath(argv) {
40
+ return typeof argv.sourcePath === "string" && argv.sourcePath.trim().length > 0
41
+ ? argv.sourcePath.trim()
42
+ : null;
43
+ }
44
+ function readRequestedDatasetName(argv) {
45
+ return typeof argv.dataset === "string" && argv.dataset.trim().length > 0
46
+ ? argv.dataset.trim()
47
+ : null;
48
+ }
49
+ function shouldSkipCompileConfirm(argv) {
50
+ return argv.skipConfirm === true;
51
+ }
52
+ function shouldSkipDatasetBanner(argv) {
53
+ return argv.skipDatasetBanner === true;
54
+ }
55
+ function compileRunTests(options) {
56
+ const checks = options.compiledConfig?.checks ?? [];
57
+ if (checks.length === 0)
58
+ return false;
59
+ const configuredMaxAttempts = resolveDatasetCompileMaxAttempts(options.compiledConfig ?? { max_attempts: undefined }, options.maxAttemptsOverride);
60
+ const maxLoops = resolveDatasetCompileMaxLoops(options.compiledConfig ?? { max_loops: undefined }, options.maxLoopsOverride);
61
+ const maxAttempts = configuredMaxAttempts ?? (maxLoops != null ? 1 : null);
62
+ return maxAttempts != null;
63
+ }
64
+ export async function runCompileCommand(argv = {}, deps = {}) {
65
+ const helpers = {
66
+ ...defaultCompileCommandDeps,
67
+ ...deps,
68
+ };
30
69
  let compiledPath = null;
31
- let sourcePath = process.cwd();
70
+ const hintedSourcePath = readHintedSourcePath(argv);
71
+ const detected = hintedSourcePath ? null : helpers.detectInterf(process.cwd());
72
+ let sourcePath = hintedSourcePath ?? process.cwd();
32
73
  let compiledConfig = null;
33
- const detected = detectInterf(process.cwd());
74
+ const requestedDatasetName = readRequestedDatasetName(argv);
75
+ const hintedDatasetConfig = (argv.datasetConfig ?? null);
76
+ const skipConfirm = shouldSkipCompileConfirm(argv);
77
+ const skipDatasetBanner = shouldSkipDatasetBanner(argv);
34
78
  if (detected) {
35
79
  compiledPath = detected.path;
36
80
  sourcePath = resolveSourceControlPath(detected.path);
37
81
  compiledConfig = sourceDatasetConfigFromInterfConfig(detected.config);
38
- if (process.stdin.isTTY && process.stdout.isTTY) {
39
- const confirmed = await p.confirm({
82
+ if (!skipConfirm && process.stdin.isTTY && process.stdout.isTTY) {
83
+ const confirmed = await helpers.confirm({
40
84
  message: `Compile dataset "${detected.config.name}" now?`,
41
85
  initialValue: true,
42
86
  });
43
87
  if (p.isCancel(confirmed) || !confirmed)
44
- return;
88
+ return null;
45
89
  }
46
90
  }
47
91
  else {
48
- const selectedCompiled = await chooseCompiledConfigToBuild({
49
- sourcePath: process.cwd(),
50
- selectMessage: "Which dataset do you want to compile?",
51
- });
92
+ const selectedCompiled = requestedDatasetName || hintedDatasetConfig
93
+ ? resolveConfiguredDatasetSelection({
94
+ sourcePath,
95
+ requestedDatasetName,
96
+ hintedDatasetConfig,
97
+ })
98
+ : await helpers.chooseCompiledConfigToBuild({
99
+ sourcePath,
100
+ selectMessage: "Which dataset do you want to compile?",
101
+ });
52
102
  if (selectedCompiled === undefined)
53
- return;
103
+ return null;
54
104
  if (!selectedCompiled) {
55
105
  process.exitCode = 1;
56
- console.log(chalk.red(" No datasets are set up for this folder yet."));
57
- console.log(chalk.dim(" Start with `interf` or `interf init` to set up this folder."));
58
- return;
106
+ if (requestedDatasetName) {
107
+ console.log(chalk.red(` Dataset "${requestedDatasetName}" is not set up in this project.`));
108
+ console.log(chalk.dim(" Run `interf list` to see the saved datasets."));
109
+ }
110
+ else {
111
+ console.log(chalk.red(" No datasets are set up for this folder yet."));
112
+ console.log(chalk.dim(" Start with `interf` or `interf init` to set up this folder."));
113
+ }
114
+ return null;
59
115
  }
60
- if (process.stdin.isTTY && process.stdout.isTTY) {
61
- const confirmed = await p.confirm({
116
+ if (!skipConfirm && process.stdin.isTTY && process.stdout.isTTY) {
117
+ const confirmed = await helpers.confirm({
62
118
  message: `Compile dataset "${selectedCompiled.name}" now?`,
63
119
  initialValue: true,
64
120
  });
65
121
  if (p.isCancel(confirmed) || !confirmed)
66
- return;
122
+ return null;
67
123
  }
68
124
  compiledConfig = selectedCompiled;
69
- compiledPath = ensureCompiledFromConfig(process.cwd(), selectedCompiled);
70
- console.log(chalk.dim(` Dataset: ${selectedCompiled.name}`));
125
+ compiledPath = helpers.ensureCompiledFromConfig(sourcePath, selectedCompiled);
126
+ if (!skipDatasetBanner) {
127
+ console.log(chalk.dim(` Dataset: ${selectedCompiled.name}`));
128
+ }
71
129
  }
72
130
  let maxAttemptsOverride = null;
73
131
  let maxLoopsOverride = null;
@@ -78,32 +136,37 @@ export async function runCompileCommand(argv = {}) {
78
136
  catch (error) {
79
137
  process.exitCode = 1;
80
138
  console.log(chalk.red(error instanceof Error ? error.message : String(error)));
81
- return;
139
+ return null;
82
140
  }
83
- const interactiveOverrides = await resolveInteractiveCompileLoopOverrides({
141
+ const interactiveOverrides = await helpers.resolveInteractiveCompileLoopOverrides({
84
142
  compiledPath,
85
143
  compiledConfig,
86
144
  maxAttemptsOverride,
87
145
  maxLoopsOverride,
88
146
  });
89
147
  if (!interactiveOverrides)
90
- return;
148
+ return null;
91
149
  compiledConfig = interactiveOverrides.compiledConfig;
92
150
  maxAttemptsOverride = interactiveOverrides.maxAttemptsOverride;
93
151
  maxLoopsOverride = interactiveOverrides.maxLoopsOverride;
152
+ const testedDuringCompile = compileRunTests({
153
+ compiledConfig,
154
+ maxAttemptsOverride,
155
+ maxLoopsOverride,
156
+ });
94
157
  const executionProfile = executionProfileFromArgv(argv);
95
- const { executor, error } = await resolveOrConfigureLocalExecutor({
158
+ const { executor, error } = await helpers.resolveOrConfigureLocalExecutor({
96
159
  executionProfile,
97
160
  purpose: "compile",
98
161
  });
99
162
  if (!executor && !error)
100
- return;
163
+ return null;
101
164
  if (!executor) {
102
165
  process.exitCode = 1;
103
166
  console.log(chalk.red(error ?? "No coding agent detected."));
104
- return;
167
+ return null;
105
168
  }
106
- await runConfiguredCompiledCompile({
169
+ const compiled = await helpers.runConfiguredCompiledCompile({
107
170
  executor,
108
171
  compiledPath,
109
172
  sourcePath,
@@ -113,6 +176,13 @@ export async function runCompileCommand(argv = {}) {
113
176
  maxLoopsOverride,
114
177
  preserveStageShells: readStageShellRetentionMode(argv),
115
178
  });
179
+ if (!compiled) {
180
+ return null;
181
+ }
182
+ return {
183
+ compiledPath,
184
+ testedDuringCompile,
185
+ };
116
186
  }
117
187
  export async function resolveInteractiveCompileLoopOverrides(options) {
118
188
  if (!process.stdin.isTTY || !process.stdout.isTTY) {
@@ -1,3 +1,7 @@
1
+ import { resolveOrConfigureLocalExecutor } from "./executor-flow.js";
2
+ import { runWorkflowAuthoringDraft } from "../lib/workflow-authoring.js";
3
+ import type { SourceDatasetConfig } from "../lib/schema.js";
4
+ import type { WorkflowExecutionProfile } from "../lib/executors.js";
1
5
  export interface WorkflowWizardPrompts {
2
6
  intro(message: string): void;
3
7
  select(options: {
@@ -17,8 +21,13 @@ export interface WorkflowWizardPrompts {
17
21
  isCancel(value: unknown): value is symbol;
18
22
  log: {
19
23
  info(message: string): void;
24
+ error?(message: string): void;
20
25
  };
21
26
  }
27
+ export interface WorkflowWizardDatasetContext {
28
+ config: SourceDatasetConfig;
29
+ datasetPath: string;
30
+ }
22
31
  export declare const clackWorkflowPrompts: WorkflowWizardPrompts;
23
32
  export declare function formatWorkflowLabel(workflow: {
24
33
  id: string;
@@ -42,5 +51,14 @@ export declare function chooseCompiledWorkflow(sourcePath: string, options?: {
42
51
  export declare function createWorkflowWizard(options?: {
43
52
  intro?: boolean;
44
53
  sourcePath?: string;
45
- }, prompts?: WorkflowWizardPrompts): Promise<string | symbol>;
46
- export declare function createCompiledWorkflowWizard(sourcePath: string, prompts?: WorkflowWizardPrompts): Promise<string | symbol>;
54
+ executionProfile?: WorkflowExecutionProfile;
55
+ datasetContext?: WorkflowWizardDatasetContext;
56
+ resolveExecutor?: typeof resolveOrConfigureLocalExecutor;
57
+ runDraft?: typeof runWorkflowAuthoringDraft;
58
+ }, prompts?: WorkflowWizardPrompts): Promise<string | symbol | null>;
59
+ export declare function createCompiledWorkflowWizard(sourcePath: string, prompts?: WorkflowWizardPrompts, options?: {
60
+ executionProfile?: WorkflowExecutionProfile;
61
+ datasetContext?: WorkflowWizardDatasetContext;
62
+ resolveExecutor?: typeof resolveOrConfigureLocalExecutor;
63
+ runDraft?: typeof runWorkflowAuthoringDraft;
64
+ }): Promise<string | symbol | null>;
@@ -1,8 +1,13 @@
1
1
  import chalk from "chalk";
2
2
  import * as p from "@clack/prompts";
3
- import { listCompiledWorkflowChoices, } from "../lib/workflow-definitions.js";
3
+ import { statSync } from "node:fs";
4
+ import { resolve } from "node:path";
5
+ import { listCompiledWorkflowChoices, getCompiledWorkflow, } from "../lib/workflow-definitions.js";
4
6
  import { createLocalWorkflowPackageFromTemplate } from "../lib/interf-workflow-package.js";
5
7
  import { isWorkflowId, } from "../lib/local-workflows.js";
8
+ import { resolveOrConfigureLocalExecutor } from "./executor-flow.js";
9
+ import { runWorkflowAuthoringDraft } from "../lib/workflow-authoring.js";
10
+ import { listSourceDatasetConfigs, loadSourceFolderConfig, resolveSourceDatasetPath, } from "../lib/source-config.js";
6
11
  import { slugify } from "../lib/util.js";
7
12
  export const clackWorkflowPrompts = {
8
13
  intro: p.intro,
@@ -11,8 +16,22 @@ export const clackWorkflowPrompts = {
11
16
  isCancel: p.isCancel,
12
17
  log: {
13
18
  info: p.log.info,
19
+ error: p.log.error,
14
20
  },
15
21
  };
22
+ function findMatchingDatasetConfig(sourcePath, datasetPath) {
23
+ const config = loadSourceFolderConfig(sourcePath);
24
+ for (const dataset of listSourceDatasetConfigs(config)) {
25
+ if (resolveSourceDatasetPath(sourcePath, dataset) === datasetPath) {
26
+ return dataset;
27
+ }
28
+ }
29
+ return null;
30
+ }
31
+ function describeSavedDataset(dataset) {
32
+ return dataset.about
33
+ ?? `${dataset.checks.length} saved truth check${dataset.checks.length === 1 ? "" : "s"} · path ${dataset.path}`;
34
+ }
16
35
  export function formatWorkflowLabel(workflow) {
17
36
  return {
18
37
  value: workflow.id,
@@ -54,15 +73,38 @@ export async function createWorkflowWizard(options = {}, prompts = clackWorkflow
54
73
  prompts.intro(chalk.bold("Create a workflow"));
55
74
  }
56
75
  const sourcePath = options.sourcePath ?? process.cwd();
57
- return createCompiledWorkflowWizard(sourcePath, prompts);
76
+ return createCompiledWorkflowWizard(sourcePath, prompts, {
77
+ executionProfile: options.executionProfile,
78
+ datasetContext: options.datasetContext,
79
+ resolveExecutor: options.resolveExecutor,
80
+ runDraft: options.runDraft,
81
+ });
58
82
  }
59
- export async function createCompiledWorkflowWizard(sourcePath, prompts = clackWorkflowPrompts) {
83
+ export async function createCompiledWorkflowWizard(sourcePath, prompts = clackWorkflowPrompts, options = {}) {
60
84
  const baseWorkflow = await prompts.select({
61
85
  message: "Start from which existing workflow?",
62
86
  options: listCompiledWorkflowChoices(sourcePath).map(formatWorkflowLabel),
63
87
  });
64
88
  if (prompts.isCancel(baseWorkflow))
65
89
  return baseWorkflow;
90
+ const resolvedBaseWorkflow = getCompiledWorkflow(String(baseWorkflow), { sourcePath });
91
+ const creationMode = await prompts.select({
92
+ message: "How do you want to create it?",
93
+ options: [
94
+ {
95
+ value: "draft",
96
+ label: "Draft a workflow from this dataset (Recommended)",
97
+ hint: "Seed a workflow, prepare a preview, then let a local agent draft a reusable method for this task",
98
+ },
99
+ {
100
+ value: "manual",
101
+ label: "Copy an existing workflow",
102
+ hint: "Start from an existing workflow and edit stage guidance directly",
103
+ },
104
+ ],
105
+ });
106
+ if (prompts.isCancel(creationMode))
107
+ return creationMode;
66
108
  const rawName = await prompts.text({
67
109
  message: "New workflow name?",
68
110
  placeholder: "founder-research",
@@ -89,36 +131,130 @@ export async function createCompiledWorkflowWizard(sourcePath, prompts = clackWo
89
131
  });
90
132
  if (prompts.isCancel(hint))
91
133
  return hint;
92
- const summarizeBias = await prompts.text({
93
- message: "What should summarize emphasize?",
94
- placeholder: "Preserve evidence tiers, decision context, and source metadata",
95
- validate: (value) => (value.trim().length === 0 ? "Summarize guidance is required" : undefined),
96
- });
97
- if (prompts.isCancel(summarizeBias))
98
- return summarizeBias;
99
- const structureBias = await prompts.text({
100
- message: "What should structure emphasize?",
101
- placeholder: "Build retrieval-ready entities, claims, timelines, and indexes",
102
- validate: (value) => (value.trim().length === 0 ? "Structure guidance is required" : undefined),
103
- });
104
- if (prompts.isCancel(structureBias))
105
- return structureBias;
106
- const shapeBias = await prompts.text({
107
- message: "What should shape emphasize?",
108
- placeholder: "Bias home.md and navigation toward the questions this dataset should answer best",
109
- validate: (value) => (value.trim().length === 0 ? "Shape guidance is required" : undefined),
110
- });
111
- if (prompts.isCancel(shapeBias))
112
- return shapeBias;
134
+ if (creationMode === "draft") {
135
+ let datasetPath = options.datasetContext?.datasetPath ?? null;
136
+ let matchedDataset = options.datasetContext?.config ?? null;
137
+ if (!datasetPath) {
138
+ const savedDatasets = listSourceDatasetConfigs(loadSourceFolderConfig(sourcePath));
139
+ if (savedDatasets.length > 0) {
140
+ const datasetChoice = await prompts.select({
141
+ message: "Which dataset should shape this workflow?",
142
+ options: [
143
+ ...savedDatasets.map((dataset) => ({
144
+ value: dataset.name,
145
+ label: dataset.name,
146
+ hint: describeSavedDataset(dataset),
147
+ })),
148
+ {
149
+ value: "__manual__",
150
+ label: "Enter folder path manually",
151
+ hint: "Use a folder that is not saved as a dataset yet",
152
+ },
153
+ ],
154
+ });
155
+ if (prompts.isCancel(datasetChoice))
156
+ return datasetChoice;
157
+ if (datasetChoice !== "__manual__") {
158
+ matchedDataset = savedDatasets.find((dataset) => dataset.name === datasetChoice) ?? null;
159
+ datasetPath = matchedDataset
160
+ ? resolveSourceDatasetPath(sourcePath, matchedDataset)
161
+ : null;
162
+ }
163
+ }
164
+ }
165
+ if (!datasetPath) {
166
+ const datasetFolder = await prompts.text({
167
+ message: "Which dataset folder should shape this workflow?",
168
+ placeholder: ".",
169
+ initialValue: ".",
170
+ validate: (value) => {
171
+ const trimmed = value.trim();
172
+ if (trimmed.length === 0)
173
+ return "Dataset folder is required";
174
+ const absolutePath = resolve(sourcePath, trimmed);
175
+ try {
176
+ const stat = statSync(absolutePath);
177
+ return stat.isDirectory() ? undefined : "Dataset folder must be a directory";
178
+ }
179
+ catch {
180
+ return "Dataset folder was not found";
181
+ }
182
+ },
183
+ });
184
+ if (prompts.isCancel(datasetFolder))
185
+ return datasetFolder;
186
+ datasetPath = resolve(sourcePath, String(datasetFolder).trim());
187
+ matchedDataset = matchedDataset ?? findMatchingDatasetConfig(sourcePath, datasetPath);
188
+ }
189
+ const taskPrompt = await prompts.text({
190
+ message: "What task should this workflow prepare the dataset for?",
191
+ placeholder: "Example: chart reads, board-prep questions, or latest planned launch status",
192
+ validate: (value) => (value.trim().length === 0 ? "Task focus is required" : undefined),
193
+ });
194
+ if (prompts.isCancel(taskPrompt))
195
+ return taskPrompt;
196
+ if (matchedDataset) {
197
+ prompts.log.info(`Shaping this workflow from dataset "${matchedDataset.name}".`);
198
+ }
199
+ if (matchedDataset?.checks.length) {
200
+ prompts.log.info(`Using ${matchedDataset.checks.length} saved truth check${matchedDataset.checks.length === 1 ? "" : "s"} from dataset "${matchedDataset.name}" as authoring context.`);
201
+ }
202
+ const resolveExecutor = options.resolveExecutor ?? resolveOrConfigureLocalExecutor;
203
+ const runDraft = options.runDraft ?? runWorkflowAuthoringDraft;
204
+ const { executor, error } = await resolveExecutor({
205
+ executionProfile: options.executionProfile,
206
+ purpose: "workflow",
207
+ });
208
+ if (!executor && !error) {
209
+ return null;
210
+ }
211
+ if (!executor) {
212
+ process.exitCode = 1;
213
+ (prompts.log.error ?? prompts.log.info)(error ?? "No coding agent detected.");
214
+ return null;
215
+ }
216
+ prompts.log.info("Preparing a workflow-authoring preview from the dataset, then drafting the package.");
217
+ const result = await runDraft({
218
+ sourcePath,
219
+ datasetPath,
220
+ baseWorkflowId: baseWorkflow,
221
+ workflowId,
222
+ label,
223
+ hint: hint.trim(),
224
+ taskPrompt: taskPrompt.trim(),
225
+ checks: matchedDataset?.checks ?? [],
226
+ executor,
227
+ preparePreview: true,
228
+ });
229
+ if (result.status === "updated") {
230
+ prompts.log.info(`Saved local workflow: ${result.workflowPath}`);
231
+ return workflowId;
232
+ }
233
+ process.exitCode = 1;
234
+ (prompts.log.error ?? prompts.log.info)(result.status === "no-change"
235
+ ? `${result.summary} Draft mode only succeeds when it produces a task-specific package change.`
236
+ : result.summary);
237
+ prompts.log.info(`Workflow shell kept at: ${result.shellPath}`);
238
+ return null;
239
+ }
240
+ const stagePolicyNotes = {};
241
+ for (const stage of resolvedBaseWorkflow.stages) {
242
+ const stagePrompt = await prompts.text({
243
+ message: `What should ${stage.id} (${stage.label}) emphasize?`,
244
+ placeholder: stage.description,
245
+ validate: (value) => (value.trim().length === 0 ? `${stage.label} guidance is required` : undefined),
246
+ });
247
+ if (prompts.isCancel(stagePrompt))
248
+ return stagePrompt;
249
+ stagePolicyNotes[stage.id] = [String(stagePrompt).trim()];
250
+ }
113
251
  const workflowPath = createLocalWorkflowPackageFromTemplate({
114
252
  sourcePath,
115
253
  baseWorkflowId: baseWorkflow,
116
254
  workflowId,
117
255
  label,
118
256
  hint: hint.trim(),
119
- summarizeBias: summarizeBias.trim(),
120
- structureBias: structureBias.trim(),
121
- shapeBias: shapeBias.trim(),
257
+ stagePolicyNotes,
122
258
  });
123
259
  prompts.log.info(`Saved local workflow: ${workflowPath}`);
124
260
  return workflowId;
@@ -5,4 +5,4 @@ export declare function createCompiledWizard(options?: {
5
5
  intro?: boolean;
6
6
  executionProfile?: WorkflowExecutionProfile;
7
7
  }): Promise<void>;
8
- export { type WorkflowWizardPrompts, formatWorkflowLabel, chooseCompiledWorkflow, createWorkflowWizard, createCompiledWorkflowWizard, } from "./create-workflow-wizard.js";
8
+ export { type WorkflowWizardPrompts, formatWorkflowLabel, createWorkflowWizard, createCompiledWorkflowWizard, } from "./create-workflow-wizard.js";