@interf/compiler 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (160) hide show
  1. package/README.md +71 -69
  2. package/builtin-workflows/interf/README.md +6 -6
  3. package/builtin-workflows/interf/compile/stages/shape/SKILL.md +7 -7
  4. package/builtin-workflows/interf/compile/stages/structure/SKILL.md +2 -2
  5. package/builtin-workflows/interf/compile/stages/summarize/SKILL.md +1 -1
  6. package/builtin-workflows/interf/{workspace.schema.json → compiled.schema.json} +5 -5
  7. package/builtin-workflows/interf/improve/SKILL.md +3 -3
  8. package/builtin-workflows/interf/use/query/SKILL.md +2 -2
  9. package/builtin-workflows/interf/workflow.json +42 -31
  10. package/dist/commands/check-draft.d.ts +19 -0
  11. package/dist/commands/check-draft.js +110 -0
  12. package/dist/commands/compile-controller.d.ts +4 -4
  13. package/dist/commands/compile-controller.js +117 -81
  14. package/dist/commands/compile.d.ts +5 -5
  15. package/dist/commands/compile.js +61 -62
  16. package/dist/commands/compiled-flow.d.ts +23 -0
  17. package/dist/commands/compiled-flow.js +112 -0
  18. package/dist/commands/create-workflow-wizard.d.ts +3 -3
  19. package/dist/commands/create-workflow-wizard.js +11 -11
  20. package/dist/commands/create.d.ts +2 -2
  21. package/dist/commands/create.js +50 -57
  22. package/dist/commands/default.js +2 -2
  23. package/dist/commands/executor-flow.d.ts +20 -1
  24. package/dist/commands/executor-flow.js +67 -7
  25. package/dist/commands/init.js +242 -289
  26. package/dist/commands/list.js +14 -10
  27. package/dist/commands/reset.js +6 -6
  28. package/dist/commands/source-config-wizard.d.ts +12 -8
  29. package/dist/commands/source-config-wizard.js +356 -119
  30. package/dist/commands/status.js +49 -26
  31. package/dist/commands/test-flow.d.ts +23 -10
  32. package/dist/commands/test-flow.js +278 -58
  33. package/dist/commands/test.d.ts +7 -1
  34. package/dist/commands/test.js +264 -65
  35. package/dist/commands/verify.js +23 -14
  36. package/dist/index.d.ts +7 -7
  37. package/dist/index.js +4 -4
  38. package/dist/lib/agent-args.js +2 -1
  39. package/dist/lib/agent-constants.js +1 -1
  40. package/dist/lib/agent-render.js +4 -4
  41. package/dist/lib/agent-shells.d.ts +8 -8
  42. package/dist/lib/agent-shells.js +231 -142
  43. package/dist/lib/compiled-compile.d.ts +52 -0
  44. package/dist/lib/compiled-compile.js +274 -0
  45. package/dist/lib/compiled-home.d.ts +5 -0
  46. package/dist/lib/compiled-home.js +32 -0
  47. package/dist/lib/compiled-layout.d.ts +2 -0
  48. package/dist/lib/compiled-layout.js +60 -0
  49. package/dist/lib/compiled-paths.d.ts +41 -0
  50. package/dist/lib/compiled-paths.js +111 -0
  51. package/dist/lib/{workspace-raw.d.ts → compiled-raw.d.ts} +8 -7
  52. package/dist/lib/{workspace-raw.js → compiled-raw.js} +16 -14
  53. package/dist/lib/compiled-reset.d.ts +1 -0
  54. package/dist/lib/compiled-reset.js +44 -0
  55. package/dist/lib/compiled-schema.d.ts +27 -0
  56. package/dist/lib/compiled-schema.js +110 -0
  57. package/dist/lib/config.d.ts +0 -1
  58. package/dist/lib/config.js +0 -1
  59. package/dist/lib/discovery.d.ts +1 -1
  60. package/dist/lib/discovery.js +3 -3
  61. package/dist/lib/interf-bootstrap.d.ts +1 -1
  62. package/dist/lib/interf-bootstrap.js +4 -4
  63. package/dist/lib/interf-detect.d.ts +10 -10
  64. package/dist/lib/interf-detect.js +78 -56
  65. package/dist/lib/interf-scaffold.d.ts +2 -2
  66. package/dist/lib/interf-scaffold.js +90 -57
  67. package/dist/lib/interf-workflow-package.d.ts +3 -3
  68. package/dist/lib/interf-workflow-package.js +30 -30
  69. package/dist/lib/interf.d.ts +5 -5
  70. package/dist/lib/interf.js +4 -4
  71. package/dist/lib/local-workflows.d.ts +4 -4
  72. package/dist/lib/local-workflows.js +35 -70
  73. package/dist/lib/obsidian.d.ts +1 -1
  74. package/dist/lib/parse.js +92 -1
  75. package/dist/lib/project-paths.d.ts +13 -0
  76. package/dist/lib/project-paths.js +29 -0
  77. package/dist/lib/runtime-acceptance.d.ts +7 -1
  78. package/dist/lib/runtime-acceptance.js +194 -59
  79. package/dist/lib/runtime-contracts.d.ts +2 -4
  80. package/dist/lib/runtime-contracts.js +17 -161
  81. package/dist/lib/runtime-inventory.d.ts +7 -0
  82. package/dist/lib/runtime-inventory.js +29 -0
  83. package/dist/lib/runtime-paths.js +5 -5
  84. package/dist/lib/runtime-prompt.js +9 -6
  85. package/dist/lib/runtime-reconcile.d.ts +2 -3
  86. package/dist/lib/runtime-reconcile.js +92 -171
  87. package/dist/lib/runtime-runs.js +30 -39
  88. package/dist/lib/runtime-types.d.ts +10 -19
  89. package/dist/lib/runtime.d.ts +2 -2
  90. package/dist/lib/runtime.js +1 -1
  91. package/dist/lib/schema.d.ts +163 -140
  92. package/dist/lib/schema.js +163 -124
  93. package/dist/lib/source-config.d.ts +24 -20
  94. package/dist/lib/source-config.js +154 -116
  95. package/dist/lib/state-artifacts.d.ts +5 -5
  96. package/dist/lib/state-artifacts.js +8 -8
  97. package/dist/lib/state-health.d.ts +4 -4
  98. package/dist/lib/state-health.js +108 -126
  99. package/dist/lib/state-io.d.ts +8 -8
  100. package/dist/lib/state-io.js +77 -50
  101. package/dist/lib/state-paths.js +5 -5
  102. package/dist/lib/state-view.d.ts +4 -4
  103. package/dist/lib/state-view.js +52 -55
  104. package/dist/lib/state.d.ts +5 -5
  105. package/dist/lib/state.js +4 -4
  106. package/dist/lib/summarize-plan.d.ts +3 -2
  107. package/dist/lib/summarize-plan.js +18 -16
  108. package/dist/lib/test-execution.js +9 -9
  109. package/dist/lib/test-matrices.d.ts +3 -3
  110. package/dist/lib/test-matrices.js +6 -6
  111. package/dist/lib/test-paths.d.ts +4 -4
  112. package/dist/lib/test-paths.js +16 -10
  113. package/dist/lib/test-sandbox.d.ts +1 -1
  114. package/dist/lib/test-sandbox.js +38 -31
  115. package/dist/lib/test-targets.d.ts +2 -2
  116. package/dist/lib/test-targets.js +11 -11
  117. package/dist/lib/test-types.d.ts +1 -1
  118. package/dist/lib/test.d.ts +1 -1
  119. package/dist/lib/test.js +1 -1
  120. package/dist/lib/util.d.ts +2 -0
  121. package/dist/lib/util.js +14 -1
  122. package/dist/lib/validate-compiled.d.ts +27 -0
  123. package/dist/lib/validate-compiled.js +236 -0
  124. package/dist/lib/validate-helpers.d.ts +0 -8
  125. package/dist/lib/validate-helpers.js +0 -30
  126. package/dist/lib/validate.d.ts +4 -4
  127. package/dist/lib/validate.js +49 -15
  128. package/dist/lib/workflow-abi.d.ts +37 -46
  129. package/dist/lib/workflow-abi.js +51 -76
  130. package/dist/lib/workflow-definitions.d.ts +11 -11
  131. package/dist/lib/workflow-definitions.js +36 -53
  132. package/dist/lib/workflow-helpers.d.ts +2 -3
  133. package/dist/lib/workflow-helpers.js +9 -13
  134. package/dist/lib/workflow-improvement.d.ts +3 -3
  135. package/dist/lib/workflow-improvement.js +48 -48
  136. package/dist/lib/workflow-review-paths.d.ts +3 -3
  137. package/dist/lib/workflow-review-paths.js +11 -11
  138. package/dist/lib/workflow-stage-runner.d.ts +1 -1
  139. package/dist/lib/workflow-stage-runner.js +8 -8
  140. package/dist/lib/workflows.d.ts +9 -9
  141. package/dist/lib/workflows.js +15 -17
  142. package/package.json +10 -9
  143. package/dist/commands/workspace-flow.d.ts +0 -23
  144. package/dist/commands/workspace-flow.js +0 -109
  145. package/dist/lib/registry.d.ts +0 -16
  146. package/dist/lib/registry.js +0 -65
  147. package/dist/lib/validate-workspace.d.ts +0 -121
  148. package/dist/lib/validate-workspace.js +0 -407
  149. package/dist/lib/workspace-compile.d.ts +0 -54
  150. package/dist/lib/workspace-compile.js +0 -476
  151. package/dist/lib/workspace-home.d.ts +0 -5
  152. package/dist/lib/workspace-home.js +0 -32
  153. package/dist/lib/workspace-layout.d.ts +0 -2
  154. package/dist/lib/workspace-layout.js +0 -60
  155. package/dist/lib/workspace-paths.d.ts +0 -41
  156. package/dist/lib/workspace-paths.js +0 -107
  157. package/dist/lib/workspace-reset.d.ts +0 -1
  158. package/dist/lib/workspace-reset.js +0 -43
  159. package/dist/lib/workspace-schema.d.ts +0 -17
  160. package/dist/lib/workspace-schema.js +0 -74
