@interf/compiler 0.6.3 → 0.6.4

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 (115) hide show
  1. package/README.md +70 -64
  2. package/dist/cli/commands/check-draft.js +4 -4
  3. package/dist/cli/commands/compile-controller.js +23 -23
  4. package/dist/cli/commands/compile.js +2 -2
  5. package/dist/cli/commands/compiled-flow.js +4 -4
  6. package/dist/cli/commands/create-workflow-wizard.js +8 -8
  7. package/dist/cli/commands/create.js +5 -5
  8. package/dist/cli/commands/default.js +1 -1
  9. package/dist/cli/commands/init.js +43 -43
  10. package/dist/cli/commands/list.js +2 -2
  11. package/dist/cli/commands/reset.js +1 -1
  12. package/dist/cli/commands/source-config-wizard.d.ts +1 -1
  13. package/dist/cli/commands/source-config-wizard.js +40 -40
  14. package/dist/cli/commands/status.js +5 -5
  15. package/dist/cli/commands/test-flow.js +26 -26
  16. package/dist/cli/commands/test.js +12 -12
  17. package/dist/lib/chart-guidance.d.ts +1 -1
  18. package/dist/lib/chart-guidance.js +1 -8
  19. package/dist/lib/discovery.d.ts +1 -7
  20. package/dist/lib/discovery.js +1 -84
  21. package/dist/lib/filesystem.d.ts +1 -2
  22. package/dist/lib/filesystem.js +1 -55
  23. package/dist/lib/logger.d.ts +1 -3
  24. package/dist/lib/logger.js +1 -10
  25. package/dist/lib/parse.d.ts +1 -8
  26. package/dist/lib/parse.js +1 -145
  27. package/dist/lib/util.d.ts +1 -4
  28. package/dist/lib/util.js +1 -25
  29. package/dist/packages/agents/index.d.ts +1 -0
  30. package/dist/packages/agents/index.js +1 -0
  31. package/dist/packages/agents/lib/chart-guidance.d.ts +1 -0
  32. package/dist/packages/agents/lib/chart-guidance.js +8 -0
  33. package/dist/packages/agents/lib/compiled-bootstrap.d.ts +3 -0
  34. package/dist/packages/agents/lib/compiled-bootstrap.js +18 -0
  35. package/dist/packages/agents/lib/executors.d.ts +2 -2
  36. package/dist/packages/agents/lib/shells.d.ts +3 -1
  37. package/dist/packages/agents/lib/shells.js +22 -20
  38. package/dist/packages/agents/lib/user-config.js +1 -1
  39. package/dist/packages/compiler/compiled-compile.d.ts +4 -48
  40. package/dist/packages/compiler/compiled-compile.js +4 -256
  41. package/dist/packages/compiler/compiled-paths.d.ts +40 -0
  42. package/dist/packages/compiler/compiled-paths.js +106 -0
  43. package/dist/packages/compiler/compiled-pipeline.d.ts +39 -0
  44. package/dist/packages/compiler/compiled-pipeline.js +134 -0
  45. package/dist/packages/compiler/compiled-schema.js +2 -2
  46. package/dist/packages/compiler/compiled-stage-plan.d.ts +15 -0
  47. package/dist/packages/compiler/compiled-stage-plan.js +79 -0
  48. package/dist/packages/compiler/compiled-stage-runner.d.ts +10 -0
  49. package/dist/packages/compiler/compiled-stage-runner.js +46 -0
  50. package/dist/packages/compiler/compiled-target.d.ts +11 -0
  51. package/dist/packages/compiler/compiled-target.js +16 -0
  52. package/dist/packages/compiler/discovery.d.ts +7 -0
  53. package/dist/packages/compiler/discovery.js +80 -0
  54. package/dist/packages/compiler/lib/schema.js +2 -0
  55. package/dist/packages/compiler/raw-snapshot.d.ts +49 -0
  56. package/dist/packages/compiler/raw-snapshot.js +102 -0
  57. package/dist/packages/compiler/reset.d.ts +2 -0
  58. package/dist/packages/compiler/reset.js +72 -0
  59. package/dist/packages/compiler/runtime-acceptance.js +3 -3
  60. package/dist/packages/compiler/runtime-contracts.js +1 -1
  61. package/dist/packages/compiler/runtime-paths.js +1 -1
  62. package/dist/packages/compiler/runtime-reconcile.js +3 -3
  63. package/dist/packages/compiler/runtime-runs.js +2 -2
  64. package/dist/packages/compiler/state-health.js +3 -3
  65. package/dist/packages/compiler/state-io.js +3 -3
  66. package/dist/packages/compiler/state-paths.js +1 -1
  67. package/dist/packages/compiler/state-view.js +2 -2
  68. package/dist/packages/compiler/validate-compiled.js +3 -3
  69. package/dist/packages/compiler/validate.js +4 -4
  70. package/dist/packages/project-model/compiled-paths.d.ts +1 -40
  71. package/dist/packages/project-model/compiled-paths.js +1 -106
  72. package/dist/packages/project-model/compiled-raw.d.ts +1 -49
  73. package/dist/packages/project-model/compiled-raw.js +1 -102
  74. package/dist/packages/project-model/compiled-reset.d.ts +1 -2
  75. package/dist/packages/project-model/compiled-reset.js +1 -72
  76. package/dist/packages/project-model/interf-bootstrap.d.ts +1 -3
  77. package/dist/packages/project-model/interf-bootstrap.js +1 -18
  78. package/dist/packages/project-model/interf-detect.js +4 -4
  79. package/dist/packages/project-model/interf-scaffold.js +7 -7
  80. package/dist/packages/project-model/source-config.js +6 -5
  81. package/dist/packages/shared/file-types.d.ts +1 -0
  82. package/dist/packages/shared/file-types.js +4 -0
  83. package/dist/packages/shared/filesystem.d.ts +2 -0
  84. package/dist/packages/shared/filesystem.js +55 -0
  85. package/dist/packages/shared/index.d.ts +7 -0
  86. package/dist/packages/shared/index.js +7 -0
  87. package/dist/packages/shared/logger.d.ts +3 -0
  88. package/dist/packages/shared/logger.js +10 -0
  89. package/dist/packages/shared/naming.d.ts +1 -0
  90. package/dist/packages/shared/naming.js +8 -0
  91. package/dist/packages/shared/parse.d.ts +8 -0
  92. package/dist/packages/shared/parse.js +145 -0
  93. package/dist/packages/shared/path-guards.d.ts +2 -0
  94. package/dist/packages/shared/path-guards.js +14 -0
  95. package/dist/packages/shared/util.d.ts +3 -0
  96. package/dist/packages/shared/util.js +3 -0
  97. package/dist/packages/testing/test-execution.js +3 -3
  98. package/dist/packages/testing/test-paths.js +1 -1
  99. package/dist/packages/testing/test-sandbox.js +3 -3
  100. package/dist/packages/testing/test-specs.js +1 -1
  101. package/dist/packages/workflow-authoring/workflow-authoring.js +5 -4
  102. package/dist/packages/workflow-authoring/workflow-improvement.js +6 -5
  103. package/dist/packages/workflow-package/builtin-compiled-workflow.js +1 -1
  104. package/dist/packages/workflow-package/context-interface.d.ts +96 -0
  105. package/dist/packages/workflow-package/context-interface.js +146 -0
  106. package/dist/packages/workflow-package/index.d.ts +2 -0
  107. package/dist/packages/workflow-package/index.js +2 -0
  108. package/dist/packages/workflow-package/interf-workflow-package.js +75 -28
  109. package/dist/packages/workflow-package/local-workflows.d.ts +5 -2
  110. package/dist/packages/workflow-package/local-workflows.js +15 -13
  111. package/dist/packages/workflow-package/workflow-definitions.d.ts +11 -7
  112. package/dist/packages/workflow-package/workflow-definitions.js +10 -3
  113. package/dist/packages/workflow-package/workflow-helpers.js +4 -4
  114. package/dist/packages/workflow-package/workflow-review-paths.js +1 -1
  115. package/package.json +2 -2
