@interf/compiler 0.7.1 → 0.7.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/README.md +77 -72
  2. package/builtin-workflows/interf/README.md +4 -4
  3. package/builtin-workflows/interf/compile/stages/shape/SKILL.md +4 -4
  4. package/builtin-workflows/interf/improve/SKILL.md +1 -1
  5. package/builtin-workflows/interf/use/query/SKILL.md +1 -1
  6. package/builtin-workflows/interf/workflow.json +4 -4
  7. package/builtin-workflows/interf/workflow.schema.json +1 -1
  8. package/dist/cli/commands/compile-controller.js +5 -5
  9. package/dist/cli/commands/compile.js +1 -1
  10. package/dist/cli/commands/create-workflow-wizard.d.ts +6 -0
  11. package/dist/cli/commands/create-workflow-wizard.js +57 -5
  12. package/dist/cli/commands/create.js +21 -11
  13. package/dist/cli/commands/default.js +2 -1
  14. package/dist/cli/commands/init.js +65 -54
  15. package/dist/cli/commands/source-config-wizard.d.ts +0 -1
  16. package/dist/cli/commands/source-config-wizard.js +1 -4
  17. package/dist/cli/commands/status.js +3 -3
  18. package/dist/cli/commands/test-flow.js +9 -7
  19. package/dist/cli/commands/test.js +7 -7
  20. package/dist/index.d.ts +1 -1
  21. package/dist/index.js +1 -1
  22. package/dist/packages/agents/lib/shells.js +22 -19
  23. package/dist/packages/compiler/compiled-paths.js +1 -1
  24. package/dist/packages/compiler/runtime-prompt.js +1 -1
  25. package/dist/packages/project-model/interf-detect.js +24 -10
  26. package/dist/packages/project-model/interf-scaffold.d.ts +1 -0
  27. package/dist/packages/project-model/interf-scaffold.js +30 -11
  28. package/dist/packages/project-model/interf.d.ts +1 -1
  29. package/dist/packages/project-model/interf.js +1 -1
  30. package/dist/packages/project-model/project-paths.d.ts +3 -1
  31. package/dist/packages/project-model/project-paths.js +6 -2
  32. package/dist/packages/project-model/source-config.d.ts +5 -0
  33. package/dist/packages/project-model/source-config.js +60 -7
  34. package/dist/packages/testing/test-paths.js +6 -3
  35. package/dist/packages/workflow-authoring/workflow-authoring.js +4 -2
  36. package/dist/packages/workflow-authoring/workflow-edit-session.js +5 -2
  37. package/dist/packages/workflow-package/context-interface.js +1 -1
  38. package/dist/packages/workflow-package/workflow-review-paths.js +5 -1
  39. package/package.json +2 -4
@@ -65,7 +65,7 @@ export function resolveSourceInputPath(compiledPath) {
65
65
  const projectPath = resolveSourceControlPathForCompiled(compiledPath);
66
66
  return assertPathWithinRoot(projectPath, resolve(compiledPath, config.source.dataset_path), "Dataset source path");
67
67
  }
68
- throw new Error(`Context folder is missing source.dataset_path in ${compiledInterfConfigPath(compiledPath)}.`);
68
+ throw new Error(`Compiled context is missing source.dataset_path in ${compiledInterfConfigPath(compiledPath)}.`);
69
69
  }
