@interf/compiler 0.5.0 → 0.5.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 (42) hide show
  1. package/README.md +6 -7
  2. package/dist/commands/compile-controller.js +3 -3
  3. package/dist/commands/test-flow.js +5 -16
  4. package/dist/lib/agent-shells.js +1 -1
  5. package/dist/lib/{workflow-abi.d.ts → builtin-compiled-workflow.d.ts} +2 -2
  6. package/dist/lib/{workflow-abi.js → builtin-compiled-workflow.js} +2 -5
  7. package/dist/lib/compiled-compile.js +2 -2
  8. package/dist/lib/compiled-paths.d.ts +0 -2
  9. package/dist/lib/compiled-paths.js +5 -13
  10. package/dist/lib/compiled-raw.d.ts +2 -2
  11. package/dist/lib/compiled-schema.d.ts +2 -2
  12. package/dist/lib/compiled-schema.js +2 -2
  13. package/dist/lib/interf-detect.d.ts +0 -1
  14. package/dist/lib/interf-detect.js +7 -18
  15. package/dist/lib/interf.d.ts +1 -1
  16. package/dist/lib/interf.js +1 -1
  17. package/dist/lib/local-workflows.js +1 -1
  18. package/dist/lib/project-paths.d.ts +2 -4
  19. package/dist/lib/project-paths.js +13 -10
  20. package/dist/lib/runtime-prompt.js +1 -3
  21. package/dist/lib/runtime-reconcile.js +3 -14
  22. package/dist/lib/runtime-runs.js +2 -87
  23. package/dist/lib/schema.d.ts +33 -40
  24. package/dist/lib/schema.js +17 -104
  25. package/dist/lib/source-config.js +21 -22
  26. package/dist/lib/state-health.js +4 -2
  27. package/dist/lib/state-io.js +2 -110
  28. package/dist/lib/state-view.js +2 -2
  29. package/dist/lib/summarize-plan.js +1 -5
  30. package/dist/lib/test-paths.js +12 -3
  31. package/dist/lib/test-sandbox.js +4 -17
  32. package/dist/lib/test-specs.js +1 -1
  33. package/dist/lib/validate-compiled.js +4 -2
  34. package/dist/lib/validate.d.ts +2 -0
  35. package/dist/lib/validate.js +27 -12
  36. package/dist/lib/workflow-definitions.d.ts +3 -2
  37. package/dist/lib/workflow-definitions.js +9 -2
  38. package/dist/lib/workflow-primitives.d.ts +2 -0
  39. package/dist/lib/workflow-primitives.js +5 -0
  40. package/package.json +6 -6
  41. package/dist/lib/compiled-layout.d.ts +0 -2
  42. package/dist/lib/compiled-layout.js +0 -60
@@ -108,11 +108,7 @@ function readSourceReference(synthPath) {
108
108
  const parsed = parseJsonFrontmatter(content);
109
109
  const source = typeof parsed?.frontmatter.source === "string"
110
110
  ? parsed.frontmatter.source
111
- : typeof parsed?.frontmatter.source_file === "string"
112
- ? parsed.frontmatter.source_file
113
- : typeof parsed?.frontmatter.raw === "string"
114
- ? parsed.frontmatter.raw
115
- : null;
111
+ : null;
116
112
  return source?.trim() ?? null;
117
113
  }
