@akanjs/cli 2.4.0 → 2.4.1-rc.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 (59) hide show
  1. package/agent.command-h4afc69n.js +26 -0
  2. package/application.command-4ctkfdan.js +165 -0
  3. package/applicationBuildRunner-esa1kj7v.js +284 -0
  4. package/applicationReleasePackager-brvth6rs.js +245 -0
  5. package/capacitorApp-y0h6cgft.js +58 -0
  6. package/cloud.command-rpztn4fh.js +94 -0
  7. package/commandManifest.json +1 -0
  8. package/context.command-nqbtak4f.js +82 -0
  9. package/dependencyScanner-m4x5maek.js +9 -0
  10. package/guideline.command-ya0dh44f.js +356 -0
  11. package/incrementalBuilder.proc.js +89 -17394
  12. package/index-1xdrsbry.js +1447 -0
  13. package/index-45aj5ry0.js +990 -0
  14. package/index-5vvwc0cz.js +559 -0
  15. package/index-61keag0s.js +40 -0
  16. package/index-6pz1j0zj.js +62 -0
  17. package/index-73pr2cmy.js +534 -0
  18. package/index-76rn3g2c.js +76 -0
  19. package/index-85msc0wg.js +161 -0
  20. package/index-8pkbzj26.js +840 -0
  21. package/index-8rc0bm04.js +514 -0
  22. package/index-9sp6fsc5.js +1884 -0
  23. package/index-a6sbyy0b.js +2769 -0
  24. package/index-b0brjbp3.js +83 -0
  25. package/index-fgc8r6dj.js +33 -0
  26. package/index-h6ca6qg0.js +2777 -0
  27. package/index-hdqztm58.js +758 -0
  28. package/index-hwzpw9c1.js +202 -0
  29. package/index-pmm9e2jf.js +120 -0
  30. package/index-qaq13qk3.js +80 -0
  31. package/index-qhtr07v8.js +1072 -0
  32. package/index-r24hmh0q.js +4 -0
  33. package/index-ss469dec.js +11 -0
  34. package/index-swf4bmbg.js +25 -0
  35. package/index-w7fyqjrw.js +462 -0
  36. package/index-wnp7hwq7.js +193 -0
  37. package/index-wq8jwx8z.js +224 -0
  38. package/index-x53a5nya.js +301 -0
  39. package/index-xmc2w32q.js +4359 -0
  40. package/index-y3hdhy4p.js +229 -0
  41. package/index.js +54 -23340
  42. package/library.command-r15zdqvp.js +33 -0
  43. package/localRegistry.command-5tcahs3f.js +178 -0
  44. package/module.command-qrj3kmyz.js +54 -0
  45. package/package.command-r8sq5kzp.js +43 -0
  46. package/package.json +2 -2
  47. package/page.command-c6xdx0xm.js +24 -0
  48. package/primitive.command-pv9ssmtf.js +62 -0
  49. package/quality.command-es67wvdp.js +809 -0
  50. package/repair.command-677675vw.js +67 -0
  51. package/routeSourceValidator-wbhmbwpj.js +132 -0
  52. package/scalar.command-kabkd6wd.js +35 -0
  53. package/templates/facetIndex/index.ts +1 -1
  54. package/typeChecker-kravn7ns.js +8 -0
  55. package/typecheck.proc.js +4 -194
  56. package/workflow.command-64r6cw0w.js +108 -0
  57. package/workspace.command-vrws0rgx.js +435 -0
  58. package/README.ko.md +0 -72
  59. package/README.md +0 -85
