@lssm/module.contractspec-workspace 0.0.0-canary-20251217063201 → 0.0.0-canary-20251217073102
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.
- package/dist/ai/code-generation.js +50 -13
- package/dist/ai/spec-creation.js +50 -18
- package/dist/analysis/deps/graph.js +84 -2
- package/dist/analysis/deps/parse-imports.js +30 -1
- package/dist/analysis/diff/semantic.js +96 -1
- package/dist/analysis/feature-scan.js +151 -1
- package/dist/analysis/spec-scan.js +344 -1
- package/dist/analysis/validate/spec-structure.js +122 -1
- package/dist/index.js +25 -1
- package/dist/templates/app-config.js +100 -28
- package/dist/templates/data-view.js +41 -27
- package/dist/templates/event.js +28 -14
- package/dist/templates/experiment.js +76 -51
- package/dist/templates/handler.js +49 -17
- package/dist/templates/integration-utils.js +97 -26
- package/dist/templates/integration.js +46 -23
- package/dist/templates/knowledge.js +59 -19
- package/dist/templates/migration.js +49 -26
- package/dist/templates/operation.js +40 -28
- package/dist/templates/presentation.js +45 -20
- package/dist/templates/telemetry.js +73 -53
- package/dist/templates/utils.js +38 -1
- package/dist/templates/workflow-runner.js +12 -6
- package/dist/templates/workflow.js +50 -24
- package/dist/types/generation-types.js +20 -1
- package/package.json +5 -5
|
@@ -1,69 +1,89 @@
|
|
|
1
|
-
import{toPascalCase
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
`
|
|
7
|
-
|
|
8
|
-
type: '${
|
|
9
|
-
${
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}
|
|
14
|
-
|
|
1
|
+
import { toPascalCase } from "./utils.js";
|
|
2
|
+
|
|
3
|
+
//#region src/templates/telemetry.ts
|
|
4
|
+
function generateTelemetrySpec(data) {
|
|
5
|
+
const specVar = toPascalCase(data.name.split(".").pop() ?? "Telemetry") + "Telemetry";
|
|
6
|
+
const providers = data.providers?.length ? `providers: [
|
|
7
|
+
${data.providers.map((provider) => ` {
|
|
8
|
+
type: '${provider.type}',
|
|
9
|
+
config: ${formatConfigValue(provider.config)},
|
|
10
|
+
}`).join(",\n")}
|
|
11
|
+
],` : "";
|
|
12
|
+
const events = data.events.map((event) => {
|
|
13
|
+
const properties = event.properties.map((prop) => ` '${prop.name}': {
|
|
14
|
+
type: '${prop.type}',
|
|
15
|
+
${prop.required ? "required: true," : ""}
|
|
16
|
+
${prop.pii ? "pii: true," : ""}
|
|
17
|
+
${prop.redact ? "redact: true," : ""}
|
|
18
|
+
${prop.description ? `description: '${escapeString(prop.description)}',` : ""}
|
|
19
|
+
}`).join(",\n");
|
|
20
|
+
const anomalyRules = event.anomalyRules?.length ? ` anomalyDetection: {
|
|
15
21
|
enabled: true,
|
|
16
|
-
${typeof
|
|
22
|
+
${typeof event.anomalyMinimumSample === "number" ? `minimumSample: ${event.anomalyMinimumSample},` : ""}
|
|
17
23
|
thresholds: [
|
|
18
|
-
${
|
|
19
|
-
metric: '${
|
|
20
|
-
${typeof
|
|
21
|
-
${typeof
|
|
22
|
-
}`).join(
|
|
23
|
-
`)}
|
|
24
|
+
${event.anomalyRules.map((rule) => ` {
|
|
25
|
+
metric: '${escapeString(rule.metric)}',
|
|
26
|
+
${typeof rule.min === "number" ? `min: ${rule.min},` : ""}
|
|
27
|
+
${typeof rule.max === "number" ? `max: ${rule.max},` : ""}
|
|
28
|
+
}`).join(",\n")}
|
|
24
29
|
],
|
|
25
|
-
actions: [${(
|
|
26
|
-
}
|
|
30
|
+
actions: [${(event.anomalyActions ?? []).map((action) => `'${action}'`).join(", ")}],
|
|
31
|
+
},` : event.anomalyEnabled ? ` anomalyDetection: {
|
|
27
32
|
enabled: true,
|
|
28
|
-
${typeof
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
|
|
33
|
+
${typeof event.anomalyMinimumSample === "number" ? `minimumSample: ${event.anomalyMinimumSample},` : ""}
|
|
34
|
+
},` : "";
|
|
35
|
+
return ` {
|
|
36
|
+
name: '${escapeString(event.name)}',
|
|
37
|
+
version: ${event.version},
|
|
32
38
|
semantics: {
|
|
33
|
-
what: '${
|
|
34
|
-
${
|
|
35
|
-
${
|
|
39
|
+
what: '${escapeString(event.what)}',
|
|
40
|
+
${event.who ? `who: '${escapeString(event.who)}',` : ""}
|
|
41
|
+
${event.why ? `why: '${escapeString(event.why)}',` : ""}
|
|
36
42
|
},
|
|
37
|
-
privacy: '${
|
|
43
|
+
privacy: '${event.privacy}',
|
|
38
44
|
properties: {
|
|
39
|
-
${
|
|
45
|
+
${properties}
|
|
40
46
|
},
|
|
41
|
-
${typeof
|
|
42
|
-
${typeof
|
|
43
|
-
${
|
|
44
|
-
${
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
+
${typeof event.retentionDays === "number" ? `retention: { days: ${event.retentionDays}, ${event.retentionPolicy ? `policy: '${event.retentionPolicy}'` : ""} },` : ""}
|
|
48
|
+
${typeof event.samplingRate === "number" ? `sampling: { rate: ${event.samplingRate}${event.samplingConditions ? `, conditions: ['${escapeString(event.samplingConditions)}']` : ""} },` : ""}
|
|
49
|
+
${anomalyRules}
|
|
50
|
+
${event.tags?.length ? `tags: [${event.tags.map((tag) => `'${escapeString(tag)}'`).join(", ")}],` : ""}
|
|
51
|
+
}`;
|
|
52
|
+
}).join(",\n");
|
|
53
|
+
return `import type { TelemetrySpec } from '@lssm/lib.contracts/telemetry';
|
|
47
54
|
|
|
48
|
-
export const ${
|
|
55
|
+
export const ${specVar}: TelemetrySpec = {
|
|
49
56
|
meta: {
|
|
50
|
-
name: '${
|
|
51
|
-
version: ${
|
|
52
|
-
title: '${
|
|
53
|
-
description: '${
|
|
54
|
-
domain: '${
|
|
55
|
-
owners: [${
|
|
56
|
-
tags: [${
|
|
57
|
-
stability: '${
|
|
57
|
+
name: '${escapeString(data.name)}',
|
|
58
|
+
version: ${data.version},
|
|
59
|
+
title: '${escapeString(data.name)} telemetry',
|
|
60
|
+
description: '${escapeString(data.description || "Describe the purpose of this telemetry spec.")}',
|
|
61
|
+
domain: '${escapeString(data.domain)}',
|
|
62
|
+
owners: [${data.owners.map((owner) => `'${escapeString(owner)}'`).join(", ")}],
|
|
63
|
+
tags: [${data.tags.map((tag) => `'${escapeString(tag)}'`).join(", ")}],
|
|
64
|
+
stability: '${data.stability}',
|
|
58
65
|
},
|
|
59
66
|
config: {
|
|
60
|
-
${typeof
|
|
61
|
-
${typeof
|
|
62
|
-
${
|
|
63
|
-
${
|
|
67
|
+
${typeof data.defaultRetentionDays === "number" ? `defaultRetentionDays: ${data.defaultRetentionDays},` : ""}
|
|
68
|
+
${typeof data.defaultSamplingRate === "number" ? `defaultSamplingRate: ${data.defaultSamplingRate},` : ""}
|
|
69
|
+
${data.anomalyEnabled ? `anomalyDetection: { enabled: true${typeof data.anomalyCheckIntervalMs === "number" ? `, checkIntervalMs: ${data.anomalyCheckIntervalMs}` : ""} },` : ""}
|
|
70
|
+
${providers}
|
|
64
71
|
},
|
|
65
72
|
events: [
|
|
66
|
-
${
|
|
73
|
+
${events}
|
|
67
74
|
],
|
|
68
75
|
};
|
|
69
|
-
|
|
76
|
+
`;
|
|
77
|
+
}
|
|
78
|
+
function escapeString(value) {
|
|
79
|
+
return value.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
|
|
80
|
+
}
|
|
81
|
+
function formatConfigValue(value) {
|
|
82
|
+
const trimmed = value.trim();
|
|
83
|
+
if (!trimmed) return "{}";
|
|
84
|
+
if (trimmed.startsWith("{") && trimmed.endsWith("}") || trimmed.startsWith("[") && trimmed.endsWith("]")) return trimmed;
|
|
85
|
+
return `'${escapeString(trimmed)}'`;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
//#endregion
|
|
89
|
+
export { generateTelemetrySpec };
|
package/dist/templates/utils.js
CHANGED
|
@@ -1 +1,38 @@
|
|
|
1
|
-
|
|
1
|
+
//#region src/templates/utils.ts
|
|
2
|
+
/**
|
|
3
|
+
* Utility functions for template generation.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Convert string to camelCase.
|
|
7
|
+
*/
|
|
8
|
+
function toCamelCase(str) {
|
|
9
|
+
const pascal = toPascalCase(str);
|
|
10
|
+
return pascal.charAt(0).toLowerCase() + pascal.slice(1);
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Convert string to PascalCase.
|
|
14
|
+
*/
|
|
15
|
+
function toPascalCase(str) {
|
|
16
|
+
return str.split(/[-_.]/).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Convert string to kebab-case.
|
|
20
|
+
*/
|
|
21
|
+
function toKebabCase(str) {
|
|
22
|
+
return str.replace(/\./g, "-").replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Capitalize first letter.
|
|
26
|
+
*/
|
|
27
|
+
function capitalize(str) {
|
|
28
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Escape single quotes in string.
|
|
32
|
+
*/
|
|
33
|
+
function escapeString(value) {
|
|
34
|
+
return value.replace(/'/g, "\\'");
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
//#endregion
|
|
38
|
+
export { capitalize, escapeString, toCamelCase, toKebabCase, toPascalCase };
|
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
|
|
1
|
+
//#region src/templates/workflow-runner.ts
|
|
2
|
+
function generateWorkflowRunnerTemplate({ exportName, specImportPath, runnerName, workflowName }) {
|
|
3
|
+
return `import {
|
|
2
4
|
InMemoryStateStore,
|
|
3
5
|
WorkflowRegistry,
|
|
4
6
|
WorkflowRunner,
|
|
5
7
|
} from '@lssm/lib.contracts/workflow';
|
|
6
|
-
import { ${
|
|
8
|
+
import { ${exportName} } from '${specImportPath}';
|
|
7
9
|
|
|
8
10
|
/**
|
|
9
|
-
* Runner wiring for ${
|
|
11
|
+
* Runner wiring for ${workflowName}.
|
|
10
12
|
*
|
|
11
13
|
* TODO:
|
|
12
14
|
* - Replace the in-memory state store with a persistent adapter if needed.
|
|
@@ -14,11 +16,11 @@ import { ${e} } from '${t}';
|
|
|
14
16
|
* - Wire eventEmitter to telemetry sinks.
|
|
15
17
|
*/
|
|
16
18
|
const registry = new WorkflowRegistry();
|
|
17
|
-
registry.register(${
|
|
19
|
+
registry.register(${exportName});
|
|
18
20
|
|
|
19
21
|
const stateStore = new InMemoryStateStore();
|
|
20
22
|
|
|
21
|
-
export const ${
|
|
23
|
+
export const ${runnerName} = new WorkflowRunner({
|
|
22
24
|
registry,
|
|
23
25
|
stateStore,
|
|
24
26
|
opExecutor: async (operation, input, ctx) => {
|
|
@@ -39,4 +41,8 @@ export const ${n} = new WorkflowRunner({
|
|
|
39
41
|
// TODO: forward workflow events to telemetry or logging sinks
|
|
40
42
|
},
|
|
41
43
|
});
|
|
42
|
-
|
|
44
|
+
`;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
//#endregion
|
|
48
|
+
export { generateWorkflowRunnerTemplate };
|
|
@@ -1,10 +1,18 @@
|
|
|
1
|
-
import{escapeString
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
import { escapeString, toPascalCase } from "./utils.js";
|
|
2
|
+
|
|
3
|
+
//#region src/templates/workflow.ts
|
|
4
|
+
/**
|
|
5
|
+
* Generate workflow spec TypeScript code.
|
|
6
|
+
*/
|
|
7
|
+
function generateWorkflowSpec(data) {
|
|
8
|
+
const specVarName = toPascalCase(data.name.split(".").pop() ?? "Workflow") + "Workflow";
|
|
9
|
+
const stepsCode = data.steps.map((step) => formatStep(step)).join(",\n");
|
|
10
|
+
const transitionsCode = data.transitions.map((transition) => ` {
|
|
11
|
+
from: '${transition.from}',
|
|
12
|
+
to: '${transition.to}',
|
|
13
|
+
${transition.condition ? ` condition: '${escapeString(transition.condition)}',` : ""}
|
|
14
|
+
}`).join(",\n");
|
|
15
|
+
return `import type { WorkflowSpec } from '@lssm/lib.contracts/workflow';
|
|
8
16
|
|
|
9
17
|
/**
|
|
10
18
|
* Workflow generated via contractspec CLI.
|
|
@@ -14,28 +22,46 @@ ${t.condition?` condition: '${e(t.condition)}',`:``}
|
|
|
14
22
|
* - Provide form renderers for human steps.
|
|
15
23
|
* - Add guards/conditions as needed.
|
|
16
24
|
*/
|
|
17
|
-
export const ${
|
|
25
|
+
export const ${specVarName}: WorkflowSpec = {
|
|
18
26
|
meta: {
|
|
19
|
-
name: '${
|
|
20
|
-
version: ${
|
|
21
|
-
title: '${
|
|
22
|
-
description: '${
|
|
23
|
-
domain: '${
|
|
24
|
-
stability: '${
|
|
25
|
-
owners: [${
|
|
26
|
-
tags: [${
|
|
27
|
+
name: '${data.name}',
|
|
28
|
+
version: ${data.version},
|
|
29
|
+
title: '${escapeString(data.title)}',
|
|
30
|
+
description: '${escapeString(data.description)}',
|
|
31
|
+
domain: '${escapeString(data.domain)}',
|
|
32
|
+
stability: '${data.stability}',
|
|
33
|
+
owners: [${data.owners.map((owner) => `'${owner}'`).join(", ")}],
|
|
34
|
+
tags: [${data.tags.map((tag) => `'${tag}'`).join(", ")}],
|
|
27
35
|
},
|
|
28
36
|
definition: {
|
|
29
|
-
${
|
|
30
|
-
${
|
|
37
|
+
${data.entryStepId ? ` entryStepId: '${data.entryStepId}',\n` : ""} steps: [
|
|
38
|
+
${stepsCode}
|
|
31
39
|
],
|
|
32
40
|
transitions: [
|
|
33
|
-
${
|
|
41
|
+
${transitionsCode}
|
|
34
42
|
],
|
|
35
43
|
},
|
|
36
|
-
${
|
|
37
|
-
flags: [${
|
|
38
|
-
}
|
|
44
|
+
${data.policyFlags.length > 0 ? `policy: {
|
|
45
|
+
flags: [${data.policyFlags.map((flag) => `'${flag}'`).join(", ")}],
|
|
46
|
+
},` : "// policy: { flags: [] },"}
|
|
39
47
|
};
|
|
40
|
-
|
|
41
|
-
|
|
48
|
+
`;
|
|
49
|
+
}
|
|
50
|
+
function formatStep(step) {
|
|
51
|
+
const lines = [
|
|
52
|
+
` {`,
|
|
53
|
+
` id: '${step.id}',`,
|
|
54
|
+
` type: '${step.type}',`,
|
|
55
|
+
` label: '${escapeString(step.label)}',`
|
|
56
|
+
];
|
|
57
|
+
if (step.description) lines.push(` description: '${escapeString(step.description)}',`);
|
|
58
|
+
const actionLines = [];
|
|
59
|
+
if (step.operation) actionLines.push(`operation: { name: '${step.operation.name}', version: ${step.operation.version} }`);
|
|
60
|
+
if (step.form) actionLines.push(`form: { key: '${step.form.key}', version: ${step.form.version} }`);
|
|
61
|
+
if (actionLines.length) lines.push(` action: { ${actionLines.join(", ")} },`);
|
|
62
|
+
lines.push(` }`);
|
|
63
|
+
return lines.join("\n");
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
//#endregion
|
|
67
|
+
export { generateWorkflowSpec };
|
|
@@ -1 +1,20 @@
|
|
|
1
|
-
|
|
1
|
+
//#region src/types/generation-types.ts
|
|
2
|
+
/**
|
|
3
|
+
* Default workspace configuration.
|
|
4
|
+
*/
|
|
5
|
+
const DEFAULT_WORKSPACE_CONFIG = {
|
|
6
|
+
aiProvider: "claude",
|
|
7
|
+
agentMode: "simple",
|
|
8
|
+
outputDir: "./src",
|
|
9
|
+
conventions: {
|
|
10
|
+
operations: "interactions/commands|queries",
|
|
11
|
+
events: "events",
|
|
12
|
+
presentations: "presentations",
|
|
13
|
+
forms: "forms"
|
|
14
|
+
},
|
|
15
|
+
defaultOwners: [],
|
|
16
|
+
defaultTags: []
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
//#endregion
|
|
20
|
+
export { DEFAULT_WORKSPACE_CONFIG };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lssm/module.contractspec-workspace",
|
|
3
|
-
"version": "0.0.0-canary-
|
|
3
|
+
"version": "0.0.0-canary-20251217073102",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -23,13 +23,13 @@
|
|
|
23
23
|
"test": "bun run"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@lssm/lib.contracts": "0.0.0-canary-
|
|
27
|
-
"@lssm/lib.schema": "0.0.0-canary-
|
|
26
|
+
"@lssm/lib.contracts": "0.0.0-canary-20251217073102",
|
|
27
|
+
"@lssm/lib.schema": "0.0.0-canary-20251217073102",
|
|
28
28
|
"zod": "^4.1.13"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
|
-
"@lssm/tool.tsdown": "0.0.0-canary-
|
|
32
|
-
"@lssm/tool.typescript": "0.0.0-canary-
|
|
31
|
+
"@lssm/tool.tsdown": "0.0.0-canary-20251217073102",
|
|
32
|
+
"@lssm/tool.typescript": "0.0.0-canary-20251217073102",
|
|
33
33
|
"tsdown": "^0.17.4",
|
|
34
34
|
"typescript": "^5.9.3"
|
|
35
35
|
},
|