70
70
  export function listCompiledDatasetsForSourceFolder(sourcePath) {
71
71
  const interfRoot = projectInterfRoot(sourcePath);
@@ -82,7 +82,8 @@ export function listCompiledDatasetsForSourceFolder(sourcePath) {
82
82
  return readdirSync(interfRoot)
83
83
  .filter((entry) => !entry.startsWith(".") &&
84
84
  entry !== WORKFLOW_CONTAINER_NAME &&
85
- entry !== TEST_CONTAINER_NAME)
85
+ entry !== TEST_CONTAINER_NAME &&
86
+ entry !== INTERF_CONFIG_FILE)
86
87
  .map((entry) => compiledCompiledPathForDataset(sourcePath, entry))
87
88
  .filter((compiledPath) => existsSync(compiledPath))
88
89
  .map((compiledPath) => {
@@ -102,6 +103,15 @@ export function assertCompiledContainer(sourcePath) {
102
103
  if (entry.startsWith("."))
103
104
  return false;
104
105
  const entryPath = join(interfRoot, entry);
106
+ if (entry === INTERF_CONFIG_FILE) {
107
+ try {
108
+ return !statSync(entryPath).isFile();
109
+ }
110
+ catch (error) {
111
+ warnInterf(`Warning: failed to inspect Interf config path at ${entryPath}: ${error instanceof Error ? error.message : String(error)}`);
112
+ return true;
113
+ }
114
+ }
105
115
  if (entry === WORKFLOW_CONTAINER_NAME || entry === TEST_CONTAINER_NAME) {
106
116
  try {
107
117
  return !statSync(entryPath).isDirectory();
@@ -112,14 +122,12 @@ export function assertCompiledContainer(sourcePath) {
112
122
  }
113
123
  }
114
124
  try {
115
- if (!statSync(entryPath).isDirectory())
116
- return true;
125
+ return !statSync(entryPath).isDirectory();
117
126
  }
118
127
  catch (error) {
119
128
  warnInterf(`Warning: failed to inspect Interf entry at ${entryPath}: ${error instanceof Error ? error.message : String(error)}`);
120
129
  return true;
121
130
  }
122
- return false;
123
131
  });
124
132
  if (unexpectedRootEntries.length > 0) {
125
133
  throw new Error(`Interf container contains unexpected entries: ${interfRoot}`);
@@ -136,6 +144,16 @@ export function assertCompiledContainer(sourcePath) {
136
144
  const unexpectedEntries = readdirSync(containerPath).filter((entry) => {
137
145
  if (entry.startsWith("."))
138
146
  return false;
147
+ if (entry === INTERF_CONFIG_FILE) {
148
+ const entryPath = join(containerPath, entry);
149
+ try {
150
+ return !statSync(entryPath).isFile();
151
+ }
152
+ catch (error) {
153
+ warnInterf(`Warning: failed to inspect Interf config path at ${entryPath}: ${error instanceof Error ? error.message : String(error)}`);
154
+ return true;
155
+ }
156
+ }
139
157
  if (entry === WORKFLOW_CONTAINER_NAME || entry === TEST_CONTAINER_NAME)
140
158
  return false;
141
159
  const entryPath = join(containerPath, entry);
@@ -147,11 +165,7 @@ export function assertCompiledContainer(sourcePath) {
147
165
  warnInterf(`Warning: failed to inspect Interf entry at ${entryPath}: ${error instanceof Error ? error.message : String(error)}`);
148
166
  return true;
149
167
  }
150
- const compiledPath = compiledCompiledPathForDataset(sourcePath, entry);
151
- if (!existsSync(compiledPath)) {
152
- return false;
153
- }
154
- return !readInterfConfig(compiledPath);
168
+ return false;
155
169
  });
156
170
  if (unexpectedEntries.length > 0) {
157
171
  throw new Error(`Interf container contains invalid dataset entries: ${containerPath}`);
@@ -1,2 +1,3 @@
1
+ export declare function ensurePortableContextScaffold(sourcePath: string, datasetName: string, workflowId?: string): string;
1
2
  export declare function createCompiled(name: string, sourcePath: string, workflowId?: string, about?: string, datasetPath?: string): string;
2
3
  export declare function defaultCompiledNameForSource(sourcePath: string): string;
@@ -1,15 +1,16 @@
1
1
  import { mkdirSync, existsSync, writeFileSync, } from "node:fs";
2
2
  import { basename, join, relative, sep } from "node:path";
3
3
  import { getCompiledWorkflow } from "../workflow-package/workflow-definitions.js";
4
+ import { loadWorkflowDefinitionFromDir, seedLocalDefaultWorkflow } from "../workflow-package/local-workflows.js";
4
5
  import { initializeCompiledRuntimeState, } from "../compiler/state.js";
5
6
  import { refreshCompiledBootstrapGuidance } from "../agents/lib/compiled-bootstrap.js";
6
7
  import { syncCompiledRawSnapshot } from "../compiler/raw-snapshot.js";
7
- import { assertCompiledContainer, assertWritableTargetDir, assertCompiledName, } from "./interf-detect.js";
8
+ import { assertCompiledContainer, assertCompiledName, } from "./interf-detect.js";
8
9
  import { seedCompiledWorkflowPackage } from "../workflow-package/interf-workflow-package.js";
9
10
  import { compiledCompiledPathForDataset } from "./project-paths.js";
10
11
  import { ensureCompiledZoneTargets, readCompiledSchemaFile } from "../compiler/compiled-schema.js";
11
12
  import { findSourceDatasetConfig, listSourceDatasetConfigs, loadSourceFolderConfig, resolveSourceDatasetPath, saveCompiledInterfConfig, } from "./source-config.js";
12
- import { defaultControlPathForCompiled, workflowPackagePathForCompiled } from "../compiler/compiled-paths.js";
13
+ import { defaultControlPathForCompiled, testRootForCompiled, workflowPackagePathForCompiled } from "../compiler/compiled-paths.js";
13
14
  const DEFAULT_INTERFIGNORE = [
14
15
  ".claude/",
15
16
  ".codex/",
@@ -61,14 +62,37 @@ function scaffoldCompiledOutputs(compiledPath, compiledName, about) {
61
62
  writeFileSync(targetPath, renderUncompiledCompiledFile(compiledName, zone.path, about));
62
63
  }
63
64
  }
64
- export function createCompiled(name, sourcePath, workflowId = "interf", about, datasetPath) {
65
- assertCompiledName(name, "Portable context");
65
+ function localWorkflowMatches(compiledPath, workflowId) {
66
+ const localWorkflow = loadWorkflowDefinitionFromDir(workflowPackagePathForCompiled(compiledPath));
67
+ return localWorkflow?.id === workflowId;
68
+ }
69
+ export function ensurePortableContextScaffold(sourcePath, datasetName, workflowId = "interf") {
70
+ assertCompiledName(datasetName, "Portable context");
66
71
  assertCompiledContainer(sourcePath);
67
- const compiledPath = compiledCompiledPathForDataset(sourcePath, name);
68
- assertWritableTargetDir(compiledPath, "Portable context");
72
+ const compiledPath = compiledCompiledPathForDataset(sourcePath, datasetName);
69
73
  mkdirSync(compiledPath, { recursive: true });
74
+ mkdirSync(testRootForCompiled(compiledPath), { recursive: true });
75
+ if (workflowId === "interf-default") {
76
+ seedLocalDefaultWorkflow({ sourcePath });
77
+ }
78
+ const selectedWorkflow = getCompiledWorkflow(workflowId, { sourcePath });
79
+ if (!localWorkflowMatches(compiledPath, selectedWorkflow.id)) {
80
+ seedCompiledWorkflowPackage({
81
+ compiledPath,
82
+ sourcePath,
83
+ workflowId: selectedWorkflow.id,
84
+ });
85
+ }
86
+ if (!existsSync(join(compiledPath, ".gitignore"))) {
87
+ writeFileSync(join(compiledPath, ".gitignore"), [...compiledGitignoreEntries(compiledPath), ""].join("\n"));
88
+ }
89
+ return compiledPath;
90
+ }
91
+ export function createCompiled(name, sourcePath, workflowId = "interf", about, datasetPath) {
92
+ assertCompiledName(name, "Portable context");
70
93
  const savedCompiled = findSourceDatasetConfig(loadSourceFolderConfig(sourcePath), name);
71
94
  const selectedWorkflow = getCompiledWorkflow(workflowId, { sourcePath });
95
+ const compiledPath = ensurePortableContextScaffold(sourcePath, name, selectedWorkflow.id);
72
96
  const resolvedAbout = about ?? savedCompiled?.about;
73
97
  const resolvedDatasetPath = (() => {
74
98
  if (savedCompiled) {
@@ -108,11 +132,6 @@ export function createCompiled(name, sourcePath, workflowId = "interf", about, d
108
132
  mkdirSync(join(compiledPath, "raw"), { recursive: true });
109
133
  syncCompiledRawSnapshot(compiledPath, resolvedDatasetPath);
110
134
  writeFileSync(join(compiledPath, ".interfignore"), DEFAULT_INTERFIGNORE);
111
- seedCompiledWorkflowPackage({
112
- compiledPath,
113
- sourcePath,
114
- workflowId: selectedWorkflow.id,
115
- });
116
135
  scaffoldCompiledOutputs(compiledPath, name, about);
117
136
  refreshCompiledBootstrapGuidance(compiledPath);
118
137
  writeFileSync(join(compiledPath, ".gitignore"), [...compiledGitignoreEntries(compiledPath), ""].join("\n"));
@@ -2,4 +2,4 @@ export { INTERF_CONTAINER_NAME, WORKFLOW_CONTAINER_NAME, TEST_CONTAINER_NAME, IN
2
2
  export type { InterfConfig, ResolvedCompiled } from "./interf-detect.js";
3
3
  export { ensureCompiledRawBinding, resolveCompiledRawPath, syncCompiledRawSnapshot, } from "./compiled-raw.js";
4
4
  export { refreshCompiledBootstrapGuidance, renderClaudeBootstrap, } from "./interf-bootstrap.js";
5
- export { createCompiled, defaultCompiledNameForSource, } from "./interf-scaffold.js";
5
+ export { createCompiled, defaultCompiledNameForSource, ensurePortableContextScaffold, } from "./interf-scaffold.js";
@@ -1,4 +1,4 @@
1
1
  export { INTERF_CONTAINER_NAME, WORKFLOW_CONTAINER_NAME, TEST_CONTAINER_NAME, INTERF_CONFIG_FILE, WORKFLOW_PACKAGE_DIR, readInterfConfig, detectInterf, resolveCompiled, resolveSourceFolderPath, resolveSourceControlPath, resolveSourceInputPath, listCompiledDatasetsForSourceFolder, hasSourceFolderInput, assertCompiledContainer, assertWritableTargetDir, assertCompiledName, } from "./interf-detect.js";
2
2
  export { ensureCompiledRawBinding, resolveCompiledRawPath, syncCompiledRawSnapshot, } from "./compiled-raw.js";
3
3
  export { refreshCompiledBootstrapGuidance, renderClaudeBootstrap, } from "./interf-bootstrap.js";
4
- export { createCompiled, defaultCompiledNameForSource, } from "./interf-scaffold.js";
4
+ export { createCompiled, defaultCompiledNameForSource, ensurePortableContextScaffold, } from "./interf-scaffold.js";
@@ -1,7 +1,9 @@
1
1
  export declare const PROJECT_INTERF_DIR = "interf";
2
- export declare const PROJECT_TESTS_DIR = "tests";
2
+ export declare const DATASET_INTERF_DIR = ".interf";
3
+ export declare const PORTABLE_CONTEXT_TESTS_DIR = "tests";
3
4
  export declare function projectInterfRoot(projectPath: string): string;
4
5
  export declare function compiledCompiledPathForDataset(projectPath: string, datasetName: string): string;
6
+ export declare function portableContextPath(projectPath: string, datasetName: string): string;
5
7
  export declare function datasetTestsRoot(projectPath: string, datasetName: string): string;
6
8
  export type DatasetTestTargetLabel = "file-as-is" | "compiled";
7
9
  export declare function datasetTestRunsRoot(projectPath: string, datasetName: string, target: DatasetTestTargetLabel): string;
@@ -1,14 +1,18 @@
1
1
  import { join } from "node:path";
2
2
  export const PROJECT_INTERF_DIR = "interf";
3
- export const PROJECT_TESTS_DIR = "tests";
3
+ export const DATASET_INTERF_DIR = ".interf";
4
+ export const PORTABLE_CONTEXT_TESTS_DIR = "tests";
4
5
  export function projectInterfRoot(projectPath) {
5
6
  return join(projectPath, PROJECT_INTERF_DIR);
6
7
  }
7
8
  export function compiledCompiledPathForDataset(projectPath, datasetName) {
8
9
  return join(projectInterfRoot(projectPath), datasetName);
9
10
  }
11
+ export function portableContextPath(projectPath, datasetName) {
12
+ return compiledCompiledPathForDataset(projectPath, datasetName);
13
+ }
10
14
  export function datasetTestsRoot(projectPath, datasetName) {
11
- return join(projectInterfRoot(projectPath), PROJECT_TESTS_DIR, datasetName);
15
+ return join(portableContextPath(projectPath, datasetName), DATASET_INTERF_DIR, PORTABLE_CONTEXT_TESTS_DIR);
12
16
  }
13
17
  export function datasetTestRunsRoot(projectPath, datasetName, target) {
14
18
  return join(datasetTestsRoot(projectPath, datasetName), target, "runs");
@@ -1,10 +1,15 @@
1
1
  import { type InterfConfig, type SourceTruthCheck, type SourceDatasetConfig, type SourceFolderConfig } from "./lib/schema.js";
2
2
  import type { TestSpec, TestTargetType } from "../testing/lib/schema.js";
3
3
  export declare const SOURCE_FOLDER_CONFIG_FILE = "interf.json";
4
+ export declare const SOURCE_FOLDER_CONFIG_PATH = "interf/interf.json";
4
5
  export interface LoadedSourceTestSpec extends TestSpec {
5
6
  id: string;
6
7
  filePath: string;
7
8
  }
9
+ export declare function sourceFolderConfigPath(sourcePath: string): string;
10
+ export declare function legacySourceFolderConfigPath(sourcePath: string): string;
11
+ export declare function resolveSourceFolderConfigPath(sourcePath: string): string;
12
+ export declare function migrateLegacySourceFolderConfig(sourcePath: string): boolean;
8
13
  export declare function fingerprintTruthChecks(checks: SourceTruthCheck[]): string;
9
14
  export declare function loadSourceFolderConfig(sourcePath: string): SourceFolderConfig | null;
10
15
  export interface WritableSourceProjectConfig {
@@ -1,5 +1,5 @@
1
1
  import { createHash } from "node:crypto";
2
- import { existsSync, mkdirSync, writeFileSync } from "node:fs";
2
+ import { existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
3
3
  import { join, relative, resolve, sep } from "node:path";
4
4
  import { refreshCompiledBootstrapGuidance } from "../agents/lib/compiled-bootstrap.js";
5
5
  import { readInterfConfig, } from "./interf.js";
@@ -10,10 +10,61 @@ import { SourceFolderConfigSchema, } from "./lib/schema.js";
10
10
  import { slugify } from "../shared/naming.js";
11
11
  import { assertPathWithinRoot } from "../shared/path-guards.js";
12
12
  import { defaultControlPathForCompiled, resolveSourceControlPathForCompiled, compiledInterfConfigPath, compiledInterfRoot, } from "../compiler/compiled-paths.js";
13
+ import { projectInterfRoot, PROJECT_INTERF_DIR } from "./project-paths.js";
13
14
  export const SOURCE_FOLDER_CONFIG_FILE = "interf.json";
14
- function sourceConfigPath(sourcePath) {
15
+ export const SOURCE_FOLDER_CONFIG_PATH = `${PROJECT_INTERF_DIR}/${SOURCE_FOLDER_CONFIG_FILE}`;
16
+ export function sourceFolderConfigPath(sourcePath) {
17
+ return join(projectInterfRoot(sourcePath), SOURCE_FOLDER_CONFIG_FILE);
18
+ }
19
+ export function legacySourceFolderConfigPath(sourcePath) {
15
20
  return join(sourcePath, SOURCE_FOLDER_CONFIG_FILE);
16
21
  }
22
+ export function resolveSourceFolderConfigPath(sourcePath) {
23
+ const primaryPath = sourceFolderConfigPath(sourcePath);
24
+ if (existsSync(primaryPath))
25
+ return primaryPath;
26
+ const legacyPath = legacySourceFolderConfigPath(sourcePath);
27
+ if (existsSync(legacyPath))
28
+ return legacyPath;
29
+ return primaryPath;
30
+ }
31
+ function readSourceFolderConfigFile(filePath) {
32
+ return readJsonFileWithSchema(filePath, "Interf project config", SourceFolderConfigSchema);
33
+ }
34
+ function readJsonFileUncheckedQuiet(filePath) {
35
+ try {
36
+ return JSON.parse(readFileSync(filePath, "utf-8"));
37
+ }
38
+ catch {
39
+ return null;
40
+ }
41
+ }
42
+ function isValidLegacySourceFolderConfig(sourcePath) {
43
+ const legacyPath = legacySourceFolderConfigPath(sourcePath);
44
+ if (!existsSync(legacyPath))
45
+ return false;
46
+ const raw = readJsonFileUncheckedQuiet(legacyPath);
47
+ return SourceFolderConfigSchema.safeParse(raw).success;
48
+ }
49
+ export function migrateLegacySourceFolderConfig(sourcePath) {
50
+ const primaryPath = sourceFolderConfigPath(sourcePath);
51
+ const legacyPath = legacySourceFolderConfigPath(sourcePath);
52
+ if (existsSync(primaryPath) || !existsSync(legacyPath))
53
+ return false;
54
+ if (!isValidLegacySourceFolderConfig(sourcePath))
55
+ return false;
56
+ mkdirSync(projectInterfRoot(sourcePath), { recursive: true });
57
+ renameSync(legacyPath, primaryPath);
58
+ return true;
59
+ }
60
+ function removeLegacySourceFolderConfig(sourcePath) {
61
+ const legacyPath = legacySourceFolderConfigPath(sourcePath);
62
+ if (!existsSync(legacyPath))
63
+ return;
64
+ if (!isValidLegacySourceFolderConfig(sourcePath))
65
+ return;
66
+ rmSync(legacyPath, { force: true });
67
+ }
17
68
  function normalizeTruthChecks(cases) {
18
69
  const seen = new Set();
19
70
  return cases.map((caseSpec, index) => {
@@ -47,10 +98,10 @@ export function fingerprintTruthChecks(checks) {
47
98
  .slice(0, 16);
48
99
  }
49
100
  export function loadSourceFolderConfig(sourcePath) {
50
- const filePath = sourceConfigPath(sourcePath);
101
+ const filePath = resolveSourceFolderConfigPath(sourcePath);
51
102
  if (!existsSync(filePath))
52
103
  return null;
53
- return readJsonFileWithSchema(filePath, "Interf project config", SourceFolderConfigSchema);
104
+ return readSourceFolderConfigFile(filePath);
54
105
  }
55
106
  export function listSourceDatasetConfigs(config) {
56
107
  return config?.datasets ?? [];
@@ -101,7 +152,9 @@ function toWritableSourceDatasetConfig(dataset) {
101
152
  };
102
153
  }
103
154
  export function saveSourceFolderConfig(sourcePath, config) {
104
- writeFileSync(sourceConfigPath(sourcePath), JSON.stringify(toWritableSourceProjectConfig(config), null, 2) + "\n");
155
+ mkdirSync(projectInterfRoot(sourcePath), { recursive: true });
156
+ writeFileSync(sourceFolderConfigPath(sourcePath), JSON.stringify(toWritableSourceProjectConfig(config), null, 2) + "\n");
157
+ removeLegacySourceFolderConfig(sourcePath);
105
158
  }
106
159
  export function appendSourceDatasetChecks(sourcePath, datasetName, checks) {
107
160
  const existing = loadSourceFolderConfig(sourcePath);
@@ -263,7 +316,7 @@ export function buildTestSpecFromSourceFolderConfig(options) {
263
316
  : getDefaultSourceDatasetConfig(config);
264
317
  if (!match)
265
318
  return null;
266
- const configPath = sourceConfigPath(sourcePath);
319
+ const configPath = resolveSourceFolderConfigPath(sourcePath);
267
320
  return buildLoadedTestSpec({
268
321
  id: match.id,
269
322
  name: match.name,
@@ -273,7 +326,7 @@ export function buildTestSpecFromSourceFolderConfig(options) {
273
326
  filePath: targetType === "raw"
274
327
  ? `${configPath}#datasets/${match.name}:file-as-is`
275
328
  : `${configPath}#datasets/${match.name}:compiled`,
276
- fallbackDescription: `Derived from saved dataset checks in ${SOURCE_FOLDER_CONFIG_FILE}`,
329
+ fallbackDescription: `Derived from saved dataset checks in ${SOURCE_FOLDER_CONFIG_PATH}`,
277
330
  });
278
331
  }
279
332
  export function buildTestSpecFromCompiledDatasetConfig(options) {
@@ -10,7 +10,10 @@ export function testSpecTypePath(sourcePath, type) {
10
10
  return join(testSpecRootPath(sourcePath), type);
11
11
  }
12
12
  function isDatasetTestsRootPath(artifactRootPath) {
13
- return basename(dirname(artifactRootPath)) === "tests";
13
+ const portableContextTestsRoot = basename(artifactRootPath) === "tests" &&
14
+ basename(dirname(artifactRootPath)) === ".interf";
15
+ const legacyProjectTestsRoot = basename(dirname(artifactRootPath)) === "tests";
16
+ return portableContextTestsRoot || legacyProjectTestsRoot;
14
17
  }
15
18
  export function targetTestRunsPath(compiledPath, type) {
16
19
  if (existsSync(compiledInterfConfigPath(compiledPath))) {
@@ -19,7 +22,7 @@ export function targetTestRunsPath(compiledPath, type) {
19
22
  if (isDatasetTestsRootPath(compiledPath)) {
20
23
  return join(compiledPath, type === "raw" ? "file-as-is" : "compiled", "runs");
21
24
  }
22
- throw new Error(`Unsupported test artifact root: ${compiledPath}. Expected a compiled context or interf/tests/<dataset> root.`);
25
+ throw new Error(`Unsupported test artifact root: ${compiledPath}. Expected a compiled context or interf/<dataset>/.interf/tests root.`);
23
26
  }
24
27
  export function targetTestRunGitignorePath(compiledPath, type) {
25
28
  return join(targetTestRunsPath(compiledPath, type), ".gitignore");
@@ -31,7 +34,7 @@ export function targetTestSandboxesPath(compiledPath, type) {
31
34
  if (isDatasetTestsRootPath(compiledPath)) {
32
35
  return join(compiledPath, type === "raw" ? "file-as-is" : "compiled", "sandboxes");
33
36
  }
34
- throw new Error(`Unsupported test artifact root: ${compiledPath}. Expected a compiled context or interf/tests/<dataset> root.`);
37
+ throw new Error(`Unsupported test artifact root: ${compiledPath}. Expected a compiled context or interf/<dataset>/.interf/tests root.`);
35
38
  }
36
39
  export function targetTestSandboxGitignorePath(compiledPath, type) {
37
40
  return join(targetTestSandboxesPath(compiledPath, type), ".gitignore");
@@ -13,15 +13,17 @@ function buildWorkflowAuthoringPrompt() {
13
13
  return [
14
14
  "This is an automated Interf workflow-authoring run, not an open-ended chat session.",
15
15
  "Execute it now.",
16
- "Create one standalone workflow for the files and checks in this source folder.",
16
+ "Create one standalone workflow for the source data, desired portable-context outputs, and proof requirements in this source folder.",
17
17
  "Read `runtime/authoring-context.json` first.",
18
+ "Treat `task_prompt` as the user's produce-and-prove brief: source data, output shape, and evidence that should show the data is ready.",
18
19
  `Then read \`workflow/README.md\`, \`workflow/workflow.json\`, and \`workflow/${CONTEXT_INTERFACE_FILE}\`.`,
19
20
  "Review `artifacts/source-dataset/raw/` and any `artifacts/preview-compiled/` notes before editing the package.",
20
21
  "Prefer direct file-reading and search tools over shell commands for routine file inspection.",
21
22
  "Do not use shell helpers like `cat`, `sed`, `ls`, or `find` when a native read/search tool can inspect the same files.",
22
23
  "Edit only files under `workflow/`.",
23
24
  "Keep the workflow valid for the current compiler API and workflow schema.",
24
- "Make the package materially more specific to this dataset task than the seeded base workflow. A no-op copy is not acceptable.",
25
+ "When editing acceptance rules: `zone_counts_at_least` takes numeric fixed minimums; `zone_counts_at_least_counts` takes runtime count-key strings such as `source_total`, never numbers.",
26
+ "Make the package materially more specific to this dataset task, output shape, and proof requirement than the seeded base workflow. A no-op copy is not acceptable.",
25
27
  "Treat the workflow package as four aligned layers: purpose, inputs, context interface, and stages.",
26
28
  "Prefer explicit stage-doc, stage-policy, purpose, input-contract, and context-interface edits over vague rewrites.",
27
29
  "Do not introduce wikilinks unless the workflow also creates the target note by exact basename or explicit relative path.",
@@ -37,13 +37,16 @@ export async function runWorkflowEditSession(options) {
37
37
  const validation = options.validate(options.workflowPath);
38
38
  if (!validation.ok) {
39
39
  copyDirectory(options.shell.workflowBeforePath, options.workflowPath);
40
+ const details = validation.errors.length > 0
41
+ ? `: ${validation.errors.slice(0, 6).join("; ")}`
42
+ : "";
40
43
  return {
41
44
  status: "invalid",
42
45
  changed,
43
46
  validation,
44
47
  summary: changed
45
- ? `Workflow package failed validation: ${validation.summary}`
46
- : `Workflow package is invalid without any workflow edits: ${validation.summary}`,
48
+ ? `Workflow package failed validation: ${validation.summary}${details}`
49
+ : `Workflow package is invalid without any workflow edits: ${validation.summary}${details}`,
47
50
  };
48
51
  }
49
52
  return {
@@ -13,7 +13,7 @@ export const ContextInterfaceSchema = WorkflowCompiledSchemaSchema;
13
13
  export const ContextInterfaceZoneSchema = WorkflowCompiledZoneSchema;
14
14
  export const ContextInterfaceZoneIdSchema = WorkflowZoneIdSchema;
15
15
  export const ContextInterfaceZoneRoleSchema = WorkflowZoneRoleSchema;
16
- // Package-owned input contract for authoring, review, and future Studio flows.
16
+ // Package-owned input contract for authoring, review, and future authoring flows.
17
17
  // This does not change compiler execution semantics; it describes what data a
18
18
  // workflow expects to organize before the compiler materializes the context
19
19
  // interface on disk.
@@ -1,4 +1,5 @@
1
1
  import { existsSync } from "node:fs";
2
+ import { join } from "node:path";
2
3
  import { testRootForCompiled, targetTestRunsRootForCompiled, targetTestSandboxesRootForCompiled, stageExecutionShellsRoot, compiledRuntimeRoot, } from "../compiler/compiled-paths.js";
3
4
  export function resolveWorkflowImprovementReviewSourcePaths(compiledPath) {
4
5
  const compiledRuntime = compiledRuntimeRoot(compiledPath);
@@ -8,7 +9,10 @@ export function resolveWorkflowImprovementReviewSourcePaths(compiledPath) {
8
9
  const targetTestSandboxes = targetTestSandboxesRootForCompiled(compiledPath);
9
10
  return {
10
11
  compiledRuntime: existsSync(compiledRuntime) ? compiledRuntime : null,
11
- testComparisons: existsSync(testComparisons) ? testComparisons : null,
12
+ testComparisons: existsSync(join(testComparisons, "latest.json")) ||
13
+ existsSync(join(testComparisons, "latest.md"))
14
+ ? testComparisons
15
+ : null,
12
16
  executionShells: existsSync(executionShells) ? executionShells : null,
13
17
  targetTestRuns: existsSync(targetTestRuns) ? targetTestRuns : null,
14
18
  targetTestSandboxes: existsSync(targetTestSandboxes) ? targetTestSandboxes : null,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@interf/compiler",
3
- "version": "0.7.1",
4
- "description": "Local, open-source context compiler for agent work. Build portable context from your files with a compilation workflow you define. Check on your own questions.",
3
+ "version": "0.7.3",
4
+ "description": "Interf prepares data for agent work. It runs locally, processes your files, shows evidence that your data is ready, and writes portable context: a local folder with verifiable outputs agents can use.",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "interf": "dist/bin.js"
@@ -43,8 +43,6 @@
43
43
  "scripts": {
44
44
  "build": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\" && tsc && chmod 755 dist/bin.js",
45
45
  "dev": "tsc --watch",
46
- "setup:local-skills": "bash scripts/setup-local-skills.sh",
47
- "refresh:bootstrap-mirror": "node scripts/docs/sync-bootstrap-mirror.mjs",
48
46
  "docs:sync-public-test-example": "npm run build && node scripts/docs/sync-public-test-example.mjs",
49
47
  "test:matrix": "npm run build && node scripts/matrix/run.mjs",
50
48
  "test:smoke": "npm run build && node --test test/**/*.test.mjs",