@@ -1,11 +1,11 @@
1
1
  import { existsSync, readdirSync, statSync, } from "node:fs";
2
2
  import { join, resolve } from "node:path";
3
- import { warnInterf } from "../../lib/logger.js";
4
- import { readJsonFileUnchecked } from "../../lib/parse.js";
3
+ import { warnInterf } from "../shared/logger.js";
4
+ import { readJsonFileUnchecked } from "../shared/parse.js";
5
5
  import { compiledCompiledPathForDataset, projectInterfRoot, } from "./project-paths.js";
6
- import { resolveSourceControlPathForCompiled, compiledInterfConfigPath, } from "./compiled-paths.js";
6
+ import { resolveSourceControlPathForCompiled, compiledInterfConfigPath, } from "../compiler/compiled-paths.js";
7
7
  import { InterfConfigSchema, } from "./lib/schema.js";
8
- import { assertPathWithinRoot } from "../../lib/util.js";
8
+ import { assertPathWithinRoot } from "../shared/path-guards.js";
9
9
  export const INTERF_CONTAINER_NAME = "interf";
10
10
  export const WORKFLOW_CONTAINER_NAME = "workflows";
11
11
  export const TEST_CONTAINER_NAME = "tests";
@@ -2,14 +2,14 @@ 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
4
  import { initializeCompiledRuntimeState, } from "../compiler/state.js";
5
+ import { refreshCompiledBootstrapGuidance } from "../agents/lib/compiled-bootstrap.js";
6
+ import { syncCompiledRawSnapshot } from "../compiler/raw-snapshot.js";
5
7
  import { assertCompiledContainer, assertWritableTargetDir, assertCompiledName, } from "./interf-detect.js";
6
- import { refreshCompiledBootstrapGuidance } from "./interf-bootstrap.js";
7
8
  import { seedCompiledWorkflowPackage } from "../workflow-package/interf-workflow-package.js";
8
9
  import { compiledCompiledPathForDataset } from "./project-paths.js";
9
- import { syncCompiledRawSnapshot } from "./compiled-raw.js";
10
10
  import { ensureCompiledZoneTargets, readCompiledSchemaFile } from "../compiler/compiled-schema.js";
11
11
  import { findSourceDatasetConfig, listSourceDatasetConfigs, loadSourceFolderConfig, resolveSourceDatasetPath, saveCompiledInterfConfig, } from "./source-config.js";
