@rse/ase 0.9.21 → 0.9.23

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,
@@ -0,0 +1,23 @@
1
+ /*
2
+ ** Agentic Software Engineering (ASE)
3
+ ** Copyright (c) 2025-2026 Dr. Ralf S. Engelschall <rse@engelschall.com>
4
+ ** Licensed under GPL 3.0 <https://spdx.org/licenses/GPL-3.0-only>
5
+ */
6
+ import { Chalk } from "chalk";
7
+ /* auto-detecting chalk instance: colors on a TTY and degrades cleanly
8
+ on pipes/redirects (unlike ase-statusline.ts, which forces level 1
9
+ because Claude Code pipes its stdout) */
10
+ const c = new Chalk();
11
+ /* CLI command "ase hello" */
12
+ export default class HelloCommand {
13
+ register(program) {
14
+ program
15
+ .command("hello")
16
+ .description("Print a nice greeting to the terminal")
17
+ .option("-s, --subject <subject>", "subject to greet", "World")
18
+ .action((opts) => {
19
+ process.stdout.write(c.blue(`Hello ${opts.subject}!`) + "\n");
20
+ process.exit(0);
21
+ });
22
+ }
23
+ }
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.21",
9
+ "version": "0.9.23",
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.21",
3
+ "version": "0.9.23",
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.21",
3
+ "version": "0.9.23",
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.21",
3
+ "version": "0.9.23",
4
4
  "description": "Agentic Software Engineering (ASE)",
5
5
  "keywords": [ "agentic", "software", "engineering" ],
6
6
  "homepage": "https://ase.tools",
@@ -935,12 +935,12 @@ its purpose, and the alternatives that were considered but not chosen.
935
935
 
936
936
  ## COMPONENT: <arch-ts-component-name/> <a id="ARCH-TS-<arch-ts-component-id/>"></a>
937
937
 
938
- - When: <arch-ts-component-when/>
939
- - Tier: <arch-ts-component-tier/>
940
- - Coverage: <arch-ts-component-coverage/>
941
938
  - Product: <arch-ts-component-product/>
942
- - Realizes: <arch-ts-component-element/>[, ...]
943
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
944
 
945
945
  <arch-ts-component-description/>,
946
946
  **BECAUSE** <arch-ts-component-rationale/>.
@@ -958,17 +958,12 @@ its purpose, and the alternatives that were considered but not chosen.
958
958
  technology component (e.g. `UI Framework`, `Web Server`, `Relational
959
959
  Database`).
960
960
 
961
- - <arch-ts-component-when/> is the lifecycle phase in which the
962
- component is relevant, one of:
963
-
964
- - `Build-Time`: Used during development, compilation, or packaging.
965
- - `Run-Time`: Used while the solution executes in production.
966
-
967
- - <arch-ts-component-tier/> is the architectural tier the component
968
- belongs to, one of:
961
+ - <arch-ts-component-product/> is the concrete product, library, or
962
+ framework chosen for this component (e.g. `VueJS`, `Node.js`,
963
+ `PostgreSQL`).
969
964
 
970
- - `Client`: Runs on the client side (e.g. browser, desktop, mobile).
971
- - `Server`: Runs on the server side (e.g. backend, application, API).
965
+ - <arch-ts-component-alternative/> is a product that would also fit
966
+ this component but was not chosen (e.g. `React`, `Svelte`).
972
967
 
973
968
  - <arch-ts-component-coverage/> is either one or more of the
974
969
  *Client Aspects* or one or more of the *Server Aspects* defined
@@ -976,16 +971,21 @@ its purpose, and the alternatives that were considered but not chosen.
976
971
  aspects per <arch-ts-component-tier/> with the minimum total
977
972
  number of <arch-ts-component-product/>.
978
973
 
979
- - <arch-ts-component-product/> is the concrete product, library, or
980
- framework chosen for this component (e.g. `VueJS`, `Node.js`,
981
- `PostgreSQL`).
982
-
983
974
  - <arch-ts-component-element/> is an `ARCH-FV-<arch-fv-component-id/>`
984
975
  or `ARCH-DP-<arch-dp-node-id/>` reference to the functional element
985
976
  or deployment node this product realizes.
986
977
 
987
- - <arch-ts-component-alternative/> is a product that would also fit
988
- this component but was not chosen (e.g. `React`, `Svelte`).
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
989
 
990
990
  - <arch-ts-component-description/> is a concise paragraph (1-3
991
991
  sentences) of prose describing how the product is used within the
@@ -1165,3 +1165,15 @@ its purpose, and the alternatives that were considered but not chosen.
1165
1165
  - **Database Bootstrapping**:
1166
1166
  Create, update or downgrade both mandatory bootstrapping and optional
1167
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/>`
@@ -630,6 +630,59 @@ manages, defining how information is organized and connected.
630
630
  - In case any rationale is not present, the
631
631
  entire `, **BECAUSE** [...]` clause is omitted.
632
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
+
633
686
  State Model (SM)
634
687
  ----------------
635
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.21",
9
+ "version": "0.9.23",
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?