@rse/ase 0.9.8 → 0.9.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/dst/ase-getopt.js +60 -4
  2. package/dst/ase-hook.js +6 -21
  3. package/dst/ase-markdown.js +32 -11
  4. package/dst/ase-mcp.js +22 -8
  5. package/dst/ase-notify.js +32 -0
  6. package/dst/ase-service.js +5 -2
  7. package/dst/ase-setup.js +45 -131
  8. package/dst/ase-skills.js +17 -13
  9. package/dst/ase-statusline.js +8 -12
  10. package/dst/ase-task.js +12 -2
  11. package/package.json +2 -2
  12. package/plugin/.claude-plugin/plugin.json +1 -1
  13. package/plugin/.github/plugin/plugin.json +1 -1
  14. package/plugin/meta/ase-dialog.md +133 -7
  15. package/plugin/meta/ase-format-arch.md +3 -3
  16. package/plugin/meta/ase-format-spec.md +13 -4
  17. package/plugin/meta/ase-getopt.md +40 -28
  18. package/plugin/meta/ase-skill.md +69 -6
  19. package/plugin/package.json +1 -1
  20. package/plugin/skills/ase-arch-analyze/help.md +2 -2
  21. package/plugin/skills/ase-arch-discover/SKILL.md +43 -27
  22. package/plugin/skills/ase-arch-discover/help.md +1 -1
  23. package/plugin/skills/ase-code-analyze/help.md +2 -2
  24. package/plugin/skills/ase-code-craft/SKILL.md +47 -41
  25. package/plugin/skills/ase-code-craft/help.md +2 -2
  26. package/plugin/skills/ase-code-explain/help.md +1 -1
  27. package/plugin/skills/ase-code-insight/SKILL.md +5 -4
  28. package/plugin/skills/ase-code-insight/help.md +1 -1
  29. package/plugin/skills/ase-code-lint/SKILL.md +23 -14
  30. package/plugin/skills/ase-code-lint/help.md +2 -2
  31. package/plugin/skills/ase-code-refactor/SKILL.md +46 -41
  32. package/plugin/skills/ase-code-refactor/help.md +2 -2
  33. package/plugin/skills/ase-code-resolve/SKILL.md +46 -40
  34. package/plugin/skills/ase-code-resolve/help.md +3 -3
  35. package/plugin/skills/ase-docs-distill/help.md +1 -1
  36. package/plugin/skills/ase-docs-proofread/SKILL.md +21 -13
  37. package/plugin/skills/ase-docs-proofread/help.md +1 -1
  38. package/plugin/skills/ase-meta-brainstorm/SKILL.md +24 -5
  39. package/plugin/skills/ase-meta-brainstorm/help.md +1 -1
  40. package/plugin/skills/ase-meta-changelog/help.md +1 -1
  41. package/plugin/skills/ase-meta-chat/help.md +1 -1
  42. package/plugin/skills/ase-meta-commit/help.md +1 -1
  43. package/plugin/skills/ase-meta-diaboli/SKILL.md +4 -4
  44. package/plugin/skills/ase-meta-diaboli/help.md +2 -2
  45. package/plugin/skills/ase-meta-diff/SKILL.md +2 -2
  46. package/plugin/skills/ase-meta-diff/help.md +1 -1
  47. package/plugin/skills/ase-meta-evaluate/help.md +2 -2
  48. package/plugin/skills/ase-meta-persona/help.md +1 -1
  49. package/plugin/skills/ase-meta-quorum/help.md +1 -1
  50. package/plugin/skills/ase-meta-review/SKILL.md +0 -1
  51. package/plugin/skills/ase-meta-review/help.md +2 -2
  52. package/plugin/skills/ase-meta-search/SKILL.md +9 -1
  53. package/plugin/skills/ase-meta-search/help.md +1 -1
  54. package/plugin/skills/ase-meta-steelman/help.md +2 -2
  55. package/plugin/skills/ase-meta-why/SKILL.md +6 -4
  56. package/plugin/skills/ase-meta-why/help.md +1 -1
  57. package/plugin/skills/ase-task-condense/SKILL.md +5 -2
  58. package/plugin/skills/ase-task-condense/help.md +2 -2
  59. package/plugin/skills/ase-task-delete/help.md +2 -2
  60. package/plugin/skills/ase-task-edit/SKILL.md +10 -4
  61. package/plugin/skills/ase-task-edit/help.md +2 -2
  62. package/plugin/skills/ase-task-grill/SKILL.md +5 -2
  63. package/plugin/skills/ase-task-grill/help.md +3 -3
  64. package/plugin/skills/ase-task-id/help.md +2 -2
  65. package/plugin/skills/ase-task-implement/SKILL.md +5 -2
  66. package/plugin/skills/ase-task-implement/help.md +2 -2
  67. package/plugin/skills/ase-task-list/help.md +2 -2
  68. package/plugin/skills/ase-task-preflight/SKILL.md +5 -2
  69. package/plugin/skills/ase-task-preflight/help.md +2 -2
  70. package/plugin/skills/ase-task-reboot/SKILL.md +5 -2
  71. package/plugin/skills/ase-task-reboot/help.md +2 -2
  72. package/plugin/skills/ase-task-rename/help.md +2 -2
  73. package/plugin/skills/ase-task-view/help.md +2 -2
