@lssm/module.contractspec-workspace 0.0.0-canary-20251213172311
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/README.md +39 -0
- package/dist/ai/code-generation.js +100 -0
- package/dist/ai/spec-creation.js +69 -0
- package/dist/analysis/deps/graph.js +2 -0
- package/dist/analysis/deps/parse-imports.js +1 -0
- package/dist/analysis/diff/semantic.js +1 -0
- package/dist/analysis/spec-scan.js +1 -0
- package/dist/analysis/validate/spec-structure.js +1 -0
- package/dist/index.js +1 -0
- package/dist/templates/app-config.js +33 -0
- package/dist/templates/data-view.js +54 -0
- package/dist/templates/event.js +24 -0
- package/dist/templates/experiment.js +62 -0
- package/dist/templates/handler.js +63 -0
- package/dist/templates/integration-utils.js +33 -0
- package/dist/templates/integration.js +39 -0
- package/dist/templates/knowledge.js +28 -0
- package/dist/templates/migration.js +37 -0
- package/dist/templates/operation.js +88 -0
- package/dist/templates/presentation.js +53 -0
- package/dist/templates/telemetry.js +69 -0
- package/dist/templates/utils.js +1 -0
- package/dist/templates/workflow-runner.js +42 -0
- package/dist/templates/workflow.js +41 -0
- package/dist/types/generation-types.js +1 -0
- package/package.json +46 -0
package/README.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# @lssm/module.contractspec-workspace
|
|
2
|
+
|
|
3
|
+
Pure, deterministic domain logic and static analysis utilities for ContractSpec workspace operations.
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
|
|
7
|
+
This module contains platform-agnostic logic used by ContractSpec tooling:
|
|
8
|
+
|
|
9
|
+
- **Types**: Shared type definitions for specs, templates, and analysis results
|
|
10
|
+
- **Analysis**: Static code analysis (spec scanning, dependency graphs, semantic diff)
|
|
11
|
+
- **Templates**: Code generation templates for specs and handlers
|
|
12
|
+
- **AI Prompts**: Prompt builders for AI-assisted spec creation and code generation
|
|
13
|
+
|
|
14
|
+
## Design Principles
|
|
15
|
+
|
|
16
|
+
- **No side effects**: All functions are pure and deterministic
|
|
17
|
+
- **No CLI dependencies**: No `chalk`, `ora`, `commander`, or `inquirer`
|
|
18
|
+
- **No filesystem access**: Operations take code/data as input, return results
|
|
19
|
+
- **Reusable**: Can be used by CLI, web apps, VS Code extensions, etc.
|
|
20
|
+
|
|
21
|
+
## Usage
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
import {
|
|
25
|
+
scanSpecSource,
|
|
26
|
+
computeSemanticDiff,
|
|
27
|
+
buildDependencyGraph,
|
|
28
|
+
validateSpecStructure,
|
|
29
|
+
generateOperationSpec,
|
|
30
|
+
} from '@lssm/module.contractspec-workspace';
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Exports
|
|
34
|
+
|
|
35
|
+
- `analysis/` - Static analysis utilities
|
|
36
|
+
- `templates/` - Code generation templates
|
|
37
|
+
- `ai/` - AI prompt builders
|
|
38
|
+
- `types/` - Shared type definitions
|
|
39
|
+
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
function e(e){return`You are a senior TypeScript developer implementing a handler for a contract specification.
|
|
2
|
+
|
|
3
|
+
Here is the contract spec:
|
|
4
|
+
|
|
5
|
+
\`\`\`typescript
|
|
6
|
+
${e}
|
|
7
|
+
\`\`\`
|
|
8
|
+
|
|
9
|
+
Generate a complete handler implementation that:
|
|
10
|
+
|
|
11
|
+
1. **Matches the spec signature**: Input/output types from the spec
|
|
12
|
+
2. **Handles errors**: Implement error cases defined in spec.io.errors
|
|
13
|
+
3. **Emits events**: Use the events declared in spec.sideEffects.emits
|
|
14
|
+
4. **Validates input**: Use zod validation from the schema
|
|
15
|
+
5. **Follows best practices**: Clean, type-safe TypeScript
|
|
16
|
+
6. **Includes comments**: Explain business logic
|
|
17
|
+
|
|
18
|
+
The handler should be production-ready with proper error handling, logging points, and clear structure.
|
|
19
|
+
|
|
20
|
+
Return only the TypeScript code for the handler function.`}function t(e){return`You are a senior React developer creating a component for a presentation specification.
|
|
21
|
+
|
|
22
|
+
Here is the presentation spec:
|
|
23
|
+
|
|
24
|
+
\`\`\`typescript
|
|
25
|
+
${e}
|
|
26
|
+
\`\`\`
|
|
27
|
+
|
|
28
|
+
Generate a complete React component that:
|
|
29
|
+
|
|
30
|
+
1. **Props interface**: Typed props from the spec
|
|
31
|
+
2. **Accessibility**: Proper ARIA labels, roles, keyboard navigation
|
|
32
|
+
3. **Mobile-first**: Optimized for small screens and touch
|
|
33
|
+
4. **Clean UI**: Simple, intuitive interface
|
|
34
|
+
5. **Type-safe**: Full TypeScript with no 'any' types
|
|
35
|
+
6. **Best practices**: React hooks, proper state management
|
|
36
|
+
|
|
37
|
+
The component should follow Atomic Design principles and be reusable.
|
|
38
|
+
|
|
39
|
+
Return only the TypeScript/TSX code for the component.`}function n(e){return`You are a senior React developer creating a form component from a form specification.
|
|
40
|
+
|
|
41
|
+
Here is the form spec:
|
|
42
|
+
|
|
43
|
+
\`\`\`typescript
|
|
44
|
+
${e}
|
|
45
|
+
\`\`\`
|
|
46
|
+
|
|
47
|
+
Generate a complete form component using react-hook-form that:
|
|
48
|
+
|
|
49
|
+
1. **Form validation**: Use zod schema for validation
|
|
50
|
+
2. **Field types**: Proper inputs for each field type
|
|
51
|
+
3. **Conditional logic**: Support visibleWhen, enabledWhen, requiredWhen predicates
|
|
52
|
+
4. **Error handling**: Clear, user-friendly error messages
|
|
53
|
+
5. **Accessibility**: Labels, hints, ARIA attributes
|
|
54
|
+
6. **Mobile-optimized**: Touch-friendly, appropriate input types
|
|
55
|
+
7. **Type-safe**: Full TypeScript
|
|
56
|
+
|
|
57
|
+
The form should provide excellent UX with real-time validation and helpful feedback.
|
|
58
|
+
|
|
59
|
+
Return only the TypeScript/TSX code for the form component.`}function r(e,t,n){return`You are a senior developer writing comprehensive tests.
|
|
60
|
+
|
|
61
|
+
Spec:
|
|
62
|
+
\`\`\`typescript
|
|
63
|
+
${e}
|
|
64
|
+
\`\`\`
|
|
65
|
+
|
|
66
|
+
Implementation:
|
|
67
|
+
\`\`\`typescript
|
|
68
|
+
${t}
|
|
69
|
+
\`\`\`
|
|
70
|
+
|
|
71
|
+
Generate complete test suite using Vitest that:
|
|
72
|
+
${n===`handler`?`
|
|
73
|
+
- Test all acceptance scenarios from the spec
|
|
74
|
+
- Test error cases defined in spec.io.errors
|
|
75
|
+
- Verify events are emitted correctly
|
|
76
|
+
- Test input validation
|
|
77
|
+
- Test happy path and edge cases`:`
|
|
78
|
+
- Test rendering with various props
|
|
79
|
+
- Test user interactions
|
|
80
|
+
- Test accessibility (a11y)
|
|
81
|
+
- Test responsive behavior
|
|
82
|
+
- Test error states`}
|
|
83
|
+
|
|
84
|
+
Use clear test descriptions and follow AAA pattern (Arrange, Act, Assert).
|
|
85
|
+
|
|
86
|
+
Return only the TypeScript test code.`}function i(){return`You are an expert TypeScript developer with deep knowledge of:
|
|
87
|
+
- Type-safe API design
|
|
88
|
+
- React and modern hooks
|
|
89
|
+
- Test-driven development
|
|
90
|
+
- Accessibility best practices
|
|
91
|
+
- Clean code principles
|
|
92
|
+
|
|
93
|
+
Generate production-ready code that is:
|
|
94
|
+
- Fully typed (no 'any' or type assertions unless absolutely necessary)
|
|
95
|
+
- Well-documented with TSDoc comments
|
|
96
|
+
- Following project conventions
|
|
97
|
+
- Defensive and error-safe
|
|
98
|
+
- Easy to maintain and extend
|
|
99
|
+
|
|
100
|
+
Always prioritize code quality, safety, and user experience.`}export{t as buildComponentPrompt,n as buildFormPrompt,e as buildHandlerPrompt,r as buildTestPrompt,i as getCodeGenSystemPrompt};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
function e(e,t){return`You are a senior software architect creating a contract specification for an operation.
|
|
2
|
+
|
|
3
|
+
The operation is a ${t} (${t===`command`?`changes state, has side effects`:`read-only, idempotent`}).
|
|
4
|
+
|
|
5
|
+
User description: ${e}
|
|
6
|
+
|
|
7
|
+
Create a complete contract specification following these guidelines:
|
|
8
|
+
|
|
9
|
+
1. **Name**: Use dot notation like "domain.operationName" (e.g., "user.signup", "payment.charge")
|
|
10
|
+
2. **Version**: Start at 1
|
|
11
|
+
3. **Description**: Clear, concise summary (1-2 sentences)
|
|
12
|
+
4. **Goal**: Business purpose - why this operation exists
|
|
13
|
+
5. **Context**: Background, constraints, scope (what it does and doesn't do)
|
|
14
|
+
6. **Input/Output**: Describe the shape (we'll create schemas separately)
|
|
15
|
+
7. **Auth**: Who can call this - anonymous, user, or admin
|
|
16
|
+
8. **Feature Flags**: Any flags that gate this operation
|
|
17
|
+
9. **Side Effects**: What events might be emitted, analytics to track
|
|
18
|
+
|
|
19
|
+
Respond with a structured spec.`}function t(e){return`You are a senior software architect creating an event specification.
|
|
20
|
+
|
|
21
|
+
User description: ${e}
|
|
22
|
+
|
|
23
|
+
Create a complete event specification following these guidelines:
|
|
24
|
+
|
|
25
|
+
1. **Name**: Use dot notation like "domain.event_name" (e.g., "user.signup_completed", "payment.charged")
|
|
26
|
+
2. **Version**: Start at 1
|
|
27
|
+
3. **Description**: Clear description of when this event is emitted
|
|
28
|
+
4. **Payload**: Describe what data the event carries
|
|
29
|
+
5. **PII Fields**: List any personally identifiable information fields (e.g., ["email", "name"])
|
|
30
|
+
|
|
31
|
+
Events represent things that have already happened and should use past tense.
|
|
32
|
+
|
|
33
|
+
Respond with a structured spec.`}function n(e,t){return`You are a senior software architect creating a presentation specification.
|
|
34
|
+
|
|
35
|
+
This is a ${t} presentation - ${{web_component:`a React component with props schema`,markdown:`markdown/MDX documentation or guide`,data:`structured data export (JSON/XML)`}[t]}.
|
|
36
|
+
|
|
37
|
+
User description: ${e}
|
|
38
|
+
|
|
39
|
+
Create a complete presentation specification following these guidelines:
|
|
40
|
+
|
|
41
|
+
1. **Name**: Use dot notation like "domain.presentation_name" (e.g., "user.profile_card", "docs.api_guide")
|
|
42
|
+
2. **Version**: Start at 1
|
|
43
|
+
3. **Description**: What this presentation shows/provides
|
|
44
|
+
4. **Kind-specific details**:
|
|
45
|
+
${t===`web_component`?`- Component key (symbolic, resolved by host app)
|
|
46
|
+
- Props structure
|
|
47
|
+
- Analytics events to track`:t===`markdown`?`- Content or resource URI
|
|
48
|
+
- Target audience`:`- MIME type (e.g., application/json)
|
|
49
|
+
- Data structure description`}
|
|
50
|
+
|
|
51
|
+
Respond with a structured spec.`}function r(){return`You are an expert software architect specializing in API design and contract-driven development.
|
|
52
|
+
|
|
53
|
+
You create clear, well-documented specifications that serve as the single source of truth for operations, events, and presentations.
|
|
54
|
+
|
|
55
|
+
Your specs are:
|
|
56
|
+
- Precise and unambiguous
|
|
57
|
+
- Following TypeScript conventions
|
|
58
|
+
- Business-oriented (capturing the "why" not just "what")
|
|
59
|
+
- Designed for both humans and AI agents to understand
|
|
60
|
+
|
|
61
|
+
Always use proper dot notation for names and ensure all metadata is meaningful and accurate.`}function i(e,t){return t.length===0?e:`${e}
|
|
62
|
+
|
|
63
|
+
Here are some good examples for reference:
|
|
64
|
+
|
|
65
|
+
${t.join(`
|
|
66
|
+
|
|
67
|
+
`)}
|
|
68
|
+
|
|
69
|
+
Follow this structure and quality level.`}export{i as addExampleContext,t as buildEventSpecPrompt,e as buildOperationSpecPrompt,n as buildPresentationSpecPrompt,r as getSystemPrompt};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
function e(e){for(let t of e.values())t.dependents=[];for(let[t,n]of e)for(let r of n.dependencies){let n=e.get(r);n&&n.dependents.push(t)}for(let t of e.values())t.dependents.sort((e,t)=>e.localeCompare(t))}function t(e){let t=new Set,n=new Set,r=[];function i(a,o){if(n.has(a)){let e=o.indexOf(a);e>=0&&r.push([...o.slice(e),a]);return}if(t.has(a))return;t.add(a),n.add(a);let s=e.get(a);if(s)for(let e of s.dependencies)i(e,[...o,a]);n.delete(a)}for(let n of e.keys())t.has(n)||i(n,[]);return r}function n(e){let t=[];for(let[n,r]of e){let i=r.dependencies.filter(t=>!e.has(t));i.length>0&&t.push({contract:n,missing:i})}return t}function r(e){let t=[];t.push(`digraph ContractDependencies {`),t.push(` rankdir=LR;`),t.push(` node [shape=box];`);for(let[n,r]of e){for(let e of r.dependencies)t.push(` "${n}" -> "${e}";`);r.dependencies.length===0&&t.push(` "${n}";`)}return t.push(`}`),t.join(`
|
|
2
|
+
`)}function i(){return new Map}function a(e,t,n,r){e.set(t,{name:t,file:n,dependencies:r,dependents:[]})}export{a as addContractNode,e as buildReverseEdges,i as createContractGraph,t as detectCycles,n as findMissingDependencies,r as toDot};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function e(e,t){let n=[],r=/import\s+.*?\s+from\s+['"]([^'"]+\.(?:contracts|event|presentation|workflow|data-view|migration|telemetry|experiment|app-config|integration|knowledge)(?:\.[jt]s)?)['"]/g,i;for(;(i=r.exec(e))!==null;){let e=i[1];if(!e||!e.startsWith(`.`)&&!e.startsWith(`/`))continue;let t=e.split(`/`),r=(t[t.length-1]??``).replace(/\.(ts|js)$/,``).replace(/\.(contracts|event|presentation|workflow|data-view|migration|telemetry|experiment|app-config|integration|knowledge)$/,``);r.length>0&&n.push(r)}return Array.from(new Set(n)).sort((e,t)=>e.localeCompare(t))}export{e as parseImportedSpecNames};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{scanSpecSource as e}from"../spec-scan.js";function t(t,o,s,c,l={}){let u=e(t,o),d=e(s,c),f=[];return n(f,`specType`,u.specType,d.specType,{breaking:!0,label:`Spec type`}),n(f,`name`,u.name,d.name,{breaking:!0,label:`Name`}),n(f,`version`,u.version,d.version,{breaking:!0,label:`Version`}),n(f,`kind`,u.kind,d.kind,{breaking:!0,label:`Kind`}),n(f,`stability`,u.stability,d.stability,{breaking:i(u,d),label:`Stability`}),r(f,`owners`,u.owners??[],d.owners??[],{label:`Owners`}),r(f,`tags`,u.tags??[],d.tags??[],{label:`Tags`}),a(f,u,d),l.breakingOnly?f.filter(e=>e.type===`breaking`):f}function n(e,t,n,r,i){n!==r&&e.push({type:i.breaking?`breaking`:`changed`,path:t,oldValue:n,newValue:r,description:`${i.label} changed`})}function r(e,t,n,r,i){let a=[...n].sort(),o=[...r].sort();JSON.stringify(a)!==JSON.stringify(o)&&e.push({type:`changed`,path:t,oldValue:a,newValue:o,description:`${i.label} changed`})}function i(e,t){let n={experimental:0,beta:1,stable:2,deprecated:3},r=e.stability?n[e.stability]??0:0;return(t.stability?n[t.stability]??0:0)>r}function a(e,t,r){n(e,`hasMeta`,t.hasMeta,r.hasMeta,{breaking:t.specType===`operation`||r.specType===`operation`,label:`meta section presence`}),n(e,`hasIo`,t.hasIo,r.hasIo,{breaking:t.specType===`operation`||r.specType===`operation`,label:`io section presence`}),n(e,`hasPolicy`,t.hasPolicy,r.hasPolicy,{breaking:t.specType===`operation`||r.specType===`operation`,label:`policy section presence`}),n(e,`hasPayload`,t.hasPayload,r.hasPayload,{breaking:t.specType===`event`||r.specType===`event`,label:`payload section presence`}),n(e,`hasContent`,t.hasContent,r.hasContent,{breaking:t.specType===`presentation`||r.specType===`presentation`,label:`content section presence`}),n(e,`hasDefinition`,t.hasDefinition,r.hasDefinition,{breaking:t.specType===`workflow`||r.specType===`workflow`,label:`definition section presence`})}export{t as computeSemanticDiff};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function e(e){return e.includes(`.contracts.`)?`operation`:e.includes(`.event.`)?`event`:e.includes(`.presentation.`)?`presentation`:e.includes(`.workflow.`)?`workflow`:e.includes(`.data-view.`)?`data-view`:e.includes(`.migration.`)?`migration`:e.includes(`.telemetry.`)?`telemetry`:e.includes(`.experiment.`)?`experiment`:e.includes(`.app-config.`)?`app-config`:e.includes(`.integration.`)?`integration`:e.includes(`.knowledge.`)?`knowledge`:`unknown`}function t(t,o){let s=e(o),c=n(t,`name`),l=n(t,`description`),u=n(t,`stability`),d=a(u)?u:void 0,f=i(t,`owners`),p=i(t,`tags`),m=r(t,`version`),h=n(t,`kind`),g=h===`command`||h===`query`?h:`unknown`,_=/meta\s*:\s*{/.test(t),v=/\bio\s*:\s*{/.test(t),y=/\bpolicy\s*:\s*{/.test(t),b=/\bpayload\s*:\s*{/.test(t),x=/\bcontent\s*:\s*{/.test(t),S=/\bdefinition\s*:\s*{/.test(t);return{filePath:o,specType:s,name:c??void 0,description:l??void 0,stability:d,owners:f,tags:p,version:m??void 0,kind:g,hasMeta:_,hasIo:v,hasPolicy:y,hasPayload:b,hasContent:x,hasDefinition:S}}function n(e,t){let n=RegExp(`${o(t)}\\s*:\\s*['"]([^'"]+)['"]`);return e.match(n)?.[1]??null}function r(e,t){let n=RegExp(`${o(t)}\\s*:\\s*(\\d+)`),r=e.match(n);if(!r?.[1])return null;let i=Number(r[1]);return Number.isFinite(i)?i:null}function i(e,t){let n=RegExp(`${o(t)}\\s*:\\s*\\[([\\s\\S]*?)\\]`),r=e.match(n);if(!r?.[1])return;let i=r[1],a=Array.from(i.matchAll(/['"]([^'"]+)['"]/g)).map(e=>e[1]).filter(e=>typeof e==`string`&&e.length>0);return a.length>0?a:void 0}function a(e){return e===`experimental`||e===`beta`||e===`stable`||e===`deprecated`}function o(e){return e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}export{e as inferSpecTypeFromFilePath,t as scanSpecSource};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function e(e,d){let f=[],p=[];return/export\s+(const|let)\s+\w+/.test(e)||f.push(`No exported spec found`),d.includes(`.contracts.`)&&t(e,f,p),d.includes(`.event.`)&&a(e,f,p),d.includes(`.presentation.`)&&o(e,f,p),d.includes(`.workflow.`)&&s(e,f,p),d.includes(`.data-view.`)&&u(e,f,p),d.includes(`.migration.`)&&c(e,f,p),d.includes(`.telemetry.`)&&n(e,f,p),d.includes(`.experiment.`)&&r(e,f,p),d.includes(`.app-config.`)&&i(e,f,p),l(e,f,p),{valid:f.length===0,errors:f,warnings:p}}function t(e,t,n){/define(Command|Query)/.test(e)||t.push(`Missing defineCommand or defineQuery call`),e.includes(`meta:`)||t.push(`Missing meta section`),e.includes(`io:`)||t.push(`Missing io section`),e.includes(`policy:`)||t.push(`Missing policy section`),e.match(/name:\s*['"][^'"]+['"]/)||t.push(`Missing or invalid name field`),e.match(/version:\s*\d+/)||t.push(`Missing or invalid version field`),e.match(/kind:\s*['"](?:command|query)['"]/)||t.push(`Missing or invalid kind field (must be "command" or "query")`),e.includes(`acceptance:`)||n.push(`No acceptance scenarios defined`),e.includes(`examples:`)||n.push(`No examples provided`),e.includes(`TODO`)&&n.push(`Contains TODO items that need completion`)}function n(e,t,n){e.match(/:\s*TelemetrySpec\s*=/)||t.push(`Missing TelemetrySpec type annotation`),e.match(/meta:\s*{[\s\S]*name:/)||t.push(`TelemetrySpec.meta is required`),e.includes(`events:`)||t.push(`TelemetrySpec must declare events`),e.match(/privacy:\s*'(public|internal|pii|sensitive)'/)||n.push(`No explicit privacy classification found`)}function r(e,t,n){e.match(/:\s*ExperimentSpec\s*=/)||t.push(`Missing ExperimentSpec type annotation`),e.includes(`controlVariant`)||t.push(`ExperimentSpec must declare controlVariant`),e.includes(`variants:`)||t.push(`ExperimentSpec must declare variants`),e.match(/allocation:\s*{/)||n.push(`ExperimentSpec missing allocation configuration`)}function i(e,t,n){e.match(/:\s*AppBlueprintSpec\s*=/)||t.push(`Missing AppBlueprintSpec type annotation`),e.includes(`meta:`)||t.push(`AppBlueprintSpec must define meta`),e.includes(`appId`)||n.push(`AppBlueprint meta missing appId assignment`),e.includes(`capabilities`)||n.push(`App blueprint spec does not declare capabilities`)}function a(e,t,n){e.includes(`defineEvent`)||t.push(`Missing defineEvent call`),e.match(/name:\s*['"][^'"]+['"]/)||t.push(`Missing or invalid name field`),e.match(/version:\s*\d+/)||t.push(`Missing or invalid version field`),e.includes(`payload:`)||t.push(`Missing payload field`);let r=e.match(/name:\s*['"]([^'"]+)['"]/);r?.[1]&&((r[1].split(`.`).pop()??``).match(/(ed|created|updated|deleted|completed)$/i)||n.push(`Event name should use past tense (e.g., "created", "updated")`))}function o(e,t,n){e.match(/:\s*PresentationSpec\s*=/)||t.push(`Missing PresentationSpec type annotation`),e.includes(`meta:`)||t.push(`Missing meta section`),e.includes(`content:`)||t.push(`Missing content section`),e.match(/kind:\s*['"](?:web_component|markdown|data)['"]/)||t.push(`Missing or invalid kind field`)}function s(e,t,n){e.match(/:\s*WorkflowSpec\s*=/)||t.push(`Missing WorkflowSpec type annotation`),e.includes(`definition:`)||t.push(`Missing definition section`),e.includes(`steps:`)||t.push(`Workflow must declare steps`),e.includes(`transitions:`)||n.push(`No transitions declared; workflow will complete after first step.`),e.match(/title:\s*['"][^'"]+['"]/)||n.push(`Missing workflow title`),e.match(/domain:\s*['"][^'"]+['"]/)||n.push(`Missing domain field`),e.includes(`TODO`)&&n.push(`Contains TODO items that need completion`)}function c(e,t,n){e.match(/:\s*MigrationSpec\s*=/)||t.push(`Missing MigrationSpec type annotation`),e.includes(`plan:`)?e.includes(`up:`)||t.push(`Migration must define at least one up step`):t.push(`Missing plan section`),e.match(/name:\s*['"][^'"]+['"]/)||t.push(`Missing or invalid migration name`),e.match(/version:\s*\d+/)||t.push(`Missing or invalid migration version`),e.includes(`TODO`)&&n.push(`Contains TODO items that need completion`)}function l(e,t,n){e.includes(`SchemaModel`)&&!e.includes(`from '@lssm/lib.schema'`)&&t.push(`Missing import for SchemaModel from @lssm/lib.schema`),e.includes(`from '@lssm/lib.contracts'`)||t.push(`Missing import from @lssm/lib.contracts`);let r=e.match(/owners:\s*\[(.*?)\]/s);r?.[1]&&(r[1].includes(`@`)||n.push(`Owners should start with @ (e.g., "@team")`)),e.match(/stability:\s*['"](?:experimental|beta|stable|deprecated)['"]/)||n.push(`Missing or invalid stability field`)}function u(e,t,n){e.match(/:\s*DataViewSpec\s*=/)||t.push(`Missing DataViewSpec type annotation`),e.includes(`meta:`)||t.push(`Missing meta section`),e.includes(`source:`)||t.push(`Missing source section`),e.includes(`view:`)||t.push(`Missing view section`),e.match(/kind:\s*['"](list|table|detail|grid)['"]/)||t.push(`Missing or invalid view.kind (list/table/detail/grid)`),e.match(/fields:\s*\[/)||t.push(`No fields defined for data view`)}export{e as validateSpecStructure};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{DEFAULT_WORKSPACE_CONFIG as e}from"./types/generation-types.js";import{inferSpecTypeFromFilePath as t,scanSpecSource as n}from"./analysis/spec-scan.js";import{computeSemanticDiff as r}from"./analysis/diff/semantic.js";import{addContractNode as i,buildReverseEdges as a,createContractGraph as o,detectCycles as s,findMissingDependencies as c,toDot as l}from"./analysis/deps/graph.js";import{parseImportedSpecNames as u}from"./analysis/deps/parse-imports.js";import{validateSpecStructure as d}from"./analysis/validate/spec-structure.js";import{capitalize as f,escapeString as p,toCamelCase as m,toKebabCase as h,toPascalCase as g}from"./templates/utils.js";import{generateOperationSpec as _}from"./templates/operation.js";import{generateEventSpec as v}from"./templates/event.js";import{generatePresentationSpec as y}from"./templates/presentation.js";import{generateWorkflowSpec as b}from"./templates/workflow.js";import{generateWorkflowRunnerTemplate as x}from"./templates/workflow-runner.js";import{generateDataViewSpec as S}from"./templates/data-view.js";import{generateTelemetrySpec as C}from"./templates/telemetry.js";import{generateExperimentSpec as w}from"./templates/experiment.js";import{generateAppBlueprintSpec as T}from"./templates/app-config.js";import{generateMigrationSpec as E}from"./templates/migration.js";import{generateIntegrationSpec as D}from"./templates/integration.js";import{generateKnowledgeSpaceSpec as O}from"./templates/knowledge.js";import{generateComponentTemplate as k,generateHandlerTemplate as A,generateTestTemplate as j}from"./templates/handler.js";import{addExampleContext as M,buildEventSpecPrompt as N,buildOperationSpecPrompt as P,buildPresentationSpecPrompt as F,getSystemPrompt as I}from"./ai/spec-creation.js";import{buildComponentPrompt as L,buildFormPrompt as R,buildHandlerPrompt as z,buildTestPrompt as B,getCodeGenSystemPrompt as V}from"./ai/code-generation.js";export{e as DEFAULT_WORKSPACE_CONFIG,i as addContractNode,M as addExampleContext,L as buildComponentPrompt,N as buildEventSpecPrompt,R as buildFormPrompt,z as buildHandlerPrompt,P as buildOperationSpecPrompt,F as buildPresentationSpecPrompt,a as buildReverseEdges,B as buildTestPrompt,f as capitalize,r as computeSemanticDiff,o as createContractGraph,s as detectCycles,p as escapeString,c as findMissingDependencies,T as generateAppBlueprintSpec,k as generateComponentTemplate,S as generateDataViewSpec,v as generateEventSpec,w as generateExperimentSpec,A as generateHandlerTemplate,D as generateIntegrationSpec,O as generateKnowledgeSpaceSpec,E as generateMigrationSpec,_ as generateOperationSpec,y as generatePresentationSpec,C as generateTelemetrySpec,j as generateTestTemplate,x as generateWorkflowRunnerTemplate,b as generateWorkflowSpec,V as getCodeGenSystemPrompt,I as getSystemPrompt,t as inferSpecTypeFromFilePath,u as parseImportedSpecNames,n as scanSpecSource,m as toCamelCase,l as toDot,h as toKebabCase,g as toPascalCase,d as validateSpecStructure};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import{toPascalCase as e}from"./utils.js";function t(t){let d=e(t.name.split(`.`).pop()??`App`)+`AppConfig`,f=n(t),m=r(t),h=i(`dataViews`,t.dataViews),g=i(`workflows`,t.workflows),_=a(t),v=o(t),y=s(t),b=c(t),x=l(t),S=u(t),C=t.notes?` notes: '${p(t.notes)}',\n`:``;return`import type { AppBlueprintSpec } from '@lssm/lib.contracts/app-config';
|
|
2
|
+
|
|
3
|
+
export const ${d}: AppBlueprintSpec = {
|
|
4
|
+
meta: {
|
|
5
|
+
name: '${p(t.name)}',
|
|
6
|
+
version: ${t.version},
|
|
7
|
+
title: '${p(t.title)}',
|
|
8
|
+
description: '${p(t.description)}',
|
|
9
|
+
domain: '${p(t.domain)}',
|
|
10
|
+
owners: [${t.owners.map(e=>`'${p(e)}'`).join(`, `)}],
|
|
11
|
+
tags: [${t.tags.map(e=>`'${p(e)}'`).join(`, `)}],
|
|
12
|
+
stability: '${t.stability}',
|
|
13
|
+
appId: '${p(t.appId)}',
|
|
14
|
+
},
|
|
15
|
+
${f}${m}${h}${g}${_}${v}${y}${b}${x}${S}${C}};\n`}function n(e){return e.capabilitiesEnabled.length===0&&e.capabilitiesDisabled.length===0?``:` capabilities: {\n${e.capabilitiesEnabled.length>0?` enabled: [${e.capabilitiesEnabled.map(e=>d(e)).join(`, `)}],\n`:``}${e.capabilitiesDisabled.length>0?` disabled: [${e.capabilitiesDisabled.map(e=>d(e)).join(`, `)}],\n`:``} },\n`}function r(e){return e.featureIncludes.length===0&&e.featureExcludes.length===0?``:` features: {\n${e.featureIncludes.length>0?` include: [${e.featureIncludes.map(e=>`{ key: '${p(e)}' }`).join(`, `)}],\n`:``}${e.featureExcludes.length>0?` exclude: [${e.featureExcludes.map(e=>`{ key: '${p(e)}' }`).join(`, `)}],\n`:``} },\n`}function i(e,t){return t.length===0?``:` ${e}: {\n${t.map(e=>` ${e.slot}: {
|
|
16
|
+
name: '${p(e.name)}',
|
|
17
|
+
${typeof e.version==`number`?`version: ${e.version},`:``}
|
|
18
|
+
}`).join(`,
|
|
19
|
+
`)}\n },\n`}function a(e){return e.policyRefs.length===0?``:` policies: [\n${e.policyRefs.map(e=>` {
|
|
20
|
+
name: '${p(e.name)}'${typeof e.version==`number`?`,\n version: ${e.version}`:``}
|
|
21
|
+
}`).join(`,
|
|
22
|
+
`)}\n ],\n`}function o(e){return e.theme?` theme: {\n${` primary: { name: '${p(e.theme.name)}', version: ${e.theme.version} },\n`}${e.themeFallbacks.length>0?` fallbacks: [${e.themeFallbacks.map(e=>`{ name: '${p(e.name)}', version: ${e.version} }`).join(`, `)}],\n`:``} },\n`:``}function s(e){return e.telemetry?` telemetry: {
|
|
23
|
+
spec: {
|
|
24
|
+
name: '${p(e.telemetry.name)}'${typeof e.telemetry.version==`number`?`,\n version: ${e.telemetry.version}`:``}
|
|
25
|
+
},
|
|
26
|
+
},\n`:``}function c(e){return e.activeExperiments.length===0&&e.pausedExperiments.length===0?``:` experiments: {\n${e.activeExperiments.length>0?` active: [${e.activeExperiments.map(e=>f(e)).join(`, `)}],\n`:``}${e.pausedExperiments.length>0?` paused: [${e.pausedExperiments.map(e=>f(e)).join(`, `)}],\n`:``} },\n`}function l(e){return e.featureFlags.length===0?``:` featureFlags: [\n${e.featureFlags.map(e=>` {
|
|
27
|
+
key: '${p(e.key)}',
|
|
28
|
+
enabled: ${e.enabled},
|
|
29
|
+
${e.variant?`variant: '${p(e.variant)}',`:``}
|
|
30
|
+
${e.description?`description: '${p(e.description)}',`:``}
|
|
31
|
+
}`).join(`,
|
|
32
|
+
`)}\n ],\n`}function u(e){return e.routes.length===0?``:` routes: [\n${e.routes.map(e=>` { ${[`path: '${p(e.path)}'`,e.label?`label: '${p(e.label)}'`:null,e.dataView?`dataView: '${p(e.dataView)}'`:null,e.workflow?`workflow: '${p(e.workflow)}'`:null,e.guardName?`guard: { name: '${p(e.guardName)}'${typeof e.guardVersion==`number`?`, version: ${e.guardVersion}`:``} }`:null,e.featureFlag?`featureFlag: '${p(e.featureFlag)}'`:null,e.experimentName?`experiment: { name: '${p(e.experimentName)}'${typeof e.experimentVersion==`number`?`, version: ${e.experimentVersion}`:``} }`:null].filter(Boolean).join(`, `)} }`).join(`,
|
|
33
|
+
`)}\n ],\n`}function d(e){return`{ key: '${p(e)}' }`}function f(e){let t=typeof e.version==`number`?`, version: ${e.version}`:``;return`{ name: '${p(e.name)}'${t} }`}function p(e){return e.replace(/\\/g,`\\\\`).replace(/'/g,`\\'`)}export{t as generateAppBlueprintSpec};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import{escapeString as e,toPascalCase as t}from"./utils.js";function n(n){let i=t(n.name.split(`.`).pop()??`DataView`)+`DataView`,a=n.fields.map(t=>` {
|
|
2
|
+
key: '${e(t.key)}',
|
|
3
|
+
label: '${r(t.label)}',
|
|
4
|
+
dataPath: '${e(t.dataPath)}',
|
|
5
|
+
${t.format?`format: '${e(t.format)}',`:``}
|
|
6
|
+
${t.sortable?`sortable: true,`:``}
|
|
7
|
+
${t.filterable?`filterable: true,`:``}
|
|
8
|
+
}`).join(`,
|
|
9
|
+
`),o=n.secondaryFields?.length?`secondaryFields: [${n.secondaryFields.map(t=>`'${e(t)}'`).join(`, `)}],`:``,s=n.itemOperation?`item: { name: '${e(n.itemOperation.name)}', version: ${n.itemOperation.version} },`:``;return`import type { DataViewSpec } from '@lssm/lib.contracts/data-views';
|
|
10
|
+
|
|
11
|
+
export const ${i}: DataViewSpec = {
|
|
12
|
+
meta: {
|
|
13
|
+
name: '${e(n.name)}',
|
|
14
|
+
version: ${n.version},
|
|
15
|
+
entity: '${e(n.entity)}',
|
|
16
|
+
title: '${r(n.title)}',
|
|
17
|
+
description: '${r(n.description||`Describe the purpose of this data view.`)}',
|
|
18
|
+
domain: '${r(n.domain||n.entity)}',
|
|
19
|
+
owners: [${n.owners.map(t=>`'${e(t)}'`).join(`, `)}],
|
|
20
|
+
tags: [${n.tags.map(t=>`'${e(t)}'`).join(`, `)}],
|
|
21
|
+
stability: '${n.stability}',
|
|
22
|
+
},
|
|
23
|
+
source: {
|
|
24
|
+
primary: {
|
|
25
|
+
name: '${e(n.primaryOperation.name)}',
|
|
26
|
+
version: ${n.primaryOperation.version},
|
|
27
|
+
},
|
|
28
|
+
${s}
|
|
29
|
+
refreshEvents: [
|
|
30
|
+
// { name: 'entity.updated', version: 1 },
|
|
31
|
+
],
|
|
32
|
+
},
|
|
33
|
+
view: {
|
|
34
|
+
kind: '${n.kind}',
|
|
35
|
+
fields: [
|
|
36
|
+
${a}
|
|
37
|
+
],
|
|
38
|
+
${n.primaryField?`primaryField: '${e(n.primaryField)}',`:``}
|
|
39
|
+
${o}
|
|
40
|
+
filters: [
|
|
41
|
+
// Example filter:
|
|
42
|
+
// { key: 'search', label: 'Search', field: 'fullName', type: 'search' },
|
|
43
|
+
],
|
|
44
|
+
actions: [
|
|
45
|
+
// Example action:
|
|
46
|
+
// { key: 'open', label: 'Open', kind: 'navigation' },
|
|
47
|
+
],
|
|
48
|
+
},
|
|
49
|
+
states: {
|
|
50
|
+
// empty: { name: 'app.data.empty', version: 1 },
|
|
51
|
+
// error: { name: 'app.data.error', version: 1 },
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
`}function r(e){return e.replace(/'/g,`\\'`)}export{n as generateDataViewSpec};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import{toPascalCase as e}from"./utils.js";function t(t){let{name:n,version:r,description:i,stability:a,owners:o,tags:s,piiFields:c}=t,l=e(n.replace(/\./g,`_`))+`V`+r,u=l+`Payload`;return`import { defineEvent } from '@lssm/lib.contracts';
|
|
2
|
+
import { ScalarTypeEnum, SchemaModel } from '@lssm/lib.schema';
|
|
3
|
+
|
|
4
|
+
// TODO: Define event payload schema
|
|
5
|
+
export const ${u} = new SchemaModel({
|
|
6
|
+
name: '${u}',
|
|
7
|
+
description: 'Payload for ${n}',
|
|
8
|
+
fields: {
|
|
9
|
+
// Add your payload fields here
|
|
10
|
+
// example: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
11
|
+
},
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
export const ${l} = defineEvent({
|
|
15
|
+
name: '${n}',
|
|
16
|
+
version: ${r},
|
|
17
|
+
description: '${i}',
|
|
18
|
+
stability: '${a}',
|
|
19
|
+
owners: [${o.map(e=>`'${e}'`).join(`, `)}],
|
|
20
|
+
tags: [${s.map(e=>`'${e}'`).join(`, `)}],
|
|
21
|
+
${c.length>0?`pii: [${c.map(e=>`'${e}'`).join(`, `)}],`:`// pii: [],`}
|
|
22
|
+
payload: ${u},
|
|
23
|
+
});
|
|
24
|
+
`}export{t as generateEventSpec};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import{toPascalCase as e}from"./utils.js";function t(t){let i=e(t.name.split(`.`).pop()??`Experiment`)+`Experiment`,a=t.variants.map(e=>{let t=e.overrides?.length?` overrides: [
|
|
2
|
+
${e.overrides.map(e=>` {
|
|
3
|
+
type: '${e.type}',
|
|
4
|
+
target: '${r(e.target)}',
|
|
5
|
+
${typeof e.version==`number`?`version: ${e.version},`:``}
|
|
6
|
+
}`).join(`,
|
|
7
|
+
`)}
|
|
8
|
+
],`:``;return` {
|
|
9
|
+
id: '${r(e.id)}',
|
|
10
|
+
name: '${r(e.name)}',
|
|
11
|
+
${e.description?`description: '${r(e.description)}',`:``}
|
|
12
|
+
${typeof e.weight==`number`?`weight: ${e.weight},`:``}
|
|
13
|
+
${t}
|
|
14
|
+
}`}).join(`,
|
|
15
|
+
`),o=n(t.allocation),s=t.successMetrics?.length?` successMetrics: [
|
|
16
|
+
${t.successMetrics.map(e=>` {
|
|
17
|
+
name: '${r(e.name)}',
|
|
18
|
+
telemetryEvent: { name: '${r(e.eventName)}', version: ${e.eventVersion} },
|
|
19
|
+
aggregation: '${e.aggregation}',
|
|
20
|
+
${typeof e.target==`number`?`target: ${e.target},`:``}
|
|
21
|
+
}`).join(`,
|
|
22
|
+
`)}
|
|
23
|
+
],`:``;return`import type { ExperimentSpec } from '@lssm/lib.contracts/experiments';
|
|
24
|
+
|
|
25
|
+
export const ${i}: ExperimentSpec = {
|
|
26
|
+
meta: {
|
|
27
|
+
name: '${r(t.name)}',
|
|
28
|
+
version: ${t.version},
|
|
29
|
+
title: '${r(t.name)} experiment',
|
|
30
|
+
description: '${r(t.description||`Describe the experiment goal.`)}',
|
|
31
|
+
domain: '${r(t.domain)}',
|
|
32
|
+
owners: [${t.owners.map(e=>`'${r(e)}'`).join(`, `)}],
|
|
33
|
+
tags: [${t.tags.map(e=>`'${r(e)}'`).join(`, `)}],
|
|
34
|
+
stability: '${t.stability}',
|
|
35
|
+
},
|
|
36
|
+
controlVariant: '${r(t.controlVariant)}',
|
|
37
|
+
variants: [
|
|
38
|
+
${a}
|
|
39
|
+
],
|
|
40
|
+
allocation: ${o},
|
|
41
|
+
${s}
|
|
42
|
+
};
|
|
43
|
+
`}function n(e){switch(e.type){case`random`:return`{
|
|
44
|
+
type: 'random',
|
|
45
|
+
${e.salt?`salt: '${r(e.salt)}',`:``}
|
|
46
|
+
}`;case`sticky`:return`{
|
|
47
|
+
type: 'sticky',
|
|
48
|
+
attribute: '${e.attribute}',
|
|
49
|
+
${e.salt?`salt: '${r(e.salt)}',`:``}
|
|
50
|
+
}`;case`targeted`:return`{
|
|
51
|
+
type: 'targeted',
|
|
52
|
+
rules: [
|
|
53
|
+
${e.rules.map(e=>` {
|
|
54
|
+
variantId: '${r(e.variantId)}',
|
|
55
|
+
${typeof e.percentage==`number`?`percentage: ${e.percentage},`:``}
|
|
56
|
+
${e.policy?`policy: { name: '${r(e.policy.name)}'${typeof e.policy.version==`number`?`, version: ${e.policy.version}`:``} },`:``}
|
|
57
|
+
${e.expression?`expression: '${r(e.expression)}',`:``}
|
|
58
|
+
}`).join(`,
|
|
59
|
+
`)}
|
|
60
|
+
],
|
|
61
|
+
fallback: '${e.fallback??`control`}',
|
|
62
|
+
}`;default:return i(e)}}function r(e){return e.replace(/\\/g,`\\\\`).replace(/'/g,`\\'`)}function i(e){throw Error(`Unsupported allocation type ${e}`)}export{t as generateExperimentSpec};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import{toCamelCase as e,toKebabCase as t,toPascalCase as n}from"./utils.js";function r(r,i){let a=e(r.split(`.`).pop()??`unknown`)+`Handler`,o=n(r.split(`.`).pop()??`Unknown`)+`Spec`;return`import type { ContractHandler } from '@lssm/lib.contracts';
|
|
2
|
+
import { ${o} } from '../contracts/${t(r)}.contracts';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Handler for ${r}
|
|
6
|
+
*/
|
|
7
|
+
export const ${a}: ContractHandler<typeof ${o}> = async (
|
|
8
|
+
input,
|
|
9
|
+
context
|
|
10
|
+
) => {
|
|
11
|
+
// TODO: Implement ${i} logic
|
|
12
|
+
|
|
13
|
+
try {
|
|
14
|
+
// 1. Validate prerequisites
|
|
15
|
+
// 2. Perform business logic
|
|
16
|
+
// 3. Emit events if needed
|
|
17
|
+
// 4. Return result
|
|
18
|
+
|
|
19
|
+
return {
|
|
20
|
+
ok: true,
|
|
21
|
+
};
|
|
22
|
+
} catch (error) {
|
|
23
|
+
// Handle and map errors to spec.io.errors
|
|
24
|
+
throw error;
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
`}function i(e,t){let r=n(e);return`import React from 'react';
|
|
28
|
+
|
|
29
|
+
interface ${r}Props {
|
|
30
|
+
// TODO: Define props based on presentation spec
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* ${t}
|
|
35
|
+
*/
|
|
36
|
+
export const ${r}: React.FC<${r}Props> = (props) => {
|
|
37
|
+
return (
|
|
38
|
+
<div>
|
|
39
|
+
{/* TODO: Implement component UI */}
|
|
40
|
+
<p>Component: ${r}</p>
|
|
41
|
+
</div>
|
|
42
|
+
);
|
|
43
|
+
};
|
|
44
|
+
`}function a(e,r){let i=r===`handler`?`../handlers`:`../components`,a=n(e);return`import { describe, it, expect } from 'bun:test';
|
|
45
|
+
import { ${a} } from '${i}/${t(e)}';
|
|
46
|
+
|
|
47
|
+
describe('${a}', () => {
|
|
48
|
+
it('should ${r===`handler`?`handle valid input`:`render correctly`}', async () => {
|
|
49
|
+
// TODO: Implement test
|
|
50
|
+
expect(true).toBe(true);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('should handle edge cases', async () => {
|
|
54
|
+
// TODO: Test edge cases
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
${r===`handler`?`it('should handle errors appropriately', async () => {
|
|
58
|
+
// TODO: Test error scenarios
|
|
59
|
+
});`:`it('should be accessible', async () => {
|
|
60
|
+
// TODO: Test accessibility
|
|
61
|
+
});`}
|
|
62
|
+
});
|
|
63
|
+
`}export{i as generateComponentTemplate,r as generateHandlerTemplate,a as generateTestTemplate};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
function e(e){let t=e.filter(e=>e.required);return` schema: {
|
|
2
|
+
type: 'object',
|
|
3
|
+
${t.length>0?` required: [${t.map(e=>`'${e.key}'`).join(`, `)}],
|
|
4
|
+
`:``} properties: {
|
|
5
|
+
${(e.length?e.map(e=>{let t=e.description?`, description: '${u(e.description)}'`:``;return` ${e.key}: { type: '${o(e.type)}'${t} }`}).join(`,
|
|
6
|
+
`):``)||` `}
|
|
7
|
+
},
|
|
8
|
+
},\n`}function t(e){let t=e.filter(e=>e.required);return` schema: {
|
|
9
|
+
type: 'object',
|
|
10
|
+
${t.length>0?` required: [${t.map(e=>`'${e.key}'`).join(`, `)}],
|
|
11
|
+
`:``} properties: {
|
|
12
|
+
${(e.length?e.map(e=>{let t=e.description?`, description: '${u(e.description)}'`:``;return` ${e.key}: { type: 'string'${t} }`}).join(`,
|
|
13
|
+
`):``)||` `}
|
|
14
|
+
},
|
|
15
|
+
},\n`}function n(e){return e.length===0?`{}`:`{
|
|
16
|
+
${e.map(e=>{switch(e.type){case`number`:return` ${e.key}: 0`;case`boolean`:return` ${e.key}: true`;case`string`:default:return` ${e.key}: '${e.key.toUpperCase()}_VALUE'`}}).join(`,
|
|
17
|
+
`)}
|
|
18
|
+
}`}function r(e){return e.length===0?`{}`:`{
|
|
19
|
+
${e.map(e=>` ${e.key}: '${e.key.toUpperCase()}_SECRET'`).join(`,
|
|
20
|
+
`)}
|
|
21
|
+
}`}function i(e,t){if(e==null&&t==null)return``;let n=[];return e!=null&&n.push(` rpm: ${e}`),t!=null&&n.push(` rph: ${t}`),` constraints: {
|
|
22
|
+
rateLimit: {
|
|
23
|
+
${n.join(`,
|
|
24
|
+
`)}
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
`}function a(e,t,n){if(!e.includes(`byok`))return``;let r=t?` setupInstructions: '${u(t)}',\n`:``,i=n&&n.length?` requiredScopes: [${n.map(e=>`'${u(e)}'`).join(`, `)}],\n`:``;return!r&&!i?``:` byokSetup: {
|
|
28
|
+
${r}${i} },
|
|
29
|
+
`}function o(e){switch(e){case`number`:return`number`;case`boolean`:return`boolean`;case`string`:default:return`string`}}function s(e){switch(e){case`beta`:return`Beta`;case`stable`:return`Stable`;case`deprecated`:return`Deprecated`;case`experimental`:default:return`Experimental`}}function c(e){return e.capabilitiesProvided.map(e=>` { key: '${e.key}', version: ${e.version} }`).join(`,
|
|
30
|
+
`)}function l(e){return e.capabilitiesRequired.length===0?``:` requires: [
|
|
31
|
+
${e.capabilitiesRequired.map(e=>{let t=typeof e.version==`number`?`, version: ${e.version}`:``,n=e.optional?`, optional: true`:``,r=e.reason?`, reason: '${u(e.reason)}'`:``;return` { key: '${e.key}'${t}${n}${r} }`}).join(`,
|
|
32
|
+
`)}
|
|
33
|
+
],`}function u(e){return e.replace(/`/g,"\\`").replace(/'/g,`\\'`)}export{u as escape,a as renderByokSetup,n as renderConfigExample,e as renderConfigSchema,i as renderConstraints,c as renderProvides,l as renderRequires,r as renderSecretExample,t as renderSecretSchema,s as stabilityToEnum};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import{toPascalCase as e}from"./utils.js";import{escape as t,renderByokSetup as n,renderConfigExample as r,renderConfigSchema as i,renderConstraints as a,renderProvides as o,renderRequires as s,renderSecretExample as c,renderSecretSchema as l,stabilityToEnum as u}from"./integration-utils.js";function d(d){let f=e(d.name.split(`.`).pop()??`Integration`),p=`${f}IntegrationSpec`,m=`register${f}Integration`,h=d.supportedModes.length?d.supportedModes:[`managed`],g=h.map(e=>`'${e}'`).join(`, `),_=o(d),v=s(d),y=i(d.configFields),b=r(d.configFields),x=l(d.secretFields),S=c(d.secretFields),C=d.docsUrl?` docsUrl: '${t(d.docsUrl)}',\n`:``,w=a(d.rateLimitRpm,d.rateLimitRph),T=n(h,d.byokSetupInstructions,d.byokRequiredScopes);return`import { StabilityEnum } from '@lssm/lib.contracts/ownership';
|
|
2
|
+
import type { IntegrationSpec } from '@lssm/lib.contracts/integrations/spec';
|
|
3
|
+
import type { IntegrationSpecRegistry } from '@lssm/lib.contracts/integrations/spec';
|
|
4
|
+
|
|
5
|
+
export const ${p}: IntegrationSpec = {
|
|
6
|
+
meta: {
|
|
7
|
+
key: '${t(d.name)}',
|
|
8
|
+
version: ${d.version},
|
|
9
|
+
category: '${d.category}',
|
|
10
|
+
displayName: '${t(d.displayName)}',
|
|
11
|
+
title: '${t(d.title)}',
|
|
12
|
+
description: '${t(d.description)}',
|
|
13
|
+
domain: '${t(d.domain)}',
|
|
14
|
+
owners: [${d.owners.map(e=>`'${t(e)}'`).join(`, `)}],
|
|
15
|
+
tags: [${d.tags.map(e=>`'${t(e)}'`).join(`, `)}],
|
|
16
|
+
stability: StabilityEnum.${u(d.stability)},
|
|
17
|
+
},
|
|
18
|
+
supportedModes: [${g}],
|
|
19
|
+
capabilities: {
|
|
20
|
+
provides: [
|
|
21
|
+
${_}
|
|
22
|
+
],
|
|
23
|
+
${v.length>0?`${v}\n`:``} },
|
|
24
|
+
configSchema: {
|
|
25
|
+
${y} example: ${b},
|
|
26
|
+
},
|
|
27
|
+
secretSchema: {
|
|
28
|
+
${x} example: ${S},
|
|
29
|
+
},
|
|
30
|
+
${C}${w}${T} healthCheck: {
|
|
31
|
+
method: '${d.healthCheckMethod}',
|
|
32
|
+
timeoutMs: ${d.healthCheckTimeoutMs??5e3},
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export function ${m}(registry: IntegrationSpecRegistry): IntegrationSpecRegistry {
|
|
37
|
+
return registry.register(${p});
|
|
38
|
+
}
|
|
39
|
+
`}export{d as generateIntegrationSpec};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import{escapeString as e,toPascalCase as t}from"./utils.js";function n(n){let c=t(n.name.split(`.`).pop()??`KnowledgeSpace`),l=`${c}KnowledgeSpace`,u=`register${c}KnowledgeSpace`,d=r(n),f=i(n),p=a(n),m=n.policyName&&!n.policyVersion?` // defaults to latest version`:``;return`import { StabilityEnum } from '@lssm/lib.contracts/ownership';
|
|
2
|
+
import type { KnowledgeSpaceSpec } from '@lssm/lib.contracts/knowledge/spec';
|
|
3
|
+
import type { KnowledgeSpaceRegistry } from '@lssm/lib.contracts/knowledge/spec';
|
|
4
|
+
|
|
5
|
+
export const ${l}: KnowledgeSpaceSpec = {
|
|
6
|
+
meta: {
|
|
7
|
+
key: '${e(n.name)}',
|
|
8
|
+
version: ${n.version},
|
|
9
|
+
category: '${n.category}',
|
|
10
|
+
displayName: '${s(n.displayName)}',
|
|
11
|
+
title: '${s(n.title)}',
|
|
12
|
+
description: '${s(n.description)}',
|
|
13
|
+
domain: '${s(n.domain)}',
|
|
14
|
+
owners: [${n.owners.map(t=>`'${e(t)}'`).join(`, `)}],
|
|
15
|
+
tags: [${n.tags.map(t=>`'${e(t)}'`).join(`, `)}],
|
|
16
|
+
stability: StabilityEnum.${o(n.stability)},
|
|
17
|
+
},
|
|
18
|
+
retention: ${d},
|
|
19
|
+
access: {
|
|
20
|
+
${f}${n.policyName?` policy: { name: '${e(n.policyName)}',${n.policyVersion?` version: ${n.policyVersion}`:``} },${m}\n`:``} },
|
|
21
|
+
${p} description: '${s(n.description||n.displayName)}',
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export function ${u}(registry: KnowledgeSpaceRegistry): KnowledgeSpaceRegistry {
|
|
25
|
+
return registry.register(${l});
|
|
26
|
+
}
|
|
27
|
+
`}function r(e){return`{ ttlDays: ${e.retention.ttlDays===null?`null`:typeof e.retention.ttlDays==`number`?String(e.retention.ttlDays):`null`}${typeof e.retention.archiveAfterDays==`number`?`, archiveAfterDays: ${e.retention.archiveAfterDays}`:``} }`}function i(e){return`${` trustLevel: '${e.trustLevel}',\n`}${` automationWritable: ${e.automationWritable},\n`}`}function a(e){let t=[];return e.embeddingModel&&t.push(` embeddingModel: '${s(e.embeddingModel)}'`),typeof e.chunkSize==`number`&&t.push(` chunkSize: ${e.chunkSize}`),e.vectorDbIntegration&&t.push(` vectorDbIntegration: '${s(e.vectorDbIntegration)}'`),t.length===0?``:` indexing: {\n${t.join(`,
|
|
28
|
+
`)}\n },\n`}function o(e){switch(e){case`beta`:return`Beta`;case`stable`:return`Stable`;case`deprecated`:return`Deprecated`;case`experimental`:default:return`Experimental`}}function s(e){return e.replace(/`/g,"\\`").replace(/'/g,`\\'`)}export{n as generateKnowledgeSpaceSpec};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import{escapeString as e,toPascalCase as t}from"./utils.js";function n(n){let a=`${t(n.name.split(`.`).pop()??`Migration`)}Migration`,o=n.dependencies.length>0?`dependencies: [${n.dependencies.map(t=>`'${e(t)}'`).join(`, `)}],`:``;return`import type { MigrationSpec } from '@lssm/lib.contracts/migrations';
|
|
2
|
+
|
|
3
|
+
export const ${a}: MigrationSpec = {
|
|
4
|
+
meta: {
|
|
5
|
+
name: '${e(n.name)}',
|
|
6
|
+
version: ${n.version},
|
|
7
|
+
title: '${i(n.title)}',
|
|
8
|
+
description: '${i(n.description??``)}',
|
|
9
|
+
domain: '${i(n.domain)}',
|
|
10
|
+
owners: [${n.owners.map(t=>`'${e(t)}'`).join(`, `)}],
|
|
11
|
+
tags: [${n.tags.map(t=>`'${e(t)}'`).join(`, `)}],
|
|
12
|
+
stability: '${n.stability}',
|
|
13
|
+
},
|
|
14
|
+
plan: {
|
|
15
|
+
up: [
|
|
16
|
+
${r(n.up)}
|
|
17
|
+
],${n.down&&n.down.length?`
|
|
18
|
+
down: [
|
|
19
|
+
${r(n.down)}
|
|
20
|
+
],`:``}
|
|
21
|
+
},
|
|
22
|
+
${o}
|
|
23
|
+
};
|
|
24
|
+
`}function r(e){return e.map(e=>{let t=e.description?`description: '${i(e.description)}',`:``;switch(e.kind){case`schema`:return` {
|
|
25
|
+
kind: 'schema',
|
|
26
|
+
${t}
|
|
27
|
+
sql: \`${i(e.sql??``)}\`,
|
|
28
|
+
}`;case`data`:return` {
|
|
29
|
+
kind: 'data',
|
|
30
|
+
${t}
|
|
31
|
+
script: \`${i(e.script??``)}\`,
|
|
32
|
+
}`;case`validation`:default:return` {
|
|
33
|
+
kind: 'validation',
|
|
34
|
+
${t}
|
|
35
|
+
assertion: \`${i(e.assertion??``)}\`,
|
|
36
|
+
}`}}).join(`,
|
|
37
|
+
`)}function i(e){return e.replace(/`/g,"\\`").replace(/'/g,`\\'`)}export{n as generateMigrationSpec};
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import{capitalize as e,toPascalCase as t}from"./utils.js";function n(n){let{name:r,version:i,kind:a,description:o,goal:s,context:c,stability:l,owners:u,tags:d,auth:f,flags:p}=n,m=t(r.split(`.`).pop()??`Unknown`)+`Spec`,h=m.replace(`Spec`,`Input`),g=m.replace(`Spec`,`Output`);return`import { define${e(a)} } from '@lssm/lib.contracts';
|
|
2
|
+
import { ScalarTypeEnum, SchemaModel } from '@lssm/lib.schema';
|
|
3
|
+
|
|
4
|
+
// TODO: Define input schema
|
|
5
|
+
export const ${h} = new SchemaModel({
|
|
6
|
+
name: '${h}',
|
|
7
|
+
description: 'Input for ${r}',
|
|
8
|
+
fields: {
|
|
9
|
+
// Add your fields here
|
|
10
|
+
// example: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
11
|
+
},
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
// TODO: Define output schema
|
|
15
|
+
export const ${g} = new SchemaModel({
|
|
16
|
+
name: '${g}',
|
|
17
|
+
description: 'Output for ${r}',
|
|
18
|
+
fields: {
|
|
19
|
+
// Add your fields here
|
|
20
|
+
ok: { type: ScalarTypeEnum.Boolean(), isOptional: false },
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
export const ${m} = define${e(a)}({
|
|
25
|
+
meta: {
|
|
26
|
+
name: '${r}',
|
|
27
|
+
version: ${i},
|
|
28
|
+
stability: '${l}',
|
|
29
|
+
owners: [${u.map(e=>`'${e}'`).join(`, `)}],
|
|
30
|
+
tags: [${d.map(e=>`'${e}'`).join(`, `)}],
|
|
31
|
+
description: '${o}',
|
|
32
|
+
goal: '${s}',
|
|
33
|
+
context: '${c}',
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
io: {
|
|
37
|
+
input: ${h},
|
|
38
|
+
output: ${g},
|
|
39
|
+
errors: {
|
|
40
|
+
// Define possible errors
|
|
41
|
+
// EXAMPLE_ERROR: {
|
|
42
|
+
// description: 'Example error description',
|
|
43
|
+
// http: 400,
|
|
44
|
+
// when: 'When this error occurs',
|
|
45
|
+
// },
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
|
|
49
|
+
policy: {
|
|
50
|
+
auth: '${f}',
|
|
51
|
+
${p.length>0?`flags: [${p.map(e=>`'${e}'`).join(`, `)}],`:`// flags: [],`}
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
sideEffects: {
|
|
55
|
+
${n.emitsEvents?`emits: [
|
|
56
|
+
// Define events to emit
|
|
57
|
+
// { ref: SomeEventSpec, when: 'always' }
|
|
58
|
+
],`:`// emits: [],`}
|
|
59
|
+
analytics: [
|
|
60
|
+
// Define analytics events
|
|
61
|
+
],
|
|
62
|
+
},
|
|
63
|
+
|
|
64
|
+
transport: {
|
|
65
|
+
rest: { method: '${a===`command`?`POST`:`GET`}' },
|
|
66
|
+
gql: { field: '${r.replace(/\./g,`_`)}' },
|
|
67
|
+
mcp: { toolName: '${r}.v${i}' },
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
acceptance: {
|
|
71
|
+
scenarios: [
|
|
72
|
+
{
|
|
73
|
+
name: 'Happy path',
|
|
74
|
+
given: ['preconditions'],
|
|
75
|
+
when: ['action taken'],
|
|
76
|
+
then: ['expected outcome'],
|
|
77
|
+
},
|
|
78
|
+
],
|
|
79
|
+
examples: [
|
|
80
|
+
{
|
|
81
|
+
name: 'Example usage',
|
|
82
|
+
input: { /* example input */ },
|
|
83
|
+
output: { ok: true },
|
|
84
|
+
},
|
|
85
|
+
],
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
`}export{n as generateOperationSpec};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import{toPascalCase as e}from"./utils.js";function t(t){let{name:n,version:r,description:i,stability:a,owners:o,tags:s,presentationKind:c}=t,l=e(n.replace(/\./g,`_`))+`Presentation`,u=``;switch(c){case`web_component`:u=` content: {
|
|
2
|
+
kind: 'web_component',
|
|
3
|
+
framework: 'react',
|
|
4
|
+
componentKey: '${n.replace(/\./g,`_`)}',
|
|
5
|
+
props: new SchemaModel({
|
|
6
|
+
name: '${l}Props',
|
|
7
|
+
description: 'Props for ${n}',
|
|
8
|
+
fields: {
|
|
9
|
+
// TODO: Define component props
|
|
10
|
+
},
|
|
11
|
+
}),
|
|
12
|
+
analytics: [
|
|
13
|
+
// TODO: Define analytics events
|
|
14
|
+
],
|
|
15
|
+
},`;break;case`markdown`:u=` content: {
|
|
16
|
+
kind: 'markdown',
|
|
17
|
+
content: \`
|
|
18
|
+
# ${i}
|
|
19
|
+
|
|
20
|
+
TODO: Add markdown content here
|
|
21
|
+
\`,
|
|
22
|
+
// Or use resourceUri: 'feature://${n}/guide.md'
|
|
23
|
+
},`;break;case`data`:u=` content: {
|
|
24
|
+
kind: 'data',
|
|
25
|
+
mimeType: 'application/json',
|
|
26
|
+
model: new SchemaModel({
|
|
27
|
+
name: '${l}Data',
|
|
28
|
+
description: 'Data structure for ${n}',
|
|
29
|
+
fields: {
|
|
30
|
+
// TODO: Define data structure
|
|
31
|
+
},
|
|
32
|
+
}),
|
|
33
|
+
},`;break}return`import type { PresentationSpec } from '@lssm/lib.contracts/presentations';
|
|
34
|
+
import { SchemaModel, ScalarTypeEnum } from '@lssm/lib.schema';
|
|
35
|
+
|
|
36
|
+
export const ${l}: PresentationSpec = {
|
|
37
|
+
meta: {
|
|
38
|
+
name: '${n}',
|
|
39
|
+
version: ${r},
|
|
40
|
+
stability: '${a}',
|
|
41
|
+
owners: [${o.map(e=>`'${e}'`).join(`, `)}],
|
|
42
|
+
tags: [${s.map(e=>`'${e}'`).join(`, `)}],
|
|
43
|
+
description: '${i}',
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
policy: {
|
|
47
|
+
// flags: [],
|
|
48
|
+
// pii: [],
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
${u}
|
|
52
|
+
};
|
|
53
|
+
`}export{t as generatePresentationSpec};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import{toPascalCase as e}from"./utils.js";function t(t){let i=e(t.name.split(`.`).pop()??`Telemetry`)+`Telemetry`,a=t.providers?.length?`providers: [
|
|
2
|
+
${t.providers.map(e=>` {
|
|
3
|
+
type: '${e.type}',
|
|
4
|
+
config: ${r(e.config)},
|
|
5
|
+
}`).join(`,
|
|
6
|
+
`)}
|
|
7
|
+
],`:``,o=t.events.map(e=>{let t=e.properties.map(e=>` '${e.name}': {
|
|
8
|
+
type: '${e.type}',
|
|
9
|
+
${e.required?`required: true,`:``}
|
|
10
|
+
${e.pii?`pii: true,`:``}
|
|
11
|
+
${e.redact?`redact: true,`:``}
|
|
12
|
+
${e.description?`description: '${n(e.description)}',`:``}
|
|
13
|
+
}`).join(`,
|
|
14
|
+
`),r=e.anomalyRules?.length?` anomalyDetection: {
|
|
15
|
+
enabled: true,
|
|
16
|
+
${typeof e.anomalyMinimumSample==`number`?`minimumSample: ${e.anomalyMinimumSample},`:``}
|
|
17
|
+
thresholds: [
|
|
18
|
+
${e.anomalyRules.map(e=>` {
|
|
19
|
+
metric: '${n(e.metric)}',
|
|
20
|
+
${typeof e.min==`number`?`min: ${e.min},`:``}
|
|
21
|
+
${typeof e.max==`number`?`max: ${e.max},`:``}
|
|
22
|
+
}`).join(`,
|
|
23
|
+
`)}
|
|
24
|
+
],
|
|
25
|
+
actions: [${(e.anomalyActions??[]).map(e=>`'${e}'`).join(`, `)}],
|
|
26
|
+
},`:e.anomalyEnabled?` anomalyDetection: {
|
|
27
|
+
enabled: true,
|
|
28
|
+
${typeof e.anomalyMinimumSample==`number`?`minimumSample: ${e.anomalyMinimumSample},`:``}
|
|
29
|
+
},`:``;return` {
|
|
30
|
+
name: '${n(e.name)}',
|
|
31
|
+
version: ${e.version},
|
|
32
|
+
semantics: {
|
|
33
|
+
what: '${n(e.what)}',
|
|
34
|
+
${e.who?`who: '${n(e.who)}',`:``}
|
|
35
|
+
${e.why?`why: '${n(e.why)}',`:``}
|
|
36
|
+
},
|
|
37
|
+
privacy: '${e.privacy}',
|
|
38
|
+
properties: {
|
|
39
|
+
${t}
|
|
40
|
+
},
|
|
41
|
+
${typeof e.retentionDays==`number`?`retention: { days: ${e.retentionDays}, ${e.retentionPolicy?`policy: '${e.retentionPolicy}'`:``} },`:``}
|
|
42
|
+
${typeof e.samplingRate==`number`?`sampling: { rate: ${e.samplingRate}${e.samplingConditions?`, conditions: ['${n(e.samplingConditions)}']`:``} },`:``}
|
|
43
|
+
${r}
|
|
44
|
+
${e.tags?.length?`tags: [${e.tags.map(e=>`'${n(e)}'`).join(`, `)}],`:``}
|
|
45
|
+
}`}).join(`,
|
|
46
|
+
`);return`import type { TelemetrySpec } from '@lssm/lib.contracts/telemetry';
|
|
47
|
+
|
|
48
|
+
export const ${i}: TelemetrySpec = {
|
|
49
|
+
meta: {
|
|
50
|
+
name: '${n(t.name)}',
|
|
51
|
+
version: ${t.version},
|
|
52
|
+
title: '${n(t.name)} telemetry',
|
|
53
|
+
description: '${n(t.description||`Describe the purpose of this telemetry spec.`)}',
|
|
54
|
+
domain: '${n(t.domain)}',
|
|
55
|
+
owners: [${t.owners.map(e=>`'${n(e)}'`).join(`, `)}],
|
|
56
|
+
tags: [${t.tags.map(e=>`'${n(e)}'`).join(`, `)}],
|
|
57
|
+
stability: '${t.stability}',
|
|
58
|
+
},
|
|
59
|
+
config: {
|
|
60
|
+
${typeof t.defaultRetentionDays==`number`?`defaultRetentionDays: ${t.defaultRetentionDays},`:``}
|
|
61
|
+
${typeof t.defaultSamplingRate==`number`?`defaultSamplingRate: ${t.defaultSamplingRate},`:``}
|
|
62
|
+
${t.anomalyEnabled?`anomalyDetection: { enabled: true${typeof t.anomalyCheckIntervalMs==`number`?`, checkIntervalMs: ${t.anomalyCheckIntervalMs}`:``} },`:``}
|
|
63
|
+
${a}
|
|
64
|
+
},
|
|
65
|
+
events: [
|
|
66
|
+
${o}
|
|
67
|
+
],
|
|
68
|
+
};
|
|
69
|
+
`}function n(e){return e.replace(/\\/g,`\\\\`).replace(/'/g,`\\'`)}function r(e){let t=e.trim();return t?t.startsWith(`{`)&&t.endsWith(`}`)||t.startsWith(`[`)&&t.endsWith(`]`)?t:`'${n(t)}'`:`{}`}export{t as generateTelemetrySpec};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function e(e){let n=t(e);return n.charAt(0).toLowerCase()+n.slice(1)}function t(e){return e.split(/[-_.]/).map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(``)}function n(e){return e.replace(/\./g,`-`).replace(/([a-z])([A-Z])/g,`$1-$2`).toLowerCase()}function r(e){return e.charAt(0).toUpperCase()+e.slice(1)}function i(e){return e.replace(/'/g,`\\'`)}export{r as capitalize,i as escapeString,e as toCamelCase,n as toKebabCase,t as toPascalCase};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
function e({exportName:e,specImportPath:t,runnerName:n,workflowName:r}){return`import {
|
|
2
|
+
InMemoryStateStore,
|
|
3
|
+
WorkflowRegistry,
|
|
4
|
+
WorkflowRunner,
|
|
5
|
+
} from '@lssm/lib.contracts/workflow';
|
|
6
|
+
import { ${e} } from '${t}';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Runner wiring for ${r}.
|
|
10
|
+
*
|
|
11
|
+
* TODO:
|
|
12
|
+
* - Replace the in-memory state store with a persistent adapter if needed.
|
|
13
|
+
* - Implement opExecutor to invoke the correct contract handlers.
|
|
14
|
+
* - Wire eventEmitter to telemetry sinks.
|
|
15
|
+
*/
|
|
16
|
+
const registry = new WorkflowRegistry();
|
|
17
|
+
registry.register(${e});
|
|
18
|
+
|
|
19
|
+
const stateStore = new InMemoryStateStore();
|
|
20
|
+
|
|
21
|
+
export const ${n} = new WorkflowRunner({
|
|
22
|
+
registry,
|
|
23
|
+
stateStore,
|
|
24
|
+
opExecutor: async (operation, input, ctx) => {
|
|
25
|
+
// TODO: route to the appropriate contract handler
|
|
26
|
+
// Example: return contractRegistry.execute(operation.name, operation.version, input, ctx);
|
|
27
|
+
throw new Error(
|
|
28
|
+
\`opExecutor for \${operation.name}.v\${operation.version} is not implemented\`
|
|
29
|
+
);
|
|
30
|
+
},
|
|
31
|
+
// appConfigProvider: async (state) => {
|
|
32
|
+
// // TODO: return the ResolvedAppConfig for this workflow run (tenant/environment)
|
|
33
|
+
// return undefined;
|
|
34
|
+
// },
|
|
35
|
+
// enforceCapabilities: async (operation, context) => {
|
|
36
|
+
// // TODO: ensure required capabilities are satisfied using context.integrations/context.resolvedAppConfig
|
|
37
|
+
// },
|
|
38
|
+
eventEmitter: (_event, _payload) => {
|
|
39
|
+
// TODO: forward workflow events to telemetry or logging sinks
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
`}export{e as generateWorkflowRunnerTemplate};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import{escapeString as e,toPascalCase as t}from"./utils.js";function n(n){let i=t(n.name.split(`.`).pop()??`Workflow`)+`Workflow`,a=n.steps.map(e=>r(e)).join(`,
|
|
2
|
+
`),o=n.transitions.map(t=>` {
|
|
3
|
+
from: '${t.from}',
|
|
4
|
+
to: '${t.to}',
|
|
5
|
+
${t.condition?` condition: '${e(t.condition)}',`:``}
|
|
6
|
+
}`).join(`,
|
|
7
|
+
`);return`import type { WorkflowSpec } from '@lssm/lib.contracts/workflow';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Workflow generated via contractspec CLI.
|
|
11
|
+
* TODO:
|
|
12
|
+
* - Review step definitions and descriptions.
|
|
13
|
+
* - Wire automation steps to actual operations.
|
|
14
|
+
* - Provide form renderers for human steps.
|
|
15
|
+
* - Add guards/conditions as needed.
|
|
16
|
+
*/
|
|
17
|
+
export const ${i}: WorkflowSpec = {
|
|
18
|
+
meta: {
|
|
19
|
+
name: '${n.name}',
|
|
20
|
+
version: ${n.version},
|
|
21
|
+
title: '${e(n.title)}',
|
|
22
|
+
description: '${e(n.description)}',
|
|
23
|
+
domain: '${e(n.domain)}',
|
|
24
|
+
stability: '${n.stability}',
|
|
25
|
+
owners: [${n.owners.map(e=>`'${e}'`).join(`, `)}],
|
|
26
|
+
tags: [${n.tags.map(e=>`'${e}'`).join(`, `)}],
|
|
27
|
+
},
|
|
28
|
+
definition: {
|
|
29
|
+
${n.entryStepId?` entryStepId: '${n.entryStepId}',\n`:``} steps: [
|
|
30
|
+
${a}
|
|
31
|
+
],
|
|
32
|
+
transitions: [
|
|
33
|
+
${o}
|
|
34
|
+
],
|
|
35
|
+
},
|
|
36
|
+
${n.policyFlags.length>0?`policy: {
|
|
37
|
+
flags: [${n.policyFlags.map(e=>`'${e}'`).join(`, `)}],
|
|
38
|
+
},`:`// policy: { flags: [] },`}
|
|
39
|
+
};
|
|
40
|
+
`}function r(t){let n=[` {`,` id: '${t.id}',`,` type: '${t.type}',`,` label: '${e(t.label)}',`];t.description&&n.push(` description: '${e(t.description)}',`);let r=[];return t.operation&&r.push(`operation: { name: '${t.operation.name}', version: ${t.operation.version} }`),t.form&&r.push(`form: { key: '${t.form.key}', version: ${t.form.version} }`),r.length&&n.push(` action: { ${r.join(`, `)} },`),n.push(` }`),n.join(`
|
|
41
|
+
`)}export{n as generateWorkflowSpec};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const e={aiProvider:`claude`,agentMode:`simple`,outputDir:`./src`,conventions:{operations:`interactions/commands|queries`,events:`events`,presentations:`presentations`,forms:`forms`},defaultOwners:[],defaultTags:[]};export{e as DEFAULT_WORKSPACE_CONFIG};
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@lssm/module.contractspec-workspace",
|
|
3
|
+
"version": "0.0.0-canary-20251213172311",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"module": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist",
|
|
10
|
+
"README.md"
|
|
11
|
+
],
|
|
12
|
+
"scripts": {
|
|
13
|
+
"publish:pkg": "bun publish --tolerate-republish --ignore-scripts --verbose",
|
|
14
|
+
"build": "bun build:bundle && bun build:types",
|
|
15
|
+
"build:bundle": "tsdown",
|
|
16
|
+
"build:types": "tsc --noEmit",
|
|
17
|
+
"dev": "bun build:bundle --watch",
|
|
18
|
+
"clean": "rimraf dist .turbo",
|
|
19
|
+
"lint": "bun lint:fix",
|
|
20
|
+
"lint:fix": "eslint src --fix",
|
|
21
|
+
"lint:check": "eslint src",
|
|
22
|
+
"test": "bun run"
|
|
23
|
+
},
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"@lssm/lib.contracts": "workspace:*",
|
|
26
|
+
"@lssm/lib.schema": "workspace:*",
|
|
27
|
+
"zod": "^4.1.13"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@lssm/tool.tsdown": "workspace:*",
|
|
31
|
+
"@lssm/tool.typescript": "workspace:*",
|
|
32
|
+
"tsdown": "^0.17.0",
|
|
33
|
+
"typescript": "^5.9.3"
|
|
34
|
+
},
|
|
35
|
+
"exports": {
|
|
36
|
+
".": "./src/index.ts",
|
|
37
|
+
"./*": "./*"
|
|
38
|
+
},
|
|
39
|
+
"publishConfig": {
|
|
40
|
+
"access": "public",
|
|
41
|
+
"exports": {
|
|
42
|
+
".": "./dist/index.js",
|
|
43
|
+
"./*": "./*"
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|