118
114
  function defaultSummaryPath(sourcePath) {
@@ -1,5 +1,5 @@
1
1
  import { existsSync } from "node:fs";
2
- import { join } from "node:path";
2
+ import { basename, dirname, join } from "node:path";
3
3
  import { targetTestRunsRootForCompiled, targetTestSandboxesRootForCompiled, compiledInterfConfigPath, } from "./compiled-paths.js";
4
4
  const TEST_ID_PATTERN = /^[a-z0-9][a-z0-9-]{0,79}$/;
5
5
  export const TEST_SPEC_EXTENSIONS = new Set([".json"]);
@@ -9,11 +9,17 @@ export function testSpecRootPath(sourcePath) {
9
9
  export function testSpecTypePath(sourcePath, type) {
10
10
  return join(testSpecRootPath(sourcePath), type);
11
11
  }
12
+ function isDatasetTestsRootPath(artifactRootPath) {
13
+ return basename(dirname(artifactRootPath)) === "tests";
14
+ }
12
15
  export function targetTestRunsPath(compiledPath, type) {
13
16
  if (existsSync(compiledInterfConfigPath(compiledPath))) {
14
17
  return join(targetTestRunsRootForCompiled(compiledPath), type);
15
18
  }
16
- return join(compiledPath, "tests", type === "raw" ? "file-as-is" : "compiled", "runs");
19
+ if (isDatasetTestsRootPath(compiledPath)) {
20
+ return join(compiledPath, type === "raw" ? "file-as-is" : "compiled", "runs");
21
+ }
22
+ throw new Error(`Unsupported test artifact root: ${compiledPath}. Expected a compiled dataset or interf/tests/<dataset> root.`);
17
23
  }
18
24
  export function targetTestRunGitignorePath(compiledPath, type) {
19
25
  return join(targetTestRunsPath(compiledPath, type), ".gitignore");
@@ -22,7 +28,10 @@ export function targetTestSandboxesPath(compiledPath, type) {
22
28
  if (existsSync(compiledInterfConfigPath(compiledPath))) {
23
29
  return join(targetTestSandboxesRootForCompiled(compiledPath), type);
24
30
  }
25
- return join(compiledPath, "tests", type === "raw" ? "file-as-is" : "compiled", "sandboxes");
31
+ if (isDatasetTestsRootPath(compiledPath)) {
32
+ return join(compiledPath, type === "raw" ? "file-as-is" : "compiled", "sandboxes");
33
+ }
34
+ throw new Error(`Unsupported test artifact root: ${compiledPath}. Expected a compiled dataset or interf/tests/<dataset> root.`);
26
35
  }
27
36
  export function targetTestSandboxGitignorePath(compiledPath, type) {
28
37
  return join(targetTestSandboxesPath(compiledPath, type), ".gitignore");
@@ -2,10 +2,10 @@ import { cpSync, existsSync, mkdirSync, mkdtempSync, renameSync, rmSync, } from
2
2
  import { tmpdir } from "node:os";
3
3
  import { dirname, join, relative, sep } from "node:path";
4
4
  import { refreshCompiledBootstrapGuidance } from "./interf-bootstrap.js";
5
- import { readInterfConfig, resolveSourceControlPath, resolveCompiledRawPath } from "./interf.js";
5
+ import { readInterfConfig, resolveCompiledRawPath } from "./interf.js";
6
6
  import { projectRawTestQueryShell } from "./agent-shells.js";
7
7
  import { compiledCompiledPathForDataset } from "./project-paths.js";
8
- import { findSourceDatasetConfig, loadSourceFolderConfig, resolveSourceDatasetPath, saveCompiledInterfConfig, } from "./source-config.js";
8
+ import { saveCompiledInterfConfig } from "./source-config.js";
9
9
  import { refreshCompiledArtifacts } from "./state.js";
10
10
  import { projectRawSnapshot } from "./compiled-raw.js";
11
11
  import { testRootForCompiled, stageExecutionShellsRoot, targetTestSandboxesRootForCompiled, workflowImprovementLoopsRoot, compiledQueryAcceptanceRoot, compiledRuntimeLogsRoot, } from "./compiled-paths.js";
@@ -46,27 +46,14 @@ export function createTestSandbox(target) {
46
46
  throw new Error(`Sandbox compiled is missing interf.json: ${sandboxTargetPath()}`);
47
47
  }
48
48
  if (!existsSync(resolveCompiledRawPath(sandboxTargetPath(), sandboxConfig))) {
49
- const projectPath = resolveSourceControlPath(target.path);
50
- const projectConfig = loadSourceFolderConfig(projectPath);
51
- const datasetConfig = findSourceDatasetConfig(projectConfig, sandboxConfig.name);
52
- if (!datasetConfig) {
53
- throw new Error(`Sandbox compiled is missing a trusted dataset binding for "${sandboxConfig.name}": ${target.path}`);
54
- }
55
- const controlSourcePath = resolveSourceDatasetPath(projectPath, datasetConfig);
56
- projectRawSnapshot({
57
- sourcePath: controlSourcePath,
58
- destinationPath: sandboxRawPath(),
59
- compiledPath: target.path,
60
- mode: "link-or-copy",
61
- prune: false,
62
- preserveTimestamps: false,
63
- });
49
+ throw new Error(`Sandbox compiled is missing its local raw snapshot: ${sandboxTargetPath()}. Rebuild the compiled dataset before testing it.`);
64
50
  }
65
51
  saveCompiledInterfConfig(sandboxTargetPath(), {
66
52
  ...sandboxConfig,
67
53
  checks: [],
68
54
  source: {
69
55
  path: toPortableRelativePath(sandboxTargetPath(), sandboxRawPath()),
56
+ dataset_path: toPortableRelativePath(sandboxTargetPath(), sandboxRawPath()),
70
57
  },
71
58
  });
72
59
  refreshCompiledBootstrapGuidance(sandboxTargetPath());
@@ -21,7 +21,7 @@ function serializeTestSpec(spec) {
21
21
  type: spec.type,
22
22
  name: spec.name,
23
23
  ...(spec.description ? { description: spec.description } : {}),
24
- checks: spec.cases.map((testCase) => ({
24
+ cases: spec.cases.map((testCase) => ({
25
25
  id: testCase.id,
26
26
  question: testCase.question,
27
27
  ...(testCase.file ? { file: testCase.file } : {}),
@@ -7,7 +7,7 @@ import { compiledInterfConfigPath, workflowPackagePathForCompiled } from "./comp
7
7
  import { readCompiledConfig } from "./validate.js";
8
8
  import { loadState } from "./state.js";
9
9
  import { validateResolvedStageAcceptance, stageRecordFromState } from "./runtime-acceptance.js";
10
- import { getActiveCompiledWorkflow, resolveCompiledWorkflowFromConfig, } from "./workflow-definitions.js";
10
+ import { getActiveCompiledWorkflow, resolveRequiredCompiledWorkflowFromConfig, } from "./workflow-definitions.js";
11
11
  import { listFilesRecursive } from "./filesystem.js";
12
12
  function countZoneArtifacts(compiledPath, zonePath, kind) {
13
13
  const absolutePath = compiledZoneAbsolutePath(compiledPath, { path: zonePath });
@@ -19,7 +19,9 @@ function countZoneArtifacts(compiledPath, zonePath, kind) {
19
19
  }
20
20
  function readWorkflowContext(dirPath) {
21
21
  const config = readCompiledConfig(dirPath);
22
- const workflowId = config.valid ? resolveCompiledWorkflowFromConfig(config.value) : null;
22
+ const workflowId = config.valid
23
+ ? resolveRequiredCompiledWorkflowFromConfig(config.value, `.interf/interf.json for ${dirPath}`)
24
+ : null;
23
25
  let workflow = null;
24
26
  if (workflowId) {
25
27
  try {
@@ -13,5 +13,7 @@ export declare function countBrokenWikilinks(compiledRoot: string, noteIndexRoot
13
13
  export declare function asNumber(value: unknown): number;
14
14
  export declare function isOutputMarkdownFile(filePath: string): boolean;
15
15
  export declare function safeReadText(filePath: string): string | null;
16
+ export declare function extractSynthAbstract(frontmatter: Record<string, unknown>, body: string): string | null;
17
+ export declare function countSynthAbstractWords(frontmatter: Record<string, unknown>, body: string): number;
16
18
  export { validateCompiled, validateCompiledStage, validateCompiledWorkflow, validateCompiledSummarize, validateCompiledStructure, validateCompiledCompile, } from "./validate-compiled.js";
17
19
  export type { CompiledValidationSummary, CompiledStageValidation, CompiledWorkflowValidation, } from "./validate-compiled.js";
@@ -48,7 +48,7 @@ export function validateSynthFiles(files) {
48
48
  invalidFrontmatter += 1;
49
49
  continue;
50
50
  }
51
- const abstractWords = countAbstractWords(parsed.frontmatter, parsed.body);
51
+ const abstractWords = countSynthAbstractWords(parsed.frontmatter, parsed.body);
52
52
  if (abstractWords < MIN_ABSTRACT_WORDS) {
53
53
  shortAbstracts += 1;
54
54
  }
@@ -139,21 +139,36 @@ function dedupeFiles(dirPaths) {
139
139
  return files;
140
140
  }
141
141
  function hasRequiredSynthFields(frontmatter) {
142
- const hasSourceReference = "source" in frontmatter || "source_file" in frontmatter || "raw" in frontmatter;
142
+ const hasSourceReference = "source" in frontmatter;
143
143
  return hasSourceReference && REQUIRED_DIGEST_FIELDS.every((field) => field in frontmatter);
144
144
  }
145
- function countAbstractWords(frontmatter, body) {
146
- const frontmatterAbstract = typeof frontmatter.abstract === "string" ? frontmatter.abstract : null;
147
- if (frontmatterAbstract && frontmatterAbstract.trim().length > 0) {
148
- return countWords(frontmatterAbstract);
145
+ function extractBodyAbstract(body) {
146
+ const lines = body.split(/\r?\n/);
147
+ const abstractHeadingIndex = lines.findIndex((line) => /^#{1,2}\s+Abstract\s*$/.test(line.trim()));
148
+ if (abstractHeadingIndex < 0)
149
+ return null;
150
+ const abstractLines = [];
151
+ for (let index = abstractHeadingIndex + 1; index < lines.length; index += 1) {
152
+ const line = lines[index] ?? "";
153
+ if (/^#{1,2}\s+\S/.test(line.trim()))
154
+ break;
155
+ abstractLines.push(line);
149
156
  }
150
- const match = body.match(/^## Abstract\s+([\s\S]*?)(?:\n## |\n# |$)/m);
151
- if (!match)
152
- return 0;
153
- const abstractText = match[1];
154
- if (!abstractText)
157
+ const abstractText = abstractLines.join("\n").trim();
158
+ return abstractText.length > 0 ? abstractText : null;
159
+ }
160
+ export function extractSynthAbstract(frontmatter, body) {
161
+ const frontmatterAbstract = typeof frontmatter.abstract === "string" ? frontmatter.abstract.trim() : "";
162
+ if (frontmatterAbstract.length > 0) {
163
+ return frontmatterAbstract;
164
+ }
165
+ return extractBodyAbstract(body);
166
+ }
167
+ export function countSynthAbstractWords(frontmatter, body) {
168
+ const abstract = extractSynthAbstract(frontmatter, body);
169
+ if (!abstract)
155
170
  return 0;
156
- return countWords(abstractText);
171
+ return countWords(abstract);
157
172
  }
158
173
  function countWords(text) {
159
174
  return text
@@ -48,8 +48,9 @@ export declare function getCompiledWorkflow(workflowId: CompiledWorkflowId, opti
48
48
  sourcePath?: string;
49
49
  }): WorkflowDefinition<string>;
50
50
  export declare function getActiveCompiledWorkflow(compiledPath: string, fallbackWorkflowId: CompiledWorkflowId): WorkflowDefinition<string>;
51
- export declare function resolveCompiledWorkflowId(value: unknown): CompiledWorkflowId;
52
- export declare function resolveCompiledWorkflowFromConfig(config: unknown): CompiledWorkflowId;
51
+ export declare function resolveCompiledWorkflowId(value: unknown): CompiledWorkflowId | null;
52
+ export declare function resolveCompiledWorkflowFromConfig(config: unknown): CompiledWorkflowId | null;
53
+ export declare function resolveRequiredCompiledWorkflowFromConfig(config: unknown, label?: string): CompiledWorkflowId;
53
54
  export declare function formatCompiledWorkflowStageStep(workflowId: CompiledWorkflowId, stage: string, options?: {
54
55
  sourcePath?: string;
55
56
  }): string;
@@ -133,14 +133,21 @@ export function resolveCompiledWorkflowId(value) {
133
133
  if (typeof value === "string" && isWorkflowId(value)) {
134
134
  return value;
135
135
  }
136
- return "interf";
136
+ return null;
137
137
  }
138
138
  export function resolveCompiledWorkflowFromConfig(config) {
139
139
  if (!config || typeof config !== "object")
140
- return "interf";
140
+ return null;
141
141
  const raw = config;
142
142
  return resolveCompiledWorkflowId(raw.workflow);
143
143
  }
144
+ export function resolveRequiredCompiledWorkflowFromConfig(config, label = "compiled config") {
145
+ const workflowId = resolveCompiledWorkflowFromConfig(config);
146
+ if (!workflowId) {
147
+ throw new Error(`Missing or invalid workflow in ${label}.`);
148
+ }
149
+ return workflowId;
150
+ }
144
151
  export function formatCompiledWorkflowStageStep(workflowId, stage, options = {}) {
145
152
  return formatWorkflowStageStep(getCompiledWorkflow(workflowId, options), stage);
146
153
  }
@@ -0,0 +1,2 @@
1
+ export declare const COMPILED_ZONE_KINDS: readonly ["directory", "file", "runtime"];
2
+ export type CompiledZoneKind = typeof COMPILED_ZONE_KINDS[number];
@@ -0,0 +1,5 @@
1
+ export const COMPILED_ZONE_KINDS = [
2
+ "directory",
3
+ "file",
4
+ "runtime",
5
+ ];
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@interf/compiler",
3
- "version": "0.5.0",
4
- "description": "Interf Compiler is a local runtime for data-processing workflows that turn datasets into compiled datasets for local agents.",
3
+ "version": "0.5.1",
4
+ "description": "Interf Compiler is a local runtime for data-processing workflows that prepare datasets for accurate local agent use.",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "interf": "dist/bin.js"
@@ -37,11 +37,11 @@
37
37
  "test:internal:cbre:max:keep": "npm run test:matrix -- --matrix internal/test-matrices/cbre-chart-tier1-max.json --keep-project-clones",
38
38
  "test:full": "npm test && npm run test:e2e:quick:matrix",
39
39
  "test:release:matrix": "npm run test:internal:cbre:max",
40
- "test:release": "npm test && npm run test:e2e:claude && npm run test:e2e:codex",
40
+ "test:release": "npm test && npm run test:acceptance-live -- --agent claude-code --with-test && npm run test:acceptance-live -- --agent codex --with-test",
41
41
  "test:acceptance-live": "npm run build && node scripts/acceptance-live.mjs",
42
- "test:acceptance-cache:refresh": "npm run test:acceptance-cache:refresh:claude",
43
- "test:acceptance-cache:refresh:claude": "npm run build && node scripts/acceptance-live.mjs --agent claude-code --output-root .interf-test-cache/claude-code",
44
- "test:acceptance-cache:refresh:codex": "npm run build && node scripts/acceptance-live.mjs --agent codex --output-root .interf-test-cache/codex",
42
+ "test:acceptance-cache:refresh": "npm run test:acceptance-cache:refresh:claude && npm run test:acceptance-cache:refresh:codex",
43
+ "test:acceptance-cache:refresh:claude": "node scripts/acceptance-cache-refresh.mjs --agent claude-code",
44
+ "test:acceptance-cache:refresh:codex": "node scripts/acceptance-cache-refresh.mjs --agent codex",
45
45
  "test:acceptance-quick:create-compiled": "npm run build && node scripts/acceptance-targeted.mjs create-compiled",
46
46
  "test:acceptance-quick:compiled-query": "npm run build && node scripts/acceptance-targeted.mjs compiled-query",
47
47
  "test:acceptance-quick:self-improving": "npm run build && node scripts/acceptance-targeted.mjs self-improving-compile",
@@ -1,2 +0,0 @@
1
- export declare function normalizeLegacyCompiledLayout(compiledPath: string): boolean;
2
- export declare function compiledNeedsLegacyLayoutNormalization(compiledPath: string): boolean;
@@ -1,60 +0,0 @@
1
- import { existsSync, mkdirSync, readdirSync, renameSync, } from "node:fs";
2
- import { dirname, join } from "node:path";
3
- import { COMPILED_CONFIG_FILE, COMPILED_INTERF_DIR, COMPILED_RUNTIME_DIR, COMPILED_TEST_DIR, COMPILED_WORKFLOW_DIR, workflowPackagePathForCompiled, compiledInterfConfigPath, compiledInterfRoot, compiledRuntimeRoot, } from "./compiled-paths.js";
4
- const LEGACY_COMPILED_CONFIG_FILE = "interf.json";
5
- const LEGACY_WORKFLOW_DIR = "workflow";
6
- function movePathIfMissing(sourcePath, targetPath) {
7
- if (!existsSync(sourcePath)) {
8
- return false;
9
- }
10
- if (existsSync(targetPath)) {
11
- return false;
12
- }
13
- mkdirSync(dirname(targetPath), { recursive: true });
14
- renameSync(sourcePath, targetPath);
15
- return true;
16
- }
17
- export function normalizeLegacyCompiledLayout(compiledPath) {
18
- const interfRoot = compiledInterfRoot(compiledPath);
19
- const runtimeRoot = compiledRuntimeRoot(compiledPath);
20
- let changed = false;
21
- changed = movePathIfMissing(join(compiledPath, LEGACY_COMPILED_CONFIG_FILE), compiledInterfConfigPath(compiledPath)) || changed;
22
- changed = movePathIfMissing(join(compiledPath, LEGACY_WORKFLOW_DIR), workflowPackagePathForCompiled(compiledPath)) || changed;
23
- if (!existsSync(interfRoot)) {
24
- return changed;
25
- }
26
- for (const entry of readdirSync(interfRoot)) {
27
- if (entry === COMPILED_RUNTIME_DIR ||
28
- entry === COMPILED_TEST_DIR ||
29
- entry === COMPILED_WORKFLOW_DIR ||
30
- entry === COMPILED_CONFIG_FILE) {
31
- continue;
32
- }
33
- changed = movePathIfMissing(join(interfRoot, entry), join(runtimeRoot, entry)) || changed;
34
- }
35
- return changed;
36
- }
37
- export function compiledNeedsLegacyLayoutNormalization(compiledPath) {
38
- if (existsSync(join(compiledPath, LEGACY_COMPILED_CONFIG_FILE)) &&
39
- !existsSync(compiledInterfConfigPath(compiledPath))) {
40
- return true;
41
- }
42
- if (!existsSync(join(compiledPath, COMPILED_INTERF_DIR)))
43
- return false;
44
- if (existsSync(join(compiledPath, LEGACY_WORKFLOW_DIR)) &&
45
- !existsSync(workflowPackagePathForCompiled(compiledPath))) {
46
- return true;
47
- }
48
- for (const entry of readdirSync(join(compiledPath, COMPILED_INTERF_DIR))) {
49
- if (entry === COMPILED_RUNTIME_DIR ||
50
- entry === COMPILED_TEST_DIR ||
51
- entry === COMPILED_WORKFLOW_DIR ||
52
- entry === COMPILED_CONFIG_FILE) {
53
- continue;
54
- }
55
- if (!existsSync(join(compiledRuntimeRoot(compiledPath), entry))) {
56
- return true;
57
- }
58
- }
59
- return false;
60
- }