@@ -245,12 +245,14 @@ export default class StatuslineCommand {
245
245
  out += ansi;
246
246
  col += raw.length;
247
247
  };
248
- /* active <color> span state: when non-null, renderer/literal output is buffered
249
- instead of appended directly, and flushed via c[color](buf) on </color> */
248
+ /* active <color> span state: when non-null, each emitted chunk is colored
249
+ individually and passed straight through appendOutput, so column
250
+ accounting and line-wrapping continue to work per-chunk inside the span
251
+ instead of treating the whole colored run as one atomic chunk */
250
252
  let span = null;
251
253
  const emit = (chunk) => {
252
- if (span !== null)
253
- span.buf += chunk;
254
+ if (span !== null && span.color !== "default")
255
+ appendOutput((c[span.color])(chunk));
254
256
  else
255
257
  appendOutput(chunk);
256
258
  };
@@ -446,13 +448,7 @@ export default class StatuslineCommand {
446
448
  };
447
449
  /* walk each template line and render */
448
450
  const closeSpan = () => {
449
- if (span !== null) {
450
- const wrapped = span.color === "default" ?
451
- span.buf :
452
- (c[span.color])(span.buf);
453
- span = null;
454
- appendOutput(wrapped);
455
- }
451
+ span = null;
456
452
  };