12
- import { defaultControlPathForCompiled, workflowPackagePathForCompiled } from "./compiled-paths.js";
12
+ import { defaultControlPathForCompiled, workflowPackagePathForCompiled } from "../compiler/compiled-paths.js";
13
13
  const DEFAULT_INTERFIGNORE = [
14
14
  ".claude/",
15
15
  ".codex/",
@@ -20,7 +20,7 @@ const DEFAULT_INTERFIGNORE = [
20
20
  ".interf/runtime/",
21
21
  "",
22
22
  ].join("\n");
23
- const UNCOMPILED_COMPILED_PLACEHOLDER = "Not yet compiled. Run `interf compile` to build this context folder.";
23
+ const UNCOMPILED_COMPILED_PLACEHOLDER = "Not yet compiled. Run `interf compile` to build this portable context.";
24
24
  function renderUncompiledCompiledFile(compiledName, relativePath, about) {
25
25
  return [
26
26
  `# ${compiledName} — ${relativePath}`,
@@ -62,10 +62,10 @@ function scaffoldCompiledOutputs(compiledPath, compiledName, about) {
62
62
  }
63
63
  }
64
64
  export function createCompiled(name, sourcePath, workflowId = "interf", about, datasetPath) {
65
- assertCompiledName(name, "Context folder");
65
+ assertCompiledName(name, "Portable context");
66
66
  assertCompiledContainer(sourcePath);
67
67
  const compiledPath = compiledCompiledPathForDataset(sourcePath, name);
68
- assertWritableTargetDir(compiledPath, "Context folder");
68
+ assertWritableTargetDir(compiledPath, "Portable context");
69
69
  mkdirSync(compiledPath, { recursive: true });
70
70
  const savedCompiled = findSourceDatasetConfig(loadSourceFolderConfig(sourcePath), name);
71
71
  const selectedWorkflow = getCompiledWorkflow(workflowId, { sourcePath });
@@ -81,7 +81,7 @@ export function createCompiled(name, sourcePath, workflowId = "interf", about, d
81
81
  if (configuredDatasets.length === 1) {
82
82
  return resolveSourceDatasetPath(sourcePath, configuredDatasets[0]);
83
83
  }
84
- throw new Error("Cannot infer the source folder for this context folder. Select a source folder first or pass an explicit dataset path.");
84
+ throw new Error("Cannot infer the source folder for this portable context. Select a source folder first or pass an explicit dataset path.");
85
85
  })();
86
86
  saveCompiledInterfConfig(compiledPath, {
87
87
  type: "compiled",
@@ -1,14 +1,15 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import { existsSync, mkdirSync, writeFileSync } from "node:fs";
3
3
  import { join, relative, resolve, sep } from "node:path";
4
- import { readInterfConfig, refreshCompiledBootstrapGuidance, } from "./interf.js";
4
+ import { refreshCompiledBootstrapGuidance } from "../agents/lib/compiled-bootstrap.js";
5
+ import { readInterfConfig, } from "./interf.js";
5
6
  import { seedCompiledWorkflowPackage } from "../workflow-package/interf-workflow-package.js";
6
- import { readJsonFileWithSchema } from "../../lib/parse.js";
7
+ import { readJsonFileWithSchema } from "../shared/parse.js";
7
8
  import { getCompiledWorkflow } from "../workflow-package/workflow-definitions.js";
8
9
  import { SourceFolderConfigSchema, } from "./lib/schema.js";
9
- import { slugify } from "../../lib/util.js";
10
- import { assertPathWithinRoot } from "../../lib/util.js";
11
- import { defaultControlPathForCompiled, resolveSourceControlPathForCompiled, compiledInterfConfigPath, compiledInterfRoot, } from "./compiled-paths.js";
10
+ import { slugify } from "../shared/naming.js";
11
+ import { assertPathWithinRoot } from "../shared/path-guards.js";
12
+ import { defaultControlPathForCompiled, resolveSourceControlPathForCompiled, compiledInterfConfigPath, compiledInterfRoot, } from "../compiler/compiled-paths.js";
12
13
  export const SOURCE_FOLDER_CONFIG_FILE = "interf.json";
13
14
  function sourceConfigPath(sourcePath) {
14
15
  return join(sourcePath, SOURCE_FOLDER_CONFIG_FILE);
@@ -0,0 +1 @@
1
+ export declare function isMarkdownFile(filePath: string): boolean;
@@ -0,0 +1,4 @@
1
+ import { extname } from "node:path";
2
+ export function isMarkdownFile(filePath) {
3
+ return extname(filePath).toLowerCase() === ".md";
4
+ }
@@ -0,0 +1,2 @@
1
+ export declare function countFilesRecursive(dirPath: string): number;
2
+ export declare function listFilesRecursive(dirPath: string, predicate?: (filePath: string) => boolean): string[];
@@ -0,0 +1,55 @@
1
+ import { existsSync, readdirSync, realpathSync, statSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ export function countFilesRecursive(dirPath) {
4
+ if (!existsSync(dirPath))
5
+ return 0;
6
+ let total = 0;
7
+ walkFilesRecursive(dirPath, () => {
8
+ total += 1;
9
+ });
10
+ return total;
11
+ }
12
+ export function listFilesRecursive(dirPath, predicate) {
13
+ const files = [];
14
+ if (!existsSync(dirPath))
15
+ return files;
16
+ walkFilesRecursive(dirPath, (filePath) => {
17
+ if (!predicate || predicate(filePath)) {
18
+ files.push(filePath);
19
+ }
20
+ });
21
+ return files;
22
+ }
23
+ function walkFilesRecursive(dirPath, onFile, visitedDirs = new Set()) {
24
+ if (!existsSync(dirPath))
25
+ return;
26
+ walkFilesRecursiveInternal(dirPath, onFile, visitedDirs);
27
+ }
28
+ function walkFilesRecursiveInternal(dirPath, onFile, visitedDirs) {
29
+ let resolvedDir;
30
+ try {
31
+ resolvedDir = realpathSync(dirPath);
32
+ }
33
+ catch {
34
+ return;
35
+ }
36
+ if (visitedDirs.has(resolvedDir))
37
+ return;
38
+ visitedDirs.add(resolvedDir);
39
+ for (const entry of readdirSync(dirPath)) {
40
+ const fullPath = join(dirPath, entry);
41
+ let stat;
42
+ try {
43
+ stat = statSync(fullPath);
44
+ }
45
+ catch {
46
+ continue;
47
+ }
48
+ if (stat.isDirectory()) {
49
+ walkFilesRecursiveInternal(fullPath, onFile, visitedDirs);
50
+ }
51
+ else if (stat.isFile()) {
52
+ onFile(fullPath);
53
+ }
54
+ }
55
+ }
@@ -0,0 +1,7 @@
1
+ export * from "./file-types.js";
2
+ export * from "./filesystem.js";
3
+ export * from "./logger.js";
4
+ export * from "./naming.js";
5
+ export * from "./parse.js";
6
+ export * from "./path-guards.js";
7
+ export * from "./util.js";
@@ -0,0 +1,7 @@
1
+ export * from "./file-types.js";
2
+ export * from "./filesystem.js";
3
+ export * from "./logger.js";
4
+ export * from "./naming.js";
5
+ export * from "./parse.js";
6
+ export * from "./path-guards.js";
7
+ export * from "./util.js";
@@ -0,0 +1,3 @@
1
+ export type InterfWarningHandler = (message: string) => void;
2
+ export declare function setInterfWarningHandler(handler?: InterfWarningHandler): void;
3
+ export declare function warnInterf(message: string): void;
@@ -0,0 +1,10 @@
1
+ const defaultWarningHandler = (message) => {
2
+ console.warn(message);
3
+ };
4
+ let currentWarningHandler = defaultWarningHandler;
5
+ export function setInterfWarningHandler(handler) {
6
+ currentWarningHandler = handler ?? defaultWarningHandler;
7
+ }
8
+ export function warnInterf(message) {
9
+ currentWarningHandler(message);
10
+ }
@@ -0,0 +1 @@
1
+ export declare function slugify(input: string): string;
@@ -0,0 +1,8 @@
1
+ export function slugify(input) {
2
+ return input
3
+ .toLowerCase()
4
+ .trim()
5
+ .replace(/[^a-z0-9]+/g, "-")
6
+ .replace(/^-+|-+$/g, "")
7
+ .slice(0, 80);
8
+ }
@@ -0,0 +1,8 @@
1
+ import type { ZodType } from "zod";
2
+ export declare function readJsonFileUnchecked<T>(filePath: string, label: string): T | null;
3
+ export declare function readJsonFileWithSchema<T>(filePath: string, label: string, schema: ZodType<T>): T | null;
4
+ export declare function renderJsonFrontmatter(frontmatter: Record<string, unknown>): string;
5
+ export declare function parseJsonFrontmatter(content: string): {
6
+ frontmatter: Record<string, unknown>;
7
+ body: string;
8
+ } | null;
@@ -0,0 +1,145 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { warnInterf } from "./logger.js";
3
+ function formatError(error) {
4
+ return error instanceof Error ? error.message : String(error);
5
+ }
6
+ export function readJsonFileUnchecked(filePath, label) {
7
+ try {
8
+ return JSON.parse(readFileSync(filePath, "utf-8"));
9
+ }
10
+ catch (error) {
11
+ warnInterf(`Warning: failed to parse ${label} at ${filePath}: ${formatError(error)}`);
12
+ return null;
13
+ }
14
+ }
15
+ export function readJsonFileWithSchema(filePath, label, schema) {
16
+ const raw = readJsonFileUnchecked(filePath, label);
17
+ if (raw === null)
18
+ return null;
19
+ const parsed = schema.safeParse(raw);
20
+ if (!parsed.success) {
21
+ warnInterf(`Warning: failed to validate ${label} at ${filePath}: ${parsed.error.issues.map((issue) => issue.message).join("; ")}`);
22
+ return null;
23
+ }
24
+ return parsed.data;
25
+ }
26
+ export function renderJsonFrontmatter(frontmatter) {
27
+ return [
28
+ "---",
29
+ JSON.stringify(frontmatter, null, 2),
30
+ "---",
31
+ ].join("\n");
32
+ }
33
+ function parseQuotedString(value) {
34
+ if (value.length < 2)
35
+ return null;
36
+ const quote = value[0];
37
+ if ((quote !== "\"" && quote !== "'") || value[value.length - 1] !== quote)
38
+ return null;
39
+ const inner = value.slice(1, -1);
40
+ if (quote === "\"") {
41
+ try {
42
+ return JSON.parse(value);
43
+ }
44
+ catch {
45
+ return null;
46
+ }
47
+ }
48
+ return inner.replace(/\\'/g, "'");
49
+ }
50
+ function parseYamlScalar(value) {
51
+ const trimmed = value.trim();
52
+ if (trimmed.length === 0)
53
+ return "";
54
+ const quoted = parseQuotedString(trimmed);
55
+ if (quoted !== null)
56
+ return quoted;
57
+ if (trimmed === "true")
58
+ return true;
59
+ if (trimmed === "false")
60
+ return false;
61
+ if (trimmed === "null")
62
+ return null;
63
+ if (/^-?\d+(?:\.\d+)?$/.test(trimmed))
64
+ return Number(trimmed);
65
+ if ((trimmed.startsWith("[") && trimmed.endsWith("]"))
66
+ || (trimmed.startsWith("{") && trimmed.endsWith("}"))) {
67
+ try {
68
+ return JSON.parse(trimmed);
69
+ }
70
+ catch {
71
+ return trimmed;
72
+ }
73
+ }
74
+ return trimmed;
75
+ }
76
+ function parseYamlFrontmatter(frontmatterText) {
77
+ const lines = frontmatterText.split("\n");
78
+ const frontmatter = {};
79
+ for (let index = 0; index < lines.length; index += 1) {
80
+ const line = lines[index] ?? "";
81
+ const trimmed = line.trim();
82
+ if (trimmed.length === 0 || trimmed.startsWith("#"))
83
+ continue;
84
+ const match = line.match(/^([A-Za-z0-9_-]+):(?:\s+(.*))?$/);
85
+ if (!match)
86
+ return null;
87
+ const [, key, inlineValue] = match;
88
+ if (!key)
89
+ return null;
90
+ if (inlineValue && inlineValue.trim().length > 0) {
91
+ frontmatter[key] = parseYamlScalar(inlineValue);
92
+ continue;
93
+ }
94
+ const items = [];
95
+ let cursor = index + 1;
96
+ while (cursor < lines.length) {
97
+ const nextLine = lines[cursor] ?? "";
98
+ const nextTrimmed = nextLine.trim();
99
+ if (nextTrimmed.length === 0) {
100
+ cursor += 1;
101
+ continue;
102
+ }
103
+ const itemMatch = nextLine.match(/^\s*-\s+(.*)$/);
104
+ if (!itemMatch || !/^\s+/.test(nextLine))
105
+ break;
106
+ items.push(parseYamlScalar(itemMatch[1] ?? ""));
107
+ cursor += 1;
108
+ }
109
+ if (items.length > 0) {
110
+ frontmatter[key] = items;
111
+ index = cursor - 1;
112
+ continue;
113
+ }
114
+ frontmatter[key] = "";
115
+ }
116
+ return Object.keys(frontmatter).length > 0 ? frontmatter : null;
117
+ }
118
+ export function parseJsonFrontmatter(content) {
119
+ const normalized = content.replace(/\r\n/g, "\n");
120
+ const match = normalized.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
121
+ if (!match)
122
+ return null;
123
+ const [, frontmatterText, body = ""] = match;
124
+ if (frontmatterText === undefined)
125
+ return null;
126
+ try {
127
+ const frontmatter = JSON.parse(frontmatterText);
128
+ if (!frontmatter || typeof frontmatter !== "object" || Array.isArray(frontmatter)) {
129
+ return null;
130
+ }
131
+ return {
132
+ frontmatter: frontmatter,
133
+ body,
134
+ };
135
+ }
136
+ catch {
137
+ const frontmatter = parseYamlFrontmatter(frontmatterText);
138
+ if (!frontmatter)
139
+ return null;
140
+ return {
141
+ frontmatter,
142
+ body,
143
+ };
144
+ }
145
+ }
@@ -0,0 +1,2 @@
1
+ export declare function isPathWithinRoot(rootPath: string, candidatePath: string): boolean;
2
+ export declare function assertPathWithinRoot(rootPath: string, candidatePath: string, label: string): string;
@@ -0,0 +1,14 @@
1
+ import { isAbsolute, relative, resolve, sep } from "node:path";
2
+ export function isPathWithinRoot(rootPath, candidatePath) {
3
+ const root = resolve(rootPath);
4
+ const candidate = resolve(candidatePath);
5
+ const relativePath = relative(root, candidate);
6
+ return relativePath === "" || (!isAbsolute(relativePath) && relativePath !== ".." && !relativePath.startsWith(`..${sep}`));
7
+ }
8
+ export function assertPathWithinRoot(rootPath, candidatePath, label) {
9
+ const resolvedPath = resolve(candidatePath);
10
+ if (!isPathWithinRoot(rootPath, resolvedPath)) {
11
+ throw new Error(`${label} must stay inside ${resolve(rootPath)}: ${resolvedPath}`);
12
+ }
13
+ return resolvedPath;
14
+ }
@@ -0,0 +1,3 @@
1
+ export { isMarkdownFile } from "./file-types.js";
2
+ export { slugify } from "./naming.js";
3
+ export { assertPathWithinRoot, isPathWithinRoot } from "./path-guards.js";
@@ -0,0 +1,3 @@
1
+ export { isMarkdownFile } from "./file-types.js";
2
+ export { slugify } from "./naming.js";
3
+ export { assertPathWithinRoot, isPathWithinRoot } from "./path-guards.js";
@@ -199,10 +199,10 @@ function buildTestQueryPrompt(target, testCase, answerPath, tracePath) {
199
199
  ? [
200
200
  "You are running an Interf test inside an isolated sandboxed compiled context.",
201
201
  "Read `AGENTS.md` first.",
202
- "Use the local native `interf-query` skill available in this context folder.",
203
- "Answer the check question the same way you would answer a real user inside this context folder.",
202
+ "Use the local native `interf-query` skill available in this portable context.",
203
+ "Answer the check question the same way you would answer a real user inside this portable context.",
204
204
  "Prefer the workflow-declared context outputs before raw fallback.",
205
- "This sandbox is self-contained: the copied context folder has its own sanitized `raw/` fallback via `.interf/interf.json` `source.path`.",
205
+ "This sandbox is self-contained: the copied portable context has its own sanitized `raw/` fallback via `.interf/interf.json` `source.path`.",
206
206
  "The original project root is intentionally absent from this sandbox. Work only from this sandboxed compiled context and its embedded raw files.",
207
207
  ]
208
208
  : [
@@ -1,6 +1,6 @@
1
1
  import { existsSync } from "node:fs";
2
2
  import { basename, dirname, join } from "node:path";
3
- import { targetTestRunsRootForCompiled, targetTestSandboxesRootForCompiled, compiledInterfConfigPath, } from "../project-model/compiled-paths.js";
3
+ import { targetTestRunsRootForCompiled, targetTestSandboxesRootForCompiled, compiledInterfConfigPath, } from "../compiler/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"]);
6
6
  export function testSpecRootPath(sourcePath) {
@@ -1,14 +1,14 @@
1
1
  import { cpSync, existsSync, mkdirSync, mkdtempSync, renameSync, rmSync, } from "node:fs";
2
2
  import { tmpdir } from "node:os";
3
3
  import { dirname, join, relative, sep } from "node:path";
4
- import { refreshCompiledBootstrapGuidance } from "../project-model/interf-bootstrap.js";
4
+ import { refreshCompiledBootstrapGuidance } from "../agents/lib/compiled-bootstrap.js";
5
5
  import { readInterfConfig, resolveCompiledRawPath } from "../project-model/interf.js";
6
6
  import { projectRawTestQueryShell } from "../agents/lib/shells.js";
7
7
  import { compiledCompiledPathForDataset } from "../project-model/project-paths.js";
8
8
  import { saveCompiledInterfConfig } from "../project-model/source-config.js";
9
+ import { projectRawSnapshot } from "../compiler/raw-snapshot.js";
9
10
  import { refreshCompiledArtifacts } from "../compiler/state.js";
10
- import { projectRawSnapshot } from "../project-model/compiled-raw.js";
11
- import { testRootForCompiled, stageExecutionShellsRoot, targetTestSandboxesRootForCompiled, workflowImprovementLoopsRoot, compiledQueryAcceptanceRoot, compiledRuntimeLogsRoot, } from "../project-model/compiled-paths.js";
11
+ import { testRootForCompiled, stageExecutionShellsRoot, targetTestSandboxesRootForCompiled, workflowImprovementLoopsRoot, compiledQueryAcceptanceRoot, compiledRuntimeLogsRoot, } from "../compiler/compiled-paths.js";
12
12
  function toPortableRelativePath(fromPath, toPath) {
13
13
  return relative(fromPath, toPath).split(sep).join("/");
14
14
  }
@@ -1,6 +1,6 @@
1
1
  import { existsSync, mkdirSync, readdirSync, writeFileSync, } from "node:fs";
2
2
  import { basename, extname, join } from "node:path";
3
- import { readJsonFileWithSchema } from "../../lib/parse.js";
3
+ import { readJsonFileWithSchema } from "../shared/parse.js";
4
4
  import { TestSpecSchema } from "./lib/schema.js";
5
5
  import { TEST_SPEC_EXTENSIONS, assertTestId, assertWritableTestSpecPath, testSpecFilePath, testSpecTypePath, normalizeTestId, } from "./test-paths.js";
6
6
  function readTestSpecFile(filePath) {
@@ -2,11 +2,11 @@ import { mkdtempSync, rmSync, } from "node:fs";
2
2
  import { tmpdir } from "node:os";
3
3
  import { join } from "node:path";
4
4
  import { createWorkflowAuthoringShell } from "../agents/lib/shells.js";
5
- import { WORKFLOW_SCHEMA_FILE } from "../compiler/compiled-schema.js";
6
5
  import { seedLocalWorkflowPackageFromBase } from "../workflow-package/interf-workflow-package.js";
6
+ import { CONTEXT_INTERFACE_FILE } from "../workflow-package/context-interface.js";
7
7
  import { validateWorkflowPackage, workflowDefinitionPath } from "../workflow-package/local-workflows.js";
8
8
  import { createCompiled, compileCompiled } from "../compiler/workflows.js";
9
- import { projectRawSnapshot } from "../project-model/compiled-raw.js";
9
+ import { projectRawSnapshot } from "../compiler/raw-snapshot.js";
10
10
  import { runWorkflowEditSession } from "./workflow-edit-session.js";
11
11
  import { copyDirectory } from "./lib/workflow-edit-utils.js";
12
12
  function buildWorkflowAuthoringPrompt() {
@@ -15,14 +15,15 @@ function buildWorkflowAuthoringPrompt() {
15
15
  "Execute it now.",
16
16
  "Create one standalone workflow for the files and checks in this source folder.",
17
17
  "Read `runtime/authoring-context.json` first.",
18
- `Then read \`workflow/README.md\`, \`workflow/workflow.json\`, and \`workflow/${WORKFLOW_SCHEMA_FILE}\`.`,
18
+ `Then read \`workflow/README.md\`, \`workflow/workflow.json\`, and \`workflow/${CONTEXT_INTERFACE_FILE}\`.`,
19
19
  "Review `artifacts/source-dataset/raw/` and any `artifacts/preview-compiled/` notes before editing the package.",
20
20
  "Prefer direct file-reading and search tools over shell commands for routine file inspection.",
21
21
  "Do not use shell helpers like `cat`, `sed`, `ls`, or `find` when a native read/search tool can inspect the same files.",
22
22
  "Edit only files under `workflow/`.",
23
23
  "Keep the workflow valid for the current compiler API and workflow schema.",
24
24
  "Make the package materially more specific to this dataset task than the seeded base workflow. A no-op copy is not acceptable.",
25
- "Prefer explicit stage-doc, stage-policy, purpose, and zone-contract edits over vague rewrites.",
25
+ "Treat the workflow package as four aligned layers: purpose, inputs, context interface, and stages.",
26
+ "Prefer explicit stage-doc, stage-policy, purpose, input-contract, and context-interface edits over vague rewrites.",
26
27
  "Do not introduce wikilinks unless the workflow also creates the target note by exact basename or explicit relative path.",
27
28
  "Respect stage boundaries: a stage may only introduce links that resolve within that stage's declared writes or already-existing read zones.",
28
29
  "Do not make one stage point at files or notes that are only created later by another stage.",
@@ -1,11 +1,11 @@
1
1
  import { appendFileSync, existsSync, mkdirSync, writeFileSync, } from "node:fs";
2
2
  import { join, relative } from "node:path";
3
3
  import { createWorkflowImprovementShell, freezeWorkflowImprovementShell, } from "../agents/lib/shells.js";
4
- import { WORKFLOW_SCHEMA_FILE } from "../compiler/compiled-schema.js";
5
4
  import { validateWorkflowPackage } from "../workflow-package/local-workflows.js";
6
- import { readJsonFileWithSchema } from "../../lib/parse.js";
5
+ import { CONTEXT_INTERFACE_FILE } from "../workflow-package/context-interface.js";
6
+ import { readJsonFileWithSchema } from "../shared/parse.js";
7
7
  import { resolveWorkflowImprovementReviewPaths } from "../workflow-package/workflow-review-paths.js";
8
- import { targetTestRunsRootForCompiled, targetTestSandboxesRootForCompiled, workflowImprovementRunRoot, workflowPackagePathForCompiled, } from "../project-model/compiled-paths.js";
8
+ import { targetTestRunsRootForCompiled, targetTestSandboxesRootForCompiled, workflowImprovementRunRoot, workflowPackagePathForCompiled, } from "../compiler/compiled-paths.js";
9
9
  import { readInterfConfig } from "../project-model/interf.js";
10
10
  import { saveCompiledInterfConfig } from "../project-model/source-config.js";
11
11
  import { WorkflowImprovementRunLedgerSchema, } from "../compiler/lib/schema.js";
@@ -58,10 +58,11 @@ function buildWorkflowImprovementPrompt() {
58
58
  "This is an automated Interf workflow-improvement run, not an open-ended chat session.",
59
59
  "The user already invoked this through `interf compile` with self-improving loops enabled. Execute it now.",
60
60
  "Read `runtime/loop-context.json` first.",
61
- `Then read \`workflow/README.md\`, \`workflow/workflow.json\`, \`workflow/${WORKFLOW_SCHEMA_FILE}\`, and \`workflow/improve/SKILL.md\` if it exists.`,
61
+ `Then read \`workflow/README.md\`, \`workflow/workflow.json\`, \`workflow/${CONTEXT_INTERFACE_FILE}\`, and \`workflow/improve/SKILL.md\` if it exists.`,
62
62
  "Review preserved evidence from earlier failures under `artifacts/` before you edit the workflow.",
63
63
  "Treat `workflow/improve/SKILL.md` as guidance for how to improve the workflow, not as the default file to edit.",
64
- "Prefer editing the stage docs, workflow contract, or schema ownership that actually change compiled outputs.",
64
+ "Treat the workflow package as four aligned layers: purpose, inputs, context interface, and stages.",
65
+ "Prefer editing the stage docs, workflow contract, input contract, or schema ownership that actually change compiled outputs.",
65
66
  "Edit only files under `workflow/`.",
66
67
  "Do not edit checks, test specs, raw dataset files, or generated compiled outputs.",
67
68
  "Keep the workflow valid for the current compiler API and workflow schema.",
@@ -1,6 +1,6 @@
1
1
  import { join } from "node:path";
2
2
  import { z } from "zod";
3
- import { readJsonFileWithSchema } from "../../lib/parse.js";
3
+ import { readJsonFileWithSchema } from "../shared/parse.js";
4
4
  import { COMPILED_ZONE_KINDS } from "../compiler/workflow-primitives.js";
5
5
  import { WorkflowCompiledSchemaSchema } from "../compiler/lib/schema.js";
6
6
  import { PACKAGE_ROOT } from "./lib/package-root.js";
@@ -0,0 +1,96 @@
1
+ import { z } from "zod";
2
+ import { type WorkflowCompiledSchema, type WorkflowCompiledZone, type WorkflowZoneId } from "../compiler/lib/schema.js";
3
+ export declare const CONTEXT_INTERFACE_FILE = "workflow.schema.json";
4
+ export declare const ContextInterfaceSchema: z.ZodObject<{
5
+ kind: z.ZodLiteral<"workflow-schema">;
6
+ version: z.ZodLiteral<1>;
7
+ target_type: z.ZodLiteral<"compiled">;
8
+ label: z.ZodString;
9
+ zones: z.ZodArray<z.ZodObject<{
10
+ id: z.ZodString;
11
+ role: z.ZodEnum<{
12
+ output: "output";
13
+ runtime: "runtime";
14
+ input: "input";
15
+ working: "working";
16
+ }>;
17
+ path: z.ZodString;
18
+ kind: z.ZodEnum<{
19
+ runtime: "runtime";
20
+ directory: "directory";
21
+ file: "file";
22
+ }>;
23
+ required: z.ZodBoolean;
24
+ owned_by: z.ZodArray<z.ZodString>;
25
+ description: z.ZodString;
26
+ }, z.core.$strip>>;
27
+ }, z.core.$strip>;
28
+ export declare const ContextInterfaceZoneSchema: z.ZodObject<{
29
+ id: z.ZodString;
30
+ role: z.ZodEnum<{
31
+ output: "output";
32
+ runtime: "runtime";
33
+ input: "input";
34
+ working: "working";
35
+ }>;
36
+ path: z.ZodString;
37
+ kind: z.ZodEnum<{
38
+ runtime: "runtime";
39
+ directory: "directory";
40
+ file: "file";
41
+ }>;
42
+ required: z.ZodBoolean;
43
+ owned_by: z.ZodArray<z.ZodString>;
44
+ description: z.ZodString;
45
+ }, z.core.$strip>;
46
+ export declare const ContextInterfaceZoneIdSchema: z.ZodString;
47
+ export declare const ContextInterfaceZoneRoleSchema: z.ZodEnum<{
48
+ output: "output";
49
+ runtime: "runtime";
50
+ input: "input";
51
+ working: "working";
52
+ }>;
53
+ export declare const WorkflowInputSpecSchema: z.ZodObject<{
54
+ id: z.ZodString;
55
+ label: z.ZodString;
56
+ description: z.ZodString;
57
+ required: z.ZodDefault<z.ZodBoolean>;
58
+ examples: z.ZodOptional<z.ZodArray<z.ZodString>>;
59
+ }, z.core.$strict>;
60
+ export declare const WorkflowInputContractSchema: z.ZodArray<z.ZodObject<{
61
+ id: z.ZodString;
62
+ label: z.ZodString;
63
+ description: z.ZodString;
64
+ required: z.ZodDefault<z.ZodBoolean>;
65
+ examples: z.ZodOptional<z.ZodArray<z.ZodString>>;
66
+ }, z.core.$strict>>;
67
+ export type ContextInterface = WorkflowCompiledSchema;
68
+ export type ContextInterfaceZone = WorkflowCompiledZone;
69
+ export type ContextInterfaceZoneId = WorkflowZoneId;
70
+ export type ContextInterfaceZoneRole = z.infer<typeof ContextInterfaceZoneRoleSchema>;
71
+ export type WorkflowInputSpec = z.infer<typeof WorkflowInputSpecSchema>;
72
+ export interface ContextInterfaceStageLike {
73
+ id: string;
74
+ writes: readonly string[];
75
+ }
76
+ export interface ContextInterfaceSummary {
77
+ inputZones: ContextInterfaceZone[];
78
+ workingZones: ContextInterfaceZone[];
79
+ outputZones: ContextInterfaceZone[];
80
+ runtimeZones: ContextInterfaceZone[];
81
+ }
82
+ export declare function contextInterfaceFilePath(rootPath: string): string;
83
+ export declare function resolveContextInterfacePath(rootPath: string): string | null;
84
+ export declare function contextInterfaceExists(rootPath: string): boolean;
85
+ export declare function contextInterfaceRelativePath(): string;
86
+ export declare function listContextInterfaceZones(contextInterface: ContextInterface): ContextInterfaceZone[];
87
+ export declare function findContextInterfaceZone(contextInterface: ContextInterface, zoneId: ContextInterfaceZoneId): ContextInterfaceZone | null;
88
+ export declare function contextInterfaceZoneAbsolutePath(compiledPath: string, zone: Pick<ContextInterfaceZone, "path">): string;
89
+ export declare function contextInterfaceArtifactPath(zone: Pick<ContextInterfaceZone, "path" | "kind">): string;
90
+ export declare function contextInterfaceArtifactPathsForZoneIds(contextInterface: ContextInterface, zoneIds: readonly ContextInterfaceZoneId[]): string[];
91
+ export declare function summarizeContextInterface(contextInterface: ContextInterface): ContextInterfaceSummary;
92
+ export declare function deriveWorkflowInputsFromContextInterface(contextInterface: ContextInterface | null | undefined): WorkflowInputSpec[];
93
+ export declare function buildContextInterface(stages: ContextInterfaceStageLike[], label?: string): ContextInterface;
94
+ export declare function writeContextInterfaceFile(rootPath: string, stages: ContextInterfaceStageLike[], label?: string): ContextInterface;
95
+ export declare function writeContextInterface(rootPath: string, contextInterface: ContextInterface): ContextInterface;
96
+ export declare function readContextInterface(rootPath: string): ContextInterface | null;