@adhamalkhaja/seyola-runtime 0.11.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 (135) hide show
  1. package/LICENSE +56 -0
  2. package/README.md +87 -0
  3. package/dist/adapters/claude-code-local/index.d.ts +60 -0
  4. package/dist/adapters/claude-code-local/index.d.ts.map +1 -0
  5. package/dist/adapters/claude-code-local/index.js +270 -0
  6. package/dist/adapters/claude-code-local/index.js.map +1 -0
  7. package/dist/bundle/index.d.ts +60 -0
  8. package/dist/bundle/index.d.ts.map +1 -0
  9. package/dist/bundle/index.js +989 -0
  10. package/dist/bundle/index.js.map +1 -0
  11. package/dist/cli/index.d.ts +12 -0
  12. package/dist/cli/index.d.ts.map +1 -0
  13. package/dist/cli/index.js +207 -0
  14. package/dist/cli/index.js.map +1 -0
  15. package/dist/compile-plan/budgets.d.ts +23 -0
  16. package/dist/compile-plan/budgets.d.ts.map +1 -0
  17. package/dist/compile-plan/budgets.js +55 -0
  18. package/dist/compile-plan/budgets.js.map +1 -0
  19. package/dist/compile-plan/graph.d.ts +40 -0
  20. package/dist/compile-plan/graph.d.ts.map +1 -0
  21. package/dist/compile-plan/graph.js +114 -0
  22. package/dist/compile-plan/graph.js.map +1 -0
  23. package/dist/compile-plan/index.d.ts +28 -0
  24. package/dist/compile-plan/index.d.ts.map +1 -0
  25. package/dist/compile-plan/index.js +423 -0
  26. package/dist/compile-plan/index.js.map +1 -0
  27. package/dist/compile-plan/registries.d.ts +35 -0
  28. package/dist/compile-plan/registries.d.ts.map +1 -0
  29. package/dist/compile-plan/registries.js +81 -0
  30. package/dist/compile-plan/registries.js.map +1 -0
  31. package/dist/compile-plan/resolver.d.ts +24 -0
  32. package/dist/compile-plan/resolver.d.ts.map +1 -0
  33. package/dist/compile-plan/resolver.js +57 -0
  34. package/dist/compile-plan/resolver.js.map +1 -0
  35. package/dist/compile-plan/types.d.ts +192 -0
  36. package/dist/compile-plan/types.d.ts.map +1 -0
  37. package/dist/compile-plan/types.js +7 -0
  38. package/dist/compile-plan/types.js.map +1 -0
  39. package/dist/doctor/index.d.ts +43 -0
  40. package/dist/doctor/index.d.ts.map +1 -0
  41. package/dist/doctor/index.js +224 -0
  42. package/dist/doctor/index.js.map +1 -0
  43. package/dist/init/index.d.ts +53 -0
  44. package/dist/init/index.d.ts.map +1 -0
  45. package/dist/init/index.js +414 -0
  46. package/dist/init/index.js.map +1 -0
  47. package/dist/lib/ajvSetup.d.ts +30 -0
  48. package/dist/lib/ajvSetup.d.ts.map +1 -0
  49. package/dist/lib/ajvSetup.js +44 -0
  50. package/dist/lib/ajvSetup.js.map +1 -0
  51. package/dist/lib/loadJson.d.ts +21 -0
  52. package/dist/lib/loadJson.d.ts.map +1 -0
  53. package/dist/lib/loadJson.js +43 -0
  54. package/dist/lib/loadJson.js.map +1 -0
  55. package/dist/lib/loadYaml.d.ts +18 -0
  56. package/dist/lib/loadYaml.d.ts.map +1 -0
  57. package/dist/lib/loadYaml.js +41 -0
  58. package/dist/lib/loadYaml.js.map +1 -0
  59. package/dist/lib/paths.d.ts +22 -0
  60. package/dist/lib/paths.d.ts.map +1 -0
  61. package/dist/lib/paths.js +61 -0
  62. package/dist/lib/paths.js.map +1 -0
  63. package/dist/run-plan/index.d.ts +17 -0
  64. package/dist/run-plan/index.d.ts.map +1 -0
  65. package/dist/run-plan/index.js +235 -0
  66. package/dist/run-plan/index.js.map +1 -0
  67. package/dist/run-plan/types.d.ts +53 -0
  68. package/dist/run-plan/types.d.ts.map +1 -0
  69. package/dist/run-plan/types.js +6 -0
  70. package/dist/run-plan/types.js.map +1 -0
  71. package/dist/run-step/contextPacket.d.ts +39 -0
  72. package/dist/run-step/contextPacket.d.ts.map +1 -0
  73. package/dist/run-step/contextPacket.js +213 -0
  74. package/dist/run-step/contextPacket.js.map +1 -0
  75. package/dist/run-step/derivation.d.ts +41 -0
  76. package/dist/run-step/derivation.d.ts.map +1 -0
  77. package/dist/run-step/derivation.js +61 -0
  78. package/dist/run-step/derivation.js.map +1 -0
  79. package/dist/run-step/effectExecutor.d.ts +42 -0
  80. package/dist/run-step/effectExecutor.d.ts.map +1 -0
  81. package/dist/run-step/effectExecutor.js +297 -0
  82. package/dist/run-step/effectExecutor.js.map +1 -0
  83. package/dist/run-step/formatExecutor.d.ts +34 -0
  84. package/dist/run-step/formatExecutor.d.ts.map +1 -0
  85. package/dist/run-step/formatExecutor.js +329 -0
  86. package/dist/run-step/formatExecutor.js.map +1 -0
  87. package/dist/run-step/index.d.ts +23 -0
  88. package/dist/run-step/index.d.ts.map +1 -0
  89. package/dist/run-step/index.js +627 -0
  90. package/dist/run-step/index.js.map +1 -0
  91. package/dist/run-step/inputResolver.d.ts +48 -0
  92. package/dist/run-step/inputResolver.d.ts.map +1 -0
  93. package/dist/run-step/inputResolver.js +268 -0
  94. package/dist/run-step/inputResolver.js.map +1 -0
  95. package/dist/run-step/types.d.ts +123 -0
  96. package/dist/run-step/types.d.ts.map +1 -0
  97. package/dist/run-step/types.js +6 -0
  98. package/dist/run-step/types.js.map +1 -0
  99. package/dist/validate-pack/checks/capabilitiesRegistry.d.ts +3 -0
  100. package/dist/validate-pack/checks/capabilitiesRegistry.d.ts.map +1 -0
  101. package/dist/validate-pack/checks/capabilitiesRegistry.js +83 -0
  102. package/dist/validate-pack/checks/capabilitiesRegistry.js.map +1 -0
  103. package/dist/validate-pack/checks/contextPolicies.d.ts +3 -0
  104. package/dist/validate-pack/checks/contextPolicies.d.ts.map +1 -0
  105. package/dist/validate-pack/checks/contextPolicies.js +40 -0
  106. package/dist/validate-pack/checks/contextPolicies.js.map +1 -0
  107. package/dist/validate-pack/checks/mvkExamples.d.ts +10 -0
  108. package/dist/validate-pack/checks/mvkExamples.d.ts.map +1 -0
  109. package/dist/validate-pack/checks/mvkExamples.js +77 -0
  110. package/dist/validate-pack/checks/mvkExamples.js.map +1 -0
  111. package/dist/validate-pack/checks/requiredFiles.d.ts +3 -0
  112. package/dist/validate-pack/checks/requiredFiles.d.ts.map +1 -0
  113. package/dist/validate-pack/checks/requiredFiles.js +35 -0
  114. package/dist/validate-pack/checks/requiredFiles.js.map +1 -0
  115. package/dist/validate-pack/checks/resolutionPolicy.d.ts +3 -0
  116. package/dist/validate-pack/checks/resolutionPolicy.d.ts.map +1 -0
  117. package/dist/validate-pack/checks/resolutionPolicy.js +88 -0
  118. package/dist/validate-pack/checks/resolutionPolicy.js.map +1 -0
  119. package/dist/validate-pack/checks/schemas.d.ts +16 -0
  120. package/dist/validate-pack/checks/schemas.d.ts.map +1 -0
  121. package/dist/validate-pack/checks/schemas.js +70 -0
  122. package/dist/validate-pack/checks/schemas.js.map +1 -0
  123. package/dist/validate-pack/index.d.ts +25 -0
  124. package/dist/validate-pack/index.d.ts.map +1 -0
  125. package/dist/validate-pack/index.js +95 -0
  126. package/dist/validate-pack/index.js.map +1 -0
  127. package/dist/validate-pack/reporting.d.ts +6 -0
  128. package/dist/validate-pack/reporting.d.ts.map +1 -0
  129. package/dist/validate-pack/reporting.js +40 -0
  130. package/dist/validate-pack/reporting.js.map +1 -0
  131. package/dist/validate-pack/types.d.ts +34 -0
  132. package/dist/validate-pack/types.d.ts.map +1 -0
  133. package/dist/validate-pack/types.js +8 -0
  134. package/dist/validate-pack/types.js.map +1 -0
  135. package/package.json +54 -0