@@ -0,0 +1,2777 @@
1
+ // @bun
2
+ import {
3
+ AppExecutor,
4
+ LibExecutor
5
+ } from "./index-a6sbyy0b.js";
6
+
7
+ // pkgs/@akanjs/devkit/workflow/utils.ts
8
+ var jsonText = (value, { trailingNewline = true } = {}) => `${JSON.stringify(value, null, 2)}${trailingNewline ? `
9
+ ` : ""}`;
10
+ var workflowStatus = (diagnostics) => diagnostics.some((diagnostic) => diagnostic.severity === "error") ? "failed" : "passed";
11
+ var commandStatus = (commands) => commands.some((command) => command.status === "failed") ? "failed" : "passed";
12
+ var uniqueBy = (values, key) => {
13
+ const seen = new Set;
14
+ return values.filter((value) => {
15
+ const itemKey = key(value);
16
+ if (seen.has(itemKey))
17
+ return false;
18
+ seen.add(itemKey);
19
+ return true;
20
+ });
21
+ };
22
+ var compactDiagnostics = (diagnostics) => diagnostics.filter((diagnostic) => !!diagnostic);
23
+
24
+ // pkgs/@akanjs/devkit/workflow/primitive.ts
25
+ var createPrimitiveWriteReport = ({
26
+ command,
27
+ status,
28
+ changedFiles = [],
29
+ generatedFiles = [],
30
+ validationCommands = [],
31
+ diagnostics = [],
32
+ nextActions = []
33
+ }) => ({
34
+ schemaVersion: 1,
35
+ command,
36
+ status: status ?? (diagnostics.some((diagnostic) => diagnostic.severity === "error") ? "failed" : "passed"),
37
+ changedFiles,
38
+ generatedFiles,
39
+ validationCommands,
40
+ diagnostics,
41
+ nextActions
42
+ });
43
+ var renderPrimitiveWriteReport = (report) => [
44
+ `# Primitive Write: ${report.command}`,
45
+ "",
46
+ `- Status: ${report.status}`,
47
+ "",
48
+ "## Changed Files",
49
+ ...report.changedFiles.length ? report.changedFiles.map((file) => `- \`${file.action}\` ${file.path}: ${file.reason}`) : ["- none"],
50
+ "",
51
+ "## Generated Files",
52
+ ...report.generatedFiles.length ? report.generatedFiles.map((file) => `- \`${file.action}\` ${file.path}: ${file.reason}`) : ["- none"],
53
+ "",
54
+ "## Validation Commands",
55
+ ...report.validationCommands.length ? report.validationCommands.map((validation) => `- \`${validation.command}\`: ${validation.reason}`) : ["- none"],
56
+ "",
57
+ "## Diagnostics",
58
+ ...report.diagnostics.length ? report.diagnostics.map((diagnostic) => `- [${diagnostic.severity}] ${diagnostic.code}: ${diagnostic.message}`) : ["- none"],
59
+ "",
60
+ "## Next Actions",
61
+ ...report.nextActions.length ? report.nextActions.map((action) => `- \`${action.command}\`: ${action.reason}`) : ["- none"],
62
+ ""
63
+ ].join(`
64
+ `);
65
+ var renderPrimitiveReport = (report, format = "markdown") => format === "json" ? jsonText(report) : renderPrimitiveWriteReport(report);
66
+
67
+ // pkgs/@akanjs/devkit/workflow/artifacts.ts
68
+ var sourceChangeBlocked = (diagnostics) => diagnostics.some((diagnostic) => diagnostic.severity === "error" && (diagnostic.failureScope === "source-change" || !diagnostic.failureScope || diagnostic.failureScope === "unknown"));
69
+ var workflowPlanApproval = {
70
+ required: true,
71
+ meaning: "Review this read-only plan before apply_workflow mutates files.",
72
+ applyTool: "apply_workflow"
73
+ };
74
+ var inferNextActionCode = (action, diagnostics) => {
75
+ if (action.action)
76
+ return action.action;
77
+ if (sourceChangeBlocked(diagnostics) && action.command.startsWith("akan workflow explain"))
78
+ return "blocked";
79
+ if (action.command.startsWith("akan workflow repair"))
80
+ return "repair";
81
+ if (action.command.startsWith("akan workflow explain"))
82
+ return "manual-review";
83
+ if (action.command.startsWith("akan "))
84
+ return "validate";
85
+ return "answer";
86
+ };
87
+ var nextActionPriority = (action, diagnostics) => {
88
+ const priority = sourceChangeBlocked(diagnostics) ? { blocked: 0, repair: 1, "manual-review": 2, validate: 3, answer: 4 } : { "manual-review": 0, validate: 1, repair: 2, blocked: 3, answer: 4 };
89
+ return priority[action.action ?? "answer"];
90
+ };
91
+ var createWorkflowApplyReport = ({
92
+ workflow,
93
+ mode,
94
+ changedFiles = [],
95
+ generatedFiles = [],
96
+ appliedCommands = [],
97
+ recommendedValidationCommands,
98
+ commands = [],
99
+ diagnostics = [],
100
+ postApplyChecks = [],
101
+ recommendations = [],
102
+ nextActions = [],
103
+ plan
104
+ }) => {
105
+ const validationCommands = recommendedValidationCommands ?? commands;
106
+ const nextActionsWithIntent = nextActions.map((action) => ({
107
+ ...action,
108
+ action: inferNextActionCode(action, diagnostics)
109
+ }));
110
+ if (sourceChangeBlocked(diagnostics) && !nextActionsWithIntent.some((action) => action.action === "blocked")) {
111
+ nextActionsWithIntent.unshift({
112
+ command: `akan workflow explain ${workflow}`,
113
+ reason: "Review source-change blockers before running validation.",
114
+ action: "blocked"
115
+ });
116
+ }
117
+ const orderedNextActions = uniqueBy(nextActionsWithIntent, (action) => action.command).sort((left, right) => nextActionPriority(left, diagnostics) - nextActionPriority(right, diagnostics));
118
+ const sourceFilesChanged = uniqueBy(changedFiles, (file) => `${file.action}:${file.path}:${file.reason}`);
119
+ const generatedFilesSynced = uniqueBy(generatedFiles, (file) => `${file.action}:${file.path}:${file.reason}`);
120
+ return {
121
+ schemaVersion: 1,
122
+ workflow,
123
+ mode,
124
+ status: workflowStatus(diagnostics),
125
+ summary: {
126
+ sourceFilesChanged,
127
+ generatedFilesSynced
128
+ },
129
+ changedFiles: sourceFilesChanged,
130
+ generatedFiles: generatedFilesSynced,
131
+ appliedCommands: uniqueBy(appliedCommands, (command) => command.command),
132
+ recommendedValidationCommands: uniqueBy(validationCommands, (command) => command.command),
133
+ commands: uniqueBy(validationCommands, (command) => command.command),
134
+ diagnostics,
135
+ postApplyChecks,
136
+ recommendations: uniqueBy(recommendations, (recommendation) => `${recommendation.kind}:${recommendation.code}`),
137
+ nextActions: orderedNextActions.slice(0, 3),
138
+ plan
139
+ };
140
+ };
141
+ var resolveWorkflowCommand = (command, plan) => {
142
+ const target = typeof plan.inputs.app === "string" ? plan.inputs.app : "<app-or-lib>";
143
+ return command.replaceAll("<app-or-lib-or-pkg>", target).replaceAll("<app-or-lib>", target).replaceAll("<app-name>", target);
144
+ };
145
+ var workflowCommandsForPlan = (plan) => plan.validation.map((validation) => ({
146
+ command: resolveWorkflowCommand(validation.command, plan),
147
+ reason: validation.reason,
148
+ kind: validation.kind
149
+ }));
150
+ var workflowRunsDir = ".akan/workflows/runs";
151
+ var createWorkflowRunId = (prefix = "run") => `${prefix}-${new Date().toISOString().replace(/[-:.TZ]/g, "").slice(0, 14)}-${Math.random().toString(36).slice(2, 8)}`;
152
+ var getRunId = (artifact) => {
153
+ if ("runId" in artifact && artifact.runId)
154
+ return artifact.runId;
155
+ return createWorkflowRunId("mode" in artifact ? artifact.mode : artifact.kind);
156
+ };
157
+ var workflowRunArtifactPath = (runId) => `${workflowRunsDir}/${runId}.json`;
158
+ var withWorkflowRunMetadata = (artifact, runId, artifactPath) => {
159
+ if ("mode" in artifact && (artifact.mode === "apply" || artifact.mode === "dry-run")) {
160
+ return { ...artifact, runId, applyReportPath: artifactPath, validationTarget: artifactPath };
161
+ }
162
+ if ("kind" in artifact)
163
+ return { ...artifact, runId, repairReportPath: artifactPath };
164
+ return artifact;
165
+ };
166
+ var writeWorkflowRunArtifact = async (workspace, artifact) => {
167
+ const runId = getRunId(artifact);
168
+ const artifactPath = workflowRunArtifactPath(runId);
169
+ const artifactWithMetadata = withWorkflowRunMetadata(artifact, runId, artifactPath);
170
+ await workspace.writeFile(artifactPath, jsonText(artifactWithMetadata), { silent: true });
171
+ return { runId, path: artifactPath, artifact: artifactWithMetadata };
172
+ };
173
+ var workflowSyncDir = ".akan/workflows/sync";
174
+ var syncStateSlug = (target) => target.trim().replace(/[^a-zA-Z0-9]+/g, "-").replace(/^-+|-+$/g, "").toLowerCase();
175
+ var workflowSyncStatePath = (target) => `${workflowSyncDir}/${syncStateSlug(target) || "target"}.json`;
176
+ var generatedFilePathsForTarget = (targetRoot, reason = "Generated files were refreshed by sync.") => [
177
+ { path: `${targetRoot}/lib/cnst.ts`, action: "sync", reason },
178
+ { path: `${targetRoot}/lib/dict.ts`, action: "sync", reason },
179
+ { path: `${targetRoot}/lib/index.ts`, action: "sync", reason }
180
+ ];
181
+ var writeGeneratedSyncState = async (workspace, state) => {
182
+ const statePath = workflowSyncStatePath(state.target);
183
+ await workspace.writeFile(statePath, jsonText(state), { silent: true });
184
+ return statePath;
185
+ };
186
+ var readWorkflowRunArtifact = async (workspace, runId) => {
187
+ const artifactPath = workflowRunArtifactPath(runId);
188
+ if (!await workspace.exists(artifactPath))
189
+ throw new Error(`Workflow run artifact does not exist: ${artifactPath}`);
190
+ return await workspace.readJson(artifactPath);
191
+ };
192
+ var failedCommandScopes = (commands) => commands.filter((command) => command.status === "failed").map((command) => command.failureScope ?? "unknown");
193
+ var errorDiagnosticScopes = (diagnostics) => diagnostics.filter((diagnostic) => diagnostic.severity === "error").map((diagnostic) => diagnostic.failureScope ?? (diagnostic.scope === "baseline" ? "workspace-config" : diagnostic.scope === "workflow" ? "source-change" : "unknown"));
194
+ var hasScopeFailure = (scopes, scope, diagnostics = []) => scopes.includes(scope) || diagnostics.some((diagnostic) => diagnostic.severity === "error" && diagnostic.failureScope === scope);
195
+ var statusForScope = (commands, diagnostics, scopes, expectedScope) => {
196
+ const hasCommands = commands.length > 0 || diagnostics.length > 0;
197
+ if (!hasCommands)
198
+ return "unknown";
199
+ return hasScopeFailure(scopes, expectedScope, diagnostics) ? "failed" : "passed";
200
+ };
201
+ var statusForValidationKind = (commands, kind) => {
202
+ const matching = commands.filter((command) => command.kind === kind);
203
+ if (matching.length === 0)
204
+ return "unknown";
205
+ return matching.some((command) => command.status === "failed") ? "failed" : "passed";
206
+ };
207
+ var statusForCommands = (commands) => {
208
+ if (commands.length === 0)
209
+ return "unknown";
210
+ return commandStatus(commands) === "failed" ? "failed" : "passed";
211
+ };
212
+ var statusForDiagnostics = (diagnostics) => {
213
+ if (diagnostics.length === 0)
214
+ return "unknown";
215
+ return workflowStatus(diagnostics) === "failed" ? "failed" : "passed";
216
+ };
217
+ var workflowDiagnosticContextPaths = (diagnostics) => uniqueBy(diagnostics.flatMap((diagnostic) => diagnostic.context?.paths ?? []), (filePath) => filePath);
218
+ var createWorkflowBaselineSummary = (diagnostics, { detailsIncluded = true, knownBlockerCount = 0 } = {}) => {
219
+ const grouped = new Map;
220
+ let totalErrors = 0;
221
+ let totalWarnings = 0;
222
+ for (const diagnostic of diagnostics) {
223
+ if (diagnostic.severity === "error")
224
+ totalErrors += 1;
225
+ else
226
+ totalWarnings += 1;
227
+ const existing = grouped.get(diagnostic.code);
228
+ if (existing) {
229
+ existing.count += 1;
230
+ if (existing.severity !== diagnostic.severity)
231
+ existing.severity = "mixed";
232
+ } else {
233
+ grouped.set(diagnostic.code, {
234
+ code: diagnostic.code,
235
+ severity: diagnostic.severity,
236
+ count: 1,
237
+ sampleMessage: diagnostic.message
238
+ });
239
+ }
240
+ }
241
+ const contextPaths = workflowDiagnosticContextPaths(diagnostics);
242
+ return {
243
+ status: totalErrors > 0 ? "failed" : diagnostics.length > 0 ? "passed" : "unknown",
244
+ total: diagnostics.length,
245
+ totalErrors,
246
+ totalWarnings,
247
+ detailsIncluded,
248
+ knownBlockerCount,
249
+ byCode: [...grouped.values()],
250
+ ...contextPaths.length ? { contextPaths } : {}
251
+ };
252
+ };
253
+ var createKnownBlockers = (commands, diagnostics) => {
254
+ const commandBlockers = commands.filter((command) => command.status === "failed" && (command.failureScope === "workspace-config" || command.failureScope === "environment")).map((command) => ({
255
+ code: `workflow-validation-${command.failureScope}`,
256
+ message: `${command.failureScope === "environment" ? "Environment" : "Workspace configuration"} blocker: ${command.command}`,
257
+ failureScope: command.failureScope ?? "unknown",
258
+ command: command.command,
259
+ kind: command.kind,
260
+ count: 1
261
+ }));
262
+ const diagnosticBlockers = diagnostics.filter((diagnostic) => diagnostic.severity === "error" && (diagnostic.failureScope === "workspace-config" || diagnostic.failureScope === "environment" || diagnostic.scope === "baseline")).map((diagnostic) => ({
263
+ code: diagnostic.code,
264
+ message: diagnostic.message,
265
+ failureScope: diagnostic.failureScope ?? "workspace-config",
266
+ command: diagnostic.command,
267
+ kind: diagnostic.kind,
268
+ count: 1
269
+ }));
270
+ const grouped = new Map;
271
+ for (const blocker of [...commandBlockers, ...diagnosticBlockers]) {
272
+ const key = `${blocker.failureScope}:${blocker.code}:${blocker.command ?? ""}:${blocker.message}`;
273
+ const existing = grouped.get(key);
274
+ if (existing)
275
+ existing.count += blocker.count;
276
+ else
277
+ grouped.set(key, blocker);
278
+ }
279
+ return [...grouped.values()];
280
+ };
281
+ var createValidationStatuses = (commands, reportDiagnostics, baselineDiagnostics, workflowDiagnostics) => {
282
+ const diagnostics = [...reportDiagnostics, ...baselineDiagnostics, ...workflowDiagnostics];
283
+ const scopes = [...failedCommandScopes(commands), ...errorDiagnosticScopes(diagnostics)];
284
+ const sourceDiagnostics = [...reportDiagnostics, ...workflowDiagnostics].filter((diagnostic) => diagnostic.failureScope === "source-change" || diagnostic.scope === "workflow" || !diagnostic.failureScope && diagnostic.scope !== "baseline");
285
+ const sourceScopes = [...failedCommandScopes(commands), ...errorDiagnosticScopes(sourceDiagnostics)];
286
+ const sourceStatus = statusForScope(commands, sourceDiagnostics, sourceScopes, "source-change");
287
+ const validationCommandsStatus = statusForCommands(commands);
288
+ const baselineStatus = statusForDiagnostics(baselineDiagnostics);
289
+ const nonBaselineDiagnostics = [...reportDiagnostics, ...workflowDiagnostics];
290
+ const workspaceStatus = hasScopeFailure(scopes, "workspace-config", diagnostics) || hasScopeFailure(scopes, "environment", diagnostics) ? "failed" : commands.length || diagnostics.length ? "passed" : "unknown";
291
+ const overallStatus = hasScopeFailure(scopes, "source-change", diagnostics) ? "failed" : validationCommandsStatus === "passed" && baselineStatus === "failed" && workflowStatus(nonBaselineDiagnostics) !== "failed" ? "passed-with-baseline-blockers" : hasScopeFailure(scopes, "workspace-config", diagnostics) ? "blocked-by-workspace-config" : hasScopeFailure(scopes, "environment", diagnostics) ? "blocked-by-environment" : workflowStatus(diagnostics) === "failed" || commandStatus(commands) === "failed" ? "failed" : "passed";
292
+ return {
293
+ sourceStatus,
294
+ workspaceStatus,
295
+ validationCommandsStatus,
296
+ baselineStatus,
297
+ overallStatus,
298
+ summary: {
299
+ sourceChange: sourceStatus,
300
+ generatedSync: statusForValidationKind(commands, "sync"),
301
+ validationCommands: validationCommandsStatus,
302
+ baseline: baselineStatus,
303
+ workspaceConfig: statusForScope(commands, diagnostics, scopes, "workspace-config"),
304
+ environment: statusForScope(commands, diagnostics, scopes, "environment")
305
+ }
306
+ };
307
+ };
308
+ var createWorkflowValidationRunReport = async ({
309
+ runId = createWorkflowRunId("validation"),
310
+ workflow,
311
+ source,
312
+ plan,
313
+ commands,
314
+ execute,
315
+ diagnostics = [],
316
+ baselineDiagnostics = [],
317
+ workflowDiagnostics = [],
318
+ repairActions = []
319
+ }) => {
320
+ const results = [];
321
+ for (const command of commands) {
322
+ results.push(await execute(command));
323
+ }
324
+ const commandDiagnostics = results.flatMap((result) => result.status === "failed" ? [
325
+ {
326
+ severity: "error",
327
+ code: "workflow-validation-command-failed",
328
+ message: `Validation command failed: ${result.command}`,
329
+ command: result.command,
330
+ kind: result.kind,
331
+ failureScope: result.failureScope
332
+ }
333
+ ] : []);
334
+ const reportDiagnostics = [...diagnostics, ...commandDiagnostics];
335
+ const scopedDiagnostics = [...reportDiagnostics, ...baselineDiagnostics, ...workflowDiagnostics];
336
+ const knownBlockers = createKnownBlockers(results, scopedDiagnostics);
337
+ const statuses = createValidationStatuses(results, reportDiagnostics, baselineDiagnostics, workflowDiagnostics);
338
+ return {
339
+ schemaVersion: 1,
340
+ runId,
341
+ workflow,
342
+ mode: "validate",
343
+ source,
344
+ status: statuses.overallStatus === "passed" ? "passed" : "failed",
345
+ ...statuses,
346
+ knownBlockers,
347
+ commands: results,
348
+ diagnostics: reportDiagnostics,
349
+ baselineSummary: createWorkflowBaselineSummary(baselineDiagnostics, {
350
+ knownBlockerCount: knownBlockers.filter((blocker) => blocker.failureScope === "workspace-config").length
351
+ }),
352
+ baselineDiagnostics,
353
+ workflowDiagnostics,
354
+ repairActions: uniqueBy(repairActions, (action) => action.command),
355
+ nextActions: results.filter((result) => result.status === "failed").map((result) => ({ command: result.command, reason: "Re-run this validation command after repair." })),
356
+ plan
357
+ };
358
+ };
359
+ var createDryRunWorkflowApplyReport = (plan) => {
360
+ const changedFiles = plan.predictedChanges.flatMap((change) => {
361
+ if (change.action !== "create" && change.action !== "modify")
362
+ return [];
363
+ return [
364
+ {
365
+ path: change.target,
366
+ action: change.action,
367
+ reason: change.reason
368
+ }
369
+ ];
370
+ });
371
+ const generatedFiles = plan.predictedChanges.flatMap((change) => {
372
+ if (change.action !== "sync")
373
+ return [];
374
+ return [
375
+ {
376
+ path: change.target,
377
+ action: "sync",
378
+ reason: change.reason
379
+ }
380
+ ];
381
+ });
382
+ const diagnostics = [...plan.diagnostics];
383
+ return createWorkflowApplyReport({
384
+ workflow: plan.workflow,
385
+ mode: "dry-run",
386
+ changedFiles,
387
+ generatedFiles,
388
+ commands: workflowCommandsForPlan(plan),
389
+ diagnostics,
390
+ recommendations: plan.recommendations,
391
+ nextActions: workflowCommandsForPlan(plan),
392
+ plan
393
+ });
394
+ };
395
+ var createRepairReport = ({
396
+ command,
397
+ kind,
398
+ target = null,
399
+ diagnostics = [],
400
+ repairActions = [],
401
+ nextActions = [],
402
+ commands = [],
403
+ generatedFiles = [],
404
+ syncedAt
405
+ }) => ({
406
+ schemaVersion: 1,
407
+ command,
408
+ kind,
409
+ target,
410
+ status: workflowStatus(diagnostics) === "failed" || commandStatus(commands) === "failed" ? "failed" : "passed",
411
+ diagnostics,
412
+ repairActions: uniqueBy(repairActions, (action) => action.command),
413
+ nextActions: uniqueBy(nextActions, (action) => action.command),
414
+ commands,
415
+ generatedFiles,
416
+ ...syncedAt ? { syncedAt } : {}
417
+ });
418
+ // pkgs/@akanjs/devkit/workflow/executor.ts
419
+ import ts3 from "typescript";
420
+
421
+ // pkgs/@akanjs/devkit/workflow/moduleIndex.ts
422
+ import { access } from "fs/promises";
423
+ import path from "path";
424
+ import ts2 from "typescript";
425
+
426
+ // pkgs/@akanjs/devkit/workflow/source.ts
427
+ import ts from "typescript";
428
+ var getSysRoot = (sys) => `${sys.type}s/${sys.name}`;
429
+ var sourceFile = (sys, path, action, reason) => ({
430
+ path: `${getSysRoot(sys)}/${path}`,
431
+ action,
432
+ reason
433
+ });
434
+ var moduleComponentName = (moduleName) => moduleName.replace(/[-_]+/g, " ").replace(/(?:^|\s+)([a-zA-Z0-9])/g, (_, char) => char.toUpperCase()).replace(/\s+/g, "");
435
+ var moduleSourcePaths = (moduleName) => {
436
+ const componentName = moduleComponentName(moduleName);
437
+ return {
438
+ abstract: `lib/${moduleName}/${moduleName}.abstract.md`,
439
+ constant: `lib/${moduleName}/${moduleName}.constant.ts`,
440
+ dictionary: `lib/${moduleName}/${moduleName}.dictionary.ts`,
441
+ service: `lib/${moduleName}/${moduleName}.service.ts`,
442
+ signal: `lib/${moduleName}/${moduleName}.signal.ts`,
443
+ store: `lib/${moduleName}/${moduleName}.store.ts`,
444
+ template: `lib/${moduleName}/${componentName}.Template.tsx`,
445
+ unit: `lib/${moduleName}/${componentName}.Unit.tsx`,
446
+ util: `lib/${moduleName}/${componentName}.Util.tsx`,
447
+ view: `lib/${moduleName}/${componentName}.View.tsx`,
448
+ zone: `lib/${moduleName}/${componentName}.Zone.tsx`
449
+ };
450
+ };
451
+ var generatedFilesForSync = (sys, reason = "Generated files may change after sync.") => generatedFilePathsForTarget(getSysRoot(sys), reason);
452
+ var validationCommandsForTarget = (target) => [
453
+ { command: `akan sync ${target}`, reason: "Refresh generated Akan files from source conventions." },
454
+ { command: `akan lint ${target}`, reason: "Validate formatting, imports, and static lint rules." }
455
+ ];
456
+ var nextActionsForTarget = (target) => [
457
+ { command: `akan sync ${target}`, reason: "Refresh generated Akan files after source changes." },
458
+ { command: `akan lint ${target}`, reason: "Validate the target after generated files are refreshed." }
459
+ ];
460
+ var createPassedPrimitiveReport = ({
461
+ command,
462
+ changedFiles,
463
+ generatedFiles,
464
+ target,
465
+ nextActions
466
+ }) => createPrimitiveWriteReport({
467
+ command,
468
+ changedFiles,
469
+ generatedFiles: generatedFiles ?? [],
470
+ validationCommands: validationCommandsForTarget(target),
471
+ diagnostics: [],
472
+ nextActions: nextActions ?? nextActionsForTarget(target)
473
+ });
474
+ var scalarChangedFiles = (sys, scalarName, files) => Object.values(files).map((file) => sourceFile(sys, `lib/__scalar/${scalarName}/${file.filename}`, "create", "Scalar source file was created."));
475
+ var titleize = (value) => value.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[-_]+/g, " ").replace(/\b\w/g, (char) => char.toUpperCase());
476
+ var lowerlize = (value) => `${value.slice(0, 1).toLowerCase()}${value.slice(1)}`;
477
+ var koLabels = {
478
+ amount: "\uAE08\uC561",
479
+ budget: "\uC608\uC0B0",
480
+ category: "\uCE74\uD14C\uACE0\uB9AC",
481
+ content: "\uB0B4\uC6A9",
482
+ count: "\uAC1C\uC218",
483
+ createdAt: "\uC0DD\uC131\uC77C",
484
+ date: "\uB0A0\uC9DC",
485
+ description: "\uC124\uBA85",
486
+ due: "\uB9C8\uAC10\uC77C",
487
+ dueAt: "\uB9C8\uAC10\uC77C",
488
+ email: "\uC774\uBA54\uC77C",
489
+ enabled: "\uD65C\uC131\uD654",
490
+ endAt: "\uC885\uB8CC\uC77C",
491
+ id: "ID",
492
+ name: "\uC774\uB984",
493
+ owner: "\uB2F4\uB2F9\uC790",
494
+ priority: "\uC6B0\uC120\uC21C\uC704",
495
+ project: "\uD504\uB85C\uC81D\uD2B8",
496
+ rating: "\uD3C9\uC810",
497
+ startAt: "\uC2DC\uC791\uC77C",
498
+ status: "\uC0C1\uD0DC",
499
+ title: "\uC81C\uBAA9",
500
+ updatedAt: "\uC218\uC815\uC77C"
501
+ };
502
+ var splitFieldWords = (fieldName) => fieldName.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[-_]+/g, " ").split(/\s+/).map((word) => word.trim()).filter(Boolean);
503
+ var koLabelForField = (fieldName) => {
504
+ if (koLabels[fieldName])
505
+ return koLabels[fieldName];
506
+ const words = splitFieldWords(fieldName);
507
+ const translated = words.map((word) => koLabels[word] ?? koLabels[lowerlize(word)] ?? null);
508
+ return translated.every(Boolean) ? translated.join(" ") : null;
509
+ };
510
+ var bilingualLabelForField = (fieldName) => {
511
+ const en = titleize(fieldName);
512
+ return { en, ko: koLabelForField(fieldName) ?? en };
513
+ };
514
+ var bilingualDescriptionForField = (fieldName) => {
515
+ const label = bilingualLabelForField(fieldName);
516
+ return {
517
+ en: `Enter ${label.en.toLowerCase()}.`,
518
+ ko: `${label.ko} \uAC12\uC744 \uC785\uB825\uD569\uB2C8\uB2E4.`
519
+ };
520
+ };
521
+ var normalizeFieldType = (typeName) => {
522
+ const normalizedTypes = {
523
+ string: "String",
524
+ boolean: "Boolean",
525
+ date: "Date",
526
+ int: "Int",
527
+ integer: "Int",
528
+ float: "Float",
529
+ double: "Float",
530
+ decimal: "Float"
531
+ };
532
+ return normalizedTypes[typeName.toLowerCase()] ?? typeName;
533
+ };
534
+ var ensureBaseTypeImport = (content, typeName) => {
535
+ if (typeName !== "Int" && typeName !== "Float")
536
+ return content;
537
+ const source = sourceFileFor("constant.ts", content);
538
+ const baseImport = findNamedImport(source, "akanjs/base");
539
+ if (baseImport) {
540
+ if (baseImport.names.includes(typeName))
541
+ return content;
542
+ const nextNames = [...baseImport.names, typeName].sort();
543
+ return spliceText(content, baseImport.namedBindingsStart, baseImport.namedBindingsEnd, `{ ${nextNames.join(", ")} }`);
544
+ }
545
+ return `import { ${typeName} } from "akanjs/base";
546
+ ${content}`;
547
+ };
548
+ var numericDefault = (typeName, rawDefault) => {
549
+ if (typeof rawDefault === "number") {
550
+ if (!Number.isFinite(rawDefault))
551
+ return null;
552
+ if (typeName === "Int" && !Number.isInteger(rawDefault))
553
+ return null;
554
+ return String(rawDefault);
555
+ }
556
+ if (typeof rawDefault !== "string")
557
+ return null;
558
+ const trimmed = rawDefault.trim();
559
+ if (!trimmed || !Number.isFinite(Number(trimmed)))
560
+ return null;
561
+ if (typeName === "Int" && !/^-?\d+$/.test(trimmed))
562
+ return null;
563
+ return trimmed;
564
+ };
565
+ var booleanDefault = (rawDefault) => {
566
+ if (typeof rawDefault === "boolean")
567
+ return String(rawDefault);
568
+ if (typeof rawDefault !== "string")
569
+ return null;
570
+ const lowered = rawDefault.trim().toLowerCase();
571
+ return lowered === "true" || lowered === "false" ? lowered : null;
572
+ };
573
+ var dateDefault = (rawDefault) => {
574
+ if (typeof rawDefault === "number" && Number.isFinite(rawDefault))
575
+ return `new Date(${rawDefault})`;
576
+ if (typeof rawDefault !== "string")
577
+ return null;
578
+ const trimmed = rawDefault.trim();
579
+ if (!trimmed)
580
+ return null;
581
+ if (trimmed === "now")
582
+ return "new Date()";
583
+ if (!Number.isNaN(Date.parse(trimmed)))
584
+ return `new Date(${JSON.stringify(trimmed)})`;
585
+ return null;
586
+ };
587
+ var coerceFieldDefault = (typeName, defaultValue, options = {}) => {
588
+ const normalizedType = typeName.toLowerCase() === "enum" ? "enum" : normalizeFieldType(typeName);
589
+ if (defaultValue === undefined || defaultValue === null || defaultValue === "") {
590
+ return { expression: null, normalized: false, normalizedType };
591
+ }
592
+ if (normalizedType === "Int" || normalizedType === "Float") {
593
+ const expression = numericDefault(normalizedType, defaultValue);
594
+ if (expression !== null)
595
+ return { expression, normalized: typeof defaultValue === "string", normalizedType };
596
+ return {
597
+ expression: null,
598
+ normalized: false,
599
+ normalizedType,
600
+ diagnostic: {
601
+ severity: "error",
602
+ code: "primitive-default-value-invalid",
603
+ input: "default",
604
+ failureScope: "source-change",
605
+ message: `Default value for ${normalizedType} must be a numeric literal. Received: ${JSON.stringify(defaultValue)}.`
606
+ }
607
+ };
608
+ }
609
+ if (normalizedType === "Boolean") {
610
+ const expression = booleanDefault(defaultValue);
611
+ if (expression !== null)
612
+ return { expression, normalized: typeof defaultValue === "string", normalizedType };
613
+ return {
614
+ expression: null,
615
+ normalized: false,
616
+ normalizedType,
617
+ diagnostic: {
618
+ severity: "error",
619
+ code: "primitive-default-value-invalid",
620
+ input: "default",
621
+ failureScope: "source-change",
622
+ message: `Default value for Boolean must be true or false. Received: ${JSON.stringify(defaultValue)}.`
623
+ }
624
+ };
625
+ }
626
+ if (normalizedType === "Date") {
627
+ const expression = dateDefault(defaultValue);
628
+ if (expression !== null)
629
+ return { expression, normalized: true, normalizedType };
630
+ return {
631
+ expression: null,
632
+ normalized: false,
633
+ normalizedType,
634
+ diagnostic: {
635
+ severity: "error",
636
+ code: "primitive-default-value-invalid",
637
+ input: "default",
638
+ failureScope: "source-change",
639
+ message: `Default value for Date must be "now", a timestamp, or a parseable date string. Received: ${JSON.stringify(defaultValue)}.`
640
+ }
641
+ };
642
+ }
643
+ if (normalizedType === "enum") {
644
+ if (typeof defaultValue === "string" && options.enumValues?.includes(defaultValue)) {
645
+ return { expression: JSON.stringify(defaultValue), normalized: false, normalizedType };
646
+ }
647
+ return {
648
+ expression: null,
649
+ normalized: false,
650
+ normalizedType,
651
+ diagnostic: {
652
+ severity: "error",
653
+ code: "primitive-default-value-invalid",
654
+ input: "default",
655
+ failureScope: "source-change",
656
+ message: `Default value for enum must be one of: ${(options.enumValues ?? []).join(", ")}. Received: ${JSON.stringify(defaultValue)}.`
657
+ }
658
+ };
659
+ }
660
+ return {
661
+ expression: JSON.stringify(String(defaultValue)),
662
+ normalized: typeof defaultValue !== "string",
663
+ normalizedType
664
+ };
665
+ };
666
+ var fieldExpression = (typeName, defaultValue, options = {}) => {
667
+ const typeExpression = normalizeFieldType(typeName);
668
+ const defaultExpression = coerceFieldDefault(options.enumValues ? "enum" : typeExpression, defaultValue, options).expression;
669
+ const defaultOption = defaultExpression ? `, { default: ${defaultExpression} }` : "";
670
+ return `${options.builderName ?? "field"}(${typeExpression}${defaultOption})`;
671
+ };
672
+ var fieldOrderingPriority = [
673
+ "id",
674
+ "name",
675
+ "title",
676
+ "status",
677
+ "category",
678
+ "description",
679
+ "content",
680
+ "startAt",
681
+ "dueAt",
682
+ "endAt",
683
+ "createdAt",
684
+ "updatedAt"
685
+ ];
686
+ var sourceFileFor = (fileName, content, scriptKind = ts.ScriptKind.TS) => ts.createSourceFile(fileName, content, ts.ScriptTarget.Latest, true, scriptKind);
687
+ var hasParseDiagnostics = (source) => (source.parseDiagnostics ?? []).length > 0;
688
+ var spliceText = (content, start, end, replacement) => `${content.slice(0, start)}${replacement}${content.slice(end)}`;
689
+ var lineStartAt = (content, position) => content.lastIndexOf(`
690
+ `, Math.max(0, position - 1)) + 1;
691
+ var lineEndAt = (content, position) => {
692
+ const end = content.indexOf(`
693
+ `, position);
694
+ return end < 0 ? content.length : end + 1;
695
+ };
696
+ var lineIndentAt = (content, position) => /^[ \t]*/.exec(content.slice(lineStartAt(content, position)))?.[0] ?? "";
697
+ var nodeName = (node) => {
698
+ if (!node)
699
+ return null;
700
+ if (ts.isIdentifier(node) || ts.isStringLiteral(node) || ts.isNumericLiteral(node))
701
+ return node.text;
702
+ return null;
703
+ };
704
+ var propertyName = (node) => ts.isPropertyAssignment(node) || ts.isShorthandPropertyAssignment(node) || ts.isMethodDeclaration(node) ? nodeName(node.name) : null;
705
+ var expressionName = (expression) => {
706
+ if (ts.isIdentifier(expression))
707
+ return expression.text;
708
+ if (ts.isPropertyAccessExpression(expression))
709
+ return expression.name.text;
710
+ if (ts.isCallExpression(expression))
711
+ return expressionName(expression.expression);
712
+ if (ts.isAsExpression(expression))
713
+ return expressionName(expression.expression);
714
+ return null;
715
+ };
716
+ var firstObjectReturnedByArrow = (node) => {
717
+ if (!ts.isArrowFunction(node) && !ts.isFunctionExpression(node))
718
+ return null;
719
+ if (ts.isObjectLiteralExpression(node.body))
720
+ return node.body;
721
+ if (ts.isParenthesizedExpression(node.body) && ts.isObjectLiteralExpression(node.body.expression)) {
722
+ return node.body.expression;
723
+ }
724
+ if (!ts.isBlock(node.body))
725
+ return null;
726
+ for (const statement of node.body.statements) {
727
+ if (ts.isReturnStatement(statement) && statement.expression && ts.isObjectLiteralExpression(statement.expression)) {
728
+ return statement.expression;
729
+ }
730
+ }
731
+ return null;
732
+ };
733
+ var isViaCall = (expression) => ts.isCallExpression(expression) && expressionName(expression.expression) === "via";
734
+ var heritageCall = (node) => {
735
+ const heritage = node.heritageClauses?.flatMap((clause) => [...clause.types]) ?? [];
736
+ const expression = heritage.find((clause) => isViaCall(clause.expression))?.expression;
737
+ return expression && ts.isCallExpression(expression) ? expression : null;
738
+ };
739
+ var callExpressionName = (node) => ts.isPropertyAccessExpression(node.expression) ? node.expression.name.text : expressionName(node.expression);
740
+ var locatedObject = (source, objectLiteral) => ({
741
+ objectStart: objectLiteral.getStart(source),
742
+ objectEnd: objectLiteral.getEnd(),
743
+ fields: objectLiteral.properties.map((property) => {
744
+ const name = propertyName(property);
745
+ if (!name)
746
+ return null;
747
+ return {
748
+ name,
749
+ start: property.getStart(source),
750
+ fullStart: property.getFullStart(),
751
+ end: property.getEnd()
752
+ };
753
+ }).filter((field) => field !== null)
754
+ });
755
+ var findConstantInputObject = (source, className) => {
756
+ let locator = null;
757
+ const visit = (node) => {
758
+ if (locator)
759
+ return;
760
+ if (!ts.isClassDeclaration(node) || node.name?.text !== className) {
761
+ ts.forEachChild(node, visit);
762
+ return;
763
+ }
764
+ const viaCall = heritageCall(node);
765
+ const callback = viaCall?.arguments.find((arg) => ts.isArrowFunction(arg) || ts.isFunctionExpression(arg));
766
+ const objectLiteral = callback ? firstObjectReturnedByArrow(callback) : null;
767
+ if (objectLiteral)
768
+ locator = locatedObject(source, objectLiteral);
769
+ };
770
+ ts.forEachChild(source, visit);
771
+ return locator;
772
+ };
773
+ var chainMethodsForCall = (node) => {
774
+ if (ts.isAsExpression(node) || ts.isParenthesizedExpression(node))
775
+ return chainMethodsForCall(node.expression);
776
+ if (!ts.isCallExpression(node))
777
+ return [];
778
+ if (ts.isPropertyAccessExpression(node.expression)) {
779
+ return [...chainMethodsForCall(node.expression.expression), node.expression.name.text];
780
+ }
781
+ const name = expressionName(node.expression);
782
+ return name ? [name] : [];
783
+ };
784
+ var outermostFluentCall = (node) => {
785
+ let current = node;
786
+ while (ts.isPropertyAccessExpression(current.parent) && current.parent.expression === current && ts.isCallExpression(current.parent.parent) && current.parent.parent.expression === current.parent) {
787
+ current = current.parent.parent;
788
+ }
789
+ return current;
790
+ };
791
+ var protectedDictionaryChainOrder = ["model", "slice", "enum", "error", "translate"];
792
+ var dictionaryChainOrderValid = (chainMethods) => {
793
+ const protectedOrder = new Map(protectedDictionaryChainOrder.map((method, index) => [method, index]));
794
+ let lastOrder = -1;
795
+ for (const method of chainMethods) {
796
+ const order = protectedOrder.get(method);
797
+ if (order === undefined)
798
+ continue;
799
+ if (order < lastOrder)
800
+ return false;
801
+ lastOrder = order;
802
+ }
803
+ return true;
804
+ };
805
+ var findDictionaryModelObject = (source, moduleClassName) => {
806
+ let locator = null;
807
+ const visit = (node) => {
808
+ if (locator)
809
+ return;
810
+ if (!ts.isCallExpression(node) || callExpressionName(node) !== "model") {
811
+ ts.forEachChild(node, visit);
812
+ return;
813
+ }
814
+ const typeArgument = node.typeArguments?.[0];
815
+ if (!typeArgument || typeArgument.getText(source) !== moduleClassName) {
816
+ ts.forEachChild(node, visit);
817
+ return;
818
+ }
819
+ const callback = node.arguments.find((arg) => ts.isArrowFunction(arg) || ts.isFunctionExpression(arg));
820
+ const objectLiteral = callback ? firstObjectReturnedByArrow(callback) : null;
821
+ if (objectLiteral) {
822
+ locator = {
823
+ ...locatedObject(source, objectLiteral),
824
+ chainMethods: chainMethodsForCall(outermostFluentCall(node))
825
+ };
826
+ }
827
+ };
828
+ ts.forEachChild(source, visit);
829
+ return locator;
830
+ };
831
+ var findLightProjectionArray = (source, moduleClassName) => {
832
+ let locator = null;
833
+ const visit = (node) => {
834
+ if (locator)
835
+ return;
836
+ if (!ts.isClassDeclaration(node) || node.name?.text !== `Light${moduleClassName}`) {
837
+ ts.forEachChild(node, visit);
838
+ return;
839
+ }
840
+ const viaCall = heritageCall(node);
841
+ const projectionArg = viaCall?.arguments.find((arg) => {
842
+ const expression = ts.isAsExpression(arg) ? arg.expression : arg;
843
+ return ts.isArrayLiteralExpression(expression);
844
+ });
845
+ const arrayLiteral = projectionArg ? ts.isAsExpression(projectionArg) ? projectionArg.expression : projectionArg : null;
846
+ if (!projectionArg || !arrayLiteral || !ts.isArrayLiteralExpression(arrayLiteral))
847
+ return;
848
+ locator = {
849
+ projectionStart: projectionArg.getStart(source),
850
+ projectionEnd: projectionArg.getEnd(),
851
+ fields: arrayLiteral.elements.map((element) => ts.isStringLiteralLike(element) ? element.text : null).filter((field) => field !== null)
852
+ };
853
+ };
854
+ ts.forEachChild(source, visit);
855
+ return locator;
856
+ };
857
+ var findNamedImport = (source, moduleSpecifier) => {
858
+ for (const statement of source.statements) {
859
+ if (!ts.isImportDeclaration(statement) || !ts.isStringLiteral(statement.moduleSpecifier))
860
+ continue;
861
+ if (statement.moduleSpecifier.text !== moduleSpecifier)
862
+ continue;
863
+ const namedBindings = statement.importClause?.namedBindings;
864
+ if (!namedBindings || !ts.isNamedImports(namedBindings))
865
+ continue;
866
+ return {
867
+ names: namedBindings.elements.map((element) => element.name.text),
868
+ namedBindingsStart: namedBindings.getStart(source),
869
+ namedBindingsEnd: namedBindings.getEnd()
870
+ };
871
+ }
872
+ return null;
873
+ };
874
+ var fieldExpressionBuilder = (property) => {
875
+ if (!ts.isPropertyAssignment(property))
876
+ return null;
877
+ const initializer = ts.isAsExpression(property.initializer) ? property.initializer.expression : property.initializer;
878
+ if (!ts.isCallExpression(initializer))
879
+ return null;
880
+ return expressionName(initializer.expression);
881
+ };
882
+ var priorityOf = (fieldName) => {
883
+ const priority = fieldOrderingPriority.indexOf(fieldName);
884
+ return priority < 0 ? null : priority;
885
+ };
886
+ var insertionIndexForFieldOrder = (fieldNames, newFieldName) => {
887
+ const newPriority = priorityOf(newFieldName);
888
+ if (newPriority !== null) {
889
+ const greaterPriorityIndex = fieldNames.findIndex((name) => {
890
+ const existingPriority = priorityOf(name);
891
+ return existingPriority !== null && existingPriority > newPriority;
892
+ });
893
+ if (greaterPriorityIndex >= 0)
894
+ return greaterPriorityIndex;
895
+ const lastPriorityIndex = fieldNames.reduce((lastIndex, name, index) => {
896
+ const existingPriority = priorityOf(name);
897
+ return existingPriority !== null ? index : lastIndex;
898
+ }, -1);
899
+ return lastPriorityIndex + 1;
900
+ }
901
+ const lastNonPriorityIndex = fieldNames.reduce((lastIndex, name, index) => priorityOf(name) === null ? index : lastIndex, -1);
902
+ return lastNonPriorityIndex >= 0 ? lastNonPriorityIndex + 1 : fieldNames.length;
903
+ };
904
+ var insertOrderedFieldLine = (content, locator, fieldName, line, options) => {
905
+ if (locator.fields.some((field) => field.name === fieldName))
906
+ return content;
907
+ const insertIndex = insertionIndexForFieldOrder(locator.fields.map((field) => field.name), fieldName);
908
+ const formattedLine = line.trim();
909
+ if (locator.fields.length === 0) {
910
+ return spliceText(content, locator.objectStart, locator.objectEnd, `{
911
+ ${options.fieldIndent}${formattedLine}
912
+ ${options.closingIndent}}`);
913
+ }
914
+ const beforeField = locator.fields[insertIndex];
915
+ if (beforeField) {
916
+ const leadingComments = ts.getLeadingCommentRanges(content, beforeField.fullStart) ?? [];
917
+ const insertAt2 = lineStartAt(content, leadingComments[0]?.pos ?? beforeField.start);
918
+ const indent2 = lineIndentAt(content, beforeField.start) || options.fieldIndent;
919
+ return spliceText(content, insertAt2, insertAt2, `${indent2}${formattedLine}
920
+ `);
921
+ }
922
+ const afterField = locator.fields[locator.fields.length - 1];
923
+ const insertAt = lineEndAt(content, afterField.end);
924
+ const indent = lineIndentAt(content, afterField.start) || options.fieldIndent;
925
+ return spliceText(content, insertAt, insertAt, `${indent}${formattedLine}
926
+ `);
927
+ };
928
+ var viaBuilderParameterName = (content, className) => {
929
+ const source = sourceFileFor("constant.ts", content);
930
+ let builderName = null;
931
+ const visit = (node) => {
932
+ if (builderName !== null)
933
+ return;
934
+ if (!ts.isClassDeclaration(node) || node.name?.text !== className) {
935
+ ts.forEachChild(node, visit);
936
+ return;
937
+ }
938
+ const viaCall = heritageCall(node);
939
+ const callback = viaCall?.arguments.find((arg) => ts.isArrowFunction(arg) || ts.isFunctionExpression(arg));
940
+ if (callback && (ts.isArrowFunction(callback) || ts.isFunctionExpression(callback))) {
941
+ builderName = nodeName(callback.parameters[0]?.name);
942
+ }
943
+ };
944
+ ts.forEachChild(source, visit);
945
+ return builderName;
946
+ };
947
+ var inspectConstantStructure = (content, className, moduleClassName) => {
948
+ const source = sourceFileFor("constant.ts", content);
949
+ const inputObject = findConstantInputObject(source, className);
950
+ const lightProjection = findLightProjectionArray(source, moduleClassName);
951
+ const baseImport = findNamedImport(source, "akanjs/base");
952
+ const fields = [];
953
+ if (inputObject) {
954
+ const visit = (node) => {
955
+ if (!ts.isClassDeclaration(node) || node.name?.text !== className) {
956
+ ts.forEachChild(node, visit);
957
+ return;
958
+ }
959
+ const viaCall = heritageCall(node);
960
+ const callback = viaCall?.arguments.find((arg) => ts.isArrowFunction(arg) || ts.isFunctionExpression(arg));
961
+ const objectLiteral = callback ? firstObjectReturnedByArrow(callback) : null;
962
+ if (!objectLiteral)
963
+ return;
964
+ fields.push(...objectLiteral.properties.map((property) => {
965
+ const name = propertyName(property);
966
+ if (!name)
967
+ return null;
968
+ return { name, expressionBuilder: fieldExpressionBuilder(property) };
969
+ }).filter((field) => field !== null));
970
+ };
971
+ ts.forEachChild(source, visit);
972
+ }
973
+ return {
974
+ parseValid: !hasParseDiagnostics(source),
975
+ inputObjectFound: inputObject !== null,
976
+ builderName: viaBuilderParameterName(content, className),
977
+ fields,
978
+ lightProjectionFields: lightProjection?.fields ?? [],
979
+ baseImports: baseImport?.names ?? []
980
+ };
981
+ };
982
+ var inspectDictionaryStructure = (content, moduleClassName) => {
983
+ const source = sourceFileFor("dictionary.ts", content);
984
+ const modelObject = findDictionaryModelObject(source, moduleClassName);
985
+ return {
986
+ parseValid: !hasParseDiagnostics(source),
987
+ modelObjectFound: modelObject !== null,
988
+ chainOrderValid: modelObject ? dictionaryChainOrderValid(modelObject.chainMethods) : false,
989
+ chainMethods: modelObject?.chainMethods ?? [],
990
+ fields: modelObject?.fields.map((field) => field.name) ?? []
991
+ };
992
+ };
993
+ var insertIntoObject = (content, className, line) => {
994
+ const fieldName = /^([A-Za-z_$][\w$]*)\s*:/.exec(line.trim())?.[1];
995
+ if (!fieldName)
996
+ return null;
997
+ const source = sourceFileFor("constant.ts", content);
998
+ const locator = findConstantInputObject(source, className);
999
+ if (!locator)
1000
+ return null;
1001
+ return insertOrderedFieldLine(content, locator, fieldName, line, { fieldIndent: " ", closingIndent: "" });
1002
+ };
1003
+ var insertLightProjectionField = (content, moduleClassName, fieldName) => {
1004
+ const source = sourceFileFor("constant.ts", content);
1005
+ const locator = findLightProjectionArray(source, moduleClassName);
1006
+ if (!locator)
1007
+ return null;
1008
+ if (locator.fields.includes(fieldName))
1009
+ return content;
1010
+ const nextFields = [...locator.fields, fieldName];
1011
+ const nextArray = nextFields.length === 0 ? "[] as const" : `[
1012
+ ${nextFields.map((field) => ` ${JSON.stringify(field)},`).join(`
1013
+ `)}
1014
+ ] as const`;
1015
+ return spliceText(content, locator.projectionStart, locator.projectionEnd, nextArray);
1016
+ };
1017
+ var insertTemplateField = ({
1018
+ content,
1019
+ moduleName,
1020
+ moduleClassName,
1021
+ fieldName,
1022
+ component
1023
+ }) => {
1024
+ if (content.includes(`l("${moduleName}.${fieldName}")`) || content.includes(`.${fieldName}`))
1025
+ return content;
1026
+ const layoutEndIndex = content.indexOf(" </Layout.Template>");
1027
+ if (layoutEndIndex < 0)
1028
+ return null;
1029
+ const formName = `${moduleName}Form`;
1030
+ if (!content.includes(`const ${formName} = st.use.${moduleName}Form();`))
1031
+ return null;
1032
+ const fieldSetter = `st.do.set${moduleComponentName(fieldName)}On${moduleClassName}`;
1033
+ const fieldBlock = ` <${component}
1034
+ label={l("${moduleName}.${fieldName}")}
1035
+ desc={l("${moduleName}.${fieldName}.desc")}
1036
+ value={${formName}.${fieldName}}
1037
+ onChange={${fieldSetter}}
1038
+ />
1039
+ `;
1040
+ return `${content.slice(0, layoutEndIndex)}${fieldBlock}${content.slice(layoutEndIndex)}`;
1041
+ };
1042
+ var ensureEnumImport = (content) => {
1043
+ if (content.includes("enumOf"))
1044
+ return content;
1045
+ const baseImport = /import \{ ([^}]+) \} from "akanjs\/base";/.exec(content);
1046
+ if (baseImport) {
1047
+ const names = baseImport[1]?.split(",").map((name) => name.trim()) ?? [];
1048
+ return content.replace(baseImport[0], `import { ${[...names, "enumOf"].sort().join(", ")} } from "akanjs/base";`);
1049
+ }
1050
+ return `import { enumOf } from "akanjs/base";
1051
+ ${content}`;
1052
+ };
1053
+ var insertEnumClass = (content, enumClassName, enumName, values) => {
1054
+ if (content.includes(`export class ${enumClassName} extends enumOf`))
1055
+ return content;
1056
+ const enumClass = `export class ${enumClassName} extends enumOf("${enumName}", [
1057
+ ${values.map((value) => ` ${JSON.stringify(value)},`).join(`
1058
+ `)}
1059
+ ] as const) {}
1060
+
1061
+ `;
1062
+ const firstClassIndex = content.indexOf("export class ");
1063
+ if (firstClassIndex < 0)
1064
+ return `${content}
1065
+ ${enumClass}`;
1066
+ return `${content.slice(0, firstClassIndex)}${enumClass}${content.slice(firstClassIndex)}`;
1067
+ };
1068
+ var dictionaryModelFieldLine = (fieldName) => {
1069
+ const label = bilingualLabelForField(fieldName);
1070
+ const desc = bilingualDescriptionForField(fieldName);
1071
+ return `${fieldName}: t([${JSON.stringify(label.en)}, ${JSON.stringify(label.ko)}]).desc([${JSON.stringify(desc.en)}, ${JSON.stringify(desc.ko)}]),`;
1072
+ };
1073
+ var insertDictionaryModelField = (content, moduleClassName, fieldName) => {
1074
+ const source = sourceFileFor("dictionary.ts", content);
1075
+ const locator = findDictionaryModelObject(source, moduleClassName);
1076
+ if (!locator)
1077
+ return null;
1078
+ return insertOrderedFieldLine(content, locator, fieldName, dictionaryModelFieldLine(fieldName), {
1079
+ fieldIndent: " ",
1080
+ closingIndent: " "
1081
+ });
1082
+ };
1083
+ var hasConstantInputField = (content, className, fieldName) => {
1084
+ const source = sourceFileFor("constant.ts", content);
1085
+ if (hasParseDiagnostics(source))
1086
+ return false;
1087
+ return findConstantInputObject(source, className)?.fields.some((field) => field.name === fieldName) ?? false;
1088
+ };
1089
+ var hasDictionaryModelField = (content, moduleClassName, fieldName) => {
1090
+ const source = sourceFileFor("dictionary.ts", content);
1091
+ if (hasParseDiagnostics(source))
1092
+ return false;
1093
+ return findDictionaryModelObject(source, moduleClassName)?.fields.some((field) => field.name === fieldName) ?? false;
1094
+ };
1095
+ var ensureConstantTypeImport = (content, constantPath, typeName) => {
1096
+ if (new RegExp(`import type \\{[^}]*\\b${typeName}\\b[^}]*\\} from "${constantPath}";`).test(content))
1097
+ return content;
1098
+ const importPattern = new RegExp(`import type \\{ ([^}]+) \\} from "${constantPath}";`);
1099
+ const existingImport = content.match(importPattern);
1100
+ if (existingImport !== null) {
1101
+ const names = existingImport[1]?.split(",").map((name) => name.trim()) ?? [];
1102
+ return content.replace(existingImport[0], `import type { ${[...names, typeName].sort().join(", ")} } from "${constantPath}";`);
1103
+ }
1104
+ return `import type { ${typeName} } from "${constantPath}";
1105
+ ${content}`;
1106
+ };
1107
+ var insertDictionaryEnum = (content, enumClassName, enumName, values) => {
1108
+ if (content.includes(`.enum<${enumClassName}>("${enumName}"`))
1109
+ return content;
1110
+ const enumBlock = ` .enum<${enumClassName}>("${enumName}", (t) => ({
1111
+ ${values.map((value) => ` ${value}: t([${JSON.stringify(titleize(value))}, ${JSON.stringify(titleize(value))}]),`).join(`
1112
+ `)}
1113
+ }))
1114
+ `;
1115
+ const chainEndIndex = content.lastIndexOf(";");
1116
+ const insertBeforeIndex = [content.indexOf(".error("), content.indexOf(".translate("), chainEndIndex].filter((index) => index >= 0).sort((a, b) => a - b)[0];
1117
+ if (insertBeforeIndex === undefined)
1118
+ return null;
1119
+ return `${content.slice(0, insertBeforeIndex)}${enumBlock}${content.slice(insertBeforeIndex)}`;
1120
+ };
1121
+ var parseValues = (value) => value?.split(",").map((item) => item.trim()).filter(Boolean) ?? [];
1122
+ var hasSourceParseErrors = (content, fileName = "source.ts") => hasParseDiagnostics(sourceFileFor(fileName, content));
1123
+ var findClassDeclaration = (source, className) => {
1124
+ let found = null;
1125
+ const visit = (node) => {
1126
+ if (found)
1127
+ return;
1128
+ if (ts.isClassDeclaration(node) && node.name?.text === className) {
1129
+ found = node;
1130
+ return;
1131
+ }
1132
+ ts.forEachChild(node, visit);
1133
+ };
1134
+ ts.forEachChild(source, visit);
1135
+ return found;
1136
+ };
1137
+ var firstHeritageCall = (node) => {
1138
+ const expression = (node.heritageClauses?.flatMap((clause) => [...clause.types]) ?? [])[0]?.expression;
1139
+ return expression && ts.isCallExpression(expression) ? expression : null;
1140
+ };
1141
+ var factoryArrowOf = (call) => {
1142
+ const arg = call.arguments.find((argument) => ts.isArrowFunction(argument) || ts.isFunctionExpression(argument));
1143
+ return arg && (ts.isArrowFunction(arg) || ts.isFunctionExpression(arg)) ? arg : null;
1144
+ };
1145
+ var hasClassMethod = (content, className, methodName) => {
1146
+ const node = findClassDeclaration(sourceFileFor("service.ts", content), className);
1147
+ return Boolean(node?.members.some((member) => ts.isMethodDeclaration(member) && nodeName(member.name) === methodName));
1148
+ };
1149
+ var insertClassMethod = (content, className, methodBlock) => {
1150
+ const source = sourceFileFor("service.ts", content);
1151
+ const node = findClassDeclaration(source, className);
1152
+ if (!node)
1153
+ return null;
1154
+ const closeBrace = node.getEnd() - 1;
1155
+ if (content[closeBrace] !== "}")
1156
+ return null;
1157
+ const lead = content.slice(0, closeBrace).endsWith(`
1158
+ `) ? "" : `
1159
+ `;
1160
+ return spliceText(content, closeBrace, closeBrace, `${lead}${methodBlock}
1161
+ `);
1162
+ };
1163
+ var arrowParamInnerRegion = (content, source, arrow) => {
1164
+ if (arrow.parameters.length > 0) {
1165
+ return {
1166
+ start: arrow.parameters[0].getStart(source),
1167
+ end: arrow.parameters[arrow.parameters.length - 1].getEnd()
1168
+ };
1169
+ }
1170
+ const open = content.indexOf("(", arrow.getStart(source));
1171
+ if (open < 0)
1172
+ return null;
1173
+ const close = content.indexOf(")", open);
1174
+ if (close < 0)
1175
+ return null;
1176
+ return { start: open + 1, end: close };
1177
+ };
1178
+ var factoryParamEdit = (content, source, arrow, plan) => {
1179
+ if (arrow.parameters.length > 1)
1180
+ return null;
1181
+ const region = arrowParamInnerRegion(content, source, arrow);
1182
+ if (!region)
1183
+ return null;
1184
+ if (arrow.parameters.length === 0) {
1185
+ return { ...region, text: plan.mode === "destructure" ? `{ ${plan.name} }` : plan.name };
1186
+ }
1187
+ const param = arrow.parameters[0];
1188
+ if (plan.mode === "positional")
1189
+ return nodeName(param.name) === plan.name ? "unchanged" : null;
1190
+ if (!ts.isObjectBindingPattern(param.name))
1191
+ return null;
1192
+ const names = param.name.elements.map((element) => ts.isIdentifier(element.name) ? element.name.text : null);
1193
+ if (names.some((name) => name === null))
1194
+ return null;
1195
+ if (names.includes(plan.name))
1196
+ return "unchanged";
1197
+ return {
1198
+ start: param.getStart(source),
1199
+ end: param.getEnd(),
1200
+ text: `{ ${[...names, plan.name].join(", ")} }`
1201
+ };
1202
+ };
1203
+ var factoryObjectOf = (source, className) => {
1204
+ const node = findClassDeclaration(source, className);
1205
+ const call = node ? firstHeritageCall(node) : null;
1206
+ const arrow = call ? factoryArrowOf(call) : null;
1207
+ const object = arrow ? firstObjectReturnedByArrow(arrow) : null;
1208
+ return arrow && object ? { arrow, object } : null;
1209
+ };
1210
+ var hasSignalFactoryEntry = (content, className, entryName) => {
1211
+ const located = factoryObjectOf(sourceFileFor("signal.ts", content), className);
1212
+ return Boolean(located?.object.properties.some((property) => propertyName(property) === entryName));
1213
+ };
1214
+ var insertSignalFactoryEntry = (content, className, entryName, entryLine, param) => {
1215
+ const source = sourceFileFor("signal.ts", content);
1216
+ const located = factoryObjectOf(source, className);
1217
+ if (!located)
1218
+ return null;
1219
+ const locator = locatedObject(source, located.object);
1220
+ if (locator.fields.some((field) => field.name === entryName))
1221
+ return content;
1222
+ const paramEdit = factoryParamEdit(content, source, located.arrow, param);
1223
+ if (paramEdit === null)
1224
+ return null;
1225
+ const withEntry = insertOrderedFieldLine(content, locator, entryName, entryLine, {
1226
+ fieldIndent: " ",
1227
+ closingIndent: ""
1228
+ });
1229
+ if (withEntry === content)
1230
+ return null;
1231
+ return paramEdit === "unchanged" ? withEntry : spliceText(withEntry, paramEdit.start, paramEdit.end, paramEdit.text);
1232
+ };
1233
+
1234
+ // pkgs/@akanjs/devkit/workflow/moduleIndex.ts
1235
+ var indexFileKinds = [
1236
+ "abstract",
1237
+ "constant",
1238
+ "dictionary",
1239
+ "service",
1240
+ "signal",
1241
+ "store",
1242
+ "template",
1243
+ "unit",
1244
+ "util",
1245
+ "view",
1246
+ "zone"
1247
+ ];
1248
+ var sourceText = async (filePath) => {
1249
+ try {
1250
+ return await Bun.file(filePath).text();
1251
+ } catch {
1252
+ return null;
1253
+ }
1254
+ };
1255
+ var fileExists = async (filePath) => {
1256
+ try {
1257
+ await access(filePath);
1258
+ return true;
1259
+ } catch {
1260
+ return false;
1261
+ }
1262
+ };
1263
+ var sourceFileFor2 = (filePath, content) => ts2.createSourceFile(filePath, content, ts2.ScriptTarget.Latest, true, ts2.ScriptKind.TS);
1264
+ var parseDiagnosticsFor = (source, filePath) => {
1265
+ const parseDiagnostics = source.parseDiagnostics ?? [];
1266
+ return parseDiagnostics.map((diagnostic) => ({
1267
+ severity: "error",
1268
+ code: "module-index-typescript-parse-error",
1269
+ message: `TypeScript parse diagnostic TS${diagnostic.code} in ${filePath}: ${ts2.flattenDiagnosticMessageText(diagnostic.messageText, `
1270
+ `)}`,
1271
+ context: { target: filePath, paths: [filePath] }
1272
+ }));
1273
+ };
1274
+ var spanFor = (source, file, node) => {
1275
+ const startOffset = node.getStart(source);
1276
+ const endOffset = node.getEnd();
1277
+ const start = source.getLineAndCharacterOfPosition(startOffset);
1278
+ const end = source.getLineAndCharacterOfPosition(endOffset);
1279
+ return {
1280
+ file,
1281
+ startLine: start.line + 1,
1282
+ endLine: end.line + 1,
1283
+ startOffset,
1284
+ endOffset
1285
+ };
1286
+ };
1287
+ var nodeName2 = (node) => {
1288
+ if (!node)
1289
+ return null;
1290
+ if (ts2.isIdentifier(node) || ts2.isStringLiteral(node) || ts2.isNumericLiteral(node))
1291
+ return node.text;
1292
+ return null;
1293
+ };
1294
+ var propertyName2 = (node) => ts2.isPropertyAssignment(node) || ts2.isShorthandPropertyAssignment(node) || ts2.isMethodDeclaration(node) ? nodeName2(node.name) : null;
1295
+ var expressionName2 = (expression) => {
1296
+ if (ts2.isIdentifier(expression))
1297
+ return expression.text;
1298
+ if (ts2.isPropertyAccessExpression(expression))
1299
+ return expression.name.text;
1300
+ if (ts2.isCallExpression(expression))
1301
+ return expressionName2(expression.expression);
1302
+ if (ts2.isAsExpression(expression))
1303
+ return expressionName2(expression.expression);
1304
+ return null;
1305
+ };
1306
+ var expressionSummary = (expression) => {
1307
+ if (ts2.isAsExpression(expression))
1308
+ return expressionSummary(expression.expression);
1309
+ if (ts2.isIdentifier(expression) || ts2.isPropertyAccessExpression(expression))
1310
+ return expressionName2(expression) ?? "expression";
1311
+ if (ts2.isArrayLiteralExpression(expression))
1312
+ return "array-literal";
1313
+ if (ts2.isObjectLiteralExpression(expression))
1314
+ return "object-literal";
1315
+ if (ts2.isStringLiteralLike(expression))
1316
+ return "string-literal";
1317
+ if (ts2.isNumericLiteral(expression))
1318
+ return "numeric-literal";
1319
+ if (expression.kind === ts2.SyntaxKind.TrueKeyword || expression.kind === ts2.SyntaxKind.FalseKeyword) {
1320
+ return "boolean-literal";
1321
+ }
1322
+ if (ts2.isCallExpression(expression)) {
1323
+ const callee = expressionName2(expression.expression);
1324
+ return callee ? `${callee}(...)` : "call-expression";
1325
+ }
1326
+ return ts2.SyntaxKind[expression.kind] ?? "expression";
1327
+ };
1328
+ var typeSummaryForInitializer = (initializer) => {
1329
+ if (!initializer)
1330
+ return;
1331
+ const expression = ts2.isAsExpression(initializer) ? initializer.expression : initializer;
1332
+ if (!ts2.isCallExpression(expression))
1333
+ return expressionSummary(expression);
1334
+ const callee = expressionName2(expression.expression);
1335
+ const firstArg = expression.arguments[0];
1336
+ const argSummary = firstArg ? expressionSummary(firstArg) : "";
1337
+ return [callee, argSummary ? `(${argSummary})` : ""].filter(Boolean).join("");
1338
+ };
1339
+ var fieldsFromObject = (source, file, objectLiteral, kind) => objectLiteral.properties.map((property, index) => {
1340
+ const name = propertyName2(property);
1341
+ if (!name)
1342
+ return null;
1343
+ const initializer = ts2.isPropertyAssignment(property) ? property.initializer : undefined;
1344
+ return {
1345
+ name,
1346
+ kind,
1347
+ order: index,
1348
+ ...initializer ? { typeSummary: typeSummaryForInitializer(initializer) } : {},
1349
+ sourceSpan: spanFor(source, file, property)
1350
+ };
1351
+ }).filter((field) => field !== null);
1352
+ var firstObjectReturnedByArrow2 = (node) => {
1353
+ if (!ts2.isArrowFunction(node) && !ts2.isFunctionExpression(node))
1354
+ return null;
1355
+ if (ts2.isObjectLiteralExpression(node.body))
1356
+ return node.body;
1357
+ if (ts2.isParenthesizedExpression(node.body) && ts2.isObjectLiteralExpression(node.body.expression)) {
1358
+ return node.body.expression;
1359
+ }
1360
+ if (!ts2.isBlock(node.body))
1361
+ return null;
1362
+ for (const statement of node.body.statements) {
1363
+ if (ts2.isReturnStatement(statement) && statement.expression && ts2.isObjectLiteralExpression(statement.expression)) {
1364
+ return statement.expression;
1365
+ }
1366
+ }
1367
+ return null;
1368
+ };
1369
+ var isViaCall2 = (expression) => ts2.isCallExpression(expression) && expressionName2(expression.expression) === "via";
1370
+ var heritageCall2 = (node) => {
1371
+ const heritage = node.heritageClauses?.flatMap((clause) => [...clause.types]) ?? [];
1372
+ const expression = heritage.find((clause) => isViaCall2(clause.expression))?.expression;
1373
+ return expression && ts2.isCallExpression(expression) ? expression : null;
1374
+ };
1375
+ var parseConstantIndex = (filePath, content, moduleClassName) => {
1376
+ const source = sourceFileFor2(filePath, content);
1377
+ const diagnostics = parseDiagnosticsFor(source, filePath);
1378
+ const inputClassName = `${moduleClassName}Input`;
1379
+ let inputClass = null;
1380
+ let inputViaFound = false;
1381
+ let inputBuilderFound = false;
1382
+ let inputBuilderObjectFound = false;
1383
+ let builderName = null;
1384
+ let fields = [];
1385
+ let lightProjection;
1386
+ const visit = (node) => {
1387
+ if (!ts2.isClassDeclaration(node) || !node.name) {
1388
+ ts2.forEachChild(node, visit);
1389
+ return;
1390
+ }
1391
+ const className = node.name.text;
1392
+ const viaCall = heritageCall2(node);
1393
+ if (className === inputClassName) {
1394
+ inputClass = node;
1395
+ if (!viaCall)
1396
+ return;
1397
+ inputViaFound = true;
1398
+ const callback = viaCall.arguments.find((arg) => ts2.isArrowFunction(arg) || ts2.isFunctionExpression(arg));
1399
+ if (callback && (ts2.isArrowFunction(callback) || ts2.isFunctionExpression(callback))) {
1400
+ inputBuilderFound = true;
1401
+ builderName = nodeName2(callback.parameters[0]?.name) ?? null;
1402
+ const objectLiteral = firstObjectReturnedByArrow2(callback);
1403
+ if (objectLiteral) {
1404
+ inputBuilderObjectFound = true;
1405
+ fields = fieldsFromObject(source, filePath, objectLiteral, "constant");
1406
+ }
1407
+ }
1408
+ }
1409
+ if (!viaCall)
1410
+ return;
1411
+ if (className === `Light${moduleClassName}`) {
1412
+ const projectionArg = viaCall.arguments.find((arg) => {
1413
+ const expression = ts2.isAsExpression(arg) ? arg.expression : arg;
1414
+ return ts2.isArrayLiteralExpression(expression);
1415
+ });
1416
+ const arrayLiteral = projectionArg ? ts2.isAsExpression(projectionArg) ? projectionArg.expression : projectionArg : null;
1417
+ if (arrayLiteral && ts2.isArrayLiteralExpression(arrayLiteral)) {
1418
+ lightProjection = {
1419
+ className,
1420
+ sourceSpan: spanFor(source, filePath, arrayLiteral),
1421
+ fields: arrayLiteral.elements.map((element, order) => ts2.isStringLiteralLike(element) ? {
1422
+ name: element.text,
1423
+ kind: "lightProjection",
1424
+ order,
1425
+ typeSummary: "string-literal",
1426
+ sourceSpan: spanFor(source, filePath, element)
1427
+ } : null).filter((field) => field !== null)
1428
+ };
1429
+ }
1430
+ }
1431
+ };
1432
+ ts2.forEachChild(source, visit);
1433
+ if (!inputClass) {
1434
+ diagnostics.push({
1435
+ severity: "error",
1436
+ code: "module-index-constant-input-missing",
1437
+ message: `Constant input class ${inputClassName} was not found in ${filePath}.`,
1438
+ context: { target: inputClassName, paths: [filePath] }
1439
+ });
1440
+ } else if (!inputViaFound) {
1441
+ diagnostics.push({
1442
+ severity: "error",
1443
+ code: "module-index-constant-via-missing",
1444
+ message: `Constant input class ${inputClassName} does not extend via(...) in ${filePath}.`,
1445
+ context: { target: inputClassName, paths: [filePath] }
1446
+ });
1447
+ } else if (!inputBuilderFound) {
1448
+ diagnostics.push({
1449
+ severity: "error",
1450
+ code: "module-index-constant-builder-missing",
1451
+ message: `Constant input class ${inputClassName} does not provide a via(...) builder callback in ${filePath}.`,
1452
+ context: { target: inputClassName, paths: [filePath] }
1453
+ });
1454
+ } else if (!inputBuilderObjectFound) {
1455
+ diagnostics.push({
1456
+ severity: "error",
1457
+ code: "module-index-constant-builder-object-missing",
1458
+ message: `Constant input class ${inputClassName} builder does not return an object literal in ${filePath}.`,
1459
+ context: { target: inputClassName, paths: [filePath] }
1460
+ });
1461
+ }
1462
+ return {
1463
+ index: {
1464
+ path: filePath,
1465
+ inputClassName,
1466
+ builderName,
1467
+ fields,
1468
+ ...lightProjection ? { lightProjection } : {},
1469
+ ...inputClass ? { sourceSpan: spanFor(source, filePath, inputClass) } : {}
1470
+ },
1471
+ diagnostics
1472
+ };
1473
+ };
1474
+ var callExpressionName2 = (node) => ts2.isPropertyAccessExpression(node.expression) ? node.expression.name.text : expressionName2(node.expression);
1475
+ var parseDictionaryIndex = (filePath, content, moduleClassName) => {
1476
+ const source = sourceFileFor2(filePath, content);
1477
+ const diagnostics = parseDiagnosticsFor(source, filePath);
1478
+ let index;
1479
+ let modelFound = false;
1480
+ const visit = (node) => {
1481
+ if (modelFound || !ts2.isCallExpression(node)) {
1482
+ ts2.forEachChild(node, visit);
1483
+ return;
1484
+ }
1485
+ if (callExpressionName2(node) !== "model") {
1486
+ ts2.forEachChild(node, visit);
1487
+ return;
1488
+ }
1489
+ const typeArgument = node.typeArguments?.[0];
1490
+ if (!typeArgument || typeArgument.getText(source) !== moduleClassName) {
1491
+ ts2.forEachChild(node, visit);
1492
+ return;
1493
+ }
1494
+ modelFound = true;
1495
+ const callback = node.arguments.find((arg) => ts2.isArrowFunction(arg) || ts2.isFunctionExpression(arg));
1496
+ if (!callback || !ts2.isArrowFunction(callback) && !ts2.isFunctionExpression(callback)) {
1497
+ diagnostics.push({
1498
+ severity: "error",
1499
+ code: "module-index-dictionary-builder-missing",
1500
+ message: `Dictionary .model<${moduleClassName}> branch does not provide a builder callback in ${filePath}.`,
1501
+ context: { target: moduleClassName, paths: [filePath] }
1502
+ });
1503
+ return;
1504
+ }
1505
+ const objectLiteral = firstObjectReturnedByArrow2(callback);
1506
+ if (!objectLiteral) {
1507
+ diagnostics.push({
1508
+ severity: "error",
1509
+ code: "module-index-dictionary-builder-object-missing",
1510
+ message: `Dictionary .model<${moduleClassName}> builder does not return an object literal in ${filePath}.`,
1511
+ context: { target: moduleClassName, paths: [filePath] }
1512
+ });
1513
+ }
1514
+ index = {
1515
+ path: filePath,
1516
+ modelClassName: moduleClassName,
1517
+ translatorName: nodeName2(callback.parameters[0]?.name),
1518
+ fields: objectLiteral ? fieldsFromObject(source, filePath, objectLiteral, "dictionary") : [],
1519
+ sourceSpan: spanFor(source, filePath, node)
1520
+ };
1521
+ };
1522
+ ts2.forEachChild(source, visit);
1523
+ return { index, diagnostics, modelFound };
1524
+ };
1525
+ var expectedFilesFor = (module) => {
1526
+ const paths = moduleSourcePaths(module.name);
1527
+ return indexFileKinds.map((kind) => {
1528
+ const expectedModulePath = paths[kind];
1529
+ const expectedFilename = path.basename(expectedModulePath);
1530
+ const actualFilename = module.files.find((file) => file === expectedFilename) ?? module.files.find((file) => file.toLowerCase() === expectedFilename.toLowerCase());
1531
+ const present = actualFilename !== undefined;
1532
+ const casing = !present ? "missing" : actualFilename === expectedFilename ? "match" : "mismatch";
1533
+ return {
1534
+ kind,
1535
+ path: `${module.path}/${actualFilename ?? expectedFilename}`,
1536
+ expectedPath: `${module.path}/${expectedFilename}`,
1537
+ filename: actualFilename ?? expectedFilename,
1538
+ expectedFilename,
1539
+ present,
1540
+ casing
1541
+ };
1542
+ });
1543
+ };
1544
+ var diagnosticsForFiles = (files) => files.flatMap((file) => {
1545
+ if (file.kind !== "constant" && file.kind !== "dictionary")
1546
+ return [];
1547
+ if (file.casing === "match")
1548
+ return [];
1549
+ return [
1550
+ {
1551
+ severity: "error",
1552
+ code: file.casing === "missing" ? "module-index-file-missing" : "module-index-file-casing-mismatch",
1553
+ message: file.casing === "missing" ? `Expected ${file.kind} file is missing: ${file.expectedPath}.` : `Expected ${file.expectedPath}, but found ${file.path}.`,
1554
+ context: { target: file.expectedPath, paths: [file.path, file.expectedPath] }
1555
+ }
1556
+ ];
1557
+ });
1558
+ var fieldPresence = (requestedField, constantFields, dictionaryFields, lightFields) => {
1559
+ const names = new Set([
1560
+ ...constantFields.map((field) => field.name),
1561
+ ...dictionaryFields.map((field) => field.name),
1562
+ ...lightFields.map((field) => field.name),
1563
+ ...requestedField ? [requestedField] : []
1564
+ ]);
1565
+ return [...names].sort().map((name) => ({
1566
+ name,
1567
+ requested: requestedField === name,
1568
+ constant: constantFields.some((field) => field.name === name),
1569
+ dictionary: dictionaryFields.some((field) => field.name === name),
1570
+ lightProjection: lightFields.some((field) => field.name === name)
1571
+ }));
1572
+ };
1573
+ var partialPresenceDiagnostics = (presence, module) => presence.filter((field) => field.constant !== field.dictionary || field.lightProjection && (!field.constant || !field.dictionary)).map((field) => ({
1574
+ severity: "warning",
1575
+ code: "module-index-field-presence-partial",
1576
+ message: `${module.sysName}:${module.name}.${field.name} presence differs across constant, dictionary, and lightProjection.`,
1577
+ context: {
1578
+ target: `${module.sysName}:${module.name}.${field.name}`,
1579
+ paths: [`${module.path}/${module.name}.constant.ts`, `${module.path}/${module.name}.dictionary.ts`]
1580
+ }
1581
+ }));
1582
+ var buildAkanModuleContextIndex = async (workspace, module, options = {}) => {
1583
+ const files = expectedFilesFor(module);
1584
+ const diagnostics = diagnosticsForFiles(files);
1585
+ const moduleClassName = moduleComponentName(module.name);
1586
+ const constantFile = files.find((file) => file.kind === "constant");
1587
+ const dictionaryFile = files.find((file) => file.kind === "dictionary");
1588
+ const constantContent = constantFile?.present && constantFile.casing === "match" ? await sourceText(path.join(workspace.workspaceRoot, constantFile.path)) : null;
1589
+ const dictionaryContent = dictionaryFile?.present && dictionaryFile.casing === "match" ? await sourceText(path.join(workspace.workspaceRoot, dictionaryFile.path)) : null;
1590
+ const parsedConstant = constantFile && constantContent ? parseConstantIndex(constantFile.path, constantContent, moduleClassName) : undefined;
1591
+ const constant = parsedConstant?.index;
1592
+ const parsedDictionary = dictionaryFile && dictionaryContent ? parseDictionaryIndex(dictionaryFile.path, dictionaryContent, moduleClassName) : undefined;
1593
+ const dictionary = parsedDictionary?.index;
1594
+ const presence = fieldPresence(options.field, constant?.fields ?? [], dictionary?.fields ?? [], constant?.lightProjection?.fields ?? []);
1595
+ if (constantFile?.present && constantFile.casing === "match" && !await fileExists(path.join(workspace.workspaceRoot, constantFile.path))) {
1596
+ diagnostics.push({
1597
+ severity: "error",
1598
+ code: "module-index-file-unreadable",
1599
+ message: `Expected constant file could not be read: ${constantFile.path}.`,
1600
+ context: { paths: [constantFile.path] }
1601
+ });
1602
+ }
1603
+ if (parsedConstant)
1604
+ diagnostics.push(...parsedConstant.diagnostics);
1605
+ if (parsedDictionary)
1606
+ diagnostics.push(...parsedDictionary.diagnostics);
1607
+ if (dictionaryFile?.present && dictionaryFile.casing === "match" && !parsedDictionary?.modelFound) {
1608
+ diagnostics.push({
1609
+ severity: "error",
1610
+ code: "module-index-dictionary-model-missing",
1611
+ message: `Dictionary .model<${moduleClassName}> branch was not found in ${dictionaryFile.path}.`,
1612
+ context: { paths: [dictionaryFile.path] }
1613
+ });
1614
+ }
1615
+ diagnostics.push(...partialPresenceDiagnostics(presence, module));
1616
+ return {
1617
+ schemaVersion: 1,
1618
+ app: module.sysName,
1619
+ module: module.name,
1620
+ moduleClassName,
1621
+ files,
1622
+ fieldPresence: presence,
1623
+ ...constant ? { constant } : {},
1624
+ ...dictionary ? { dictionary } : {},
1625
+ diagnostics
1626
+ };
1627
+ };
1628
+
1629
+ // pkgs/@akanjs/devkit/workflow/uiPolicy.ts
1630
+ var addFieldUiPolicyForType = (typeName) => {
1631
+ const normalizedType = typeName.toLowerCase() === "enum" ? "enum" : normalizeFieldType(typeName);
1632
+ if (normalizedType === "Int" || normalizedType === "Float") {
1633
+ return {
1634
+ normalizedType,
1635
+ component: "Field.Number",
1636
+ confidence: "high",
1637
+ autoTemplateSupported: true
1638
+ };
1639
+ }
1640
+ if (normalizedType === "Date") {
1641
+ return {
1642
+ normalizedType,
1643
+ component: "Field.Date",
1644
+ confidence: "high",
1645
+ autoTemplateSupported: true
1646
+ };
1647
+ }
1648
+ if (normalizedType === "Boolean" || normalizedType === "enum") {
1649
+ return {
1650
+ normalizedType,
1651
+ component: "Field.ToggleSelect",
1652
+ confidence: "medium",
1653
+ autoTemplateSupported: false
1654
+ };
1655
+ }
1656
+ if (normalizedType === "String") {
1657
+ return {
1658
+ normalizedType,
1659
+ component: "Field.Text",
1660
+ confidence: "high",
1661
+ autoTemplateSupported: true
1662
+ };
1663
+ }
1664
+ return {
1665
+ normalizedType,
1666
+ component: "Field.Text",
1667
+ confidence: "low",
1668
+ autoTemplateSupported: false
1669
+ };
1670
+ };
1671
+
1672
+ // pkgs/@akanjs/devkit/workflow/executor.ts
1673
+ var workflowStepKey = (workflow, stepId) => `${workflow}:${stepId}`;
1674
+ var primitiveReportToWorkflowStepResult = (report) => ({
1675
+ changedFiles: report.changedFiles,
1676
+ generatedFiles: report.generatedFiles,
1677
+ commands: report.validationCommands,
1678
+ diagnostics: report.diagnostics,
1679
+ recommendations: [],
1680
+ nextActions: report.nextActions
1681
+ });
1682
+ var workflowStringInput = (value) => typeof value === "string" ? value : null;
1683
+ var workflowStringListInput = (value) => Array.isArray(value) ? value.join(",") : null;
1684
+ var workflowStringArrayInput = (value) => Array.isArray(value) ? value : null;
1685
+ var workflowBooleanInput = (value) => typeof value === "boolean" ? value : null;
1686
+ var postApplyDiagnostic = (code, message, target) => ({
1687
+ severity: "error",
1688
+ code,
1689
+ message,
1690
+ failureScope: "source-change",
1691
+ context: { target }
1692
+ });
1693
+ var postApplyWarning = (code, message, target) => ({
1694
+ severity: "warning",
1695
+ code,
1696
+ message,
1697
+ failureScope: "source-change",
1698
+ context: { target }
1699
+ });
1700
+ var sourceKindForPath = (filePath) => {
1701
+ if (filePath.endsWith(".tsx"))
1702
+ return ts3.ScriptKind.TSX;
1703
+ if (filePath.endsWith(".ts"))
1704
+ return ts3.ScriptKind.TS;
1705
+ return null;
1706
+ };
1707
+ var checkPathCasing = async (workspace, filePath) => {
1708
+ const segments = filePath.split("/").filter(Boolean);
1709
+ let current = ".";
1710
+ for (const segment of segments) {
1711
+ const entries = await workspace.readdir(current);
1712
+ if (entries.includes(segment)) {
1713
+ current = current === "." ? segment : `${current}/${segment}`;
1714
+ continue;
1715
+ }
1716
+ const caseInsensitiveMatch = entries.find((entry) => entry.toLowerCase() === segment.toLowerCase());
1717
+ return caseInsensitiveMatch ? {
1718
+ code: "workflow-path-casing-mismatch",
1719
+ message: `Reported path segment "${segment}" does not match actual casing "${caseInsensitiveMatch}" in ${filePath}.`
1720
+ } : {
1721
+ code: "workflow-path-missing",
1722
+ message: `Reported path does not exist: ${filePath}.`
1723
+ };
1724
+ }
1725
+ return null;
1726
+ };
1727
+ var checkTypeScriptSyntax = async (workspace, filePath) => {
1728
+ const scriptKind = sourceKindForPath(filePath);
1729
+ if (!scriptKind)
1730
+ return null;
1731
+ const content = await workspace.readFile(filePath);
1732
+ const source = ts3.createSourceFile(filePath, content, ts3.ScriptTarget.Latest, true, scriptKind);
1733
+ const diagnostic = (source.parseDiagnostics ?? [])[0];
1734
+ if (!diagnostic)
1735
+ return null;
1736
+ const position = diagnostic.file?.getLineAndCharacterOfPosition(diagnostic.start ?? 0);
1737
+ const location = position ? `:${position.line + 1}:${position.character + 1}` : "";
1738
+ return {
1739
+ code: "workflow-post-apply-syntax-error",
1740
+ message: `Generated source has a TypeScript syntax error at ${filePath}${location}: ${ts3.flattenDiagnosticMessageText(diagnostic.messageText, " ")}`
1741
+ };
1742
+ };
1743
+ var checkChangedFile = async (workspace, file) => {
1744
+ if (file.action === "remove")
1745
+ return { postApplyChecks: [] };
1746
+ const diagnostics = [];
1747
+ const checks = [];
1748
+ const pathIssue = await checkPathCasing(workspace, file.path);
1749
+ if (pathIssue) {
1750
+ diagnostics.push(postApplyDiagnostic(pathIssue.code, pathIssue.message, file.path));
1751
+ checks.push({ ...pathIssue, target: file.path, status: "failed" });
1752
+ return { diagnostics, postApplyChecks: checks };
1753
+ }
1754
+ const syntaxIssue = await checkTypeScriptSyntax(workspace, file.path);
1755
+ if (syntaxIssue) {
1756
+ diagnostics.push(postApplyDiagnostic(syntaxIssue.code, syntaxIssue.message, file.path));
1757
+ checks.push({ ...syntaxIssue, target: file.path, status: "failed" });
1758
+ return { diagnostics, postApplyChecks: checks };
1759
+ }
1760
+ checks.push({
1761
+ code: "workflow-post-apply-file-valid",
1762
+ target: file.path,
1763
+ status: "passed",
1764
+ message: "Changed file exists with exact casing and parses as source when applicable."
1765
+ });
1766
+ return { postApplyChecks: checks };
1767
+ };
1768
+ var checkRecommendationPath = async (workspace, recommendation) => {
1769
+ if (!recommendation.target || recommendation.target.includes("*") || recommendation.target.startsWith("<"))
1770
+ return null;
1771
+ const pathIssue = await checkPathCasing(workspace, recommendation.target);
1772
+ if (!pathIssue)
1773
+ return null;
1774
+ return {
1775
+ severity: "warning",
1776
+ code: "workflow-recommendation-path-unverified",
1777
+ message: `${pathIssue.message} Recommendation "${recommendation.code}" should not be treated as an exact file target until the path is corrected.`,
1778
+ failureScope: "source-change",
1779
+ context: { target: recommendation.target }
1780
+ };
1781
+ };
1782
+ var sourceChangeError = (diagnostics) => diagnostics.some((diagnostic) => diagnostic.severity === "error" && (diagnostic.failureScope === "source-change" || !diagnostic.failureScope || diagnostic.failureScope === "unknown"));
1783
+ var fieldCount = (fields, fieldName) => fields.filter((field) => field === fieldName).length;
1784
+ var fieldOrderValid = (fields, fieldName) => {
1785
+ const actualIndex = fields.indexOf(fieldName);
1786
+ if (actualIndex < 0 || fields.lastIndexOf(fieldName) !== actualIndex)
1787
+ return false;
1788
+ const fieldsWithoutRequested = fields.filter((_, index) => index !== actualIndex);
1789
+ return insertionIndexForFieldOrder(fieldsWithoutRequested, fieldName) === actualIndex;
1790
+ };
1791
+ var workflowModuleContext = async (workspace, plan) => {
1792
+ const app = workflowStringInput(plan.inputs.app);
1793
+ const moduleName = workflowStringInput(plan.inputs.module);
1794
+ if (!app || !moduleName)
1795
+ return null;
1796
+ const [apps, libs] = await workspace.getSyss();
1797
+ const sysType = apps.includes(app) ? "app" : libs.includes(app) ? "lib" : null;
1798
+ if (!sysType)
1799
+ return null;
1800
+ const modulePath = `${sysType}s/${app}/lib/${moduleName}`;
1801
+ const files = await workspace.readdir(modulePath);
1802
+ const abstractPath = `${modulePath}/${moduleName}.abstract.md`;
1803
+ return {
1804
+ kind: "domain",
1805
+ name: moduleName,
1806
+ folderName: moduleName,
1807
+ sysName: app,
1808
+ sysType,
1809
+ path: modulePath,
1810
+ abstract: {
1811
+ path: abstractPath,
1812
+ exists: files.includes(`${moduleName}.abstract.md`),
1813
+ headings: []
1814
+ },
1815
+ files
1816
+ };
1817
+ };
1818
+ var structureCheck = (code, target, status, message) => ({
1819
+ code,
1820
+ target,
1821
+ status,
1822
+ message
1823
+ });
1824
+ var checkAddFieldStructure = async (workspace, plan) => {
1825
+ if (plan.workflow !== "add-field" && plan.workflow !== "add-enum-field")
1826
+ return {};
1827
+ const app = workflowStringInput(plan.inputs.app);
1828
+ const moduleName = workflowStringInput(plan.inputs.module);
1829
+ const fieldName = workflowStringInput(plan.inputs.field);
1830
+ const typeName = workflowStringInput(plan.inputs.type);
1831
+ if (!app || !moduleName || !fieldName || !typeName)
1832
+ return {};
1833
+ const moduleContext = await workflowModuleContext(workspace, plan);
1834
+ if (!moduleContext)
1835
+ return {};
1836
+ const paths = moduleSourcePaths(moduleName);
1837
+ const constantPath = `${moduleContext.path}/${paths.constant.replace(`lib/${moduleName}/`, "")}`;
1838
+ const dictionaryPath = `${moduleContext.path}/${paths.dictionary.replace(`lib/${moduleName}/`, "")}`;
1839
+ const moduleClassName = moduleComponentName(moduleName);
1840
+ const inputClassName = `${moduleClassName}Input`;
1841
+ const index = await buildAkanModuleContextIndex(workspace, moduleContext, { field: fieldName });
1842
+ const diagnostics = [];
1843
+ const postApplyChecks = [];
1844
+ const constantContent = await workspace.readFile(constantPath);
1845
+ const constantStructure = inspectConstantStructure(constantContent, inputClassName, moduleClassName);
1846
+ const constantNames = constantStructure.fields.map((field) => field.name);
1847
+ const requestedConstantFields = constantStructure.fields.filter((field) => field.name === fieldName);
1848
+ const normalizedType = typeName.toLowerCase() === "enum" ? typeName : normalizeFieldType(typeName);
1849
+ const constantFailures = [
1850
+ !constantStructure.parseValid ? "constant file does not parse" : null,
1851
+ !constantStructure.inputObjectFound ? `${inputClassName} via builder object was not found` : null,
1852
+ requestedConstantFields.length !== 1 ? `field "${fieldName}" appears ${requestedConstantFields.length} time(s) in ${inputClassName}` : null,
1853
+ constantStructure.builderName && requestedConstantFields[0]?.expressionBuilder && requestedConstantFields[0].expressionBuilder !== constantStructure.builderName ? `field "${fieldName}" uses builder "${requestedConstantFields[0].expressionBuilder}" instead of "${constantStructure.builderName}"` : null,
1854
+ !constantStructure.builderName ? `${inputClassName} via builder parameter was not found` : null,
1855
+ (normalizedType === "Int" || normalizedType === "Float") && !constantStructure.baseImports.includes(normalizedType) ? `missing ${normalizedType} import from "akanjs/base"` : null,
1856
+ workflowBooleanInput(plan.inputs.includeInLight) === true && fieldCount(constantStructure.lightProjectionFields, fieldName) !== 1 ? `field "${fieldName}" is not present exactly once in Light${moduleClassName}` : null,
1857
+ ...index.diagnostics.filter((diagnostic) => diagnostic.severity === "error" && diagnostic.context?.paths?.includes(constantPath)).map((diagnostic) => diagnostic.message)
1858
+ ].filter((failure) => failure !== null);
1859
+ const constantValid = constantFailures.length === 0;
1860
+ postApplyChecks.push(structureCheck(constantValid ? "workflow-post-apply-constant-shape-valid" : "workflow-post-apply-structure-invalid", constantPath, constantValid ? "passed" : "failed", constantValid ? `${inputClassName} keeps via structure, builder usage, imports, and requested field presence.` : constantFailures.join(" ")));
1861
+ if (!constantValid) {
1862
+ diagnostics.push(postApplyDiagnostic("workflow-post-apply-structure-invalid", constantFailures.join(" "), constantPath));
1863
+ }
1864
+ const dictionaryContent = await workspace.readFile(dictionaryPath);
1865
+ const dictionaryStructure = inspectDictionaryStructure(dictionaryContent, moduleClassName);
1866
+ const dictionaryFailures = [
1867
+ !dictionaryStructure.parseValid ? "dictionary file does not parse" : null,
1868
+ !dictionaryStructure.modelObjectFound ? `.model<${moduleClassName}> object was not found` : null,
1869
+ dictionaryStructure.modelObjectFound && !dictionaryStructure.chainOrderValid ? `.model(), .slice(), .enum(), .error(), and .translate() chain order is broken: ${dictionaryStructure.chainMethods.join(" -> ")}` : null,
1870
+ fieldCount(dictionaryStructure.fields, fieldName) !== 1 ? `field "${fieldName}" appears ${fieldCount(dictionaryStructure.fields, fieldName)} time(s) in .model<${moduleClassName}>` : null,
1871
+ ...index.diagnostics.filter((diagnostic) => diagnostic.severity === "error" && diagnostic.context?.paths?.includes(dictionaryPath)).map((diagnostic) => diagnostic.message)
1872
+ ].filter((failure) => failure !== null);
1873
+ const dictionaryValid = dictionaryFailures.length === 0;
1874
+ postApplyChecks.push(structureCheck(dictionaryValid ? "workflow-post-apply-dictionary-shape-valid" : "workflow-post-apply-structure-invalid", dictionaryPath, dictionaryValid ? "passed" : "failed", dictionaryValid ? `.model<${moduleClassName}> keeps the requested field inside the model object and preserves dictionary chain order.` : dictionaryFailures.join(" ")));
1875
+ if (!dictionaryValid) {
1876
+ diagnostics.push(postApplyDiagnostic("workflow-post-apply-structure-invalid", dictionaryFailures.join(" "), dictionaryPath));
1877
+ }
1878
+ const constantOrderValid = fieldOrderValid(constantNames, fieldName);
1879
+ const dictionaryOrderValid = fieldOrderValid(dictionaryStructure.fields, fieldName);
1880
+ const orderValid = constantOrderValid && dictionaryOrderValid;
1881
+ postApplyChecks.push(structureCheck("workflow-post-apply-field-order-valid", `${constantPath}, ${dictionaryPath}`, orderValid ? "passed" : "failed", orderValid ? `Field "${fieldName}" follows the shared priority ordering policy.` : `Field "${fieldName}" is present but does not match the shared priority ordering policy.`));
1882
+ if (!orderValid) {
1883
+ diagnostics.push(postApplyWarning("workflow-post-apply-field-order-mismatch", `Field "${fieldName}" is present but does not match the shared priority ordering policy.`, `${constantPath}, ${dictionaryPath}`));
1884
+ }
1885
+ return { diagnostics, postApplyChecks };
1886
+ };
1887
+ var resolveWorkflowSys = async (workspace, target) => {
1888
+ if (!target)
1889
+ return null;
1890
+ const [apps, libs] = await workspace.getSyss();
1891
+ if (apps.includes(target))
1892
+ return AppExecutor.from(workspace, target);
1893
+ if (libs.includes(target))
1894
+ return LibExecutor.from(workspace, target);
1895
+ return null;
1896
+ };
1897
+ var targetMissing = (input = "app") => ({
1898
+ severity: "error",
1899
+ code: "workflow-target-missing",
1900
+ input,
1901
+ message: "Workflow target app or library was not found."
1902
+ });
1903
+ var inputMissing = (input) => ({
1904
+ severity: "error",
1905
+ code: "workflow-input-missing",
1906
+ input,
1907
+ message: `Workflow input "${input}" is required for apply.`
1908
+ });
1909
+ var unsupportedInput = (input, message) => ({
1910
+ severity: "error",
1911
+ code: "workflow-input-unsupported",
1912
+ input,
1913
+ message
1914
+ });
1915
+ var addFieldUiSurfaceInspection = (plan) => {
1916
+ const app = workflowStringInput(plan.inputs.app);
1917
+ const module = workflowStringInput(plan.inputs.module) ?? "<module>";
1918
+ const field = workflowStringInput(plan.inputs.field) ?? "<field>";
1919
+ const typeName = workflowStringInput(plan.inputs.type);
1920
+ const policy = addFieldUiPolicyForType(typeName ?? "String");
1921
+ const surfaces = workflowStringArrayInput(plan.inputs.surfaces);
1922
+ const templateRequested = surfaces?.includes("template") ?? false;
1923
+ const moduleClassName = moduleComponentName(module);
1924
+ const target = `${app ? `apps/${app}` : "*"}/${moduleSourcePaths(module).template}`;
1925
+ return {
1926
+ recommendations: [
1927
+ {
1928
+ code: "add-field-ui-surface-review",
1929
+ kind: "manual-action",
1930
+ target,
1931
+ action: templateRequested ? `Template was requested for ${field}. If no Template file changed, users will not see the field in the form yet because the file was missing, the generated ${module}Form/Layout.Template pattern was not found, or ${policy.component} needs option binding. Add it inside Layout.Template near existing Field components.` : `Template was not selected, so users will not see ${field} in the form from this apply. If list/card display is needed, include ${field} in Light${moduleClassName} projection data and place it in the local Unit/View card layout.`,
1932
+ confidence: "medium",
1933
+ message: `Review user-visible UI for ${module}.${field}; recommended component is ${policy.component}.`
1934
+ }
1935
+ ],
1936
+ nextActions: [
1937
+ {
1938
+ command: `akan workflow explain ${plan.workflow}`,
1939
+ reason: "Review UI surface guidance before manually editing ambiguous UI files."
1940
+ }
1941
+ ]
1942
+ };
1943
+ };
1944
+ var createWorkflowStepRegistry = ({
1945
+ workspace,
1946
+ createModule,
1947
+ createScalar,
1948
+ createUi,
1949
+ addField,
1950
+ addEnumField,
1951
+ addMutation,
1952
+ addSlice
1953
+ }) => {
1954
+ const inspect = async () => {
1955
+ return;
1956
+ };
1957
+ const commandOnly = async () => {
1958
+ return;
1959
+ };
1960
+ return {
1961
+ inspectSystem: inspect,
1962
+ inspectModule: inspect,
1963
+ syncTarget: commandOnly,
1964
+ lintTarget: commandOnly,
1965
+ [workflowStepKey("create-module", "create-module")]: async (_step, plan) => {
1966
+ const app = workflowStringInput(plan.inputs.app);
1967
+ const module = workflowStringInput(plan.inputs.module);
1968
+ const sys = await resolveWorkflowSys(workspace, app);
1969
+ if (!sys || !module)
1970
+ return { diagnostics: [!sys ? targetMissing() : inputMissing("module")] };
1971
+ return primitiveReportToWorkflowStepResult(await createModule(sys, module));
1972
+ },
1973
+ [workflowStepKey("create-scalar", "create-scalar")]: async (_step, plan) => {
1974
+ const app = workflowStringInput(plan.inputs.app);
1975
+ const scalar = workflowStringInput(plan.inputs.scalar);
1976
+ const sys = await resolveWorkflowSys(workspace, app);
1977
+ if (!sys || !scalar)
1978
+ return { diagnostics: [!sys ? targetMissing() : inputMissing("scalar")] };
1979
+ return primitiveReportToWorkflowStepResult(await createScalar(sys, scalar));
1980
+ },
1981
+ [workflowStepKey("create-ui", "create-ui")]: async (_step, plan) => {
1982
+ const surface = workflowStringInput(plan.inputs.surface);
1983
+ if (surface !== "view" && surface !== "unit" && surface !== "template") {
1984
+ return {
1985
+ diagnostics: [
1986
+ unsupportedInput("surface", "Workflow apply currently supports create-ui surfaces: view, unit, template.")
1987
+ ]
1988
+ };
1989
+ }
1990
+ return primitiveReportToWorkflowStepResult(await createUi({
1991
+ app: workflowStringInput(plan.inputs.app),
1992
+ module: workflowStringInput(plan.inputs.module),
1993
+ surface
1994
+ }));
1995
+ },
1996
+ [workflowStepKey("add-field", "update-constant")]: async (_step, plan) => {
1997
+ if (workflowStringInput(plan.inputs.type)?.toLowerCase() === "enum") {
1998
+ return primitiveReportToWorkflowStepResult(await addEnumField({
1999
+ app: workflowStringInput(plan.inputs.app),
2000
+ module: workflowStringInput(plan.inputs.module),
2001
+ field: workflowStringInput(plan.inputs.field),
2002
+ values: workflowStringListInput(plan.inputs.values),
2003
+ defaultValue: workflowStringInput(plan.inputs.default),
2004
+ surfaces: workflowStringArrayInput(plan.inputs.surfaces),
2005
+ includeInLight: workflowBooleanInput(plan.inputs.includeInLight)
2006
+ }));
2007
+ }
2008
+ return primitiveReportToWorkflowStepResult(await addField({
2009
+ app: workflowStringInput(plan.inputs.app),
2010
+ module: workflowStringInput(plan.inputs.module),
2011
+ field: workflowStringInput(plan.inputs.field),
2012
+ type: workflowStringInput(plan.inputs.type),
2013
+ defaultValue: workflowStringInput(plan.inputs.default),
2014
+ surfaces: workflowStringArrayInput(plan.inputs.surfaces),
2015
+ includeInLight: workflowBooleanInput(plan.inputs.includeInLight)
2016
+ }));
2017
+ },
2018
+ [workflowStepKey("add-field", "update-dictionary")]: inspect,
2019
+ [workflowStepKey("add-field", "update-ui-surfaces")]: async (_step, plan) => addFieldUiSurfaceInspection(plan),
2020
+ [workflowStepKey("add-enum-field", "update-constant")]: async (_step, plan) => primitiveReportToWorkflowStepResult(await addEnumField({
2021
+ app: workflowStringInput(plan.inputs.app),
2022
+ module: workflowStringInput(plan.inputs.module),
2023
+ field: workflowStringInput(plan.inputs.field),
2024
+ values: workflowStringListInput(plan.inputs.values),
2025
+ defaultValue: workflowStringInput(plan.inputs.default)
2026
+ })),
2027
+ [workflowStepKey("add-enum-field", "update-dictionary")]: inspect,
2028
+ [workflowStepKey("add-enum-field", "update-option")]: inspect,
2029
+ [workflowStepKey("add-mutation", "update-service")]: async (_step, plan) => primitiveReportToWorkflowStepResult(await addMutation({
2030
+ app: workflowStringInput(plan.inputs.app),
2031
+ module: workflowStringInput(plan.inputs.module),
2032
+ mutation: workflowStringInput(plan.inputs.mutation)
2033
+ })),
2034
+ [workflowStepKey("add-mutation", "update-signal")]: inspect,
2035
+ [workflowStepKey("add-slice", "update-service-query")]: async (_step, plan) => primitiveReportToWorkflowStepResult(await addSlice({
2036
+ app: workflowStringInput(plan.inputs.app),
2037
+ module: workflowStringInput(plan.inputs.module),
2038
+ slice: workflowStringInput(plan.inputs.slice)
2039
+ })),
2040
+ [workflowStepKey("add-slice", "update-signal-slice")]: inspect
2041
+ };
2042
+ };
2043
+ class WorkflowExecutor {
2044
+ registry;
2045
+ workspace;
2046
+ constructor(registry, workspace) {
2047
+ this.registry = registry;
2048
+ this.workspace = workspace;
2049
+ }
2050
+ async apply(plan) {
2051
+ const changedFiles = [];
2052
+ const generatedFiles = [];
2053
+ const recommendedValidationCommands = [];
2054
+ const diagnostics = [...plan.diagnostics];
2055
+ const postApplyChecks = [];
2056
+ const recommendations = [...plan.recommendations];
2057
+ const nextActions = [];
2058
+ if (diagnostics.some((diagnostic) => diagnostic.severity === "error")) {
2059
+ return createWorkflowApplyReport({
2060
+ workflow: plan.workflow,
2061
+ mode: "apply",
2062
+ changedFiles,
2063
+ generatedFiles,
2064
+ recommendedValidationCommands,
2065
+ diagnostics,
2066
+ postApplyChecks,
2067
+ recommendations,
2068
+ nextActions,
2069
+ plan
2070
+ });
2071
+ }
2072
+ recommendedValidationCommands.push(...workflowCommandsForPlan(plan));
2073
+ nextActions.push(...workflowCommandsForPlan(plan));
2074
+ for (const step of plan.steps) {
2075
+ const runner = this.registry[workflowStepKey(plan.workflow, step.id)] ?? this.registry[step.tool] ?? this.registry[step.id];
2076
+ if (!runner) {
2077
+ diagnostics.push({
2078
+ severity: "error",
2079
+ code: "workflow-step-unsupported",
2080
+ message: `Workflow ${plan.workflow} step "${step.id}" is not supported by workflow apply yet.`
2081
+ });
2082
+ nextActions.push({
2083
+ command: `akan workflow explain ${plan.workflow}`,
2084
+ reason: "Review the unsupported workflow step before retrying apply."
2085
+ });
2086
+ break;
2087
+ }
2088
+ const result = await runner(step, plan);
2089
+ if (!result)
2090
+ continue;
2091
+ changedFiles.push(...result.changedFiles ?? []);
2092
+ generatedFiles.push(...result.generatedFiles ?? []);
2093
+ recommendedValidationCommands.push(...result.commands ?? []);
2094
+ diagnostics.push(...result.diagnostics ?? []);
2095
+ recommendations.push(...result.recommendations ?? []);
2096
+ nextActions.push(...result.nextActions ?? []);
2097
+ if (diagnostics.some((diagnostic) => diagnostic.severity === "error"))
2098
+ break;
2099
+ }
2100
+ if (this.workspace && !diagnostics.some((diagnostic) => diagnostic.severity === "error")) {
2101
+ for (const file of changedFiles) {
2102
+ const result = await checkChangedFile(this.workspace, file);
2103
+ postApplyChecks.push(...result.postApplyChecks ?? []);
2104
+ diagnostics.push(...result.diagnostics ?? []);
2105
+ }
2106
+ if (!sourceChangeError(diagnostics)) {
2107
+ const result = await checkAddFieldStructure(this.workspace, plan);
2108
+ postApplyChecks.push(...result.postApplyChecks ?? []);
2109
+ diagnostics.push(...result.diagnostics ?? []);
2110
+ }
2111
+ const recommendationDiagnostics = await Promise.all(recommendations.map((recommendation) => checkRecommendationPath(this.workspace, recommendation)));
2112
+ diagnostics.push(...recommendationDiagnostics.filter((diagnostic) => !!diagnostic));
2113
+ }
2114
+ return createWorkflowApplyReport({
2115
+ workflow: plan.workflow,
2116
+ mode: "apply",
2117
+ changedFiles,
2118
+ generatedFiles,
2119
+ recommendedValidationCommands,
2120
+ diagnostics,
2121
+ postApplyChecks,
2122
+ recommendations,
2123
+ nextActions,
2124
+ plan
2125
+ });
2126
+ }
2127
+ }
2128
+ // pkgs/@akanjs/devkit/workflow/plan.ts
2129
+ import { capitalize } from "akanjs/common";
2130
+ var surfaceModes = new Set(["infer", "include", "skip"]);
2131
+ var parseStringList = (value) => {
2132
+ if (Array.isArray(value)) {
2133
+ const values = value.filter((item) => typeof item === "string" && item.trim().length > 0);
2134
+ return values.length === value.length ? values : null;
2135
+ }
2136
+ if (typeof value !== "string")
2137
+ return null;
2138
+ return value.split(",").map((item) => item.trim()).filter(Boolean);
2139
+ };
2140
+ var normalizeInputValue = (name, spec, value) => {
2141
+ if (spec.type === "string")
2142
+ return typeof value === "string" && value.length > 0 ? value : null;
2143
+ if (spec.type === "string-list") {
2144
+ const values = parseStringList(value);
2145
+ return values && values.length > 0 ? values : null;
2146
+ }
2147
+ if (spec.type === "boolean") {
2148
+ if (typeof value === "boolean")
2149
+ return value;
2150
+ if (typeof value !== "string")
2151
+ return null;
2152
+ const lowered = value.trim().toLowerCase();
2153
+ if (lowered === "true")
2154
+ return true;
2155
+ if (lowered === "false")
2156
+ return false;
2157
+ return null;
2158
+ }
2159
+ if (typeof value === "string" && surfaceModes.has(value))
2160
+ return value;
2161
+ throw new Error(`Unsupported workflow input value for ${name}`);
2162
+ };
2163
+ var listWorkflowSpecs = (specs) => [...specs].sort((a, b) => a.name.localeCompare(b.name));
2164
+ var getWorkflowSpec = (specs, name) => specs.find((spec) => spec.name === name) ?? null;
2165
+ var compactWorkflowInputs = (inputs) => Object.fromEntries(Object.entries(inputs).filter(([, value]) => value !== null && value !== ""));
2166
+ var addFieldTargetRoot = (app) => app ? `apps/${app}` : "*";
2167
+ var addFieldPaths = (inputs) => {
2168
+ const app = typeof inputs.app === "string" ? inputs.app : null;
2169
+ const module = typeof inputs.module === "string" ? inputs.module : "<module>";
2170
+ const paths = moduleSourcePaths(module);
2171
+ const root = addFieldTargetRoot(app);
2172
+ return {
2173
+ constant: `${root}/${paths.constant}`,
2174
+ dictionary: `${root}/${paths.dictionary}`,
2175
+ template: `${root}/${paths.template}`,
2176
+ unit: `${root}/${paths.unit}`,
2177
+ view: `${root}/${paths.view}`
2178
+ };
2179
+ };
2180
+ var selectedAddFieldSurfaces = (inputs) => Array.isArray(inputs.surfaces) ? new Set(inputs.surfaces) : null;
2181
+ var addFieldDefaultCoercion = (inputs) => {
2182
+ const typeName = typeof inputs.type === "string" ? inputs.type : null;
2183
+ const defaultValue = typeof inputs.default === "string" ? inputs.default : null;
2184
+ if (!typeName || defaultValue === null)
2185
+ return null;
2186
+ if (typeName.toLowerCase() === "number" || typeName.toLowerCase() === "numeric")
2187
+ return null;
2188
+ const enumValues = Array.isArray(inputs.values) ? inputs.values : null;
2189
+ return coerceFieldDefault(typeName.toLowerCase() === "enum" ? "enum" : typeName, defaultValue, { enumValues });
2190
+ };
2191
+ var createAddFieldDefaultRecommendations = (inputs) => {
2192
+ const field = typeof inputs.field === "string" ? inputs.field : "<field>";
2193
+ const coercion = addFieldDefaultCoercion(inputs);
2194
+ if (!coercion?.normalized || !coercion.expression)
2195
+ return [];
2196
+ return [
2197
+ {
2198
+ code: "add-field-default-normalized",
2199
+ kind: "manual-action",
2200
+ confidence: "high",
2201
+ message: `Default for ${field} will be normalized to ${coercion.normalizedType} literal ${coercion.expression}.`,
2202
+ action: "Review the normalized default in the apply report. To leave the field without a default, omit the default input."
2203
+ }
2204
+ ];
2205
+ };
2206
+ var moneyLikeFieldPattern = /(budget|price|amount|cost|rate|fee|salary|balance)/i;
2207
+ var wholeNumberFieldPattern = /(count|quantity|total|number|index|rank|order|age)/i;
2208
+ var createAddFieldInputRecommendations = (inputs) => {
2209
+ const field = typeof inputs.field === "string" ? inputs.field : "<field>";
2210
+ const typeName = typeof inputs.type === "string" ? inputs.type : null;
2211
+ const recommendations = [];
2212
+ if (!typeName)
2213
+ return recommendations;
2214
+ if (typeName.toLowerCase() === "number" || typeName.toLowerCase() === "numeric") {
2215
+ const recommendedType = moneyLikeFieldPattern.test(field) ? "Float" : wholeNumberFieldPattern.test(field) ? "Int" : null;
2216
+ recommendations.push({
2217
+ code: "add-field-type-choice",
2218
+ kind: "input-guidance",
2219
+ confidence: recommendedType ? "high" : "medium",
2220
+ message: recommendedType ? `Use ${recommendedType} for ${field}; Float is recommended for money-like decimal values and Int for whole-number values.` : `Choose Int for whole-number ${field} values or Float for decimal ${field} values.`,
2221
+ action: recommendedType ? `Re-run plan_workflow with type="${recommendedType}".` : 'Re-run plan_workflow with type="Int" or type="Float".'
2222
+ });
2223
+ }
2224
+ if (typeName.toLowerCase() === "enum" && !Array.isArray(inputs.values)) {
2225
+ recommendations.push({
2226
+ code: "add-field-enum-values",
2227
+ kind: "input-guidance",
2228
+ confidence: "high",
2229
+ message: `Enum field ${field} needs values before apply can choose valid dictionary and default behavior.`,
2230
+ action: 'Pass values as an array or comma-separated string, for example values=["draft","done"].'
2231
+ });
2232
+ }
2233
+ if (inputs.default === undefined) {
2234
+ recommendations.push({
2235
+ code: "add-field-default-optional",
2236
+ kind: "input-guidance",
2237
+ confidence: "medium",
2238
+ message: `No default will be written for ${field} because default is omitted.`,
2239
+ action: "Keep default omitted when the field should have no default value."
2240
+ });
2241
+ }
2242
+ return recommendations;
2243
+ };
2244
+ var createAddFieldRecommendations = (inputs) => {
2245
+ const app = typeof inputs.app === "string" ? inputs.app : "<app-or-lib>";
2246
+ const module = typeof inputs.module === "string" ? inputs.module : "<module>";
2247
+ const field = typeof inputs.field === "string" ? inputs.field : "<field>";
2248
+ const typeName = typeof inputs.type === "string" ? inputs.type : null;
2249
+ if (!typeName)
2250
+ return [];
2251
+ const policy = addFieldUiPolicyForType(typeName);
2252
+ const normalizedType = policy.normalizedType;
2253
+ const paths = addFieldPaths(inputs);
2254
+ const surfaces = selectedAddFieldSurfaces(inputs);
2255
+ const templateRequested = surfaces?.has("template") ?? false;
2256
+ const includeInLight = inputs.includeInLight === true;
2257
+ return [
2258
+ ...normalizedType === "Int" || normalizedType === "Float" ? [
2259
+ {
2260
+ code: "add-field-import",
2261
+ kind: "import",
2262
+ target: paths.constant,
2263
+ confidence: "high",
2264
+ message: `Import ${normalizedType} from "akanjs/base" before writing field(${normalizedType}).`
2265
+ }
2266
+ ] : [],
2267
+ {
2268
+ code: "add-field-placement-constant",
2269
+ kind: "placement",
2270
+ target: paths.constant,
2271
+ confidence: "high",
2272
+ message: `Insert ${field}: field(${normalizedType}) in ${capitalize(module)}Input.`
2273
+ },
2274
+ {
2275
+ code: "add-field-placement-dictionary",
2276
+ kind: "placement",
2277
+ target: paths.dictionary,
2278
+ confidence: "high",
2279
+ message: `Add dictionary labels for ${module}.${field}.`
2280
+ },
2281
+ {
2282
+ code: "add-field-component",
2283
+ kind: "ui-component",
2284
+ target: paths.template,
2285
+ confidence: policy.confidence,
2286
+ action: templateRequested ? `apply_workflow will try to add ${policy.component} to Template when the existing Template has a safe generated field-list pattern.` : `Recommended component is ${policy.component}. Pass surfaces=["template"] when this field should be rendered in the Template form.`,
2287
+ message: `Recommended UI component for ${field} (${normalizedType}): ${policy.component}.`
2288
+ },
2289
+ ...!surfaces ? [
2290
+ {
2291
+ code: "add-field-template-surface-choice",
2292
+ kind: "manual-action",
2293
+ target: paths.template,
2294
+ action: `Choose whether to expose ${field} in Template by passing surfaces=["template"].`,
2295
+ confidence: "medium",
2296
+ message: `Template exposure for ${module}.${field} is not selected yet.`
2297
+ }
2298
+ ] : [],
2299
+ ...!includeInLight ? [
2300
+ {
2301
+ code: "add-field-light-projection-choice",
2302
+ kind: "manual-action",
2303
+ target: paths.constant,
2304
+ action: `Pass includeInLight=true when users should see ${field} in list/card data. Without it, the field can exist on ${capitalize(module)}Input but stay absent from Light${capitalize(module)} projections.`,
2305
+ confidence: "medium",
2306
+ message: `${module}.${field} is not selected for list/card projection data.`
2307
+ }
2308
+ ] : [],
2309
+ ...includeInLight ? [
2310
+ {
2311
+ code: "add-field-light-projection",
2312
+ kind: "placement",
2313
+ target: paths.constant,
2314
+ confidence: "high",
2315
+ message: `Add ${field} to Light${capitalize(module)} projection fields.`
2316
+ }
2317
+ ] : [],
2318
+ ...surfaces && !templateRequested ? [
2319
+ {
2320
+ code: "add-field-ui-surface-skip",
2321
+ kind: "manual-action",
2322
+ target: paths.template,
2323
+ confidence: "medium",
2324
+ message: `Template form auto-edit is skipped for ${module}.${field} because surfaces does not include "template".`,
2325
+ action: `Pass surfaces=["template"] when users should enter ${field} in the Template form.`
2326
+ }
2327
+ ] : [],
2328
+ {
2329
+ code: "add-field-ui-manual-review",
2330
+ kind: "manual-action",
2331
+ target: paths.template,
2332
+ action: `After apply, verify what users can see: Template form auto-edit only runs when a generated ${module}Form hook and Layout.Template field list are present. Unit/View cards are not auto-edited, so ${field} may be stored on ${capitalize(module)} but not shown in list/card UI until you place it in the local card layout.`,
2333
+ confidence: "medium",
2334
+ message: `${app}:${module}.${field} may need UI review for user-visible Template, Unit, and View behavior.`
2335
+ },
2336
+ ...createAddFieldDefaultRecommendations(inputs),
2337
+ ...createAddFieldInputRecommendations(inputs)
2338
+ ];
2339
+ };
2340
+ var createWorkflowPlanPredictedChanges = (spec, inputs) => {
2341
+ if (spec.name !== "add-field")
2342
+ return spec.predictedChanges;
2343
+ const paths = addFieldPaths(inputs);
2344
+ const surfaces = selectedAddFieldSurfaces(inputs);
2345
+ const includeInLight = inputs.includeInLight === true;
2346
+ return [
2347
+ {
2348
+ target: paths.constant,
2349
+ action: "modify",
2350
+ applyScope: "auto",
2351
+ reason: includeInLight ? "Field shape and Light projection are added." : "Field shape is added."
2352
+ },
2353
+ {
2354
+ target: paths.dictionary,
2355
+ action: "modify",
2356
+ applyScope: "auto",
2357
+ reason: "Field label is added."
2358
+ },
2359
+ ...!surfaces || surfaces.has("template") ? [
2360
+ {
2361
+ target: paths.template,
2362
+ action: "modify",
2363
+ applyScope: surfaces?.has("template") ? "auto" : "manual-review",
2364
+ reason: surfaces?.has("template") ? "Template form is selected for safe-pattern auto insertion." : "Form surface may include the field."
2365
+ }
2366
+ ] : [],
2367
+ {
2368
+ target: `${addFieldTargetRoot(typeof inputs.app === "string" ? inputs.app : null)}/lib/cnst.ts`,
2369
+ action: "sync",
2370
+ applyScope: "generated-sync",
2371
+ reason: "Generated constants may change after sync."
2372
+ },
2373
+ {
2374
+ target: `${addFieldTargetRoot(typeof inputs.app === "string" ? inputs.app : null)}/lib/dict.ts`,
2375
+ action: "sync",
2376
+ applyScope: "generated-sync",
2377
+ reason: "Generated dictionary barrel may change after sync."
2378
+ }
2379
+ ];
2380
+ };
2381
+ var createWorkflowPlanOptionalSurfaces = (spec, inputs) => {
2382
+ const optionalSurfaces = spec.optionalSurfaces ?? {};
2383
+ const surfaces = selectedAddFieldSurfaces(inputs);
2384
+ if (spec.name !== "add-field" || !surfaces)
2385
+ return optionalSurfaces;
2386
+ return Object.fromEntries(Object.entries(optionalSurfaces).map(([surface, mode]) => [surface, surfaces.has(surface) ? "include" : mode]));
2387
+ };
2388
+ var createWorkflowPlanRecommendations = (spec, inputs) => [
2389
+ {
2390
+ code: "workflow-apply-first",
2391
+ kind: "auto-apply",
2392
+ confidence: "high",
2393
+ action: "Call apply_workflow with the MCP planPath before editing source files directly.",
2394
+ message: `Apply the ${spec.name} plan through apply_workflow when MCP returns planPath or next.tool=apply_workflow.`
2395
+ },
2396
+ {
2397
+ code: "workflow-validate-apply-report",
2398
+ kind: "validation",
2399
+ confidence: "high",
2400
+ action: "After apply_workflow, call run_validation with validationTarget when present; otherwise use applyReportPath.",
2401
+ message: "Validate the apply report artifact so diagnostics and recommendations follow the actual apply result."
2402
+ },
2403
+ ...spec.name === "add-field" ? createAddFieldRecommendations(inputs) : []
2404
+ ];
2405
+ var createWorkflowPlan = (spec, rawInputs) => {
2406
+ const inputs = {};
2407
+ const diagnostics = [];
2408
+ for (const [name, inputSpec] of Object.entries(spec.inputs)) {
2409
+ const rawValue = rawInputs[name];
2410
+ if (rawValue === undefined || rawValue === null || rawValue === "") {
2411
+ if (inputSpec.required) {
2412
+ diagnostics.push({
2413
+ severity: "error",
2414
+ code: "workflow-input-missing",
2415
+ input: name,
2416
+ message: `Workflow ${spec.name} requires input "${name}".`
2417
+ });
2418
+ }
2419
+ continue;
2420
+ }
2421
+ const value = normalizeInputValue(name, inputSpec, rawValue);
2422
+ if (value === null) {
2423
+ diagnostics.push({
2424
+ severity: "error",
2425
+ code: "workflow-input-invalid",
2426
+ input: name,
2427
+ message: `Workflow ${spec.name} input "${name}" must be ${inputSpec.type}.`
2428
+ });
2429
+ continue;
2430
+ }
2431
+ if (inputSpec.allowedValues && typeof value === "string" && !inputSpec.allowedValues.includes(value)) {
2432
+ diagnostics.push({
2433
+ severity: "error",
2434
+ code: "workflow-input-not-allowed",
2435
+ input: name,
2436
+ message: `Workflow ${spec.name} input "${name}" must be one of: ${inputSpec.allowedValues.join(", ")}.`
2437
+ });
2438
+ continue;
2439
+ }
2440
+ inputs[name] = value;
2441
+ }
2442
+ const fieldType = inputs.type;
2443
+ if (spec.name === "add-field" && typeof fieldType === "string" && (fieldType.toLowerCase() === "number" || fieldType.toLowerCase() === "numeric")) {
2444
+ diagnostics.push({
2445
+ severity: "error",
2446
+ code: "primitive-field-type-unsupported",
2447
+ input: "type",
2448
+ message: `Field type "${fieldType}" is ambiguous in Akan. Use Int for integer fields or Float for decimal fields.`
2449
+ });
2450
+ }
2451
+ if (spec.name === "add-field") {
2452
+ const defaultCoercion = addFieldDefaultCoercion(inputs);
2453
+ if (defaultCoercion?.diagnostic) {
2454
+ diagnostics.push({
2455
+ ...defaultCoercion.diagnostic,
2456
+ code: "workflow-default-value-invalid",
2457
+ message: `Plan input default is not valid for ${defaultCoercion.normalizedType}: ${defaultCoercion.diagnostic.message}`
2458
+ });
2459
+ } else if (defaultCoercion?.normalized && defaultCoercion.expression) {
2460
+ diagnostics.push({
2461
+ severity: "warning",
2462
+ code: "workflow-default-value-normalized",
2463
+ input: "default",
2464
+ failureScope: "source-change",
2465
+ message: `Plan input default will be written as ${defaultCoercion.normalizedType} literal ${defaultCoercion.expression}.`
2466
+ });
2467
+ }
2468
+ }
2469
+ return {
2470
+ schemaVersion: 1,
2471
+ workflow: spec.name,
2472
+ mode: "plan",
2473
+ inputs,
2474
+ optionalSurfaces: createWorkflowPlanOptionalSurfaces(spec, inputs),
2475
+ steps: spec.steps,
2476
+ predictedChanges: createWorkflowPlanPredictedChanges(spec, inputs),
2477
+ validation: spec.validation,
2478
+ diagnostics,
2479
+ recommendations: createWorkflowPlanRecommendations(spec, inputs),
2480
+ requiresApproval: true,
2481
+ approval: workflowPlanApproval
2482
+ };
2483
+ };
2484
+ // pkgs/@akanjs/devkit/workflow/render.ts
2485
+ var renderWorkflowList = (specs) => [
2486
+ "# Akan Workflows",
2487
+ "",
2488
+ ...specs.flatMap((spec) => [`- \`${spec.name}\`: ${spec.description}`, ` - When: ${spec.whenToUse}`]),
2489
+ ""
2490
+ ].join(`
2491
+ `);
2492
+ var renderWorkflowExplain = (spec) => [
2493
+ `# Workflow: ${spec.name}`,
2494
+ "",
2495
+ spec.description,
2496
+ "",
2497
+ "## When To Use",
2498
+ spec.whenToUse,
2499
+ "",
2500
+ "## Inputs",
2501
+ ...Object.entries(spec.inputs).map(([name, input]) => `- \`${name}\`${input.required ? " (required)" : ""}: ${input.description}${input.allowedValues ? ` Allowed: ${input.allowedValues.join(", ")}.` : ""}`),
2502
+ "",
2503
+ "## Optional Surfaces",
2504
+ ...Object.entries(spec.optionalSurfaces ?? {}).map(([name, mode]) => `- \`${name}\`: ${mode}`),
2505
+ "",
2506
+ "## Steps",
2507
+ ...spec.steps.map((step, index) => `${index + 1}. \`${step.id}\` (${step.tool}): ${step.description}`),
2508
+ "",
2509
+ "## Validation",
2510
+ ...spec.validation.map((validation) => `- \`${validation.command}\`: ${validation.reason}`),
2511
+ ""
2512
+ ].join(`
2513
+ `);
2514
+ var renderWorkflowPlan = (plan) => [
2515
+ `# Workflow Plan: ${plan.workflow}`,
2516
+ "",
2517
+ `- Mode: ${plan.mode}`,
2518
+ `- Requires approval: ${plan.requiresApproval}`,
2519
+ `- Approval: ${plan.approval?.meaning ?? "Review this read-only plan before applying workflow mutations."}`,
2520
+ "",
2521
+ "## Inputs",
2522
+ ...Object.entries(plan.inputs).map(([name, value]) => `- \`${name}\`: ${Array.isArray(value) ? value.join(", ") : value}`),
2523
+ "",
2524
+ "## Optional Surfaces",
2525
+ ...Object.entries(plan.optionalSurfaces).map(([name, mode]) => `- \`${name}\`: ${mode}`),
2526
+ "",
2527
+ "## Steps",
2528
+ ...plan.steps.map((step, index) => `${index + 1}. \`${step.id}\` (${step.tool}): ${step.description}`),
2529
+ "",
2530
+ "## Predicted Changes",
2531
+ ...plan.predictedChanges.map((change) => {
2532
+ const scope = change.applyScope ? ` (${change.applyScope})` : "";
2533
+ return `- \`${change.action}\`${scope} ${change.target}: ${change.reason}`;
2534
+ }),
2535
+ "",
2536
+ "## Validation",
2537
+ ...plan.validation.map((validation) => `- \`${validation.command}\`: ${validation.reason}`),
2538
+ "",
2539
+ "## Diagnostics",
2540
+ ...plan.diagnostics.length ? plan.diagnostics.map((diagnostic) => `- [${diagnostic.severity}] ${diagnostic.code}: ${diagnostic.message}`) : ["- none"],
2541
+ "",
2542
+ "## Recommendations",
2543
+ ...plan.recommendations.length ? plan.recommendations.map((recommendation) => `- [${recommendation.kind}] ${recommendation.message}`) : ["- none"],
2544
+ ""
2545
+ ].join(`
2546
+ `);
2547
+ var renderRecommendation = (recommendation) => {
2548
+ const target = recommendation.target ? ` ${recommendation.target}` : "";
2549
+ const action = recommendation.action ? ` Action: ${recommendation.action}` : "";
2550
+ return `- [${recommendation.kind}]${target} ${recommendation.message}${action}`;
2551
+ };
2552
+ var renderDiagnostic = (diagnostic) => `- [${diagnostic.severity}] ${diagnostic.code}: ${diagnostic.message}`;
2553
+ var renderNextAction = (action) => `- \`${action.command}\`: ${action.reason}`;
2554
+ var applySourceStatus = (report) => report.diagnostics.some((diagnostic) => diagnostic.severity === "error" && (diagnostic.failureScope === "source-change" || !diagnostic.failureScope || diagnostic.failureScope === "unknown")) ? "failed" : "passed";
2555
+ var renderWorkflowApplyReport = (report) => {
2556
+ const applySummary = {
2557
+ sourceFilesChanged: report.summary?.sourceFilesChanged ?? report.changedFiles,
2558
+ generatedFilesSynced: report.summary?.generatedFilesSynced ?? report.generatedFiles
2559
+ };
2560
+ const manualReviewItems = [
2561
+ ...report.diagnostics.filter((diagnostic) => diagnostic.severity === "warning").map(renderDiagnostic),
2562
+ ...report.recommendations.filter((recommendation) => recommendation.kind === "manual-action").map(renderRecommendation)
2563
+ ];
2564
+ const validationBlockers = report.diagnostics.filter((diagnostic) => diagnostic.severity === "error" && (diagnostic.failureScope === "workspace-config" || diagnostic.failureScope === "environment")).map(renderDiagnostic);
2565
+ const sourceBlockers = report.diagnostics.filter((diagnostic) => diagnostic.severity === "error" && (diagnostic.failureScope === "source-change" || !diagnostic.failureScope || diagnostic.failureScope === "unknown")).map(renderDiagnostic);
2566
+ return [
2567
+ `# Workflow Apply: ${report.workflow}`,
2568
+ "",
2569
+ `- Mode: ${report.mode}`,
2570
+ `- Status: ${report.status}`,
2571
+ `- Source-change status: ${applySourceStatus(report)}`,
2572
+ `- Workspace status: ${validationBlockers.length ? "blocked" : "not blocked during apply"}`,
2573
+ `- Source files changed: ${applySummary.sourceFilesChanged.length}`,
2574
+ `- Generated files queued for sync: ${applySummary.generatedFilesSynced.length}`,
2575
+ ...report.validationTarget ? [`- Validation target: ${report.validationTarget}`] : [],
2576
+ "",
2577
+ "## Apply Checks",
2578
+ ...report.postApplyChecks?.length ? report.postApplyChecks.map((check) => `- [${check.status}] ${check.code} ${check.target}: ${check.message}`) : ["- not run"],
2579
+ "",
2580
+ "## Source Change Blockers",
2581
+ ...sourceBlockers.length ? sourceBlockers : ["- none"],
2582
+ "",
2583
+ "## Automatically Modified",
2584
+ ...applySummary.sourceFilesChanged.length ? applySummary.sourceFilesChanged.map((file) => `- \`${file.action}\` ${file.path}: ${file.reason}`) : ["- none"],
2585
+ "",
2586
+ "## Generated Sync",
2587
+ ...applySummary.generatedFilesSynced.length ? applySummary.generatedFilesSynced.map((file) => `- \`${file.action}\` ${file.path}: ${file.reason}`) : ["- none"],
2588
+ "",
2589
+ "## Applied Commands",
2590
+ ...report.appliedCommands.length ? report.appliedCommands.map((command) => `- \`${command.command}\`: ${command.reason}`) : ["- none"],
2591
+ "",
2592
+ "## Recommended Validation Commands",
2593
+ ...report.recommendedValidationCommands.length ? report.recommendedValidationCommands.map((command) => `- \`${command.command}\`: ${command.reason}`) : ["- none"],
2594
+ "",
2595
+ "## User Review Required",
2596
+ ...manualReviewItems.length ? manualReviewItems : ["- none"],
2597
+ "",
2598
+ "## Validation Blockers",
2599
+ ...validationBlockers.length ? validationBlockers : report.recommendedValidationCommands.length ? ["- none detected during apply; run validation with the validation target for command-level blockers."] : ["- none"],
2600
+ "",
2601
+ "## Diagnostics",
2602
+ ...report.diagnostics.length ? report.diagnostics.map(renderDiagnostic) : ["- none"],
2603
+ "",
2604
+ "## Recommendations",
2605
+ ...report.recommendations.length ? report.recommendations.slice(0, 3).map(renderRecommendation) : ["- none"],
2606
+ "",
2607
+ "## Next Actions",
2608
+ ...report.nextActions.length ? report.nextActions.slice(0, 3).map(renderNextAction) : ["- none"],
2609
+ ""
2610
+ ].join(`
2611
+ `);
2612
+ };
2613
+ var renderWorkflowApply = (report, format = "markdown") => format === "json" ? jsonText(report) : renderWorkflowApplyReport(report);
2614
+ var renderWorkflowValidationRunReport = (report) => {
2615
+ const baselineSummary = report.baselineSummary ?? {
2616
+ status: report.baselineDiagnostics?.some((diagnostic) => diagnostic.severity === "error") ? "failed" : "unknown",
2617
+ total: report.baselineDiagnostics?.length ?? 0,
2618
+ totalErrors: report.baselineDiagnostics?.filter((diagnostic) => diagnostic.severity === "error").length ?? 0,
2619
+ totalWarnings: report.baselineDiagnostics?.filter((diagnostic) => diagnostic.severity === "warning").length ?? 0,
2620
+ detailsIncluded: true,
2621
+ knownBlockerCount: report.knownBlockers.filter((blocker) => blocker.known).length,
2622
+ byCode: []
2623
+ };
2624
+ return [
2625
+ `# Workflow Validation: ${report.workflow}`,
2626
+ "",
2627
+ `- Run: ${report.runId}`,
2628
+ `- Status: ${report.status}`,
2629
+ `- Source status: ${report.sourceStatus}`,
2630
+ `- Workspace status: ${report.workspaceStatus}`,
2631
+ `- Validation commands status: ${report.validationCommandsStatus ?? "unknown"}`,
2632
+ `- Baseline status: ${report.baselineStatus ?? baselineSummary.status}`,
2633
+ `- Overall status: ${report.overallStatus}`,
2634
+ "",
2635
+ "## Status Summary",
2636
+ `- Source-change: ${report.summary.sourceChange}`,
2637
+ `- Generated sync: ${report.summary.generatedSync}`,
2638
+ `- Validation commands: ${report.summary.validationCommands ?? "unknown"}`,
2639
+ `- Baseline: ${report.summary.baseline ?? baselineSummary.status}`,
2640
+ `- Workspace config: ${report.summary.workspaceConfig}`,
2641
+ `- Environment: ${report.summary.environment}`,
2642
+ "",
2643
+ "## Source Change Diagnostics",
2644
+ ...report.workflowDiagnostics?.length ? report.workflowDiagnostics.map((diagnostic) => `- [${diagnostic.severity}] ${diagnostic.code}: ${diagnostic.message}`) : ["- none"],
2645
+ "",
2646
+ "## Existing Workspace Blockers",
2647
+ `- Status: ${baselineSummary.status}`,
2648
+ `- Errors: ${baselineSummary.totalErrors}`,
2649
+ `- Warnings: ${baselineSummary.totalWarnings}`,
2650
+ ...baselineSummary.byCode.length ? baselineSummary.byCode.map((item) => `- [${item.severity}] ${item.code} (${item.count}x): ${item.sampleMessage}`) : ["- none"],
2651
+ ...baselineSummary.detailsIncluded ? [] : [
2652
+ "- Baseline details are summarized by default. Re-run validation with includeBaselineDetails=true for full baselineDiagnostics."
2653
+ ],
2654
+ "",
2655
+ "## Existing Workspace Blocker Details",
2656
+ ...report.baselineDiagnostics?.length ? report.baselineDiagnostics.map((diagnostic) => `- [${diagnostic.severity}] ${diagnostic.code}: ${diagnostic.message}`) : baselineSummary.detailsIncluded ? ["- none"] : ["- omitted"],
2657
+ "",
2658
+ "## Known Blockers",
2659
+ ...report.knownBlockers.length ? report.knownBlockers.map((blocker) => {
2660
+ const command = blocker.command ? ` \`${blocker.command}\`` : "";
2661
+ const count = blocker.count > 1 ? ` (${blocker.count}x)` : "";
2662
+ const known = blocker.known ? " known" : "";
2663
+ return `- [${blocker.failureScope}${known}]${command}${count}: ${blocker.message}`;
2664
+ }) : ["- none"],
2665
+ "",
2666
+ "## Commands",
2667
+ ...report.commands.length ? report.commands.map((command) => {
2668
+ const scope = command.failureScope ? ` (${command.failureScope})` : "";
2669
+ return `- [${command.status}] \`${command.command}\`${scope}: ${command.reason}`;
2670
+ }) : ["- none"],
2671
+ "",
2672
+ "## Diagnostics",
2673
+ ...report.diagnostics.length ? report.diagnostics.map((diagnostic) => `- [${diagnostic.severity}] ${diagnostic.code}: ${diagnostic.message}`) : ["- none"],
2674
+ "",
2675
+ "## Repair Actions",
2676
+ ...report.repairActions.length ? report.repairActions.map((action) => `- \`${action.command}\`: ${action.reason}`) : ["- none"],
2677
+ "",
2678
+ "## Next Actions",
2679
+ ...report.nextActions.length ? report.nextActions.map((action) => `- \`${action.command}\`: ${action.reason}`) : ["- none"],
2680
+ ""
2681
+ ].join(`
2682
+ `);
2683
+ };
2684
+ var renderWorkflowValidation = (report, format = "markdown") => format === "json" ? jsonText(report) : renderWorkflowValidationRunReport(report);
2685
+ var renderRepairReportMarkdown = (report) => [
2686
+ `# Akan Repair: ${report.kind}`,
2687
+ "",
2688
+ `- Status: ${report.status}`,
2689
+ `- Target: ${report.target ?? "none"}`,
2690
+ "",
2691
+ "## Commands",
2692
+ ...report.commands.length ? report.commands.map((command) => `- [${command.status}] \`${command.command}\`: ${command.reason}`) : ["- none"],
2693
+ "",
2694
+ "## Diagnostics",
2695
+ ...report.diagnostics.length ? report.diagnostics.map((diagnostic) => `- [${diagnostic.severity}] ${diagnostic.code}: ${diagnostic.message}`) : ["- none"],
2696
+ "",
2697
+ "## Next Actions",
2698
+ ...report.nextActions.length ? report.nextActions.map((action) => `- \`${action.command}\`: ${action.reason}`) : ["- none"],
2699
+ ""
2700
+ ].join(`
2701
+ `);
2702
+ var renderRepairReport = (report, format = "markdown") => format === "json" ? jsonText(report) : renderRepairReportMarkdown(report);
2703
+ var renderWorkflowRunArtifact = (artifact, format = "markdown") => {
2704
+ if ("kind" in artifact)
2705
+ return renderRepairReport(artifact, format);
2706
+ if ("mode" in artifact && artifact.mode === "validate")
2707
+ return renderWorkflowValidation(artifact, format);
2708
+ if ("mode" in artifact && (artifact.mode === "apply" || artifact.mode === "dry-run")) {
2709
+ return renderWorkflowApply(artifact, format);
2710
+ }
2711
+ return jsonText(artifact);
2712
+ };
2713
+ // pkgs/@akanjs/devkit/workflow/rolloutGate.ts
2714
+ var toolingRolloutCandidates = [
2715
+ {
2716
+ packageName: "typescript",
2717
+ status: "allowed",
2718
+ role: "Primary TypeScript Compiler API baseline for AST locator, text splice, and reparse checks.",
2719
+ adoptionGate: "Already present; keep using stable Bun-compatible package builds."
2720
+ },
2721
+ {
2722
+ packageName: "@ttsc/graph",
2723
+ status: "reference-only",
2724
+ role: "Source-free graph shape and lazy resident model reference.",
2725
+ adoptionGate: "Do not add as an Akan runtime dependency without a separate proposal or milestone update."
2726
+ },
2727
+ {
2728
+ packageName: "ts-morph",
2729
+ status: "experiment-only",
2730
+ role: "Prototype candidate for complex object literal insertion, import update, and class traversal.",
2731
+ adoptionGate: "Use only in isolated prototypes until package size and formatting churn are measured."
2732
+ },
2733
+ {
2734
+ packageName: "ast-grep",
2735
+ status: "experiment-only",
2736
+ role: "Prototype candidate for shape detection, CI rules, and migration rules.",
2737
+ adoptionGate: "Use as a local rule/check experiment, not as the edit engine."
2738
+ },
2739
+ {
2740
+ packageName: "recast",
2741
+ status: "experiment-only",
2742
+ role: "Prototype candidate for formatting preservation.",
2743
+ adoptionGate: "Low priority; require proof that formatting churn is lower than the baseline."
2744
+ },
2745
+ {
2746
+ packageName: "typescript-go",
2747
+ status: "blocked",
2748
+ role: "TypeScript-Go toolchain transition placeholder.",
2749
+ adoptionGate: "Out of scope for Season 2 rollout."
2750
+ },
2751
+ {
2752
+ packageName: "@typescript/native-preview",
2753
+ status: "blocked",
2754
+ role: "TypeScript-Go native preview package placeholder.",
2755
+ adoptionGate: "Out of scope for Season 2 rollout."
2756
+ }
2757
+ ];
2758
+ var toolingRolloutGate = {
2759
+ schemaVersion: 1,
2760
+ strategy: "reference-first-dependency-later",
2761
+ dependencyPolicy: "Season 2 keeps new AST and graph tooling as references or isolated experiments until a separate proposal or milestone update approves adoption.",
2762
+ gateConditions: [
2763
+ "Works in Bun runtime and published package artifacts.",
2764
+ "Does not break dist/pkgs package verification.",
2765
+ "Keeps generated source formatting churn limited.",
2766
+ "Reduces add-field regression fixture failures compared with the current TypeScript API baseline.",
2767
+ "Does not move MCP responses toward returning source bodies."
2768
+ ],
2769
+ candidates: toolingRolloutCandidates
2770
+ };
2771
+ var isRestrictedCandidate = (candidate) => candidate.status !== "allowed";
2772
+ var restrictedCandidates = new Map;
2773
+ for (const candidate of toolingRolloutCandidates) {
2774
+ if (isRestrictedCandidate(candidate))
2775
+ restrictedCandidates.set(candidate.packageName, candidate);
2776
+ }
2777
+ export { jsonText, compactDiagnostics, workflowPlanApproval, createWorkflowApplyReport, workflowCommandsForPlan, workflowRunArtifactPath, writeWorkflowRunArtifact, workflowSyncDir, generatedFilePathsForTarget, writeGeneratedSyncState, readWorkflowRunArtifact, createWorkflowBaselineSummary, createWorkflowValidationRunReport, createDryRunWorkflowApplyReport, createRepairReport, createPrimitiveWriteReport, renderPrimitiveReport, sourceFile, moduleComponentName, moduleSourcePaths, generatedFilesForSync, validationCommandsForTarget, nextActionsForTarget, createPassedPrimitiveReport, scalarChangedFiles, lowerlize, bilingualLabelForField, bilingualDescriptionForField, normalizeFieldType, ensureBaseTypeImport, coerceFieldDefault, fieldExpression, viaBuilderParameterName, insertIntoObject, insertLightProjectionField, insertTemplateField, ensureEnumImport, insertEnumClass, insertDictionaryModelField, hasConstantInputField, hasDictionaryModelField, ensureConstantTypeImport, insertDictionaryEnum, parseValues, hasSourceParseErrors, hasClassMethod, insertClassMethod, hasSignalFactoryEntry, insertSignalFactoryEntry, buildAkanModuleContextIndex, addFieldUiPolicyForType, createWorkflowStepRegistry, WorkflowExecutor, listWorkflowSpecs, getWorkflowSpec, compactWorkflowInputs, createWorkflowPlan, renderWorkflowList, renderWorkflowExplain, renderWorkflowPlan, renderWorkflowApply, renderWorkflowValidation, renderRepairReport, renderWorkflowRunArtifact, toolingRolloutGate };