@@ -1,16 +0,0 @@
1
- export interface WorkspaceEntry {
2
- name: string;
3
- path: string;
4
- workflow: string;
5
- created: string;
6
- }
7
- export interface Registry {
8
- version: number;
9
- workspaces: WorkspaceEntry[];
10
- }
11
- export declare function loadRegistry(): Registry;
12
- export declare function saveRegistry(registry: Registry): void;
13
- export declare function listWorkspaceEntries(registry?: Registry): WorkspaceEntry[];
14
- export declare function addWorkspace(name: string, path: string, workflow: string): void;
15
- export declare function findWorkspaceByName(name: string): WorkspaceEntry[];
16
- export declare function findInterf(name: string): WorkspaceEntry | undefined;
@@ -1,65 +0,0 @@
1
- import { existsSync, mkdirSync, writeFileSync } from "node:fs";
2
- import { INTERF_HOME, REGISTRY_PATH } from "./config.js";
3
- import { readJsonFileUnchecked } from "./parse.js";
4
- function normalizeWorkspaceEntry(value) {
5
- const name = String(value.name ?? "");
6
- const path = String(value.path ?? "");
7
- if (name.length === 0 || path.length === 0)
8
- return null;
9
- return {
10
- name,
11
- path,
12
- workflow: String(value.workflow ?? "interf"),
13
- created: String(value.created ?? new Date().toISOString()),
14
- };
15
- }
16
- export function loadRegistry() {
17
- const empty = { version: 7, workspaces: [] };
18
- if (!existsSync(REGISTRY_PATH)) {
19
- return empty;
20
- }
21
- const raw = readJsonFileUnchecked(REGISTRY_PATH, "Interf registry");
22
- if (!raw)
23
- return empty;
24
- const seen = new Set();
25
- const workspaces = [];
26
- const rawWorkspaces = Array.isArray(raw.workspaces) ? raw.workspaces : [];
27
- for (const value of rawWorkspaces) {
28
- if (!value || typeof value !== "object")
29
- continue;
30
- const entry = normalizeWorkspaceEntry(value);
31
- if (!entry || seen.has(entry.path))
32
- continue;
33
- seen.add(entry.path);
34
- workspaces.push(entry);
35
- }
36
- return {
37
- version: 7,
38
- workspaces,
39
- };
40
- }
41
- export function saveRegistry(registry) {
42
- mkdirSync(INTERF_HOME, { recursive: true });
43
- writeFileSync(REGISTRY_PATH, JSON.stringify({ version: 7, workspaces: registry.workspaces }, null, 2) + "\n");
44
- }
45
- export function listWorkspaceEntries(registry = loadRegistry()) {
46
- return [...registry.workspaces].sort((left, right) => left.name.localeCompare(right.name) || left.path.localeCompare(right.path));
47
- }
48
- export function addWorkspace(name, path, workflow) {
49
- const reg = loadRegistry();
50
- reg.workspaces = reg.workspaces.filter((entry) => entry.path !== path);
51
- reg.workspaces.push({
52
- name,
53
- path,
54
- workflow,
55
- created: new Date().toISOString(),
56
- });
57
- saveRegistry(reg);
58
- }
59
- export function findWorkspaceByName(name) {
60
- return listWorkspaceEntries().filter((workspace) => workspace.name === name);
61
- }
62
- export function findInterf(name) {
63
- const matches = listWorkspaceEntries().filter((workspace) => workspace.name === name);
64
- return matches.length === 1 ? matches[0] : undefined;
65
- }
@@ -1,121 +0,0 @@
1
- export interface WorkspaceValidationSummary {
2
- config_present: boolean;
3
- config_valid: boolean;
4
- config_type_match: boolean;
5
- summary_frontmatter_valid: boolean;
6
- abstracts_valid: boolean;
7
- invalid_frontmatter: number;
8
- short_abstracts: number;
9
- broken_links: number;
10
- }
11
- export interface WorkspaceSummarizeValidation {
12
- ok: boolean;
13
- required: boolean;
14
- summary: string;
15
- counts: {
16
- source_total: number;
17
- source_covered: number;
18
- summarized: number;
19
- to_summarize: number;
20
- invalid_frontmatter: number;
21
- short_abstracts: number;
22
- inventory_total: number;
23
- };
24
- checks: {
25
- config_present: boolean;
26
- config_valid: boolean;
27
- config_type_match: boolean;
28
- summaries_present: boolean;
29
- state_present: boolean;
30
- state_valid: boolean;
31
- inventory_present: boolean;
32
- inventory_valid: boolean;
33
- inventory_complete: boolean;
34
- inventory_matches_summaries: boolean;
35
- state_covers_summaries: boolean;
36
- full_source_coverage: boolean;
37
- summary_frontmatter_valid: boolean;
38
- abstracts_valid: boolean;
39
- };
40
- errors: string[];
41
- }
42
- export interface WorkspaceCompileValidation {
43
- ok: boolean;
44
- required: boolean;
45
- summary: string;
46
- counts: {
47
- source_total: number;
48
- summarized: number;
49
- structured: number;
50
- shaped: number;
51
- compiled: number;
52
- inventory_total: number;
53
- frontmatter_scanned: number;
54
- abstracts_read: number;
55
- full_reads: number;
56
- entity_files: number;
57
- claim_files: number;
58
- index_files: number;
59
- outputs: number;
60
- };
61
- checks: {
62
- config_present: boolean;
63
- config_valid: boolean;
64
- config_type_match: boolean;
65
- summarize_complete: boolean;
66
- structure_complete: boolean;
67
- state_present: boolean;
68
- state_valid: boolean;
69
- inventory_present: boolean;
70
- inventory_valid: boolean;
71
- inventory_complete: boolean;
72
- inventory_matches_summaries: boolean;
73
- frontmatter_inventory_complete: boolean;
74
- abstracts_cover_summaries: boolean;
75
- shaped_complete: boolean;
76
- compiled_complete: boolean;
77
- outputs_present: boolean;
78
- home_present: boolean;
79
- links_valid: boolean;
80
- };
81
- errors: string[];
82
- }
83
- export interface WorkspaceStructureValidation {
84
- ok: boolean;
85
- required: boolean;
86
- summary: string;
87
- counts: {
88
- source_total: number;
89
- summarized: number;
90
- structured: number;
91
- inventory_total: number;
92
- frontmatter_scanned: number;
93
- abstracts_read: number;
94
- entity_files: number;
95
- claim_files: number;
96
- index_files: number;
97
- outputs: number;
98
- };
99
- checks: {
100
- config_present: boolean;
101
- config_valid: boolean;
102
- config_type_match: boolean;
103
- summarize_complete: boolean;
104
- state_present: boolean;
105
- state_valid: boolean;
106
- inventory_present: boolean;
107
- inventory_valid: boolean;
108
- inventory_complete: boolean;
109
- inventory_matches_summaries: boolean;
110
- frontmatter_inventory_complete: boolean;
111
- abstracts_cover_summaries: boolean;
112
- structured_complete: boolean;
113
- outputs_present: boolean;
114
- links_valid: boolean;
115
- };
116
- errors: string[];
117
- }
118
- export declare function validateWorkspace(dirPath: string): WorkspaceValidationSummary;
119
- export declare function validateWorkspaceSummarize(dirPath: string): WorkspaceSummarizeValidation;
120
- export declare function validateWorkspaceCompile(dirPath: string): WorkspaceCompileValidation;
121
- export declare function validateWorkspaceStructure(dirPath: string): WorkspaceStructureValidation;
@@ -1,407 +0,0 @@
1
- import { existsSync } from "node:fs";
2
- import { join } from "node:path";
3
- import { countFilesRecursive, listFilesRecursive } from "./filesystem.js";
4
- import { discoverSourceFiles } from "./discovery.js";
5
- import { resolveSourceFolderPath } from "./interf.js";
6
- import { readJsonFileUnchecked } from "./parse.js";
7
- import { workspaceHomeIsShaped } from "./workspace-home.js";
8
- import { WorkspaceInventorySchema, WorkspaceStateSchema, } from "./schema.js";
9
- import { readWorkspaceConfig, validateSynthFiles, countBrokenWikilinks, asNumber, isOutputMarkdownFile, } from "./validate.js";
10
- import { readInventoryFiles, readInventoryTotal, } from "./validate-helpers.js";
11
- import { workspaceInterfConfigPath, workspaceRuntimeRoot, } from "./workspace-paths.js";
12
- export function validateWorkspace(dirPath) {
13
- const config = readWorkspaceConfig(dirPath);
14
- const summaryFiles = listFilesRecursive(join(dirPath, "summaries"), isOutputMarkdownFile);
15
- const summaryValidation = validateSynthFiles(summaryFiles);
16
- const brokenLinks = countBrokenWikilinks(dirPath, [join(dirPath, "summaries"), join(dirPath, "knowledge")], [join(dirPath, "summaries"), join(dirPath, "knowledge")]);
17
- return {
18
- config_present: config.present,
19
- config_valid: config.valid,
20
- config_type_match: config.typeMatch(),
21
- summary_frontmatter_valid: summaryValidation.invalid_frontmatter === 0,
22
- abstracts_valid: summaryValidation.short_abstracts === 0,
23
- invalid_frontmatter: summaryValidation.invalid_frontmatter,
24
- short_abstracts: summaryValidation.short_abstracts,
25
- broken_links: brokenLinks,
26
- };
27
- }
28
- export function validateWorkspaceSummarize(dirPath) {
29
- const config = readWorkspaceConfig(dirPath);
30
- const sourcePath = resolveSourceFolderPath(dirPath, config.value);
31
- const discovery = discoverSourceFiles(sourcePath, dirPath);
32
- const sourceTotal = discovery.totalCount;
33
- const summariesPresent = existsSync(join(dirPath, "summaries"));
34
- const summaryFiles = listFilesRecursive(join(dirPath, "summaries"), isOutputMarkdownFile);
35
- const summaryValidation = validateSynthFiles(summaryFiles);
36
- const summarized = summaryFiles.length;
37
- const runtimeRoot = workspaceRuntimeRoot(dirPath);
38
- const statePath = join(runtimeRoot, "state.json");
39
- const inventoryPath = join(runtimeRoot, "inventory.json");
40
- const statePresent = existsSync(statePath);
41
- const inventoryPresent = existsSync(inventoryPath);
42
- const state = statePresent
43
- ? readJsonFileUnchecked(statePath, "workspace state")
44
- : null;
45
- const inventory = inventoryPresent
46
- ? readJsonFileUnchecked(inventoryPath, "workspace inventory")
47
- : null;
48
- const inventoryValid = inventory !== null && WorkspaceInventorySchema.safeParse(inventory).success;
49
- const inventoryFilesByShape = readInventoryFiles(inventory);
50
- const inventoryFiles = inventoryFilesByShape.files;
51
- const inventoryTotal = readInventoryTotal(inventory, inventoryFilesByShape);
52
- const sourceCovered = Math.min(sourceTotal, summarized);
53
- const toSummarize = Math.max(0, sourceTotal - sourceCovered);
54
- const required = sourceTotal > 0 || summarized > 0;
55
- const checks = {
56
- config_present: config.present,
57
- config_valid: config.valid,
58
- config_type_match: config.typeMatch(),
59
- summaries_present: summariesPresent,
60
- state_present: statePresent,
61
- state_valid: state !== null && WorkspaceStateSchema.safeParse(state).success,
62
- inventory_present: inventoryPresent,
63
- inventory_valid: inventoryValid,
64
- inventory_complete: Boolean(state?.inventory_complete) === true,
65
- inventory_matches_summaries: inventoryValid && inventoryTotal === summarized && inventoryFiles.length === summarized,
66
- state_covers_summaries: asNumber(state?.summarized) >= summarized &&
67
- typeof state?.last_summarize === "string" &&
68
- state.last_summarize.length > 0,
69
- full_source_coverage: toSummarize === 0,
70
- summary_frontmatter_valid: summaryValidation.invalid_frontmatter === 0,
71
- abstracts_valid: summaryValidation.short_abstracts === 0,
72
- };
73
- const errors = [];
74
- if (!checks.config_present)
75
- errors.push(`Missing ${workspaceInterfConfigPath(dirPath)}.`);
76
- else if (!checks.config_valid)
77
- errors.push(`Could not parse ${workspaceInterfConfigPath(dirPath)}.`);
78
- else if (!checks.config_type_match)
79
- errors.push("Config is not a workspace.");
80
- if (required && !checks.summaries_present)
81
- errors.push("Missing summaries/ directory.");
82
- if (required && !checks.state_present)
83
- errors.push("Missing .interf/runtime/state.json.");
84
- else if (required && !checks.state_valid)
85
- errors.push("Could not parse .interf/runtime/state.json.");
86
- if (required && !checks.inventory_present)
87
- errors.push("Missing .interf/runtime/inventory.json.");
88
- else if (required && !checks.inventory_valid)
89
- errors.push("Could not parse .interf/runtime/inventory.json or it has the wrong shape.");
90
- if (required && checks.inventory_present && checks.inventory_valid && !checks.inventory_complete) {
91
- errors.push("state.json does not mark inventory_complete.");
92
- }
93
- if (required && checks.inventory_present && checks.inventory_valid && !checks.inventory_matches_summaries) {
94
- errors.push("Inventory does not match the summary set.");
95
- }
96
- if (required && checks.state_present && checks.state_valid && !checks.state_covers_summaries) {
97
- errors.push("state.json does not prove summarize completion.");
98
- }
99
- if (!checks.full_source_coverage)
100
- errors.push("Not every source file has a summary yet.");
101
- if (!checks.summary_frontmatter_valid)
102
- errors.push("Some summary files have invalid or incomplete frontmatter.");
103
- if (!checks.abstracts_valid)
104
- errors.push("Some summary files are missing a valid abstract block.");
105
- const ok = errors.length === 0;
106
- const summary = !required
107
- ? "Summarize not required yet — no source files discovered."
108
- : ok
109
- ? `Summarize verified — ${sourceCovered}/${sourceTotal} source files are covered by valid summaries.`
110
- : `Summarize failed — ${errors[0] ?? "incomplete summary coverage."}`;
111
- return {
112
- ok,
113
- required,
114
- summary,
115
- counts: {
116
- source_total: sourceTotal,
117
- source_covered: sourceCovered,
118
- summarized,
119
- to_summarize: toSummarize,
120
- invalid_frontmatter: summaryValidation.invalid_frontmatter,
121
- short_abstracts: summaryValidation.short_abstracts,
122
- inventory_total: inventoryTotal,
123
- },
124
- checks,
125
- errors,
126
- };
127
- }
128
- export function validateWorkspaceCompile(dirPath) {
129
- const summarizeValidation = validateWorkspaceSummarize(dirPath);
130
- const structureValidation = validateWorkspaceStructure(dirPath);
131
- const config = readWorkspaceConfig(dirPath);
132
- const runtimeRoot = workspaceRuntimeRoot(dirPath);
133
- const statePath = join(runtimeRoot, "state.json");
134
- const inventoryPath = join(runtimeRoot, "inventory.json");
135
- const statePresent = existsSync(statePath);
136
- const inventoryPresent = existsSync(inventoryPath);
137
- const state = statePresent
138
- ? readJsonFileUnchecked(statePath, "workspace state")
139
- : null;
140
- const inventory = inventoryPresent
141
- ? readJsonFileUnchecked(inventoryPath, "workspace inventory")
142
- : null;
143
- const summarized = countFilesRecursive(join(dirPath, "summaries"));
144
- const structured = Math.max(asNumber(state?.structured), asNumber(state?.compiled));
145
- const shaped = Math.max(asNumber(state?.shaped), asNumber(state?.compiled));
146
- const compiled = asNumber(state?.compiled);
147
- const inventoryFilesByShape = readInventoryFiles(inventory);
148
- const { legacyFiles: legacyInventoryFiles, summaryFiles: summaryInventoryFiles, entryFiles: entryInventoryFiles, files: inventoryFiles, } = inventoryFilesByShape;
149
- const inventoryTotal = readInventoryTotal(inventory, inventoryFilesByShape);
150
- const frontmatterScanned = legacyInventoryFiles.length > 0
151
- ? inventoryFiles.filter((file) => file.frontmatter_scanned === true || file.frontmatter_read === true).length
152
- : summaryInventoryFiles.length > 0
153
- ? inventoryFiles.filter((file) => typeof file.file === "string" && typeof file.source === "string").length
154
- : inventoryFiles.filter((file) => (typeof file.summary === "string" || typeof file.digest === "string") &&
155
- typeof file.source === "string").length;
156
- const abstractsRead = legacyInventoryFiles.length > 0
157
- ? inventoryFiles.filter((file) => file.abstract_read === true).length
158
- : summaryInventoryFiles.length > 0
159
- ? inventoryFiles.filter((file) => file.abstract_read === true ||
160
- (typeof file.abstract === "string" && file.abstract.trim().length > 0) ||
161
- typeof file.status === "string" ||
162
- typeof file.state === "string").length
163
- : inventoryFiles.filter((file) => typeof file.state === "string").length;
164
- const entryAbstractsRead = entryInventoryFiles.length > 0
165
- ? entryInventoryFiles.filter((file) => typeof file.abstract === "string" && file.abstract.trim().length > 0).length
166
- : 0;
167
- const effectiveAbstractsRead = entryInventoryFiles.length > 0 && summaryInventoryFiles.length === 0 && legacyInventoryFiles.length === 0
168
- ? Math.max(abstractsRead, entryAbstractsRead)
169
- : abstractsRead;
170
- const fullReads = asNumber(state?.full_reads);
171
- const entityFiles = countFilesRecursive(join(dirPath, "knowledge", "entities"));
172
- const claimFiles = countFilesRecursive(join(dirPath, "knowledge", "claims"));
173
- const indexFiles = countFilesRecursive(join(dirPath, "knowledge", "indexes"));
174
- const outputs = entityFiles + claimFiles + indexFiles;
175
- const homePresent = existsSync(join(dirPath, "home.md"));
176
- const homeShaped = workspaceHomeIsShaped(dirPath);
177
- const brokenLinks = countBrokenWikilinks(dirPath, [join(dirPath, "summaries"), join(dirPath, "knowledge"), join(dirPath, "home.md")], [join(dirPath, "summaries"), join(dirPath, "knowledge"), join(dirPath, "home.md")]);
178
- const required = structureValidation.required || homePresent || shaped > 0 || compiled > 0 || inventoryPresent;
179
- const checks = {
180
- config_present: config.present,
181
- config_valid: config.valid,
182
- config_type_match: config.typeMatch(),
183
- summarize_complete: summarizeValidation.ok && summarizeValidation.required,
184
- structure_complete: structureValidation.ok && structureValidation.required,
185
- state_present: statePresent,
186
- state_valid: state !== null && WorkspaceStateSchema.safeParse(state).success,
187
- inventory_present: inventoryPresent,
188
- inventory_valid: inventory !== null && WorkspaceInventorySchema.safeParse(inventory).success,
189
- inventory_complete: Boolean(state?.inventory_complete) === true,
190
- inventory_matches_summaries: inventoryTotal === summarized && inventoryFiles.length === summarized,
191
- frontmatter_inventory_complete: frontmatterScanned === summarized,
192
- abstracts_cover_summaries: asNumber(state?.abstracts_read) >= summarized && effectiveAbstractsRead >= summarized,
193
- shaped_complete: shaped >= summarized &&
194
- summarized > 0 &&
195
- typeof state?.last_shape === "string" &&
196
- state.last_shape.length > 0,
197
- compiled_complete: compiled >= summarized &&
198
- summarized > 0 &&
199
- typeof state?.last_compile === "string" &&
200
- state.last_compile.length > 0,
201
- outputs_present: outputs > 0,
202
- home_present: homePresent,
203
- home_shaped: homeShaped,
204
- links_valid: brokenLinks === 0,
205
- };
206
- const errors = [];
207
- if (!checks.config_present)
208
- errors.push(`Missing ${workspaceInterfConfigPath(dirPath)}.`);
209
- else if (!checks.config_valid)
210
- errors.push(`Could not parse ${workspaceInterfConfigPath(dirPath)}.`);
211
- else if (!checks.config_type_match)
212
- errors.push("Config is not a workspace.");
213
- if (!checks.summarize_complete)
214
- errors.push("Workspace summarize is incomplete or invalid.");
215
- if (!checks.structure_complete)
216
- errors.push("Workspace structure is incomplete or invalid.");
217
- if (!checks.state_present)
218
- errors.push("Missing .interf/runtime/state.json.");
219
- else if (!checks.state_valid)
220
- errors.push("Could not parse .interf/runtime/state.json.");
221
- if (!checks.inventory_present)
222
- errors.push("Missing .interf/runtime/inventory.json.");
223
- else if (!checks.inventory_valid)
224
- errors.push("Could not parse .interf/runtime/inventory.json or it has the wrong shape.");
225
- if (checks.inventory_present && checks.inventory_valid && !checks.inventory_complete) {
226
- errors.push("state.json does not mark inventory_complete.");
227
- }
228
- if (checks.inventory_present && checks.inventory_valid && !checks.inventory_matches_summaries) {
229
- errors.push("Inventory does not match the summary set.");
230
- }
231
- if (checks.inventory_present && checks.inventory_valid && !checks.frontmatter_inventory_complete) {
232
- errors.push("Not every summary is marked frontmatter_scanned in inventory.");
233
- }
234
- if (checks.state_present && checks.state_valid && !checks.abstracts_cover_summaries) {
235
- errors.push("Abstract review does not cover the full summary set.");
236
- }
237
- if (checks.state_present && checks.state_valid && !checks.shaped_complete) {
238
- errors.push("state.json does not prove final workspace shaping.");
239
- }
240
- if (checks.state_present && checks.state_valid && !checks.compiled_complete) {
241
- errors.push("state.json compiled count does not cover the full summary set.");
242
- }
243
- if (!checks.outputs_present)
244
- errors.push("Workspace compile outputs are missing or empty.");
245
- if (!checks.home_present)
246
- errors.push("Workspace home.md is missing.");
247
- if (checks.home_present && !checks.home_shaped) {
248
- errors.push("Workspace home.md still contains the uncompiled scaffold placeholder.");
249
- }
250
- if (!checks.links_valid)
251
- errors.push("Some knowledge notes contain broken wikilinks.");
252
- const ok = required ? errors.length === 0 : true;
253
- const summary = !required
254
- ? "Workspace compile not required yet — no summaries exist yet."
255
- : ok
256
- ? `Workspace compile verified — ${compiled}/${summarized} summaries shaped and compiled, ${entityFiles} entities, ${claimFiles} claims.`
257
- : `Workspace compile failed — ${errors[0] ?? "incomplete compile."}`;
258
- return {
259
- ok,
260
- required,
261
- summary,
262
- counts: {
263
- source_total: summarizeValidation.counts.source_total,
264
- summarized,
265
- structured,
266
- shaped,
267
- compiled,
268
- inventory_total: inventoryTotal,
269
- frontmatter_scanned: frontmatterScanned,
270
- abstracts_read: Math.max(asNumber(state?.abstracts_read), effectiveAbstractsRead),
271
- full_reads: fullReads,
272
- entity_files: entityFiles,
273
- claim_files: claimFiles,
274
- index_files: indexFiles,
275
- outputs,
276
- },
277
- checks,
278
- errors,
279
- };
280
- }
281
- export function validateWorkspaceStructure(dirPath) {
282
- const summarizeValidation = validateWorkspaceSummarize(dirPath);
283
- const config = readWorkspaceConfig(dirPath);
284
- const runtimeRoot = workspaceRuntimeRoot(dirPath);
285
- const statePath = join(runtimeRoot, "state.json");
286
- const inventoryPath = join(runtimeRoot, "inventory.json");
287
- const statePresent = existsSync(statePath);
288
- const inventoryPresent = existsSync(inventoryPath);
289
- const state = statePresent
290
- ? readJsonFileUnchecked(statePath, "workspace state")
291
- : null;
292
- const inventory = inventoryPresent
293
- ? readJsonFileUnchecked(inventoryPath, "workspace inventory")
294
- : null;
295
- const summarized = countFilesRecursive(join(dirPath, "summaries"));
296
- const structured = Math.max(asNumber(state?.structured), asNumber(state?.compiled));
297
- const inventoryFilesByShape = readInventoryFiles(inventory);
298
- const { legacyFiles: legacyInventoryFiles, summaryFiles: summaryInventoryFiles, entryFiles: entryInventoryFiles, files: inventoryFiles, } = inventoryFilesByShape;
299
- const inventoryTotal = readInventoryTotal(inventory, inventoryFilesByShape);
300
- const frontmatterScanned = legacyInventoryFiles.length > 0
301
- ? inventoryFiles.filter((file) => file.frontmatter_scanned === true || file.frontmatter_read === true).length
302
- : summaryInventoryFiles.length > 0
303
- ? inventoryFiles.filter((file) => typeof file.file === "string" && typeof file.source === "string").length
304
- : inventoryFiles.filter((file) => (typeof file.summary === "string" || typeof file.digest === "string") &&
305
- typeof file.source === "string").length;
306
- const abstractsRead = legacyInventoryFiles.length > 0
307
- ? inventoryFiles.filter((file) => file.abstract_read === true).length
308
- : summaryInventoryFiles.length > 0
309
- ? inventoryFiles.filter((file) => file.abstract_read === true ||
310
- (typeof file.abstract === "string" && file.abstract.trim().length > 0) ||
311
- typeof file.status === "string" ||
312
- typeof file.state === "string").length
313
- : inventoryFiles.filter((file) => typeof file.state === "string").length;
314
- const entryAbstractsRead = entryInventoryFiles.length > 0
315
- ? entryInventoryFiles.filter((file) => typeof file.abstract === "string" && file.abstract.trim().length > 0).length
316
- : 0;
317
- const effectiveAbstractsRead = entryInventoryFiles.length > 0 && summaryInventoryFiles.length === 0 && legacyInventoryFiles.length === 0
318
- ? Math.max(abstractsRead, entryAbstractsRead)
319
- : abstractsRead;
320
- const entityFiles = countFilesRecursive(join(dirPath, "knowledge", "entities"));
321
- const claimFiles = countFilesRecursive(join(dirPath, "knowledge", "claims"));
322
- const indexFiles = countFilesRecursive(join(dirPath, "knowledge", "indexes"));
323
- const outputs = entityFiles + claimFiles + indexFiles;
324
- const brokenLinks = countBrokenWikilinks(dirPath, [join(dirPath, "summaries"), join(dirPath, "knowledge")], [join(dirPath, "summaries"), join(dirPath, "knowledge")]);
325
- const required = summarizeValidation.required || outputs > 0 || structured > 0 || inventoryPresent;
326
- const checks = {
327
- config_present: config.present,
328
- config_valid: config.valid,
329
- config_type_match: config.typeMatch(),
330
- summarize_complete: summarizeValidation.ok && summarizeValidation.required,
331
- state_present: statePresent,
332
- state_valid: state !== null && WorkspaceStateSchema.safeParse(state).success,
333
- inventory_present: inventoryPresent,
334
- inventory_valid: inventory !== null && WorkspaceInventorySchema.safeParse(inventory).success,
335
- inventory_complete: Boolean(state?.inventory_complete) === true,
336
- inventory_matches_summaries: inventoryTotal === summarized && inventoryFiles.length === summarized,
337
- frontmatter_inventory_complete: frontmatterScanned === summarized,
338
- abstracts_cover_summaries: asNumber(state?.abstracts_read) >= summarized && effectiveAbstractsRead >= summarized,
339
- structured_complete: structured >= summarized &&
340
- summarized > 0 &&
341
- typeof state?.last_structure === "string" &&
342
- state.last_structure.length > 0,
343
- outputs_present: outputs > 0,
344
- links_valid: brokenLinks === 0,
345
- };
346
- const errors = [];
347
- if (!checks.config_present)
348
- errors.push(`Missing ${workspaceInterfConfigPath(dirPath)}.`);
349
- else if (!checks.config_valid)
350
- errors.push(`Could not parse ${workspaceInterfConfigPath(dirPath)}.`);
351
- else if (!checks.config_type_match)
352
- errors.push("Config is not a workspace.");
353
- if (!checks.summarize_complete)
354
- errors.push("Workspace summarize is incomplete or invalid.");
355
- if (!checks.state_present)
356
- errors.push("Missing .interf/runtime/state.json.");
357
- else if (!checks.state_valid)
358
- errors.push("Could not parse .interf/runtime/state.json.");
359
- if (!checks.inventory_present)
360
- errors.push("Missing .interf/runtime/inventory.json.");
361
- else if (!checks.inventory_valid)
362
- errors.push("Could not parse .interf/runtime/inventory.json or it has the wrong shape.");
363
- if (checks.inventory_present && checks.inventory_valid && !checks.inventory_complete) {
364
- errors.push("state.json does not mark inventory_complete.");
365
- }
366
- if (checks.inventory_present && checks.inventory_valid && !checks.inventory_matches_summaries) {
367
- errors.push("Inventory does not match the summary set.");
368
- }
369
- if (checks.inventory_present && checks.inventory_valid && !checks.frontmatter_inventory_complete) {
370
- errors.push("Not every summary is marked frontmatter_scanned in inventory.");
371
- }
372
- if (checks.state_present && checks.state_valid && !checks.abstracts_cover_summaries) {
373
- errors.push("Abstract review does not cover the full summary set.");
374
- }
375
- if (checks.state_present && checks.state_valid && !checks.structured_complete) {
376
- errors.push("state.json does not prove workspace structure completion.");
377
- }
378
- if (!checks.outputs_present)
379
- errors.push("Workspace structure outputs are missing or empty.");
380
- if (!checks.links_valid)
381
- errors.push("Some knowledge notes contain broken wikilinks.");
382
- const ok = required ? errors.length === 0 : true;
383
- const summary = !required
384
- ? "Workspace structure not required yet — no summaries exist yet."
385
- : ok
386
- ? `Workspace structure verified — ${structured}/${summarized} summaries structured, ${entityFiles} entities, ${claimFiles} claims.`
387
- : `Workspace structure failed — ${errors[0] ?? "incomplete structure."}`;
388
- return {
389
- ok,
390
- required,
391
- summary,
392
- counts: {
393
- source_total: summarizeValidation.counts.source_total,
394
- summarized,
395
- structured,
396
- inventory_total: inventoryTotal,
397
- frontmatter_scanned: frontmatterScanned,
398
- abstracts_read: Math.max(asNumber(state?.abstracts_read), effectiveAbstractsRead),
399
- entity_files: entityFiles,
400
- claim_files: claimFiles,
401
- index_files: indexFiles,
402
- outputs,
403
- },
404
- checks,
405
- errors,
406
- };
407
- }
@@ -1,54 +0,0 @@
1
- import { type WorkflowExecutor } from "./executors.js";
2
- import { type SummarizePlan } from "./summarize-plan.js";
3
- import { type RuntimeStageContractDraft } from "./runtime.js";
4
- import { type RuntimeStageInstructions } from "./schema.js";
5
- import { type WorkspaceWorkflowId, type WorkflowStageDefinition } from "./workflow-definitions.js";
6
- import { type WorkflowReporter, type WorkflowStageResult } from "./workflow-helpers.js";
7
- export interface WorkspaceStageExecutionDefinition extends WorkflowStageDefinition {
8
- contractType: "workspace-file-evidence" | "workspace-knowledge-structure" | "workspace-query-shape";
9
- }
10
- export interface WorkspaceSummarizeResult extends WorkflowStageResult {
11
- skipped: boolean;
12
- plan: SummarizePlan;
13
- }
14
- export interface WorkspaceCompileResult {
15
- ok: boolean;
16
- summarize: WorkspaceSummarizeResult;
17
- structure: WorkflowStageResult | null;
18
- shape: WorkflowStageResult | null;
19
- compile: WorkflowStageResult | null;
20
- failedStage: string | null;
21
- }
22
- export type StageShellRetentionMode = "on-failure" | "always";
23
- export declare function resolveWorkspaceContext(workspacePath: string): {
24
- workspaceName: string;
25
- sourcePath: string;
26
- controlPath: string;
27
- workflowId: WorkspaceWorkflowId;
28
- };
29
- export declare function workspaceExecutionStages(workflowId: WorkspaceWorkflowId, workspacePath: string): WorkspaceStageExecutionDefinition[];
30
- export declare function buildWorkspaceCompileContract(workspacePath: string, workflowId: WorkspaceWorkflowId, summaryCount: number, instructions: RuntimeStageInstructions, stageId?: string, stageSkillDir?: string, shapeInputPath?: string): RuntimeStageContractDraft;
31
- export declare function runWorkspaceSummarize(options: {
32
- executor: WorkflowExecutor;
33
- workspacePath: string;
34
- sourcePath?: string;
35
- reporter?: WorkflowReporter;
36
- reportSummary?: boolean;
37
- reportStep?: boolean;
38
- stageDefinition?: WorkspaceStageExecutionDefinition;
39
- fullPass?: boolean;
40
- }): Promise<WorkspaceSummarizeResult>;
41
- export declare function runWorkspaceCompile(options: {
42
- executor: WorkflowExecutor;
43
- workspacePath: string;
44
- sourcePath?: string;
45
- reporter?: WorkflowReporter;
46
- reportStep?: boolean;
47
- preserveStageShells?: StageShellRetentionMode;
48
- }): Promise<WorkflowStageResult>;
49
- export declare function compileWorkspace(options: {
50
- executor: WorkflowExecutor;
51
- workspacePath: string;
52
- reporter?: WorkflowReporter;
53
- preserveStageShells?: StageShellRetentionMode;
54
- }): Promise<WorkspaceCompileResult>;