@@ -0,0 +1,297 @@
1
+ /**
2
+ * Effect step executor. v0.8.0 supports a single effect:
3
+ *
4
+ * file.export — copy upstream step outputs into a final export directory.
5
+ *
6
+ * Local-only. Idempotent. Low-risk. No approval gate. The runtime validates
7
+ * the effect against .effects/registry.json + the effect's policy file
8
+ * before executing. Refuses any target outside the configured outputDir.
9
+ *
10
+ * External effects (email.draft, slack.post, vercel.deploy, payment.send)
11
+ * are NOT in scope for v0.8.0. They require approval gating + tool registry
12
+ * plumbing.
13
+ */
14
+ import { copyFileSync, existsSync, mkdirSync, statSync, writeFileSync } from "node:fs";
15
+ import { resolve, basename, isAbsolute, dirname, relative, extname } from "node:path";
16
+ import { createHash } from "node:crypto";
17
+ import { resolvePackPath } from "../lib/paths.js";
18
+ import { loadJson } from "../lib/loadJson.js";
19
+ export async function executeEffectStep(args) {
20
+ const errors = [];
21
+ const stepRaw = args.selected.step;
22
+ const request = stepRaw.effect_request;
23
+ if (!request || !request.type) {
24
+ return {
25
+ ok: false,
26
+ outputs: [],
27
+ errors: [{ code: "missing_effect_request", message: `Effect step '${stepRaw.id}' has no effect_request.type.` }],
28
+ };
29
+ }
30
+ // Load effects registry.
31
+ const registryPath = resolvePackPath(args.packPath, ".effects/registry.json");
32
+ const registry = loadJson(registryPath);
33
+ if (!registry.ok) {
34
+ return {
35
+ ok: false,
36
+ outputs: [],
37
+ errors: [{ code: registry.code, message: `Cannot load .effects/registry.json: ${registry.message}` }],
38
+ effect_id: request.type,
39
+ };
40
+ }
41
+ const entry = registry.data.effects?.[request.type];
42
+ if (!entry) {
43
+ return {
44
+ ok: false,
45
+ outputs: [],
46
+ errors: [{
47
+ code: "effect_not_in_registry",
48
+ message: `Effect '${request.type}' is not registered in .effects/registry.json. v0.8.0 supports: ${Object.keys(registry.data.effects ?? {}).join(", ") || "(none)"}.`,
49
+ }],
50
+ effect_id: request.type,
51
+ };
52
+ }
53
+ // v0.8.0 only supports file.export.
54
+ if (request.type !== "file.export") {
55
+ return {
56
+ ok: false,
57
+ outputs: [],
58
+ errors: [{
59
+ code: "effect_unsupported_in_runtime",
60
+ message: `Effect '${request.type}' is registered in the pack but seyola-runtime v0.8.0 only executes 'file.export'. External effects require approval gating + tool registry (future runtime).`,
61
+ }],
62
+ effect_id: request.type,
63
+ };
64
+ }
65
+ // Validate basic invariants for file.export.
66
+ if (entry.requires_approval) {
67
+ return {
68
+ ok: false,
69
+ outputs: [],
70
+ errors: [{
71
+ code: "approval_required",
72
+ message: `Effect '${request.type}' requires approval but v0.8.0 has no approval gate UI. Cannot proceed.`,
73
+ }],
74
+ effect_id: request.type,
75
+ };
76
+ }
77
+ // Resolve upstream output paths. Two sources:
78
+ // 1. args.upstreamOutputPaths (run-plan provides these directly).
79
+ // 2. Resolved input artifact paths (when run-step is invoked standalone
80
+ // and the payload is wired through inputArtifacts).
81
+ let sourcePaths = args.upstreamOutputPaths ?? [];
82
+ if (sourcePaths.length === 0) {
83
+ // Fallback: walk resolved inputs for any artifact-upstream resource paths.
84
+ const upstream = args.resolvedInputs.find((i) => i.kind === "artifact-upstream");
85
+ if (upstream?.resolvedPath) {
86
+ sourcePaths = [upstream.resolvedPath];
87
+ }
88
+ }
89
+ if (sourcePaths.length === 0) {
90
+ return {
91
+ ok: false,
92
+ outputs: [],
93
+ errors: [{
94
+ code: "no_upstream_outputs",
95
+ message: `Effect step '${stepRaw.id}' could not resolve any source files from upstream. effect_request.payload references=${typeof request.payload === "string" ? request.payload : "(none)"}.`,
96
+ }],
97
+ effect_id: request.type,
98
+ };
99
+ }
100
+ const existingSources = sourcePaths.filter((p) => existsSync(p));
101
+ const missingSources = sourcePaths.filter((p) => !existsSync(p));
102
+ if (existingSources.length === 0) {
103
+ return {
104
+ ok: false,
105
+ outputs: [],
106
+ errors: [{
107
+ code: "source_files_all_missing",
108
+ message: `None of the resolved source files exist on disk. Missing: ${missingSources.join(", ")}.`,
109
+ }],
110
+ effect_id: request.type,
111
+ };
112
+ }
113
+ for (const m of missingSources) {
114
+ errors.push({ code: "source_file_missing", message: `Source file ${m} does not exist; skipped.` });
115
+ }
116
+ // Resolve target directory. effect_request.target is interpreted as:
117
+ // - If absolute path: use as-is (subject to boundary check below).
118
+ // - If relative path: resolve against outputDir (NOT against CWD).
119
+ // - If unset: fall back to {outputDir}/exports/{plan_id}/.
120
+ const outputDirAbs = resolve(args.outputDir);
121
+ let exportDir;
122
+ if (request.target) {
123
+ const targetAbs = isAbsolute(request.target)
124
+ ? request.target
125
+ : resolve(outputDirAbs, request.target);
126
+ if (extname(targetAbs)) {
127
+ exportDir = dirname(targetAbs);
128
+ }
129
+ else {
130
+ exportDir = targetAbs;
131
+ }
132
+ }
133
+ else {
134
+ const planId = args.selected.plan?.id ?? "unknown-plan";
135
+ exportDir = resolve(outputDirAbs, "exports", planId);
136
+ }
137
+ // Refuse if target falls outside the configured outputDir (member-root
138
+ // guard). We only allow exports under the runtime's outputDir.
139
+ const rel = relative(outputDirAbs, exportDir);
140
+ if (rel.startsWith("..") || isAbsolute(rel)) {
141
+ return {
142
+ ok: false,
143
+ outputs: [],
144
+ errors: [{
145
+ code: "target_outside_member_root",
146
+ message: `Resolved export directory ${exportDir} falls outside the configured outputDir ${outputDirAbs}. file.export is local_only and must stay within the configured boundary.`,
147
+ }],
148
+ effect_id: request.type,
149
+ };
150
+ }
151
+ // Ensure the export directory exists.
152
+ if (!existsSync(exportDir)) {
153
+ mkdirSync(exportDir, { recursive: true });
154
+ }
155
+ // Copy files. Preserve filenames.
156
+ const exportedFiles = [];
157
+ const outputs = [];
158
+ for (const source of existingSources) {
159
+ const filename = basename(source);
160
+ const target = resolve(exportDir, filename);
161
+ try {
162
+ copyFileSync(source, target);
163
+ const stat = statSync(target);
164
+ exportedFiles.push({
165
+ source_path: source,
166
+ target_path: target,
167
+ bytes: stat.size,
168
+ });
169
+ outputs.push({ format: extname(filename).slice(1) || "file", path: target, ready: true });
170
+ }
171
+ catch (err) {
172
+ const message = err instanceof Error ? err.message : String(err);
173
+ errors.push({
174
+ code: "file_copy_failed",
175
+ message: `Failed to copy ${source} to ${target}: ${message}`,
176
+ });
177
+ }
178
+ }
179
+ // Write export-manifest.json.
180
+ const plan = args.selected.plan;
181
+ const task = args.selected.task;
182
+ const idempotencyHash = computeIdempotencyHash({
183
+ planId: plan.id ?? "",
184
+ taskId: task.id ?? "",
185
+ sourceStepId: deriveUpstreamStepId(stepRaw, args.resolvedInputs),
186
+ sourcePaths: existingSources,
187
+ });
188
+ const manifest = {
189
+ exported_at: new Date().toISOString(),
190
+ plan_id: plan.id ?? null,
191
+ task_id: task.id ?? null,
192
+ source_step_id: deriveUpstreamStepId(stepRaw, args.resolvedInputs),
193
+ source_artifact_type: args.selected.outputArtifactType,
194
+ effect_id: "file.export",
195
+ exported_files: exportedFiles,
196
+ export_directory: exportDir,
197
+ idempotency_hash: idempotencyHash,
198
+ };
199
+ const manifestPath = resolve(exportDir, "export-manifest.json");
200
+ writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
201
+ // Write effect record.
202
+ const effectsDir = resolve(outputDirAbs, "effects");
203
+ if (!existsSync(effectsDir))
204
+ mkdirSync(effectsDir, { recursive: true });
205
+ const executionId = `effect-${new Date().toISOString().replace(/[:.]/g, "-")}-${idempotencyHash.slice(0, 8)}`;
206
+ const effectRecord = {
207
+ $type: "effect-record",
208
+ $schema_version: "1.0.0",
209
+ execution_id: executionId,
210
+ effect_id: "file.export",
211
+ step_id: stepRaw.id,
212
+ plan_id: plan.id ?? null,
213
+ task_id: task.id ?? null,
214
+ executed_at: manifest.exported_at,
215
+ source_step_id: manifest.source_step_id,
216
+ source_files: existingSources,
217
+ target_directory: exportDir,
218
+ exported_files: exportedFiles.map((f) => f.target_path),
219
+ manifest_path: manifestPath,
220
+ duration_ms: 0,
221
+ status: errors.filter((e) => e.code !== "source_file_missing").length === 0 ? "success" : "failed",
222
+ errors,
223
+ };
224
+ const effectRecordPath = resolve(effectsDir, `${executionId}.json`);
225
+ writeFileSync(effectRecordPath, JSON.stringify(effectRecord, null, 2));
226
+ return {
227
+ ok: effectRecord.status === "success",
228
+ outputs,
229
+ exportDirectory: exportDir,
230
+ manifestPath,
231
+ effectRecordPath,
232
+ errors,
233
+ effect_id: "file.export",
234
+ };
235
+ }
236
+ // ---------- Helpers ----------
237
+ function computeIdempotencyHash(args) {
238
+ const hash = createHash("sha256");
239
+ hash.update(args.planId);
240
+ hash.update("|");
241
+ hash.update(args.taskId);
242
+ hash.update("|");
243
+ hash.update(args.sourceStepId ?? "");
244
+ hash.update("|");
245
+ for (const p of [...args.sourcePaths].sort()) {
246
+ hash.update(p);
247
+ hash.update("|");
248
+ }
249
+ return hash.digest("hex");
250
+ }
251
+ function deriveUpstreamStepId(step, resolvedInputs) {
252
+ const payload = step.effect_request?.payload;
253
+ if (typeof payload === "string") {
254
+ const match = /\$\{(s\d+)\.output\}/.exec(payload);
255
+ if (match)
256
+ return match[1] ?? null;
257
+ }
258
+ const upstreamInput = resolvedInputs.find((i) => i.kind === "artifact-upstream");
259
+ if (upstreamInput) {
260
+ const match = /\$\{(s\d+)\.output\}/.exec(upstreamInput.rawValue);
261
+ if (match)
262
+ return match[1] ?? null;
263
+ }
264
+ return null;
265
+ }
266
+ /** Builds a StructuredResult for an effect step execution. */
267
+ export function effectStepResult(selected, exec, backend, durationMs) {
268
+ const status = exec.ok ? "success" : "failed";
269
+ return {
270
+ step_id: selected.stepId,
271
+ status,
272
+ produced_at: new Date().toISOString(),
273
+ outputs: exec.outputs.map((o) => ({
274
+ type: selected.outputArtifactType,
275
+ path: o.path,
276
+ format: o.format,
277
+ })),
278
+ evaluations: exec.ok
279
+ ? [
280
+ {
281
+ rubric: "effect-execution",
282
+ threshold: 1,
283
+ score: 1,
284
+ passed: true,
285
+ notes: `Effect ${exec.effect_id ?? "(unknown)"} executed. Exported ${exec.outputs.length} file(s) to ${exec.exportDirectory ?? "(unknown)"}.`,
286
+ },
287
+ ]
288
+ : [],
289
+ cost: { wall_clock_seconds: durationMs / 1000 },
290
+ errors: exec.errors,
291
+ audit: {
292
+ capability: selected.capability,
293
+ backend,
294
+ },
295
+ };
296
+ }
297
+ //# sourceMappingURL=effectExecutor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"effectExecutor.js","sourceRoot":"","sources":["../../src/run-step/effectExecutor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Format step executor. Handles WorkPlan steps with kind=format.
3
+ *
4
+ * Reads the upstream artifact (already validated by inputResolver), loads
5
+ * the adapter spec from .formats/registry.json + the adapter directory,
6
+ * applies simple-template substitution, writes outputs to disk.
7
+ *
8
+ * No LLM calls. No subprocess. Pure deterministic rendering.
9
+ */
10
+ import type { ResolvedInput } from "./inputResolver.js";
11
+ import type { SelectedStepContext, StructuredResult } from "./types.js";
12
+ export interface FormatExecuteArgs {
13
+ packPath: string;
14
+ selected: SelectedStepContext;
15
+ resolvedInputs: ResolvedInput[];
16
+ outputDir: string;
17
+ }
18
+ export interface FormatExecuteResult {
19
+ ok: boolean;
20
+ outputs: Array<{
21
+ format: string;
22
+ path: string;
23
+ ready: boolean;
24
+ }>;
25
+ errors: Array<{
26
+ code: string;
27
+ message: string;
28
+ }>;
29
+ adapter_id?: string;
30
+ }
31
+ export declare function executeFormatStep(args: FormatExecuteArgs): Promise<FormatExecuteResult>;
32
+ /** Builds a StructuredResult for a successful or failed format step execution. */
33
+ export declare function formatStepResult(selected: SelectedStepContext, exec: FormatExecuteResult, backend: string, durationMs: number): StructuredResult;
34
+ //# sourceMappingURL=formatExecutor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatExecutor.d.ts","sourceRoot":"","sources":["../../src/run-step/formatExecutor.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAOH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,KAAK,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AA6CxE,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,mBAAmB,CAAC;IAC9B,cAAc,EAAE,aAAa,EAAE,CAAC;IAChC,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,OAAO,CAAC;IACZ,OAAO,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IACjE,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACjD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAkI7F;AA0KD,kFAAkF;AAClF,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,mBAAmB,EAC7B,IAAI,EAAE,mBAAmB,EACzB,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,GACjB,gBAAgB,CA6BlB"}
@@ -0,0 +1,329 @@
1
+ /**
2
+ * Format step executor. Handles WorkPlan steps with kind=format.
3
+ *
4
+ * Reads the upstream artifact (already validated by inputResolver), loads
5
+ * the adapter spec from .formats/registry.json + the adapter directory,
6
+ * applies simple-template substitution, writes outputs to disk.
7
+ *
8
+ * No LLM calls. No subprocess. Pure deterministic rendering.
9
+ */
10
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from "node:fs";
11
+ import { resolve, join, dirname } from "node:path";
12
+ import { resolvePackPath } from "../lib/paths.js";
13
+ import { loadJson } from "../lib/loadJson.js";
14
+ import { makeAjv, compileSchema, formatAjvErrors } from "../lib/ajvSetup.js";
15
+ export async function executeFormatStep(args) {
16
+ const errors = [];
17
+ const outputs = [];
18
+ const stepRaw = args.selected.step;
19
+ const adapterId = stepRaw.adapter;
20
+ if (!adapterId) {
21
+ return {
22
+ ok: false,
23
+ outputs: [],
24
+ errors: [{ code: "missing_adapter_id", message: "Format step is missing the 'adapter' field." }],
25
+ };
26
+ }
27
+ // Load .formats/registry.json.
28
+ const registryPath = resolvePackPath(args.packPath, ".formats/registry.json");
29
+ const registry = loadJson(registryPath);
30
+ if (!registry.ok) {
31
+ return {
32
+ ok: false,
33
+ outputs: [],
34
+ errors: [{ code: registry.code, message: `Cannot load .formats/registry.json: ${registry.message}` }],
35
+ adapter_id: adapterId,
36
+ };
37
+ }
38
+ const adapter = registry.data.adapters?.[adapterId];
39
+ if (!adapter) {
40
+ return {
41
+ ok: false,
42
+ outputs: [],
43
+ errors: [{
44
+ code: "adapter_not_in_registry",
45
+ message: `Adapter '${adapterId}' is not registered in .formats/registry.json. Available: ${Object.keys(registry.data.adapters ?? {}).join(", ") || "(none)"}.`,
46
+ }],
47
+ adapter_id: adapterId,
48
+ };
49
+ }
50
+ // Load render policy if present (richer config than the registry entry alone).
51
+ const adapterDir = adapter.templates_dir
52
+ ? resolvePackPath(args.packPath, adapter.templates_dir)
53
+ : resolvePackPath(args.packPath, `formats/${adapterId}`);
54
+ const renderPolicyPath = join(adapterDir, "render-policy.json");
55
+ let renderPolicy = null;
56
+ if (existsSync(renderPolicyPath)) {
57
+ const rp = loadJson(renderPolicyPath);
58
+ if (rp.ok)
59
+ renderPolicy = rp.data;
60
+ }
61
+ // Locate the upstream input artifact JSON.
62
+ const docInput = args.resolvedInputs.find((i) => i.paramName === "document" || i.kind === "artifact-upstream");
63
+ if (!docInput || !docInput.parsedJson) {
64
+ return {
65
+ ok: false,
66
+ outputs: [],
67
+ errors: [{
68
+ code: "missing_input_artifact",
69
+ message: "Format step input 'document' did not resolve to a parsed JSON artifact.",
70
+ }],
71
+ adapter_id: adapterId,
72
+ };
73
+ }
74
+ // Validate the input against the adapter's input shape contract.
75
+ const shapePath = adapter.input_shape_contract ?? renderPolicy?.input_shape_contract;
76
+ if (shapePath) {
77
+ const shapeAbs = resolvePackPath(args.packPath, shapePath);
78
+ if (existsSync(shapeAbs)) {
79
+ const schemaJson = loadJson(shapeAbs);
80
+ if (schemaJson.ok) {
81
+ const ajv = makeAjv();
82
+ const compiled = compileSchema(ajv, schemaJson.data);
83
+ if (compiled.ok && !compiled.validate(docInput.parsedJson)) {
84
+ errors.push({
85
+ code: "input_artifact_invalid",
86
+ message: `Input artifact failed shape validation: ${formatAjvErrors(compiled.validate.errors).join("; ")}`,
87
+ });
88
+ // Continue with rendering but flag the issue.
89
+ }
90
+ }
91
+ }
92
+ }
93
+ // Determine output base name from the artifact type.
94
+ const outputBaseName = adapter.input_artifact_type;
95
+ // Iterate registered outputs; render the ones marked ready.
96
+ const outputList = renderPolicy?.outputs ?? adapter.outputs;
97
+ for (const out of outputList) {
98
+ if (!out.ready) {
99
+ // Emit a placeholder file documenting the deferral so the member sees what's missing.
100
+ const placeholderPath = ensureOutputPath(args.outputDir, `${outputBaseName}.${out.format}.deferred.txt`);
101
+ writeFileSync(placeholderPath, `Output '${out.format}' for adapter '${adapterId}' is deferred.\n` +
102
+ `Reason: ${("note" in out && out.note) ? out.note : "ready=false in adapter spec"}.\n` +
103
+ `Use one of the ready outputs (e.g., the .html or .md file in this directory) until a future runtime version ships this format.\n`);
104
+ outputs.push({ format: out.format, path: placeholderPath, ready: false });
105
+ continue;
106
+ }
107
+ if (!out.template) {
108
+ errors.push({
109
+ code: "adapter_output_missing_template",
110
+ message: `Output '${out.format}' has ready=true but no template path declared.`,
111
+ });
112
+ continue;
113
+ }
114
+ const templatePath = join(adapterDir, out.template);
115
+ if (!existsSync(templatePath)) {
116
+ errors.push({
117
+ code: "adapter_template_missing",
118
+ message: `Template file ${templatePath} not found for output '${out.format}'.`,
119
+ });
120
+ continue;
121
+ }
122
+ const template = readFileSync(templatePath, "utf8");
123
+ const rendered = renderSimpleTemplate(template, docInput.parsedJson, out.format === "html");
124
+ const outputPath = ensureOutputPath(args.outputDir, `${outputBaseName}${out.extension ?? "." + out.format}`);
125
+ writeFileSync(outputPath, rendered);
126
+ outputs.push({ format: out.format, path: outputPath, ready: true });
127
+ }
128
+ return {
129
+ ok: errors.length === 0,
130
+ outputs,
131
+ errors,
132
+ adapter_id: adapterId,
133
+ };
134
+ }
135
+ // ----- Renderer -----
136
+ /**
137
+ * Simple-template renderer. Supports:
138
+ * - {{path.to.field}} -> substitution
139
+ * - {{#each array}}body{{/each}} -> loops over arrays
140
+ * - {{.}} inside loops -> current item value (for primitive arrays)
141
+ * - {{field_name}} inside loops -> current item field
142
+ *
143
+ * For HTML output, section body fields ending in `.html` (e.g.,
144
+ * sections.executive_summary.html) trigger markdown-to-html conversion of
145
+ * the corresponding sections.executive_summary value.
146
+ */
147
+ function renderSimpleTemplate(template, data, htmlMode) {
148
+ // 1. Process {{#each array}}...{{/each}} blocks first.
149
+ let output = template.replace(/\{\{#each\s+([\w.]+)\}\}([\s\S]*?)\{\{\/each\}\}/g, (_match, path, body) => {
150
+ const array = readPath(data, path);
151
+ if (!Array.isArray(array))
152
+ return "";
153
+ return array.map((item) => renderEachItem(body, item, htmlMode)).join("");
154
+ });
155
+ // 2. Process simple {{path.to.field}} substitutions.
156
+ output = output.replace(/\{\{([\w.]+)\}\}/g, (_match, path) => {
157
+ return resolveSubstitution(path, data, htmlMode);
158
+ });
159
+ return output;
160
+ }
161
+ function renderEachItem(body, item, htmlMode) {
162
+ // Inside a loop: {{.}} is the item itself; {{field}} is item.field.
163
+ let out = body.replace(/\{\{\.\}\}/g, () => stringify(item));
164
+ out = out.replace(/\{\{([\w.]+)\}\}/g, (_match, path) => {
165
+ if (typeof item === "object" && item !== null) {
166
+ const value = readPath(item, path);
167
+ return formatValue(value, htmlMode);
168
+ }
169
+ return "";
170
+ });
171
+ return out;
172
+ }
173
+ function resolveSubstitution(path, data, htmlMode) {
174
+ // Handle the special section.X.html convention for HTML mode.
175
+ if (htmlMode && path.endsWith(".html")) {
176
+ const stripped = path.slice(0, -5);
177
+ const value = readPath(data, stripped);
178
+ if (typeof value === "string")
179
+ return markdownToHtml(value);
180
+ }
181
+ const value = readPath(data, path);
182
+ return formatValue(value, htmlMode);
183
+ }
184
+ function readPath(data, path) {
185
+ if (data === null || data === undefined)
186
+ return undefined;
187
+ const parts = path.split(".");
188
+ let current = data;
189
+ for (const part of parts) {
190
+ if (current === null || current === undefined)
191
+ return undefined;
192
+ if (typeof current !== "object")
193
+ return undefined;
194
+ current = current[part];
195
+ }
196
+ return current;
197
+ }
198
+ function formatValue(value, htmlMode) {
199
+ if (value === null || value === undefined)
200
+ return "";
201
+ if (Array.isArray(value))
202
+ return value.map((v) => stringify(v)).join(", ");
203
+ if (typeof value === "object")
204
+ return JSON.stringify(value);
205
+ const text = String(value);
206
+ return htmlMode ? escapeHtml(text) : text;
207
+ }
208
+ function stringify(value) {
209
+ if (value === null || value === undefined)
210
+ return "";
211
+ if (typeof value === "object")
212
+ return JSON.stringify(value);
213
+ return String(value);
214
+ }
215
+ function escapeHtml(s) {
216
+ return s
217
+ .replace(/&/g, "&amp;")
218
+ .replace(/</g, "&lt;")
219
+ .replace(/>/g, "&gt;")
220
+ .replace(/"/g, "&quot;")
221
+ .replace(/'/g, "&#39;");
222
+ }
223
+ /**
224
+ * Minimal markdown-to-html converter. Handles paragraphs, headings, bold,
225
+ * italic, links, and unordered lists. Sufficient for proposal section
226
+ * bodies that use the small markdown subset the upstream skill emits.
227
+ *
228
+ * For richer markdown support a full library (marked, markdown-it) can be
229
+ * added in a future runtime version. For v0.7.0 this avoids new deps.
230
+ */
231
+ function markdownToHtml(md) {
232
+ if (!md)
233
+ return "";
234
+ const lines = md.split(/\r?\n/);
235
+ const html = [];
236
+ let inList = false;
237
+ let paragraph = [];
238
+ const flushParagraph = () => {
239
+ if (paragraph.length > 0) {
240
+ html.push(`<p>${inlineMd(paragraph.join(" "))}</p>`);
241
+ paragraph = [];
242
+ }
243
+ };
244
+ const flushList = () => {
245
+ if (inList) {
246
+ html.push("</ul>");
247
+ inList = false;
248
+ }
249
+ };
250
+ for (const raw of lines) {
251
+ const line = raw.trim();
252
+ if (line === "") {
253
+ flushParagraph();
254
+ flushList();
255
+ continue;
256
+ }
257
+ const heading = /^(#{1,6})\s+(.*)$/.exec(line);
258
+ if (heading) {
259
+ flushParagraph();
260
+ flushList();
261
+ const level = heading[1].length;
262
+ html.push(`<h${level}>${inlineMd(heading[2])}</h${level}>`);
263
+ continue;
264
+ }
265
+ const listItem = /^[-*]\s+(.*)$/.exec(line);
266
+ if (listItem) {
267
+ flushParagraph();
268
+ if (!inList) {
269
+ html.push("<ul>");
270
+ inList = true;
271
+ }
272
+ html.push(`<li>${inlineMd(listItem[1])}</li>`);
273
+ continue;
274
+ }
275
+ paragraph.push(line);
276
+ }
277
+ flushParagraph();
278
+ flushList();
279
+ return html.join("\n");
280
+ }
281
+ function inlineMd(s) {
282
+ // Order matters: process links first, then bold, then italic.
283
+ let out = escapeHtml(s);
284
+ out = out.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2">$1</a>');
285
+ out = out.replace(/\*\*([^*]+)\*\*/g, "<strong>$1</strong>");
286
+ out = out.replace(/\*([^*]+)\*/g, "<em>$1</em>");
287
+ out = out.replace(/`([^`]+)`/g, "<code>$1</code>");
288
+ return out;
289
+ }
290
+ // ----- Helpers -----
291
+ function ensureOutputPath(outputDir, filename) {
292
+ const dir = resolve(outputDir, "mvk");
293
+ if (!existsSync(dir))
294
+ mkdirSync(dir, { recursive: true });
295
+ return join(dir, filename);
296
+ }
297
+ void dirname;
298
+ /** Builds a StructuredResult for a successful or failed format step execution. */
299
+ export function formatStepResult(selected, exec, backend, durationMs) {
300
+ const status = exec.ok ? "success" : "failed";
301
+ return {
302
+ step_id: selected.stepId,
303
+ status,
304
+ produced_at: new Date().toISOString(),
305
+ outputs: exec.outputs.map((o) => ({
306
+ type: selected.outputArtifactType,
307
+ path: o.path,
308
+ format: o.format,
309
+ })),
310
+ evaluations: exec.ok
311
+ ? [
312
+ {
313
+ rubric: "format-fidelity",
314
+ threshold: 9,
315
+ score: exec.outputs.filter((o) => o.ready).length > 0 ? 9 : 5,
316
+ passed: exec.outputs.filter((o) => o.ready).length > 0,
317
+ notes: `Adapter ${exec.adapter_id ?? "(unknown)"} produced ${exec.outputs.filter((o) => o.ready).length} ready output(s) and ${exec.outputs.filter((o) => !o.ready).length} deferred placeholder(s).`,
318
+ },
319
+ ]
320
+ : [],
321
+ cost: { wall_clock_seconds: durationMs / 1000 },
322
+ errors: exec.errors,
323
+ audit: {
324
+ capability: selected.capability,
325
+ backend,
326
+ },
327
+ };
328
+ }
329
+ //# sourceMappingURL=formatExecutor.js.map