@rse/ase 0.9.20 → 0.9.22

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.
@@ -5,7 +5,7 @@
5
5
  */
6
6
  import fs from "node:fs";
7
7
  import { InvalidArgumentError } from "commander";
8
- import { renderMermaidASCII } from "beautiful-mermaid";
8
+ import { renderMermaidASCII, renderMermaidSVG } from "beautiful-mermaid";
9
9
  import { z } from "zod";
10
10
  /* custom argument parser for Commander: non-negative integer */
11
11
  const parseInteger = (name) => (value) => {
@@ -20,6 +20,12 @@ const parseColorMode = (name) => (value) => {
20
20
  throw new InvalidArgumentError(`${name} must be "none", "ansi16", or "ansi256"`);
21
21
  return value;
22
22
  };
23
+ /* custom argument parser for Commander: output format */
24
+ const parseFormat = (name) => (value) => {
25
+ if (value !== "ascii" && value !== "svg")
26
+ throw new InvalidArgumentError(`${name} must be "ascii" or "svg"`);
27
+ return value;
28
+ };
23
29
  /* scan a CSI escape sequence starting at line[i] (where line[i]===ESC and
24
30
  line[i+1]==="["); return the index just past the terminating letter, or
25
31
  -1 if the sequence is unterminated within the line */
@@ -135,8 +141,14 @@ export class Diagram {
135
141
  return mode;
136
142
  }
137
143
  /* pure rendering helper: turn a Mermaid source string plus options into
138
- a rendered Unicode/ASCII diagram string. Throws on render failure. */
144
+ a rendered Unicode/ASCII diagram string, or an SVG document string
145
+ when "svg" format is requested. Throws on render failure. */
139
146
  static render(src, opts) {
147
+ /* render as a self-contained SVG document using the library's
148
+ themed defaults (the ANSI "colorMode" and the terminal
149
+ clipping below are meaningful only for ASCII art) */
150
+ if (opts.format === "svg")
151
+ return renderMermaidSVG(src);
140
152
  /* create diagram rendering */
141
153
  let out = renderMermaidASCII(src, {
142
154
  useAscii: opts.ascii,
@@ -216,8 +228,9 @@ export default class DiagramCommand {
216
228
  register(program) {
217
229
  program
218
230
  .command("diagram")
219
- .description("Render Mermaid diagram specification as Unicode/ASCII art")
231
+ .description("Render Mermaid diagram specification as Unicode/ASCII art or SVG")
220
232
  .option("-i, --input <file>", "read Mermaid source from file instead of stdin")
233
+ .option("-f, --format <format>", "output format (\"ascii\" or \"svg\")", parseFormat("--format"), "ascii")
221
234
  .option("-a, --ascii", "emit plain ASCII (+-|) instead of Unicode box-drawing", false)
222
235
  .option("-c, --color-mode <mode>", "force color mode (\"none\", \"ansi16\", or \"ansi256\")", parseColorMode("--color-mode"), Diagram.detectColorMode())
223
236
  .option("--node-margin-x <n>", "horizontal margin between nodes of <n> characters", parseInteger("--node-margin-x"), 3)
@@ -242,6 +255,7 @@ export default class DiagramCommand {
242
255
  let out;
243
256
  try {
244
257
  out = Diagram.render(src, {
258
+ format: opts.format,
245
259
  ascii: opts.ascii ?? false,
246
260
  colorMode: opts.colorMode,
247
261
  nodeMarginX: opts.nodeMarginX,
@@ -270,7 +284,7 @@ export class DiagramMCP {
270
284
  register(mcp) {
271
285
  mcp.registerTool("ase_diagram", {
272
286
  title: "ASE diagram render",
273
- description: "Render a Mermaid diagram as Unicode/ASCII art. " +
287
+ description: "Render a Mermaid diagram as Unicode/ASCII art or SVG. " +
274
288
  "Use for visualizing " +
275
289
  "structure/layout/components/dependencies as a Flowchart, " +
276
290
  "control-flow/branching/concurrency as a Flowchart, " +
@@ -280,10 +294,12 @@ export class DiagramMCP {
280
294
  "data-model/entities/relationships as an ER Diagram, or " +
281
295
  "metrics/distributions/time-series as an XY-Chart. " +
282
296
  "Pass the Mermaid diagram specification as `diagram`. " +
283
- "Returns the rendered art as `text`.",
297
+ "Returns the rendered art (or SVG document, for `format` \"svg\") as `text`.",
284
298
  inputSchema: {
285
299
  diagram: z.string()
286
300
  .describe("Mermaid diagram specification"),
301
+ format: z.enum(["ascii", "svg"]).default("ascii")
302
+ .describe("output format: \"ascii\" for Unicode/ASCII art, \"svg\" for an SVG document"),
287
303
  ascii: z.boolean().default(false)
288
304
  .describe("emit plain ASCII (+-|) instead of Unicode box-drawing characters"),
289
305
  colorMode: z.enum(["none", "ansi16", "ansi256"]).default("none")
@@ -306,6 +322,7 @@ export class DiagramMCP {
306
322
  }, async (args) => {
307
323
  try {
308
324
  const out = Diagram.render(args.diagram, {
325
+ format: args.format,
309
326
  ascii: args.ascii,
310
327
  colorMode: args.colorMode,
311
328
  nodeMarginX: args.nodeMarginX,
package/package.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "homepage": "http://github.com/rse/ase",
7
7
  "repository": { "url": "git+https://github.com/rse/ase.git", "type": "git" },
8
8
  "bugs": { "url": "http://github.com/rse/ase/issues" },
9
- "version": "0.9.20",
9
+ "version": "0.9.22",
10
10
  "license": "GPL-3.0-only",
11
11
  "author": {
12
12
  "name": "Dr. Ralf S. Engelschall",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ase",
3
- "version": "0.9.20",
3
+ "version": "0.9.22",
4
4
  "description": "Agentic Software Engineering (ASE)",
5
5
  "keywords": [ "agentic", "software", "engineering" ],
6
6
  "homepage": "https://ase.tools",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ase",
3
- "version": "0.9.20",
3
+ "version": "0.9.22",
4
4
  "description": "Agentic Software Engineering (ASE)",
5
5
  "keywords": [ "agentic", "software", "engineering" ],
6
6
  "homepage": "https://ase.tools",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ase",
3
- "version": "0.9.20",
3
+ "version": "0.9.22",
4
4
  "description": "Agentic Software Engineering (ASE)",
5
5
  "keywords": [ "agentic", "software", "engineering" ],
6
6
  "homepage": "https://ase.tools",
@@ -9,10 +9,11 @@ and the "how" of the Software Engineering project.
9
9
 
10
10
  Each **Artifact** of the **Artifact Set**
11
11
  **Architecture (ARCH)** is stored under
12
- `docs/arch/ARCH-<artifact-no/>-<artifact-id/>-<artifact-slug/>.md`,
13
- relative to the project root directory, with <artifact-no/> being the
14
- zero-padded, two-digit sequence number of the **Artifact** (starting at
15
- `01`) according to the order of the **Artifact** list below, and with
12
+ `<basedir/>/ARCH-<artifact-no/>-<artifact-id/>-<artifact-slug/>.md`,
13
+ relative to the project root directory, with <basedir/> being the
14
+ `project.artifact.arch.basedir` config variable, <artifact-no/> being
15
+ the zero-padded, two-digit sequence number of the **Artifact** (starting
16
+ at `01`) according to the order of the **Artifact** list below, and with
16
17
  <artifact-slug/> being derived from <artifact-name/> (see below) by
17
18
  Pascal-casing each word (upper-casing its first letter) and using `-`
18
19
  characters instead of spaces (e.g. `Context-View`).
@@ -74,6 +75,12 @@ distinct **Artifact**s (listed under their <artifact-name/> and their
74
75
  The major decisions related to the architecture, each recording the
75
76
  forces at play, the chosen response, and the reasoning that justifies it.
76
77
 
78
+ 10. **Technology Stack (TS)**:
79
+ The concrete technology products the solution is built upon, organized
80
+ by tier and lifecycle phase, recording for each component its chosen
81
+ product, its purpose, and the alternatives that were considered but not
82
+ chosen.
83
+
77
84
  The **Artifact**s have the following cross-references:
78
85
 
79
86
  ```text
@@ -89,6 +96,8 @@ ARCH-08-QP Quality Perspectives ──(affects)─► ARCH-02-FV Functionalit
89
96
  ARCH-08-QP Quality Perspectives ──(affects)─► ARCH-06-DP Deployment View
90
97
  ARCH-09-DR Decision Record ──(affects)─► ARCH-02-FV Functionality View
91
98
  ARCH-09-DR Decision Record ──(affects)─► ARCH-06-DP Deployment View
99
+ ARCH-10-TS Technology Stack ──(realizes)─► ARCH-02-FV Functionality View
100
+ ARCH-10-TS Technology Stack ──(realizes)─► ARCH-06-DP Deployment View
92
101
  ```
93
102
 
94
103
  Context View (CV)
@@ -897,3 +906,274 @@ forces at play, the chosen response, and the reasoning that justifies it.
897
906
  - **Rejected alternatives when the rejection is non-obvious.** If
898
907
  you considered GraphQL and picked REST for subtle reasons, record it -
899
908
  otherwise someone will suggest GraphQL again in six months.
909
+
910
+ Technology Stack (TS)
911
+ ---------------------
912
+
913
+ The concrete technology products the solution is built upon, organized by
914
+ tier and lifecycle phase, recording for each component its chosen product,
915
+ its purpose, and the alternatives that were considered but not chosen.
916
+
917
+ - Format:
918
+
919
+ <format>
920
+
921
+ # ARCHITECTURE: TECHNOLOGY STACK (ARCH-TS)
922
+
923
+ ✳ Created: **<timestamp-created/>**
924
+ ✎ Modified: **<timestamp-modified/>**
925
+
926
+ <arch-ts-component/>
927
+ <arch-ts-component/>
928
+ [...]
929
+
930
+ </format>
931
+
932
+ - <arch-ts-component/> format:
933
+
934
+ <format>
935
+
936
+ ## COMPONENT: <arch-ts-component-name/> <a id="ARCH-TS-<arch-ts-component-id/>"></a>
937
+
938
+ - Product: <arch-ts-component-product/>
939
+ - Alternatives: <arch-ts-component-alternative/>[, ...]
940
+ - Coverage: <arch-ts-component-coverage/>
941
+ - Realizes: <arch-ts-component-element/>[, ...]
942
+ - Tier: <arch-ts-component-tier/>
943
+ - When: <arch-ts-component-when/>
944
+
945
+ <arch-ts-component-description/>,
946
+ **BECAUSE** <arch-ts-component-rationale/>.
947
+
948
+ </format>
949
+
950
+ - <arch-ts-component/> details:
951
+
952
+ - <arch-ts-component-id/>: per-artifact unique "slug" of always 1-3
953
+ lower-cased words (concatenated with "-" characters and
954
+ in total not longer than 30 characters), derived from
955
+ <arch-ts-component-name/>.
956
+
957
+ - <arch-ts-component-name/> is a short (2-5 word) summary of the
958
+ technology component (e.g. `UI Framework`, `Web Server`, `Relational
959
+ Database`).
960
+
961
+ - <arch-ts-component-product/> is the concrete product, library, or
962
+ framework chosen for this component (e.g. `VueJS`, `Node.js`,
963
+ `PostgreSQL`).
964
+
965
+ - <arch-ts-component-alternative/> is a product that would also fit
966
+ this component but was not chosen (e.g. `React`, `Svelte`).
967
+
968
+ - <arch-ts-component-coverage/> is either one or more of the
969
+ *Client Aspects* or one or more of the *Server Aspects* defined
970
+ below. The general goal is to achieve a maximum coverage of all
971
+ aspects per <arch-ts-component-tier/> with the minimum total
972
+ number of <arch-ts-component-product/>.
973
+
974
+ - <arch-ts-component-element/> is an `ARCH-FV-<arch-fv-component-id/>`
975
+ or `ARCH-DP-<arch-dp-node-id/>` reference to the functional element
976
+ or deployment node this product realizes.
977
+
978
+ - <arch-ts-component-tier/> is the architectural tier the component
979
+ belongs to, one of:
980
+
981
+ - `Client`: Runs on the client side (e.g. browser, desktop, mobile).
982
+ - `Server`: Runs on the server side (e.g. backend, application, API).
983
+
984
+ - <arch-ts-component-when/> is the lifecycle phase in which the
985
+ component is relevant, one of:
986
+
987
+ - `Build-Time`: Used during development, compilation, or packaging.
988
+ - `Run-Time`: Used while the solution executes in production.
989
+
990
+ - <arch-ts-component-description/> is a concise paragraph (1-3
991
+ sentences) of prose describing how the product is used within the
992
+ solution and how it fits into the overall technology stack.
993
+
994
+ - <arch-ts-component-rationale/> is the 1-sentence rationale ("why")
995
+ for choosing this product over the alternatives.
996
+
997
+ - In case the element reference is not present, the
998
+ entire `- Realizes:` bullet point is omitted.
999
+
1000
+ - In case no alternatives were considered, the
1001
+ entire `- Alternatives:` bullet point is omitted.
1002
+
1003
+ - In case the rationale is not present, the
1004
+ entire `, **BECAUSE** [...]` clause is omitted.
1005
+
1006
+ - The known *Client Aspects* which usually have to covered (at least for
1007
+ clients in a Rich-Client architecture):
1008
+
1009
+ - **Interface Theme**:
1010
+ Style Reset, Shape, Color, Gradient, Shadow, Font, Icon.
1011
+
1012
+ - **Interface Widgets**:
1013
+ Icon, Label, Text Paragraph, Image, Form, Text-Field, Text-Area,
1014
+ Date Picker, Toggle, Radio Button, Checkbox, Select List, Slider,
1015
+ Progress Bar, Hyperlink, Popup Menu, Dropdown Menu, Toolbar, Tooltip,
1016
+ Tab, Pill, Breadcrumb, Pagination, Badge, Alert, Panel, Modal, Table,
1017
+ Scrollbar, Carousel.
1018
+
1019
+ - **Interface Layouting**:
1020
+ Responsive Design, Media Query, Frame, Grid, Padding, Border,
1021
+ Margin, Alignment, Force, Magnetism.
1022
+
1023
+ - **Interface Effects**:
1024
+ Transition, Transformation, Keyframes, Easing Function, Sound
1025
+ Effect, Physics.
1026
+
1027
+ - **Interface Interactions**:
1028
+ Mouse, Keyboard, Touchscreen, Gesture, Clipboard, Drag & Drop.
1029
+
1030
+ - **Interface States**:
1031
+ Rendered, Enabled, Visible, Focused, Warning, Error, Floating.
1032
+
1033
+ - **Interface Mask**:
1034
+ Markup Loading, Markup Generation, Virtual DOM, Text, Bitmaps,
1035
+ Vectors, 2D/3D Canvas, Accessibility.
1036
+
1037
+ - **Interface Internationalization**:
1038
+ Text Internationalization (I18N).
1039
+
1040
+ - **Data Conversion**:
1041
+ Value Formatting, Value Parsing, Localization (L10N).
1042
+
1043
+ - **Data Binding**:
1044
+ Reactive, Observer, Unidirectional, Bidirectional, Incremental.
1045
+
1046
+ - **Presentation Model**:
1047
+ Parameter Value, Command Value, State Value, Data Value, Event
1048
+ Value, Value Validation, Presentation Logic.
1049
+
1050
+ - **Dialog Navigation**:
1051
+ Deep Linking, Routing, Dialog Flow.
1052
+
1053
+ - **Dialog Automation**:
1054
+ Dialog Macros, Click-Through, Smoke Testing.
1055
+
1056
+ - **Dialog Communication**:
1057
+ Service, Event, Model, Socket, Hooks.
1058
+
1059
+ - **Dialog Life-Cycle**:
1060
+ Component States, Component State Transitions.
1061
+
1062
+ - **Dialog Structure**:
1063
+ Component, Model/View/Controller Roles, Hierarchical Composition.
1064
+
1065
+ - **State Persistence**:
1066
+ Local Storage, Cookies, Caching.
1067
+
1068
+ - **Business Model**:
1069
+ Entity, Field, Relationship, Universally Unique Identifiers (UUID).
1070
+
1071
+ - **Use-Case Authorization**:
1072
+ User Experience, Dialog Restriction, User, Group, Role, Use-Case,
1073
+ Data, Access.
1074
+
1075
+ - **Client Networking**:
1076
+ Request/Response, Synchronization, Push, Pull, Pulled-Push,
1077
+ REST, GraphQL, Authentication, Session.
1078
+
1079
+ - **Environment Detection**:
1080
+ Runtime Detection, Feature Detection.
1081
+
1082
+ - The known *Server Aspects* which usually have to covered (at least for
1083
+ servers, sometimes called Thin-Servers, in a Rich-Client architecture):
1084
+
1085
+ - **Environment Detection**:
1086
+ Detect the run-time environment, like underlying operating
1087
+ system, execution platform, network topology, feature toggles, etc.
1088
+
1089
+ - **Argument Parsing**:
1090
+ Parse options and arguments of the Command-Line Interface (CLI)
1091
+ to bootstrap application parameters.
1092
+
1093
+ - **Configuration Parsing**:
1094
+ Load and parse directives from configuration file to bootstrap
1095
+ application parameters.
1096
+
1097
+ - **Process Daemonizing**:
1098
+ Detach from the startup terminal and host process in order to run
1099
+ fully independently.
1100
+
1101
+ - **Process Management**:
1102
+ (Pre-)fork child processes and/or threads of execution and monitor
1103
+ and control them during the life-cycle of the application.
1104
+
1105
+ - **Component Management**:
1106
+ Structure the code into components, instantiate them under run-time
1107
+ and manage them in a stateful component life-cycle.
1108
+
1109
+ - **Component Communication**:
1110
+ Provide inter-component communication mechanisms like events, hooks,
1111
+ registry, etc.
1112
+
1113
+ - **Server Networking**:
1114
+ Listen to network sockets, accept connections and manage
1115
+ request/response and message communication.
1116
+
1117
+ - **Peer Information**:
1118
+ Determine unique identification and add-on information about the
1119
+ client peer.
1120
+
1121
+ - **Session Handling**:
1122
+ Manage secured per-connection sessions to keep state between
1123
+ communication requests and/or client sessions.
1124
+
1125
+ - **User Authentication**:
1126
+ Determine and validate the unique identity of the user communicating
1127
+ over the current network connection.
1128
+
1129
+ - **Request Validation**:
1130
+ Validate the syntactical and semantical compliance of the requests
1131
+ and sanitize the requests.
1132
+
1133
+ - **Request Processing**:
1134
+ Process the request by dispatching execution according to the
1135
+ provided request and determined context information.
1136
+
1137
+ - **Role Authorization**:
1138
+ Determine whether the role of the current user is allowed to execute
1139
+ the current request.
1140
+
1141
+ - **Client Networking**:
1142
+ Provide mechanisms to connect to peers over the network and perform
1143
+ request/response and/or publish/subscribe communication.
1144
+
1145
+ - **Task Scheduling**:
1146
+ Schedule and execute recurring tasks independent of regular I/O
1147
+ operations.
1148
+
1149
+ - **Execution Tracing**:
1150
+ Provide mechanisms for tracing the execution by logging event and
1151
+ measurement information at certain points of interest.
1152
+
1153
+ - **Database Access**:
1154
+ Map in-memory domain entities onto data store dependent persistent
1155
+ data structure.
1156
+
1157
+ - **Database Connectivity**:
1158
+ Locally or remotely connect the database access layer to the
1159
+ underlying data store.
1160
+
1161
+ - **Database Schema**:
1162
+ Create, update or downgrade the data schema inside the underlying
1163
+ data store.
1164
+
1165
+ - **Database Bootstrapping**:
1166
+ Create, update or downgrade both mandatory bootstrapping and optional
1167
+ domain-specific data inside the underlying data store.
1168
+
1169
+ - Export: `export.md`
1170
+
1171
+ The components rendered as a single, compact Markdown table -- one
1172
+ row per <arch-ts-component/>, sorted by <arch-ts-component-tier/>
1173
+ then <arch-ts-component-when/> -- with the columns:
1174
+
1175
+ - `Component` (<arch-ts-component-name/>)
1176
+ - `Product` (**<arch-ts-component-product/>**)
1177
+ - `Tier` (<arch-ts-component-tier/>)
1178
+ - `When` (<arch-ts-component-when/>)
1179
+ - `Coverage` (*<arch-ts-component-coverage/>*)
@@ -56,3 +56,35 @@ Artifact Meta Information
56
56
  unique "slug" of always 1-3 lower-cased words (concatenated with "-"
57
57
  characters and in total not longer than 30 characters). An example
58
58
  is `user-login`.
59
+
60
+ An **Artifact** *MAY* additionally declare an **Export** -- a derived,
61
+ ready-to-consume rendering of (part of) its content, materialized as a
62
+ *side-by-side* file next to the **Artifact** itself. An **Artifact**
63
+ without an `- Export:` bullet is *not* exported.
64
+
65
+ An **Export** is declared by a single `- Export:` bullet point in the
66
+ **Artifact**'s format definition (see `ase-format-spec.md` and
67
+ `ase-format-arch.md`), of the following format:
68
+
69
+ <format>
70
+
71
+ - Export: `<export-name/>.<export-ext/>`
72
+ <export-transform/>
73
+
74
+ </format>
75
+
76
+ with the following details:
77
+
78
+ - <export-ext/> is the file-name extension (without the leading dot,
79
+ e.g. `svg`, `md`) of the exported file, which also implies its
80
+ target format.
81
+
82
+ - <export-transform/> is a description of *how* the **Artifact**'s
83
+ content is transformed into the exported file (e.g. "the entities,
84
+ attributes, and relations rendered as a Mermaid `classDiagram` and
85
+ converted to SVG").
86
+
87
+ The exported file is stored *side-by-side* with the **Artifact** under
88
+ the path:
89
+
90
+ `<basedir/>/<artifact-set-id/>-<artifact-no/>-<artifact-id/>-<artifact-slug/>-<export-name/>.<export-ext/>`
@@ -9,10 +9,11 @@ and the "what" of the Software Engineering project.
9
9
 
10
10
  Each **Artifact** of the **Artifact Set**
11
11
  **Specification (SPEC)** is stored under
12
- `docs/spec/SPEC-<artifact-no/>-<artifact-id/>-<artifact-slug/>.md`,
13
- relative to the project root directory, with <artifact-no/> being the
14
- zero-padded, two-digit sequence number of the **Artifact** (starting at
15
- `01`) according to the order of the **Artifact** list below, and with
12
+ `<basedir/>/SPEC-<artifact-no/>-<artifact-id/>-<artifact-slug/>.md`,
13
+ relative to the project root directory, with <basedir/> being the
14
+ `project.artifact.spec.basedir` config variable, <artifact-no/> being
15
+ the zero-padded, two-digit sequence number of the **Artifact** (starting
16
+ at `01`) according to the order of the **Artifact** list below, and with
16
17
  <artifact-slug/> being derived from <artifact-name/> (see below) by
17
18
  Pascal-casing each word (upper-casing its first letter) and using `-`
18
19
  characters instead of spaces (e.g. `Customer-Journey`).
@@ -629,6 +630,59 @@ manages, defining how information is organized and connected.
629
630
  - In case any rationale is not present, the
630
631
  entire `, **BECAUSE** [...]` clause is omitted.
631
632
 
633
+ - Export: `export.md`
634
+
635
+ The entities, their attributes and their relations
636
+ are rendered as Markdown tables.
637
+
638
+ For this, each <spec-dm-entity/> becomes:
639
+
640
+ <format>
641
+
642
+ ## ENTITY: <a id="SPEC-DM-<spec-dm-entity-id/>"><spec-dm-entity-name/></a>
643
+
644
+ <spec-dm-entity-description/>,
645
+ **BECAUSE** <spec-dm-entity-rationale/>.
646
+
647
+ ### ATTRIBUTES
648
+
649
+ <export-table-1/>
650
+
651
+ ### RELATIONS
652
+
653
+ <export-table-2/>
654
+
655
+ </format>
656
+
657
+ With:
658
+
659
+ - <export-table-1/> is a Markdown table for the attributes with one
660
+ row per <spec-dm-attribute-id/>, sorted by <spec-dm-attribute-id/>
661
+ -- with the columns:
662
+
663
+ - `Attribute` (`**<spec-dm-attribute-id/>**`)
664
+ - `Type` (`<spec-dm-attribute-qualifier/><spec-dm-attribute-type/>`)
665
+ - `Description` (`<spec-dm-relation-description/>, **BECAUSE** <spec-dm-relation-rationale/>.`)
666
+
667
+ - <export-table-2/> is a Markdown table for the relation with one
668
+ row per <spec-dm-relation-id/>, sorted by <spec-dm-relation-id/> --
669
+ with the columns:
670
+
671
+ - `Relation` (`**<spec-dm-relation-id/>**`)
672
+ - `Target` (`[<spec-dm-relation-target/>](#<spec-dm-relation-target-id/>) (<spec-dm-relation-cardinality/>)`)
673
+ - `Description` (`<spec-dm-relation-description/>, **BECAUSE** <spec-dm-relation-rationale/>.`)
674
+
675
+ - Export: `export.svg`
676
+
677
+ The entities, their attributes and their relations are
678
+ rendered as a Mermaid `classDiagram` UML diagram and
679
+ converted to SVG. For this, each <spec-dm-entity/> becomes
680
+ a class whose members are the `<spec-dm-attribute-id/>:
681
+ <spec-dm-attribute-qualifier/><spec-dm-attribute-type/>` attributes,
682
+ and each <spec-dm-relation/> becomes a directed association
683
+ labeled with its <spec-dm-relation-id/> and annotated with its
684
+ <spec-dm-relation-cardinality/> at the target end.
685
+
632
686
  State Model (SM)
633
687
  ----------------
634
688
 
@@ -6,7 +6,7 @@
6
6
  "homepage": "http://github.com/rse/ase",
7
7
  "repository": { "url": "git+https://github.com/rse/ase.git", "type": "git" },
8
8
  "bugs": { "url": "http://github.com/rse/ase/issues" },
9
- "version": "0.9.20",
9
+ "version": "0.9.22",
10
10
  "license": "GPL-3.0-only",
11
11
  "author": {
12
12
  "name": "Dr. Ralf S. Engelschall",
@@ -44,9 +44,10 @@ for the technology stack to *provide* the *needed functionality*
44
44
  enough, let the *user interactively choose* the intended
45
45
  functionality.
46
46
 
47
- In the following, you *MUST* *NOT* use the <user-dialog-tool/>
48
- tool! Instead, you *MUST* just show a custom output, let the
49
- user enter input, and then you set the result accordingly.
47
+ In the following, you *MUST* *NOT* use your built-in
48
+ <user-dialog-tool/> tool! Instead, you *MUST* just show a
49
+ custom dialog according to the expanded `custom-dialog`
50
+ definition. You *MUST* closely follow this definition:
50
51
 
51
52
  <expand name="custom-dialog" arg1="--no-other">
52
53
  Functionality: Which functionality should the components provide?
@@ -188,9 +188,10 @@ permitted way to persist artifacts is via `ase_task_save(...)`.
188
188
 
189
189
  7. <if condition="<getopt-option-auto/> is not equal `true`">
190
190
 
191
- In the following, you *MUST* *NOT* use the <user-dialog-tool/>
192
- tool! Instead, you *MUST* just show a custom output, let the
193
- user enter input, and then you set the result accordingly.
191
+ In the following, you *MUST* *NOT* use your built-in
192
+ <user-dialog-tool/> tool! Instead, you *MUST* just show a
193
+ custom dialog according to the expanded `custom-dialog`
194
+ definition. You *MUST* closely follow this definition.
194
195
 
195
196
  Let the user choose the preferred approach A<n/> by raising
196
197
  a question with the following custom dialog, where per
@@ -253,9 +253,10 @@ related to a set of code quality aspects.
253
253
 
254
254
  6. <if condition="<getopt-option-auto/> is not 'true'">
255
255
 
256
- In the following, you *MUST* *NOT* use the <user-dialog-tool/>
257
- tool! Instead, you *MUST* just show a custom output, let the
258
- user enter input, and then you set the result accordingly.
256
+ In the following, you *MUST* *NOT* use your built-in
257
+ <user-dialog-tool/> tool! Instead, you *MUST* just show a
258
+ custom dialog according to the expanded `custom-dialog`
259
+ definition. You *MUST* closely follow this definition:
259
260
 
260
261
  <expand name="custom-dialog" arg1="--other">
261
262
  CORRECTION: How would you like to proceed with this proposed correction?
@@ -188,9 +188,10 @@ permitted way to persist artifacts is via `ase_task_save(...)`.
188
188
 
189
189
  7. <if condition="<getopt-option-auto/> is not `true`">
190
190
 
191
- In the following, you *MUST* *NOT* use the <user-dialog-tool/>
192
- tool! Instead, you *MUST* just show a custom output, let the
193
- user enter input, and then you set the result accordingly.
191
+ In the following, you *MUST* *NOT* use your built-in
192
+ <user-dialog-tool/> tool! Instead, you *MUST* just show a
193
+ custom dialog according to the expanded `custom-dialog`
194
+ definition. You *MUST* closely follow this definition.
194
195
 
195
196
  Let the user choose the preferred approach A<n/> by raising
196
197
  a question with the following custom dialog, where per
@@ -242,9 +242,10 @@ permitted way to persist artifacts is via `ase_task_save(...)`.
242
242
 
243
243
  7. <if condition="<getopt-option-auto/> is not `true`">
244
244
 
245
- In the following, you *MUST* *NOT* use the <user-dialog-tool/>
246
- tool! Instead, you *MUST* just show a custom output, let the
247
- user enter input, and then you set the result accordingly.
245
+ In the following, you *MUST* *NOT* use your built-in
246
+ <user-dialog-tool/> tool! Instead, you *MUST* just show a
247
+ custom dialog according to the expanded `custom-dialog`
248
+ definition. You *MUST* closely follow this definition.
248
249
 
249
250
  Let the user choose the preferred approach A<n/> by raising
250
251
  a question with the following custom dialog, where per
@@ -185,9 +185,10 @@ Analyze documents for spelling, punctuation, or grammar errors
185
185
 
186
186
  4. <if condition="<getopt-option-auto/> is not 'true'">
187
187
 
188
- In the following, you *MUST* *NOT* use the <user-dialog-tool/>
189
- tool! Instead, you *MUST* just show a custom output, let the
190
- user enter input, and then you set the result accordingly.
188
+ In the following, you *MUST* *NOT* use your built-in
189
+ <user-dialog-tool/> tool! Instead, you *MUST* just show a
190
+ custom dialog according to the expanded `custom-dialog`
191
+ definition. You *MUST* closely follow this definition:
191
192
 
192
193
  <expand name="custom-dialog" arg1="--other">
193
194
  CORRECTION: How would you like to proceed with this proposed correction?
@@ -117,15 +117,16 @@ Honor the following tenets throughout the brainstorming:
117
117
  <answer-M-K/> (K={1,2,3,4}) from the code base, the documented
118
118
  context, and your world knowledge.
119
119
 
120
- 3. Use an interactive user dialog with header <facet-M/> and
121
- question <question-M/>, and let the user select the
122
- <answer-M/> out of the candidate answers <answer-M-K/> (leave
123
- out the answer lines of those candidate answers you have
124
- not determined).
120
+ 3. In the following, you *MUST* *NOT* use your built-in
121
+ <user-dialog-tool/> tool! Instead, you *MUST* just show a
122
+ custom dialog according to the expanded `custom-dialog`
123
+ definition. You *MUST* closely follow this definition.
125
124
 
126
- In the following, you *MUST* *NOT* use the <user-dialog-tool/>
127
- tool! Instead, you *MUST* just show a custom output, let the
128
- user enter input, and then you set the result accordingly.
125
+ For this interactive dialog, use header <facet-M/> and
126
+ question <question-M/>, and let the user select the
127
+ <answer-M/> out of the candidate answers <answer-M-K/>
128
+ (leave out the answer lines of those candidate answers you
129
+ have not determined):
129
130
 
130
131
  <expand name="custom-dialog" arg1="--other">
131
132
  <facet-M/>: <question-M/>
@@ -0,0 +1,176 @@
1
+ ---
2
+ name: ase-sync-export
3
+ argument-hint: "[--help|-h] [--source|-s <source>[,...]] [<filter>]"
4
+ description: >
5
+ Export artifact content into side-by-side, ready-to-consume files,
6
+ one per artifact that declares an export. Use when the user wants to
7
+ "export", "render", or "materialize" artifacts like SPEC or ARCH into
8
+ derived files such as diagrams or tables.
9
+ user-invocable: true
10
+ disable-model-invocation: false
11
+ effort: xhigh
12
+ allowed-tools:
13
+ - Write
14
+ ---
15
+
16
+ @${CLAUDE_SKILL_DIR}/../../meta/ase-control.md
17
+ @${CLAUDE_SKILL_DIR}/../../meta/ase-skill.md
18
+ @${CLAUDE_SKILL_DIR}/../../meta/ase-getopt.md
19
+
20
+ <skill name="ase-sync-export">
21
+ Export Artifact Set to Side-by-Side Files
22
+ </skill>
23
+
24
+ <expand name="getopt"
25
+ arg1="ase-sync-export"
26
+ arg2="--source|-s=SPEC,ARCH">
27
+ $ARGUMENTS
28
+ </expand>
29
+
30
+ <objective>
31
+ *Export* the *source* artifact kinds (optionally filtered by
32
+ <hint/>) into side-by-side files, by reading the source artifacts
33
+ and materializing, for every artifact that declares an export,
34
+ the corresponding derived file next to the artifact itself.
35
+ <hint><getopt-arguments/></hint>.
36
+ </objective>
37
+
38
+ @${CLAUDE_SKILL_DIR}/../../meta/ase-format-meta.md
39
+ @${CLAUDE_SKILL_DIR}/../../meta/ase-format-spec.md
40
+ @${CLAUDE_SKILL_DIR}/../../meta/ase-format-arch.md
41
+
42
+ Procedure
43
+ ---------
44
+
45
+ <flow>
46
+
47
+ 1. <step id="STEP 1: Determine Source">
48
+
49
+ 1. The recognized artifact kinds are the seven tokens `TASK`,
50
+ `SPEC`, `ARCH`, `CODE`, `DOCS`, `INFR`, and `OTHR`. Parse
51
+ <getopt-source/> as the comma-separated <source/> kind list.
52
+ Upper-case and trim every parsed kind token. Do not output
53
+ anything.
54
+
55
+ 2. <if condition="<source/> is empty">
56
+
57
+ Only output the following <template/> and then immediately *STOP*
58
+ processing the entire current skill:
59
+
60
+ <template>
61
+ ⧉ **ASE**: ☻ skill: **ase-sync-export**, ▶ ERROR: empty source artifact list
62
+ </template>
63
+
64
+ </if>
65
+
66
+ 3. If any token in <source/> is *not* one of the seven recognized
67
+ kinds, only output the following <template/> (with <kind/> set to
68
+ the first offending token) and then immediately *STOP* processing
69
+ the entire current skill:
70
+
71
+ <template>
72
+ ⧉ **ASE**: ☻ skill: **ase-sync-export**, ▶ ERROR: unknown artifact kind: **<kind/>**
73
+ </template>
74
+
75
+ 4. Report the resolved source with the following <template/>:
76
+
77
+ <template>
78
+ <ase-tpl-bullet-signal/> **SOURCE**: <source/>
79
+ </template>
80
+
81
+ </step>
82
+
83
+ 2. <step id="STEP 2: Resolve and Read Artifacts">
84
+
85
+ 1. Do not output anything in this STEP 2.
86
+
87
+ 2. For all kinds in <source/>, call the `ase_artifact_list(kind: [
88
+ ... ])` tool of the `ase` MCP server *once*, passing the
89
+ lower-cased `kind` tokens, and read the returned `artifacts`
90
+ array of `{ kind, files }` objects to obtain the project-relative
91
+ file list per kind.
92
+
93
+ 3. <if condition="<hint/> is not empty">
94
+
95
+ Honor the filtering <hint/> to reduce the source artifacts
96
+ and/or the aspects of those artifacts you should take into
97
+ account.
98
+
99
+ </if>
100
+
101
+ 4. Internalize and honor the artifact-format conventions:
102
+
103
+ - the artifact-set/artifact/aspect/export meta information (`ase-format-meta.md`),
104
+ - the `SPEC` format (`ase-format-spec.md`),
105
+ - the `ARCH` format (`ase-format-arch.md`).
106
+
107
+ In particular, internalize the generic *Artifact Export*
108
+ contract of `ase-format-meta.md` (the `- Export:` bullet, the
109
+ side-by-side file-name convention, and the rule that an artifact
110
+ without an `- Export:` bullet is *not* exported), and which
111
+ artifacts declare an export in the `SPEC` and `ARCH` formats.
112
+
113
+ 5. Read all resolved source artifacts and build a precise
114
+ understanding of the content of each artifact that declares an
115
+ export.
116
+
117
+ </step>
118
+
119
+ 3. <step id="STEP 3: Materialize Exports">
120
+
121
+ 1. For *each* read source artifact that declares an `- Export:`
122
+ bullet in its format definition, *materialize* the declared
123
+ export:
124
+
125
+ - *Build* the derived rendering exactly as described by the
126
+ artifact's <export-transform/>, faithfully reflecting the
127
+ artifact's current content -- no more, no less. Honor **No
128
+ Fabrication**: never invent content the artifact does not
129
+ support.
130
+
131
+ - For an export whose <export-transform/> is a *Mermaid
132
+ diagram converted to SVG*, build the Mermaid specification
133
+ from the artifact content and render it to an SVG document by
134
+ calling the `ase_diagram(diagram: "<mermaid-spec/>", format:
135
+ "svg")` tool of the `ase` MCP server, using its `text` output
136
+ field as the SVG document. For a textual export (e.g. a
137
+ Markdown table), build the content directly. For Markdown
138
+ *tables*, honor the table-alignment rule of `ase-skill.md`.
139
+
140
+ - *Determine* the side-by-side target file name
141
+ <export-filename/>
142
+ as `<basedir/>/<artifact-set-id/>-<artifact-no/>-<artifact-id/>-<artifact-slug/>-<export-name/>.<export-ext/>`
143
+ and resolve it to a project-relative path inside the
144
+ artifact's own base directory by calling the
145
+ `ase_artifact_name(filename: "<file-name/>", kind:
146
+ "<export-filename/>")` tool of the `ase` MCP server.
147
+
148
+ - *Write* the derived rendering to that resolved path via the
149
+ `Write` tool, overwriting any pre-existing export file of the
150
+ same name.
151
+
152
+ 2. Report the materialized exports with the following <template/>,
153
+ listing one bullet line per written file (with <file/> its
154
+ project-relative path and <note/> an ultra-brief description of
155
+ what was exported):
156
+
157
+ <template>
158
+ <ase-tpl-bullet-signal/> **EXPORTED ARTIFACTS**:
159
+
160
+ - `<file/>`: <note/>
161
+ [...]
162
+ </template>
163
+
164
+ <if condition="no source artifact declares an export">
165
+
166
+ Only output the following <template/>:
167
+
168
+ <template>
169
+ <ase-tpl-bullet-normal/> **EXPORTED ARTIFACTS**: none -- no source artifact declares an export
170
+ </template>
171
+
172
+ </if>
173
+
174
+ </step>
175
+
176
+ </flow>
@@ -0,0 +1,60 @@
1
+
2
+ ## NAME
3
+
4
+ `ase-sync-export` - Export Artifact Set to Side-by-Side Files
5
+
6
+ ## SYNOPSIS
7
+
8
+ `ase-sync-export`
9
+ [`--help`|`-h`]
10
+ [`--source`|`-s` *source*[,...]]
11
+
12
+ ## DESCRIPTION
13
+
14
+ The `ase-sync-export` skill exports the content of a set of artifact
15
+ kinds (the *source*) into *derived*, ready-to-consume files placed
16
+ *side-by-side* with the artifacts themselves. For every source artifact
17
+ that declares an *export* in its format definition, the skill builds the
18
+ declared rendering and writes it to a sibling file.
19
+
20
+ The *source* is a comma-separated list over the seven recognized
21
+ artifact kinds `SPEC` (Specification), `ARCH` (Architecture), `CODE`
22
+ (Source Code), `DOCS` (Documentation), `TASK` (Task Plans), `INFR`
23
+ (Infrastructure), and `OTHR` (catch-all). The file lists for the
24
+ involved kinds are resolved via the `ase_artifact_list` MCP tool of the
25
+ `ase` MCP server.
26
+
27
+ An *export* is declared by a `- Export:` bullet point in an artifact's
28
+ format definition (see `ase-format-meta.md`, `ase-format-spec.md`, and
29
+ `ase-format-arch.md`); an artifact *without* such a bullet is *not*
30
+ exported. Each exported file is named
31
+ `YYYY-MM-DD-<set>-<slug>-<id>.<ext>` and stored in the artifact's own
32
+ base directory. Initially, the *Data Model* (`SPEC-DM`) exports as a
33
+ Mermaid UML diagram converted to SVG, and the *Technology Stack*
34
+ (`ARCH-TS`) exports as a compact Markdown table.
35
+
36
+ ## OPTIONS
37
+
38
+ `--source`|`-s` *source*[,...]:
39
+ The comma-separated list of artifact kinds to export. Defaults to
40
+ `SPEC,ARCH` (the skill errors out on an empty source).
41
+
42
+ ## EXAMPLES
43
+
44
+ Export the specification and architecture artifacts to their
45
+ side-by-side files (the default):
46
+
47
+ ```text
48
+ ❯ /ase-sync-export
49
+ ```
50
+
51
+ Export only the specification artifacts:
52
+
53
+ ```text
54
+ ❯ /ase-sync-export -s SPEC
55
+ ```
56
+
57
+ ## SEE ALSO
58
+
59
+ [`ase-sync-reconcile`](../ase-sync-reconcile/help.md),
60
+ [`ase-sync-import`](../ase-sync-import/help.md)
@@ -77,4 +77,5 @@ Import a pasted feature description into a task plan:
77
77
  ## SEE ALSO
78
78
 
79
79
  [`ase-sync-reconcile`](../ase-sync-reconcile/help.md),
80
+ [`ase-sync-export`](../ase-sync-export/help.md),
80
81
  [`ase-task-implement`](../ase-task-implement/help.md)
@@ -204,9 +204,10 @@ Procedure
204
204
 
205
205
  - If <getopt-option-next/> is equal to `none`:
206
206
 
207
- In the following, you *MUST* *NOT* use the <user-dialog-tool/>
208
- tool! Instead, you *MUST* just show a custom output, let the
209
- user enter input, and then you set the result accordingly.
207
+ In the following, you *MUST* *NOT* use your built-in
208
+ <user-dialog-tool/> tool! Instead, you *MUST* just show a
209
+ custom dialog according to the expanded `custom-dialog`
210
+ definition. You *MUST* closely follow this definition:
210
211
 
211
212
  <expand name="custom-dialog" arg1="--no-other">
212
213
  Next Step: How would you like to proceed with the plan?
@@ -225,9 +225,10 @@ Set <content-dirty>true</content-dirty>.
225
225
 
226
226
  - If <getopt-option-plan/> is equal to `none`:
227
227
 
228
- In the following, you *MUST* *NOT* use the <user-dialog-tool/>
229
- tool! Instead, you *MUST* just show a custom output, let the
230
- user enter input, and then you set the result accordingly.
228
+ In the following, you *MUST* *NOT* use your built-in
229
+ <user-dialog-tool/> tool! Instead, you *MUST* just show a
230
+ custom dialog according to the expanded `custom-dialog`
231
+ definition. You *MUST* closely follow this definition:
231
232
 
232
233
  <expand name="custom-dialog" arg1="--other">
233
234
  Previous Plan: Should the previous plan content be overwritten, refined, or preserved?
@@ -377,9 +378,10 @@ Set <content-dirty>true</content-dirty>.
377
378
 
378
379
  - If <getopt-option-next/> is equal to `none`:
379
380
 
380
- In the following, you *MUST* *NOT* use the <user-dialog-tool/>
381
- tool! Instead, you *MUST* just show a custom output, let the
382
- user enter input, and then you set the result accordingly.
381
+ In the following, you *MUST* *NOT* use your built-in
382
+ <user-dialog-tool/> tool! Instead, you *MUST* just show a
383
+ custom dialog according to the expanded `custom-dialog`
384
+ definition. You *MUST* closely follow this definition:
383
385
 
384
386
  <expand name="custom-dialog" arg1="--other">
385
387
  Next Step: How would you like to proceed with the plan?
@@ -175,10 +175,10 @@ Procedure
175
175
  alternative answers <answer-N-K/> (K={2,3,4}), so there
176
176
  are between two and four answer options in total.
177
177
 
178
- 3. In the following, you *MUST* *NOT* use the
178
+ 3. In the following, you *MUST* *NOT* use your built-in
179
179
  <user-dialog-tool/> tool! Instead, you *MUST* just show a
180
- custom output, let the user enter input, and then you set
181
- the result accordingly.
180
+ custom dialog according to the expanded `custom-dialog`
181
+ definition. You *MUST* closely follow this definition.
182
182
 
183
183
  Let the user select the <answer-N/> out of the answer
184
184
  alternatives <answer-N-K/> by raising a question with the
@@ -258,9 +258,10 @@ Procedure
258
258
 
259
259
  - If <getopt-option-next/> is equal to `none`:
260
260
 
261
- In the following, you *MUST* *NOT* use the <user-dialog-tool/>
262
- tool! Instead, you *MUST* just show a custom output, let the
263
- user enter input, and then you set the result accordingly.
261
+ In the following, you *MUST* *NOT* use your built-in
262
+ <user-dialog-tool/> tool! Instead, you *MUST* just show a
263
+ custom dialog according to the expanded `custom-dialog`
264
+ definition. You *MUST* closely follow this definition:
264
265
 
265
266
  <expand name="custom-dialog" arg1="--no-other">
266
267
  Next Step: How would you like to proceed with the plan?
@@ -183,9 +183,10 @@ Procedure
183
183
 
184
184
  - If <getopt-option-next/> is equal to `none`:
185
185
 
186
- In the following, you *MUST* *NOT* use the <user-dialog-tool/>
187
- tool! Instead, you *MUST* just show a custom output, let the
188
- user enter input, and then you set the result accordingly.
186
+ In the following, you *MUST* *NOT* use your built-in
187
+ <user-dialog-tool/> tool! Instead, you *MUST* just show a
188
+ custom dialog according to the expanded `custom-dialog`
189
+ definition. You *MUST* closely follow this definition:
189
190
 
190
191
  <expand name="custom-dialog" arg1="--no-other">
191
192
  Next Step: How would you like to proceed with the plan?
@@ -196,9 +196,10 @@ Procedure
196
196
 
197
197
  - If <getopt-option-next/> is equal to `none`:
198
198
 
199
- In the following, you *MUST* *NOT* use the <user-dialog-tool/>
200
- tool! Instead, you *MUST* just show a custom output, let the
201
- user enter input, and then you set the result accordingly.
199
+ In the following, you *MUST* *NOT* use your built-in
200
+ <user-dialog-tool/> tool! Instead, you *MUST* just show a
201
+ custom dialog according to the expanded `custom-dialog`
202
+ definition. You *MUST* closely follow this definition:
202
203
 
203
204
  <expand name="custom-dialog" arg1="--no-other">
204
205
  Next Step: How would you like to proceed with the plan?
@@ -193,9 +193,10 @@ Procedure
193
193
 
194
194
  - If <getopt-option-next/> is equal to `none`:
195
195
 
196
- In the following, you *MUST* *NOT* use the <user-dialog-tool/>
197
- tool! Instead, you *MUST* just show a custom output, let the
198
- user enter input, and then you set the result accordingly.
196
+ In the following, you *MUST* *NOT* use your built-in
197
+ <user-dialog-tool/> tool! Instead, you *MUST* just show a
198
+ custom dialog according to the expanded `custom-dialog`
199
+ definition. You *MUST* closely follow this definition:
199
200
 
200
201
  <expand name="custom-dialog" arg1="--no-other">
201
202
  Next Step: How would you like to proceed with the plan?