457
453
  for (const line of tmpl) {
458
454
  let i = 0;
@@ -465,7 +461,7 @@ export default class StatuslineCommand {
465
461
  if (m[1] === "/")
466
462
  closeSpan();
467
463
  else if (span === null)
468
- span = { color: m[2], buf: "" };
464
+ span = { color: m[2] };
469
465
  i += m[0].length;
470
466
  continue;
471
467
  }
package/dst/ase-task.js CHANGED
@@ -59,12 +59,22 @@ export class Task {
59
59
  static baseDir(log) {
60
60
  return path.join(Task.projectRoot(), Task.spec(log).basedir);
61
61
  }
62
+ /* ensure a task id's "TASK-<id>.md" filename satisfies
63
+ the configured "files" miniglob */
64
+ static enforceFiles(log, id) {
65
+ const { files } = Task.spec(log);
66
+ const filename = `TASK-${id}.md`;
67
+ if (!picomatch(files, { dot: true })(filename))
68
+ throw new Error(`task: id "${id}" yields filename "${filename}" ` +
69
+ `which does not match the configured "files" glob "${files}"`);
70
+ }
62
71
  /* resolve the on-disk path for a given task id; as a side effect,
63
72
  eagerly migrate any legacy <basedir>/<id>/plan.md files to the
64
73
  current <basedir>/TASK-<id>.md layout on first access (guarded by
65
74
  a cheap check, so it is a no-op once the store is migrated) */
66
75
  static path(log, id) {
67
76
  Task.validateId(id);
77
+ Task.enforceFiles(log, id);
68
78
  if (Task.needsMigration(log))
69
79
  Task.migrateAll(log);
70
80
  return path.join(Task.baseDir(log), `TASK-${id}.md`);
@@ -93,7 +103,7 @@ export class Task {
93
103
  return [];
94
104
  const migrated = [];
95
105
  for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
96
- if (!entry.isDirectory() || !/^[A-Za-z0-9-]+$/.test(entry.name))
106
+ if (!entry.isDirectory() || !/^[A-Za-z0-9_-]+$/.test(entry.name))
97
107
  continue;
98
108
  const id = entry.name;
99
109
  const oldFile = path.join(dir, id, "plan.md");
@@ -138,7 +148,7 @@ export class Task {
138
148
  }
139
149
  /* rename a task by moving its <project>/<basedir>/TASK-<oldId>.md file
140
150
  to <project>/<basedir>/TASK-<newId>.md; the embedded
141
- "#TASK <id>:" heading inside the plan content is rewritten to
151
+ "# TASK <id>:" heading inside the plan content is rewritten to
142
152
  the new id; returns true on success, false if the source task does
143
153
  not exist; throws if the target id already exists */
144
154
  static rename(log, oldId, newId) {
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.8",
9
+ "version": "0.9.10",
10
10
  "license": "GPL-3.0-only",
11
11
  "author": {
12
12
  "name": "Dr. Ralf S. Engelschall",
@@ -42,7 +42,7 @@
42
42
  },
43
43
  "dependencies": {
44
44
  "commander": "15.0.0",
45
- "@dotenvx/dotenvx": "1.71.2",
45
+ "@dotenvx/dotenvx": "1.71.3",
46
46
  "yaml": "2.9.0",
47
47
  "valibot": "1.4.1",
48
48
  "execa": "9.6.1",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ase",
3
- "version": "0.9.8",
3
+ "version": "0.9.10",
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.8",
3
+ "version": "0.9.10",
4
4
  "description": "Agentic Software Engineering (ASE)",
5
5
  "keywords": [ "agentic", "software", "engineering" ],
6
6
  "homepage": "https://ase.tools",
@@ -1,5 +1,4 @@
1
1
 
2
-
3
2
  User Dialog
4
3
  ===========
5
4
 
@@ -12,16 +11,20 @@ User Dialog
12
11
  </if>
13
12
 
14
13
  <define name="user-dialog">
14
+
15
15
  Let the *user interactively choose* an answer.
16
16
 
17
17
  1. Take the following question specification:
18
+
18
19
  <spec>
19
20
  <content/>
20
21
  </spec>
21
22
 
22
- Each line of <spec/> (separated by newlines) is of the format:
23
+ The first line of <spec/> (separated by newlines) is of the format:
24
+ `<question-label/>: <question-description/>`
23
25
 
24
- `<label/>: <description/>`.
26
+ The second and following lines of <spec/> (separated by newlines) are of the format:
27
+ `<label/>: <description/>`
25
28
 
26
29
  The first line provides the question label and the question
27
30
  description. The second and following lines each provide an
@@ -49,8 +52,8 @@ Let the *user interactively choose* an answer.
49
52
 
50
53
  If <n/> is less than 2:
51
54
  Set <result>ERROR: user-dialog requires 2-4 answer lines, got <n/></result>
52
- and *SKIP* the following step 2 (do not call `AskUserQuestion`)
53
- and continue with step 3 dispatch.
55
+ and *SKIP* the following step 2.2 (do not call `AskUserQuestion`)
56
+ and continue with step 2.3 dispatch.
54
57
 
55
58
  2. Call the `AskUserQuestion` tool of the agent harness with:
56
59
 
@@ -103,8 +106,8 @@ Let the *user interactively choose* an answer.
103
106
 
104
107
  If <n/> is less than 2:
105
108
  Set <result>ERROR: user-dialog requires 2-4 answer lines, got <n/></result>
106
- and *SKIP* the following step 2 (do not call `ask_user`)
107
- and continue with step 3 dispatch.
109
+ and *SKIP* the following step 2.2 (do not call `ask_user`)
110
+ and continue with step 2.3 dispatch.
108
111
 
109
112
  2. Call the `ask_user` tool of the agent harness with:
110
113
 
@@ -137,3 +140,126 @@ Let the *user interactively choose* an answer.
137
140
 
138
141
  </define>
139
142
 
143
+ <define name="custom-dialog">
144
+
145
+ In the following, you *MUST* *NOT* use the <user-dialog-tool/> tool!
146
+ Instead, you *MUST* just show a custom output, let the user enter input,
147
+ and then you set the result accordingly. For this, closely follow the
148
+ following procedure:
149
+
150
+ 1. Take the following question specification:
151
+ <spec><content/></spec>
152
+
153
+ Take the following options:
154
+ <opts><arg1/></opts>
155
+
156
+ The first line of <spec/> (separated by newlines) is of the format:
157
+ `<question-label/>: <question-description/>`
158
+
159
+ The second and following lines of <spec/> (separated by newlines) are of the format:
160
+ `<label/>: <description/>`
161
+
162
+ The first line provides the question label and the question
163
+ description. The second and following lines each provide an
164
+ answer label and an answer description.
165
+
166
+ Do not output anything in this step!
167
+
168
+ 2. Dispatch according to the agent tool:
169
+
170
+ 1. You *MUST* not output anything in this step.
171
+
172
+ Set <text></text> (set to empty).
173
+ Set <keys></keys> (set to empty).
174
+ Set <n>0</n> (set entry count to zero).
175
+ Set <width/> to the maximum length plus 3 of the <label/> strings in the
176
+ contiguous answer lines of <spec/> starting at line 2 (the answer labels only,
177
+ excluding the question label on line 1, and stopping at the first missing line --
178
+ the same lines the entry loop below renders).
179
+
180
+ <for items="2 3 4 5 6 7 8 9">
181
+ Take from <spec/> the line number <item/>.
182
+ If this line does not exist, <break/>.
183
+ If this line exists, parse it according to the format `<label/>: <description/>`.
184
+ Set <n/> to <n/> + 1 (increment entry count).
185
+ Set <label-key/> to <ase-tpl-key digit="<n/>"/>.
186
+ Set <label-text/> to `<ase-tpl-pad width="<width/>" text="<label/>:"/>`.
187
+ Append an entry to <text/>:
188
+
189
+ <text>
190
+ <text/>
191
+ <ase-tpl-boxline><label-key/> ▶ **<label-text/>** <description/></ase-tpl-boxline>
192
+ </text>
193
+
194
+ <if condition="<keys/> is empty">
195
+ Set <keys><label-key/></keys>
196
+ </if>
197
+ <else>
198
+ Set <keys><keys/>/<label-key/></keys>
199
+ </else>
200
+ </for>
201
+
202
+ <if condition="<opts/> contains `--other`">
203
+ Set <hint>Please choose *one* option by typing <keys/>/**CANCEL**, or other free-text instruction.</hint>.
204
+ </if>
205
+ <else>
206
+ Set <hint>Please choose *one* option by typing <keys/>/**CANCEL**.</hint>.
207
+ </else>
208
+
209
+ Set:
210
+
211
+ <text>
212
+ <ase-tpl-boxed title="DIALOG" subtitle="<question-label/>">
213
+
214
+ <ase-tpl-boxline>**<question-description/>**</ase-tpl-boxline>
215
+
216
+ <text/>
217
+
218
+ <hint/>
219
+
220
+ </ase-tpl-boxed>
221
+ </text>
222
+
223
+ If <n/> is less than 2:
224
+ Set <result>ERROR: custom-dialog requires 2-8 answer lines, got <n/></result>
225
+ and *SKIP* the following step 2.2 and continue with step 2.3 dispatch.
226
+
227
+ 2. Output the following <template/>, end the current turn, wait for the
228
+ user input, store the user input in <result/> and then continue with
229
+ step 2.3 below:
230
+
231
+ <template>
232
+ <text/>
233
+ </template>
234
+
235
+ 3. Do not output anything in this step!
236
+ Check the <result/> and dispatch accordingly:
237
+
238
+ 1. If <result/> is `cancel`, `CANCEL`, `reject`, `REJECT`, or
239
+ otherwise indicates that the user doesn't want to proceed,
240
+ or the user declined to answer the question, or that
241
+ the dialog was cancelled, rejected or skipped, set
242
+ <result>CANCEL</result>.
243
+
244
+ 2. Otherwise, determine the selected <label/>
245
+ by mapping the <result/> (usually containing one of the
246
+ "key" or "label" strings) to one of the answer labels in
247
+ <spec/>. Set <result><label/></result>.
248
+
249
+ 3. If <result/> is then *NEITHER* one of the "key"
250
+ *NOR* "label" values from <spec/>:
251
+ <if condition="<opts/> contains `--other`">
252
+ Set <result>OTHER: <result/></result>
253
+ (prefix result with "OTHER").
254
+ </if>
255
+ <else>
256
+ Output the following <template/> and then *START OVER*
257
+ by *GOING* to step 2.2 above.
258
+
259
+ <template>
260
+ ⧉ **ASE**: ERROR: **Invalid option selected!**
261
+ </template>
262
+ </else>
263
+
264
+ </define>
265
+
@@ -77,14 +77,14 @@ distinct **Artifact**s (listed under their <artifact-name/> and their
77
77
  The **Artifact**s have the following cross-references:
78
78
 
79
79
  ```text
80
- ARCH-02-FV Functionality View ──(depends on)─► ARCH-02-FV Functionality View
81
- ARCH-03-IV Information View ──(entity)─► SPEC-05-DM Data Model
80
+ ARCH-02-FV Functionality View ──(depends on)─► ARCH-01-CV Context View
81
+ ARCH-03-IV Information View ──(entity)─► SPEC-07-DM Data Model
82
82
  ARCH-03-IV Information View ──(owner)─► ARCH-02-FV Functionality View
83
83
  ARCH-04-CO Concurrency View ──(hosts)─► ARCH-02-FV Functionality View
84
84
  ARCH-06-DP Deployment View ──(hosts)─► ARCH-02-FV Functionality View
85
85
  ARCH-07-OV Operations View ──(element)─► ARCH-02-FV Functionality View
86
86
  ARCH-07-OV Operations View ──(element)─► ARCH-06-DP Deployment View
87
- ARCH-08-QP Quality Perspectives ──(addresses)─► SPEC-04-NR Non-Functional Requirements
87
+ ARCH-08-QP Quality Perspectives ──(addresses)─► SPEC-05-NR Non-Functional Requirements
88
88
  ARCH-08-QP Quality Perspectives ──(affects)─► ARCH-02-FV Functionality View
89
89
  ARCH-08-QP Quality Perspectives ──(affects)─► ARCH-06-DP Deployment View
90
90
  ARCH-09-DR Decision Record ──(affects)─► ARCH-02-FV Functionality View
@@ -563,7 +563,7 @@ manages, defining how information is organized and connected.
563
563
 
564
564
  ### RELATIONS
565
565
 
566
- - `<spec-dm-relation-id/>`: [`<spec-dm-relation-target/>`](#<spec-dm-relation-id/>)(`<spec-dm-relation-cardinality/>`):<br/>
566
+ - `<spec-dm-relation-id/>`: [`<spec-dm-relation-target/>`](#<spec-dm-relation-target-id/>)(`<spec-dm-relation-cardinality/>`):<br/>
567
567
  <spec-dm-relation-description/>,
568
568
  **BECAUSE** <spec-dm-relation-rationale/>.
569
569
 
@@ -615,7 +615,7 @@ manages, defining how information is organized and connected.
615
615
  - <spec-dm-relation-target/>: the <spec-dm-entity-name/> of the
616
616
  entity the directed relation targets.
617
617
 
618
- - <spec-dm-relation-id/>: the <spec-dm-entity-id/> of the
618
+ - <spec-dm-relation-target-id/>: the <spec-dm-entity-id/> of the
619
619
  entity the directed relation targets.
620
620
 
621
621
  - <spec-dm-relation-cardinality/>: the cardinality of the entity
@@ -724,8 +724,17 @@ making the forbidden moves as explicit as the allowed ones.
724
724
  is implicitly forbidden.
725
725
 
726
726
  - Every <spec-sm-state-name/> used in a transition *MUST* be
727
- declared in the `### STATES` block, and every non-final state
728
- *MUST* have at least one outgoing transition.
727
+ declared in the `### STATES` block, and every state with no
728
+ outgoing transition *MUST* be listed in <spec-sm-lifecycle-final/>
729
+ (a state with no outgoing transition that is not final would be a
730
+ stuck dead-end). The converse does *not* hold: a
731
+ <spec-sm-lifecycle-final/> state *MAY* still have outgoing
732
+ transitions, modeling a resting state that can later be left again
733
+ (e.g. a `Closed` state with a `reopen` transition back to
734
+ `Active`). Thus <spec-sm-lifecycle-final/> designates the states in
735
+ which the entity may legally come to rest, which is a superset of,
736
+ but not necessarily equal to, the set of declared states that have
737
+ no outgoing transition.
729
738
 
730
739
  - In case a transition has no side effect, the
731
740
  entire `<spec-sm-transition-effect/>,` clause is omitted.
@@ -8,31 +8,41 @@ Do not output anything in the following steps. The entire purpose is to
8
8
  set placeholders into the context as a side-effect.
9
9
 
10
10
  1. **Determine Parameters**:
11
- Set <getopt-skill><arg1/></getopt-skill>.
12
- Set <getopt-spec>--help|-h <arg2/></getopt-spec>.
13
- Set <getopt-args><content/></getopt-args>.
11
+ Set <getopt-skill><arg1/></getopt-skill>
12
+ Set <getopt-spec>--help|-h <arg2/></getopt-spec>
13
+ Set <getopt-args><content/></getopt-args>
14
14
 
15
15
  2. **Short-Circuit Processing**:
16
- If <getopt-args/> does *NOT* match the regexp `(^|\s)-` (i.e.
17
- contains no options at all):
18
-
19
- For each option token in <getopt-spec/> of the form
20
- `--<long/>[|-<short/>][=<default/>|=(<c1/>|<c2/>|...)[...]]`, set
21
- <getopt-option-<long/>/> to <default/> (for `=<default/>`
22
- form), or to <c1/> (the first choice, for `=(<c1/>|<c2>/|...)`
23
- form, or for the list form `=(<c1/>|<c2>/|...)...`),
24
- or to `false` (for value-less options). Then set
25
- <getopt-arguments><getopt-args/></getopt-arguments>.
26
-
27
- Additionally, simulate <getopt-info/> as a comma-separated
28
- markdown rendering of the parsed options in the form `<longN/>:
29
- **<valueN/>**, [...]` (joined with `, `, with each value
30
- shell-quoted if value contains spaces or special characters, and
31
- excluding the `help` option and any *internal* option whose long
32
- name starts with `int-`).
33
-
34
- Then silently *SKIP* only the following steps 3-6
35
- and proceed directly to step 7 to display the results.
16
+ You *MUST* decide here, via the following *mandatory* <if/> control
17
+ construct, whether the options are parsed *locally* (no MCP call) or
18
+ *remotely* (via the MCP call in steps 3-6). This is a *hard branch*,
19
+ not an optional optimization: when the <if/> branch is taken, steps
20
+ 3-6 are *structurally unreachable* and you *MUST NOT* call the
21
+ `ase_getopt` MCP tool under any circumstances.
22
+
23
+ <if condition="<getopt-args/> does *NOT* match the regexp `(^|\s)-` (i.e. it does not start with an option)">
24
+ Parse the options *locally*, without any MCP call:
25
+
26
+ For each option token in <getopt-spec/> of the form
27
+ `--<long/>[|-<short/>][=<default/>|=(<c1/>|<c2/>|...)[...]]`, set
28
+ <getopt-option-<long/>/> to <default/> (for `=<default/>`
29
+ form), or to the *single token* <c1/> (the first choice, both
30
+ for the choice form `=(<c1/>|<c2>/|...)` and for the list form
31
+ `=(<c1/>|<c2>/|...)...` -- an *unsupplied* list-option always
32
+ defaults to the single token <c1/>, *not* to a whole list),
33
+ or to `false` (for value-less options). Then set
34
+ <getopt-arguments><getopt-args/></getopt-arguments>.
35
+
36
+ Additionally, simulate <getopt-info/> as a comma-separated
37
+ markdown rendering of the parsed options in the form `<longN/>:
38
+ **<valueN/>**, [...]` (joined with `, `, with each value
39
+ shell-quoted if value contains spaces or special characters, and
40
+ excluding the `help` option and any *internal* option whose long
41
+ name starts with `int-`).
42
+
43
+ You then *MUST* silently *SKIP* the steps 3-6 below
44
+ and proceed directly to step 7 to display the results.
45
+ </if>
36
46
 
37
47
  3. **MCP Call**:
38
48
  Call the `ase_getopt(name: "<getopt-skill/>", spec:
@@ -44,11 +54,13 @@ set placeholders into the context as a side-effect.
44
54
  `=(<c1>|<c2>|...)` declares a value-taking option restricted to the
45
55
  listed fixed choices (the first choice acts as the default), and the
46
56
  trailing `...` (as in `=(<c1>|<c2>|...)...`) declares a value-taking
47
- option whose value is a *comma-separated list* of choice tokens
48
- (the first choice still acts as the default; only the *first*
49
- token of the list is validated by the parser against the choice
50
- set -- subsequent tokens are *not* validated, and skills validate
51
- each remaining token themselves as they consume it).
57
+ option whose *supplied* value is a *comma-separated list* of choice
58
+ tokens (when *unsupplied*, the option defaults to the *single
59
+ token* `<c1>`, identical to the non-list choice form -- the list
60
+ semantics apply only to an explicitly supplied value; only the
61
+ *first* token of a supplied list is validated by the parser against
62
+ the choice set -- subsequent tokens are *not* validated, and skills
63
+ validate each remaining token themselves as they consume it).
52
64
 
53
65
  4. **Short-Circuit for Error**:
54
66
  If <text/> starts with `ERROR:`:
@@ -215,6 +215,11 @@ Skill Identification
215
215
  @${CLAUDE_SKILL_DIR}/help.md
216
216
  </template>
217
217
 
218
+ - *IMPORTANT*:
219
+ You *MUST* *NOT* output any summaries, explanations, or next
220
+ steps at the end of a skill beside the explicit outputs via any
221
+ <template/>.
222
+
218
223
  Template Patterns
219
224
  -----------------
220
225
 
@@ -227,12 +232,13 @@ Template Patterns
227
232
  </template>
228
233
 
229
234
  - When `<ase-tpl-head title="<title/>"/>` should be expanded, use
230
- (where <bar/> = "─" x (70 - 16 - length("<title/>")), i.e., <bar/> is
231
- the "─" character repeated (70 - 16 - length("<title/>")) times):
235
+ (where <title-len/> is the number of characters in the string
236
+ `⧉ ASE: <title/>`, and <bar/> is the `─` character repeated exactly
237
+ (67 - <title-len/>) times):
232
238
 
233
239
  <template>
234
240
 
235
- ╭────━━━━**(** `<title/>` **)**━━━━────<bar/>┈┈┈┈┈┈┈┈┈┈
241
+ ╭────━━━━**(** ⧉ ASE: **`<title/>`** **)**━━━━────<bar/>┈┈┈┈┈┈┈┈┈┈
236
242
 
237
243
  </template>
238
244
 
@@ -245,15 +251,66 @@ Template Patterns
245
251
  </template>
246
252
 
247
253
  - When `<ase-tpl-foot title="<title/>"/>` should be expanded, use
248
- (where <bar/> = "─" x (70 - 16 - length("<title/>")), i.e., <bar/> is
249
- the "─" character repeated (71 - 16 - length("<title/>")) times):
254
+ (where <title-len/> is the number of characters in the string
255
+ `⧉ ASE: <title/>`, and <bar/> is the `─` character repeated exactly
256
+ (67 - <title-len/>) times):
250
257
 
251
258
  <template>
252
259
 
253
- ╰────━━━━**(** `<title/>` **)**━━━━────<bar/>┈┈┈┈┈┈┈┈┈┈
260
+ ╰────━━━━**(** ⧉ ASE: **`<title/>`** **)**━━━━────<bar/>┈┈┈┈┈┈┈┈┈┈
254
261
 
255
262
  </template>
256
263
 
264
+ - When `<ase-tpl-boxline><line/></ase-tpl-boxline>` should be expanded, use:
265
+
266
+ <if condition="<line/> is not empty">
267
+ <template>
268
+ │ <line/>
269
+ </template>
270
+ </if>
271
+ <else>
272
+ <template>
273
+
274
+ </template>
275
+ </else>
276
+
277
+ - When `<ase-tpl-boxed title="<title/>"[ subtitle="<subtitle/>"]><content/></ase-tpl-boxed>`
278
+ should be expanded use the following helper placeholder and then the <template/>:
279
+
280
+ - <if condition="<subtitle/> is not empty">
281
+ Set <raw-title>⧉ ASE: <title/>: <subtitle/><raw-title>.
282
+ Set <render-title>⧉ ASE: **`<title/>`**: `<subtitle/>`</render-title>.
283
+ </if>
284
+ <else>
285
+ Set <raw-title>⧉ ASE: <title/><raw-title>.
286
+ Set <render-title>⧉ ASE: **`<title/>`**</render-title>.
287
+ </else>
288
+ - Set <raw-title-len/> to the number of characters in <raw-title/>.
289
+ - Set <bar/> to the `─` character repeated exactly (67 - <raw-title-len/>) times.
290
+ - Set <body> to <content/> with all line-starts prefixed with `│ `.
291
+
292
+ <template>
293
+
294
+ ╭────━━━━**(** <render-title/> **)**━━━━────<bar/>┈┈┈┈┈┈┈┈┈┈
295
+
296
+ <body/>
297
+
298
+ ╰────━━━━**(** <render-title/> **)**━━━━────<bar/>┈┈┈┈┈┈┈┈┈┈
299
+
300
+ </template>
301
+
302
+ - When `<ase-tpl-key digit="<digit/>"/>` should be expanded, use:
303
+
304
+ <if condition="<digit/> is '1'"><template>➊</template></if>
305
+ <if condition="<digit/> is '2'"><template>➋</template></if>
306
+ <if condition="<digit/> is '3'"><template>➌</template></if>
307
+ <if condition="<digit/> is '4'"><template>➍</template></if>
308
+ <if condition="<digit/> is '5'"><template>➎</template></if>
309
+ <if condition="<digit/> is '6'"><template>➏</template></if>
310
+ <if condition="<digit/> is '7'"><template>➐</template></if>
311
+ <if condition="<digit/> is '8'"><template>➑</template></if>
312
+ <if condition="<digit/> is '9'"><template>➒</template></if>
313
+
257
314
  - When `<ase-tpl-bullet-secondary/>` should be expanded, use:
258
315
 
259
316
  <template>⚪</template>
@@ -265,3 +322,9 @@ Template Patterns
265
322
  - When `<ase-tpl-bullet-signal/>` should be expanded, use:
266
323
 
267
324
  <template>🟠</template>
325
+
326
+ - When `<ase-tpl-pad width="<width/>" text="<text/>"/>` should be expanded, use
327
+ (where <ws/> = ` ` x (<width/> - length("<text/>")), i.e., <ws/> is
328
+ the ` ` character repeated (<width/> - length("<text/>")) times):
329
+
330
+ <template><text/><ws/></template>
@@ -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.8",
9
+ "version": "0.9.10",
10
10
  "license": "GPL-3.0-only",
11
11
  "author": {
12
12
  "name": "Dr. Ralf S. Engelschall",
@@ -46,5 +46,5 @@ Analyze a specific module:
46
46
 
47
47
  ## SEE ALSO
48
48
 
49
- `ase-arch-discover`, `ase-code-analyze`, `ase-code-resolve`,
50
- `ase-code-refactor`, `ase-code-insight`.
49
+ [`ase-arch-discover`](../ase-arch-discover/help.md), [`ase-code-analyze`](../ase-code-analyze/help.md), [`ase-code-resolve`](../ase-code-resolve/help.md),
50
+ [`ase-code-refactor`](../ase-code-refactor/help.md), [`ase-code-insight`](../ase-code-insight/help.md).