@rse/ase 0.9.12 → 0.9.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dst/ase-compat.js +1 -1
- package/dst/ase-diagram.js +5 -2
- package/dst/ase-getopt.js +2 -1
- package/dst/ase-kv.js +30 -11
- package/dst/ase-mcp.js +2 -0
- package/dst/ase-persona.js +4 -1
- package/dst/ase-skills.js +13 -3
- package/dst/ase-statusline.js +2 -2
- package/dst/ase.js +1 -1
- package/package.json +1 -1
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/.codex-plugin/plugin.json +1 -1
- package/plugin/.github/plugin/plugin.json +1 -1
- package/plugin/agents/ase-meta-chat.md +3 -3
- package/plugin/meta/ase-dialog.md +1 -1
- package/plugin/meta/ase-format-arch.md +26 -9
- package/plugin/meta/ase-format-meta.md +7 -3
- package/plugin/meta/ase-format-spec.md +11 -6
- package/plugin/meta/ase-getopt.md +8 -3
- package/plugin/meta/ase-skill.md +49 -21
- package/plugin/package.json +1 -1
- package/plugin/skills/ase-arch-analyze/SKILL.md +26 -13
- package/plugin/skills/ase-arch-discover/SKILL.md +25 -14
- package/plugin/skills/ase-code-analyze/SKILL.md +10 -5
- package/plugin/skills/ase-code-craft/SKILL.md +16 -4
- package/plugin/skills/ase-code-explain/SKILL.md +0 -1
- package/plugin/skills/ase-code-insight/SKILL.md +1 -1
- package/plugin/skills/ase-code-lint/SKILL.md +56 -18
- package/plugin/skills/ase-code-refactor/SKILL.md +16 -4
- package/plugin/skills/ase-code-resolve/SKILL.md +17 -4
- package/plugin/skills/ase-docs-proofread/SKILL.md +48 -17
- package/plugin/skills/ase-meta-brainstorm/SKILL.md +5 -2
- package/plugin/skills/ase-meta-compat/SKILL.md +2 -12
- package/plugin/skills/ase-meta-diff/SKILL.md +3 -3
- package/plugin/skills/ase-meta-evaluate/SKILL.md +32 -24
- package/plugin/skills/ase-meta-quorum/SKILL.md +3 -3
- package/plugin/skills/ase-task-condense/SKILL.md +6 -9
- package/plugin/skills/ase-task-edit/SKILL.md +6 -2
- package/plugin/skills/ase-task-grill/SKILL.md +9 -15
- package/plugin/skills/ase-task-id/SKILL.md +7 -4
- package/plugin/skills/ase-task-implement/SKILL.md +6 -11
- package/plugin/skills/ase-task-preflight/SKILL.md +5 -10
- package/plugin/skills/ase-task-reboot/SKILL.md +21 -13
- package/plugin/skills/ase-task-rename/SKILL.md +9 -0
package/dst/ase-compat.js
CHANGED
|
@@ -12,7 +12,7 @@ const EXPECTED = {
|
|
|
12
12
|
"xml-placeholders/overwrite": "99",
|
|
13
13
|
"xml-placeholders/indexed": "+1,-1",
|
|
14
14
|
"xml-placeholders/nested-attr": "20",
|
|
15
|
-
"xml-placeholders/entity": "
|
|
15
|
+
"xml-placeholders/entity": "⦿",
|
|
16
16
|
/* control-flow */
|
|
17
17
|
"control-flow/branch": "mid",
|
|
18
18
|
"control-flow/while-sum": "15",
|
package/dst/ase-diagram.js
CHANGED
|
@@ -117,12 +117,15 @@ export class Diagram {
|
|
|
117
117
|
/* detect terminal color capability */
|
|
118
118
|
static detectColorMode() {
|
|
119
119
|
let mode = "none";
|
|
120
|
+
let explicit = false;
|
|
120
121
|
/* attempt 1: query environment variable (explicitly) */
|
|
121
122
|
if (process.env.ASE_TERM_COLORS !== undefined)
|
|
122
|
-
if (/^(?:none|ansi16|ansi256)$/.test(process.env.ASE_TERM_COLORS))
|
|
123
|
+
if (/^(?:none|ansi16|ansi256)$/.test(process.env.ASE_TERM_COLORS)) {
|
|
123
124
|
mode = process.env.ASE_TERM_COLORS;
|
|
125
|
+
explicit = true;
|
|
126
|
+
}
|
|
124
127
|
/* attempt 2: query stdout */
|
|
125
|
-
if (
|
|
128
|
+
if (!explicit && process.stdout.isTTY) {
|
|
126
129
|
const depth = process.stdout.getColorDepth();
|
|
127
130
|
if (depth >= 8)
|
|
128
131
|
mode = "ansi256";
|
package/dst/ase-getopt.js
CHANGED
|
@@ -108,7 +108,8 @@ export class GetoptMCP {
|
|
|
108
108
|
if (listOpts.length > 0) {
|
|
109
109
|
const opts = cmd.opts();
|
|
110
110
|
for (const { long, choices } of listOpts) {
|
|
111
|
-
const
|
|
111
|
+
const key = long.replace(/-(.)/g, (_, c) => c.toUpperCase());
|
|
112
|
+
const v = opts[key];
|
|
112
113
|
if (typeof v !== "string")
|
|
113
114
|
continue;
|
|
114
115
|
const items = v.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
package/dst/ase-kv.js
CHANGED
|
@@ -45,10 +45,21 @@ export class KV {
|
|
|
45
45
|
KV.validateKey(key);
|
|
46
46
|
return KV.store.delete(key);
|
|
47
47
|
}
|
|
48
|
-
/* clear all keys
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
48
|
+
/* clear all keys, or just those starting with the given `prefix`;
|
|
49
|
+
returns the number of keys removed */
|
|
50
|
+
static clear(prefix) {
|
|
51
|
+
if (prefix === undefined || prefix === "") {
|
|
52
|
+
const n = KV.store.size;
|
|
53
|
+
KV.store.clear();
|
|
54
|
+
return n;
|
|
55
|
+
}
|
|
56
|
+
let n = 0;
|
|
57
|
+
for (const key of KV.store.keys()) {
|
|
58
|
+
if (key.startsWith(prefix)) {
|
|
59
|
+
KV.store.delete(key);
|
|
60
|
+
n++;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
52
63
|
return n;
|
|
53
64
|
}
|
|
54
65
|
/* snapshot the entire store into a fresh map (for transactional batch) */
|
|
@@ -112,12 +123,17 @@ export class KVMCP {
|
|
|
112
123
|
/* key/value clear */
|
|
113
124
|
mcp.registerTool("ase_kv_clear", {
|
|
114
125
|
title: "ASE key/value clear",
|
|
115
|
-
description: "Remove
|
|
126
|
+
description: "Remove keys from the in-memory key/value store. " +
|
|
127
|
+
"If `prefix` is given, only keys starting with `prefix` are removed; " +
|
|
128
|
+
"otherwise all keys are removed. " +
|
|
116
129
|
"Returns a status `text` indicating how many keys were removed.",
|
|
117
|
-
inputSchema: {
|
|
118
|
-
|
|
130
|
+
inputSchema: {
|
|
131
|
+
prefix: z.string().optional()
|
|
132
|
+
.describe("if given, only remove keys starting with this prefix (otherwise remove all keys)")
|
|
133
|
+
}
|
|
134
|
+
}, async (args) => {
|
|
119
135
|
try {
|
|
120
|
-
const n = KV.clear();
|
|
136
|
+
const n = KV.clear(args.prefix);
|
|
121
137
|
return { content: [{ type: "text", text: `kv_clear: OK: removed ${n} key(s)` }] };
|
|
122
138
|
}
|
|
123
139
|
catch (err) {
|
|
@@ -151,8 +167,9 @@ export class KVMCP {
|
|
|
151
167
|
mcp.registerTool("ase_kv_batch", {
|
|
152
168
|
title: "ASE key/value batch",
|
|
153
169
|
description: "Execute an array of in-memory key/value `commands` in a single MCP call. " +
|
|
154
|
-
"Each entry is an object `{ command: \"clear\"|\"set\"|\"get\"|\"delete\", key?, val? }` " +
|
|
170
|
+
"Each entry is an object `{ command: \"clear\"|\"set\"|\"get\"|\"delete\", key?, val?, prefix? }` " +
|
|
155
171
|
"and is dispatched to the corresponding single-op tool. " +
|
|
172
|
+
"For `clear`, an optional `prefix` restricts removal to keys starting with it. " +
|
|
156
173
|
"If `transactional` is true, the store is snapshotted up-front and rolled back on the " +
|
|
157
174
|
"first per-command error (remaining commands are skipped); otherwise per-command errors " +
|
|
158
175
|
"are recorded and execution continues. " +
|
|
@@ -168,7 +185,9 @@ export class KVMCP {
|
|
|
168
185
|
key: z.string().optional()
|
|
169
186
|
.describe("key identifier (required for `set`/`get`/`delete`)"),
|
|
170
187
|
val: z.union([z.string(), z.number(), z.boolean(), z.null(), z.array(z.any()), z.record(z.string(), z.any())]).optional()
|
|
171
|
-
.describe("value to store (required for `set`)")
|
|
188
|
+
.describe("value to store (required for `set`)"),
|
|
189
|
+
prefix: z.string().optional()
|
|
190
|
+
.describe("if given for `clear`, only remove keys starting with this prefix (otherwise remove all keys)")
|
|
172
191
|
}))
|
|
173
192
|
.describe("ordered list of KV commands to execute"),
|
|
174
193
|
transactional: z.boolean().optional()
|
|
@@ -182,7 +201,7 @@ export class KVMCP {
|
|
|
182
201
|
for (const c of args.commands) {
|
|
183
202
|
try {
|
|
184
203
|
if (c.command === "clear") {
|
|
185
|
-
const n = KV.clear();
|
|
204
|
+
const n = KV.clear(c.prefix);
|
|
186
205
|
results.push(`kv_clear: OK: removed ${n} key(s)`);
|
|
187
206
|
cmdNames.push("clear");
|
|
188
207
|
}
|
package/dst/ase-mcp.js
CHANGED
|
@@ -133,6 +133,8 @@ export default class MCPCommand {
|
|
|
133
133
|
};
|
|
134
134
|
/* trigger a reconnect chain (idempotent while one is active) */
|
|
135
135
|
const triggerReconnect = (reason) => {
|
|
136
|
+
if (reconnecting)
|
|
137
|
+
return;
|
|
136
138
|
reconnecting = true;
|
|
137
139
|
this.log.write("warning", `mcp: ${reason} — reconnecting`);
|
|
138
140
|
reconnect(0).catch(() => { });
|
package/dst/ase-persona.js
CHANGED
|
@@ -21,7 +21,10 @@ export class Persona {
|
|
|
21
21
|
const val = cfg.get("agent.persona");
|
|
22
22
|
if (val === undefined)
|
|
23
23
|
return "engineer";
|
|
24
|
-
|
|
24
|
+
const style = String(isScalar(val) ? val.value : val);
|
|
25
|
+
if (!Persona.styles.includes(style))
|
|
26
|
+
return "engineer";
|
|
27
|
+
return style;
|
|
25
28
|
}
|
|
26
29
|
/* set the persona style on the strongest scope of an optional session */
|
|
27
30
|
static set(log, style, session) {
|
package/dst/ase-skills.js
CHANGED
|
@@ -263,10 +263,20 @@ export class Skills {
|
|
|
263
263
|
const halfLife = 365 / 2;
|
|
264
264
|
/* lifespan requires both timestamps; recentness requires the
|
|
265
265
|
updated timestamp -- any unavailable date-derived factor is
|
|
266
|
-
|
|
267
|
-
remaining metrics, instead of collapsing the product to zero
|
|
266
|
+
given a neutral default so the entry can still be ranked by the
|
|
267
|
+
remaining metrics, instead of collapsing the product to zero.
|
|
268
|
+
For `lifespan` (an unbounded duration) the multiplicative-neutral
|
|
269
|
+
`1` is also the low floor, so a missing value cannot unfairly
|
|
270
|
+
inflate the rank. For `recentness`, however, the value is an
|
|
271
|
+
exp-decay factor bounded in `(0,1]` where `1` is the *ceiling*
|
|
272
|
+
(a just-now update), not a floor -- defaulting a missing update
|
|
273
|
+
date to `1` would hand packages with absent metadata the highest
|
|
274
|
+
possible recentness and let them outrank genuinely fresh ones.
|
|
275
|
+
We therefore default a missing `recentness` to the decay value at
|
|
276
|
+
one half-life (`0.5`), a conservative midpoint that keeps the
|
|
277
|
+
entry rankable without rewarding the missing date. */
|
|
268
278
|
const lifespan = (!Number.isNaN(cMs) && !Number.isNaN(uMs)) ? Math.max(0, uMs - cMs) : 1;
|
|
269
|
-
const recentness = !Number.isNaN(uMs) ? Math.exp(-Math.max(0, (now - uMs) / msPerDay) / halfLife) :
|
|
279
|
+
const recentness = !Number.isNaN(uMs) ? Math.exp(-Math.max(0, (now - uMs) / msPerDay) / halfLife) : 0.5;
|
|
270
280
|
return d * s * lifespan * recentness;
|
|
271
281
|
}
|
|
272
282
|
/* compute the per-alternative product-sum (rating) row from a
|
package/dst/ase-statusline.js
CHANGED
|
@@ -67,7 +67,7 @@ const formatTokens = (n) => {
|
|
|
67
67
|
if (n >= 1_000_000)
|
|
68
68
|
return `${(n / 1_000_000).toFixed(1)}M`;
|
|
69
69
|
if (n >= 1_000)
|
|
70
|
-
return `${
|
|
70
|
+
return `${(n / 1_000).toFixed(1)}k`;
|
|
71
71
|
return `${n}`;
|
|
72
72
|
};
|
|
73
73
|
/* format a millisecond duration as a compact human-readable string (e.g. 6d 12hr 7m, 4hr 27m, 12m 30s) */
|
|
@@ -362,7 +362,7 @@ export default class StatuslineCommand {
|
|
|
362
362
|
emit(`${prefix("◔", "context")}${bar} ${pct}%`);
|
|
363
363
|
},
|
|
364
364
|
C: () => {
|
|
365
|
-
const pct =
|
|
365
|
+
const pct = data.context_window?.used_percentage ?? 0;
|
|
366
366
|
const tokensCur = (data.context_window?.total_input_tokens ?? 0) +
|
|
367
367
|
(data.context_window?.total_output_tokens ?? 0);
|
|
368
368
|
const tokensLim = pct > 0 && tokensCur > 0 ? Math.round(tokensCur * 100 / pct) : 0;
|
package/dst/ase.js
CHANGED
|
@@ -18,7 +18,7 @@ import ArtifactCommand from "./ase-artifact.js";
|
|
|
18
18
|
import CompatCommand from "./ase-compat.js";
|
|
19
19
|
import pkg from "../package.json" with { type: "json" };
|
|
20
20
|
/* globally initialize logger */
|
|
21
|
-
const log = new Log("ase", "
|
|
21
|
+
const log = new Log("ase", "info", "-");
|
|
22
22
|
/* main entry point (wrapped in a regular async function to avoid
|
|
23
23
|
top-level await, which would be reported as "unsettled" by Node in
|
|
24
24
|
the long-running daemon process spawned by "ase service start") */
|
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.
|
|
9
|
+
"version": "0.9.14",
|
|
10
10
|
"license": "GPL-3.0-only",
|
|
11
11
|
"author": {
|
|
12
12
|
"name": "Dr. Ralf S. Engelschall",
|
|
@@ -13,9 +13,9 @@ tools:
|
|
|
13
13
|
|
|
14
14
|
@../meta/ase-control.md
|
|
15
15
|
|
|
16
|
-
1.
|
|
17
|
-
Set <llm/> to the *first* token
|
|
18
|
-
Set <query/> to the *second and all following* tokens
|
|
16
|
+
1. Set <args>$ARGUMENTS</args>, the single whitespace-separated string.
|
|
17
|
+
Set <llm/> to the *first* token of <args/>.
|
|
18
|
+
Set <query/> to the *second and all following* tokens of <args/>.
|
|
19
19
|
You *MUST* *NOT* output anything related to this step.
|
|
20
20
|
|
|
21
21
|
2. Set <server></server> (set to empty).
|
|
@@ -185,7 +185,7 @@ following procedure:
|
|
|
185
185
|
|
|
186
186
|
Do not output anything in this step!
|
|
187
187
|
|
|
188
|
-
2.
|
|
188
|
+
2. Render the custom dialog, collect the user input, and dispatch on the result:
|
|
189
189
|
|
|
190
190
|
1. You *MUST* not output anything in this step.
|
|
191
191
|
|
|
@@ -243,7 +243,7 @@ at runtime.
|
|
|
243
243
|
for the component's existence and boundary.
|
|
244
244
|
|
|
245
245
|
- In case a component has no dependencies at all, the
|
|
246
|
-
entire `-
|
|
246
|
+
entire `- Depends On:` bullet point is omitted.
|
|
247
247
|
|
|
248
248
|
- In case the rationale is not present, the
|
|
249
249
|
entire `, **BECAUSE** [...]` clause is omitted.
|
|
@@ -666,8 +666,16 @@ How the Non-Functional Requirements (NR) are addressed.
|
|
|
666
666
|
perspective addresses, one of `Performance`, `Scalability`,
|
|
667
667
|
`Reliability`, `Availability`, `Security`, `Privacy`,
|
|
668
668
|
`Usability`, `Accessibility`, `Maintainability`, `Portability`,
|
|
669
|
-
`Compatibility`, or `Compliance
|
|
670
|
-
Requirements
|
|
669
|
+
`Compatibility`, or `Compliance`. This enumeration is a
|
|
670
|
+
solution-oriented refinement of the Non-Functional Requirements
|
|
671
|
+
(NR) categories and intentionally differs from them: the NR
|
|
672
|
+
categories follow the ISO/IEC 25010:2023 top-level characteristics
|
|
673
|
+
(and include `Safety` and `Flexibility`), whereas the perspective
|
|
674
|
+
qualities decompose some of these into the finer-grained,
|
|
675
|
+
architecturally actionable attributes `Scalability`,
|
|
676
|
+
`Availability`, `Privacy`, `Accessibility`, and `Portability`. A
|
|
677
|
+
perspective's quality therefore need not match the category of the
|
|
678
|
+
`SPEC-NR-<spec-nr-requirement-id/>` it addresses.
|
|
671
679
|
|
|
672
680
|
- <arch-qp-perspective-requirement/> is a
|
|
673
681
|
`SPEC-NR-<spec-nr-requirement-id/>` reference to the corresponding
|
|
@@ -722,10 +730,11 @@ forces at play, the chosen response, and the reasoning that justifies it.
|
|
|
722
730
|
|
|
723
731
|
## DECISION: <arch-dr-decision-name/> <a id="ARCH-DR-<arch-dr-decision-id/>"></a>
|
|
724
732
|
|
|
725
|
-
- Status:
|
|
726
|
-
- Affects:
|
|
727
|
-
-
|
|
728
|
-
-
|
|
733
|
+
- Status: <arch-dr-decision-status/>
|
|
734
|
+
- Affects: <arch-dr-decision-element/>, [...]
|
|
735
|
+
- Superseded-By: <arch-dr-decision-superseded-by/>
|
|
736
|
+
- Created: <arch-dr-decision-created/>
|
|
737
|
+
- Modified: <arch-dr-decision-modified/>
|
|
729
738
|
|
|
730
739
|
- WHEN (Context):
|
|
731
740
|
<arch-dr-decision-context/>
|
|
@@ -752,12 +761,17 @@ forces at play, the chosen response, and the reasoning that justifies it.
|
|
|
752
761
|
<arch-dr-decision-decision/>, not longer than 80 characters.
|
|
753
762
|
|
|
754
763
|
- <arch-dr-decision-status/> is one of `proposed`, `accepted`,
|
|
755
|
-
`deprecated`, or `superseded
|
|
764
|
+
`deprecated`, or `superseded`.
|
|
756
765
|
|
|
757
766
|
- <arch-dr-decision-element/> is an `ARCH-FV-<arch-fv-component-id/>`
|
|
758
767
|
or `ARCH-DP-<arch-dp-node-id/>` reference to the functional
|
|
759
768
|
element or deployment node the decision affects.
|
|
760
769
|
|
|
770
|
+
- <arch-dr-decision-superseded-by/> is an
|
|
771
|
+
`ARCH-DR-<arch-dr-decision-id/>` reference to the decision that
|
|
772
|
+
supersedes this decision. It is present if and only if the
|
|
773
|
+
<arch-dr-decision-status/> is `superseded`.
|
|
774
|
+
|
|
761
775
|
- <arch-dr-decision-created/> is the timestamp when this decision was
|
|
762
776
|
created, and <arch-dr-decision-modified/> is the timestamp when
|
|
763
777
|
this decision was last modified, both in the same ISO-style format
|
|
@@ -832,7 +846,10 @@ forces at play, the chosen response, and the reasoning that justifies it.
|
|
|
832
846
|
job.
|
|
833
847
|
|
|
834
848
|
- In case the element reference is not present, the
|
|
835
|
-
entire `-
|
|
849
|
+
entire `- Affects:` bullet point is omitted.
|
|
850
|
+
|
|
851
|
+
- In case the <arch-dr-decision-status/> is not `superseded`, the
|
|
852
|
+
entire `- Superseded-By:` bullet point is omitted.
|
|
836
853
|
|
|
837
854
|
- In case the `NOTES (Background)` content is not present, the
|
|
838
855
|
entire `NOTES (Background)` chunk is omitted.
|
|
@@ -29,9 +29,13 @@ Artifact Meta Information
|
|
|
29
29
|
- **Artifact**:
|
|
30
30
|
|
|
31
31
|
At level 2, each **Artifact Set** is composed of many **Artifact**s.
|
|
32
|
-
Each **Artifact** has
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
Each **Artifact** has an identifier <artifact-id/>, which is an
|
|
33
|
+
upper-case, two-letter identifier (e.g. `CJ` for `Customer Journey`)
|
|
34
|
+
derived from the **Artifact** name. The <artifact-id/> is unique
|
|
35
|
+
only *within* its **Artifact Set**; the globally-unique handle of an
|
|
36
|
+
**Artifact** is the qualified form <artifact-set-id/>-<artifact-id/>
|
|
37
|
+
(e.g. `SPEC-DP` and `ARCH-DP` are distinct artifacts). All
|
|
38
|
+
references to an **Artifact** *MUST* use this qualified form.
|
|
35
39
|
|
|
36
40
|
Each **Artifact** also has a sequence number <artifact-no/>, which
|
|
37
41
|
is the zero-padded, two-digit position of the **Artifact** (starting
|
|
@@ -871,8 +871,8 @@ for main, alternative, and exceptional paths.
|
|
|
871
871
|
|
|
872
872
|
- <spec-uc-usecase-description/>: a concise paragraph (1-3
|
|
873
873
|
sentences) of prose describing the use case at a glance, without
|
|
874
|
-
prescribing the step-by-step flow (which belongs to the
|
|
875
|
-
|
|
874
|
+
prescribing the step-by-step flow (which belongs to the
|
|
875
|
+
**SCENARIO** blocks of this use case).
|
|
876
876
|
|
|
877
877
|
- In case the use case realizes no specific functional requirement,
|
|
878
878
|
the entire `- Requirements:` bullet point is omitted.
|
|
@@ -884,7 +884,7 @@ for main, alternative, and exceptional paths.
|
|
|
884
884
|
|
|
885
885
|
<format>
|
|
886
886
|
|
|
887
|
-
### SCENARIO: <spec-uc-usecase-scenario-name/> (<spec-uc-usecase-scenario-type/>)
|
|
887
|
+
### SCENARIO: <spec-uc-usecase-scenario-name/> (<spec-uc-usecase-scenario-type/>) <a id="SPEC-UC-<spec-uc-usecase-id/>-<spec-uc-usecase-scenario-id/>"></a>
|
|
888
888
|
|
|
889
889
|
1. <spec-uc-usecase-scenario-step/>
|
|
890
890
|
2. <spec-uc-usecase-scenario-step/>
|
|
@@ -894,6 +894,11 @@ for main, alternative, and exceptional paths.
|
|
|
894
894
|
|
|
895
895
|
- <spec-uc-usecase-scenario/> details:
|
|
896
896
|
|
|
897
|
+
- <spec-uc-usecase-scenario-id/>: per-use-case unique "slug" of
|
|
898
|
+
always 1-3 lower-cased words (concatenated with "-" characters
|
|
899
|
+
and in total not longer than 30 characters), derived from
|
|
900
|
+
<spec-uc-usecase-scenario-name/>.
|
|
901
|
+
|
|
897
902
|
- <spec-uc-usecase-scenario-name/>: a short (3-8 word) summary of the
|
|
898
903
|
scenario.
|
|
899
904
|
|
|
@@ -1213,9 +1218,9 @@ turn.
|
|
|
1213
1218
|
visualizes (optional).
|
|
1214
1219
|
|
|
1215
1220
|
- <spec-ds-storyboard-scenario/> is a
|
|
1216
|
-
|
|
1217
|
-
the corresponding **Aspect** of the Use
|
|
1218
|
-
storyboard visualizes (optional).
|
|
1221
|
+
`SPEC-UC-<spec-uc-usecase-id/>-<spec-uc-usecase-scenario-id/>`
|
|
1222
|
+
reference to the corresponding scenario **Aspect** of the Use
|
|
1223
|
+
Case **Artifact** the storyboard visualizes (optional).
|
|
1219
1224
|
|
|
1220
1225
|
- <spec-ds-frame-name/>: a short (2-5 word) label for the screen,
|
|
1221
1226
|
turn, or state depicted by the storyboard frame. Frames are
|
|
@@ -27,8 +27,8 @@ set placeholders into the context as a side-effect.
|
|
|
27
27
|
`--<long/>[|-<short/>][=<default/>|=(<c1/>|<c2/>|...)[...]]`, set
|
|
28
28
|
<getopt-option-<long/>/> to <default/> (for `=<default/>`
|
|
29
29
|
form), or to the *single token* <c1/> (the first choice, both
|
|
30
|
-
for the choice form `=(<c1/>|<c2
|
|
31
|
-
`=(<c1/>|<c2
|
|
30
|
+
for the choice form `=(<c1/>|<c2/>|...)` and for the list form
|
|
31
|
+
`=(<c1/>|<c2/>|...)...` -- an *unsupplied* list-option always
|
|
32
32
|
defaults to the single token <c1/>, *not* to a whole list),
|
|
33
33
|
or to `false` (for value-less options). Then set
|
|
34
34
|
<getopt-arguments><getopt-args/></getopt-arguments>.
|
|
@@ -63,6 +63,10 @@ set placeholders into the context as a side-effect.
|
|
|
63
63
|
validate each remaining token themselves as they consume it).
|
|
64
64
|
|
|
65
65
|
4. **Short-Circuit for Error**:
|
|
66
|
+
This step is the *sole* and *authoritative* handler for an
|
|
67
|
+
`ERROR:`-prefixed `ase_getopt` response; the generic MCP-Tool-Calls
|
|
68
|
+
error rule (see `ase-skill.md`) explicitly does *NOT* apply here, so
|
|
69
|
+
only the <template/> below is emitted (never both).
|
|
66
70
|
If <text/> starts with `ERROR:`:
|
|
67
71
|
Remove all `ERROR:` or `error:` prefixes from <text/>.
|
|
68
72
|
Then only output the following <template/> and
|
|
@@ -92,7 +96,8 @@ set placeholders into the context as a side-effect.
|
|
|
92
96
|
`<getopt-result/>.opts[<longN/>]`.
|
|
93
97
|
Set <getopt-arguments/> to the value of `<getopt-result/>.args`.
|
|
94
98
|
Set <getopt-info/> to `<getopt-result/>.info`, but remove
|
|
95
|
-
information about the `help` option
|
|
99
|
+
information about the `help` option and any *internal* option
|
|
100
|
+
whose long name starts with `int-`.
|
|
96
101
|
|
|
97
102
|
7. **Display Results**:
|
|
98
103
|
Just output the following <template/>:
|
package/plugin/meta/ase-skill.md
CHANGED
|
@@ -119,15 +119,25 @@ Skill Sequential Processing
|
|
|
119
119
|
For speed, emit *all* `TaskCreate` calls together in a *single* turn
|
|
120
120
|
(issued in parallel), *not* one-per-turn sequentially. Do *not*
|
|
121
121
|
rely on the call order to establish the step order, as the parallel
|
|
122
|
-
results carry no guaranteed ordering.
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
122
|
+
results carry no guaranteed ordering.
|
|
123
|
+
|
|
124
|
+
Instead, in the *immediately single following* turn, first
|
|
125
|
+
reconstruct the step-id-to-taskId mapping: because each task's
|
|
126
|
+
`subject` equals the originating <step/> `id` (and <step/> ids are
|
|
127
|
+
unique), match every created task back to its <step/> by comparing
|
|
128
|
+
the task's `subject` to the step `id` -- read the ids straight from
|
|
129
|
+
the `TaskCreate` results, or call `TaskList` if the results are
|
|
130
|
+
no longer at hand.
|
|
131
|
+
|
|
132
|
+
Then establish the strict order explicitly by chaining the created
|
|
133
|
+
tasks with `TaskUpdate`: for each <step/> after the first one,
|
|
134
|
+
resolve <this/> and <prev/> to the mapped `taskId` values and
|
|
135
|
+
call `TaskUpdate({ taskId: "<this/>", addBlockedBy: [ "<prev/>" ]
|
|
136
|
+
})` so that every step (with `taskId` <this/>) is blocked by its
|
|
137
|
+
predecessor step (with `taskId` <prev/>).
|
|
128
138
|
|
|
129
139
|
- *IMPORTANT*: For each <step/> you *MUST* use the `TaskUpdate` tool
|
|
130
|
-
for updating its status during processing.
|
|
140
|
+
for updating its status *during* processing, once a <step/> finished.
|
|
131
141
|
|
|
132
142
|
- *IMPORTANT*: You *MUST* sequentially execute every <step/> in
|
|
133
143
|
a <flow/> *EXACTLY* as the instructions specify.
|
|
@@ -172,6 +182,12 @@ MCP Tool Calls
|
|
|
172
182
|
⧉ **ASE**: **ERROR:** MCP tool failed: <info/>
|
|
173
183
|
</template>
|
|
174
184
|
|
|
185
|
+
*EXCEPTION*: this rule does *NOT* apply to the `ase_getopt` tool,
|
|
186
|
+
whose `ERROR:`-prefixed output is *expected* option-parsing
|
|
187
|
+
feedback handled exclusively by step 4 of the `getopt` procedure
|
|
188
|
+
(see `ase-getopt.md`); never emit this generic template for an
|
|
189
|
+
`ase_getopt` response.
|
|
190
|
+
|
|
175
191
|
- Only on a clean response: proceed as the skill instructs.
|
|
176
192
|
|
|
177
193
|
Skill Identification
|
|
@@ -232,9 +248,12 @@ Template Patterns
|
|
|
232
248
|
</template>
|
|
233
249
|
|
|
234
250
|
- When `<ase-tpl-head title="<title/>"/>` should be expanded, use
|
|
235
|
-
(where <title
|
|
236
|
-
|
|
237
|
-
(67 - <title-len/>)
|
|
251
|
+
(where <raw-title/> is the visible un-styled text `⧉ ASE: <title/>`,
|
|
252
|
+
<raw-title-len/> is the number of characters in <raw-title/>, and
|
|
253
|
+
<bar/> is the `─` character repeated exactly max(0, 67 - <raw-title-len/>)
|
|
254
|
+
times -- clamped to zero so an over-long title never yields a negative
|
|
255
|
+
count -- the very same bar-width rule as `<ase-tpl-foot/>` and
|
|
256
|
+
`<ase-tpl-boxed/>`, so equal visible text yields equal total width):
|
|
238
257
|
|
|
239
258
|
<template>
|
|
240
259
|
|
|
@@ -251,9 +270,12 @@ Template Patterns
|
|
|
251
270
|
</template>
|
|
252
271
|
|
|
253
272
|
- When `<ase-tpl-foot title="<title/>"/>` should be expanded, use
|
|
254
|
-
(where <title
|
|
255
|
-
|
|
256
|
-
(67 - <title-len/>)
|
|
273
|
+
(where <raw-title/> is the visible un-styled text `⧉ ASE: <title/>`,
|
|
274
|
+
<raw-title-len/> is the number of characters in <raw-title/>, and
|
|
275
|
+
<bar/> is the `─` character repeated exactly max(0, 67 - <raw-title-len/>)
|
|
276
|
+
times -- clamped to zero so an over-long title never yields a negative
|
|
277
|
+
count -- the very same bar-width rule as `<ase-tpl-head/>` and
|
|
278
|
+
`<ase-tpl-boxed/>`, so equal visible text yields equal total width):
|
|
257
279
|
|
|
258
280
|
<template>
|
|
259
281
|
|
|
@@ -275,19 +297,24 @@ Template Patterns
|
|
|
275
297
|
</else>
|
|
276
298
|
|
|
277
299
|
- When `<ase-tpl-boxed title="<title/>"[ subtitle="<subtitle/>"]><content/></ase-tpl-boxed>`
|
|
278
|
-
should be expanded use the following helper
|
|
300
|
+
should be expanded use the following helper placeholders and then
|
|
301
|
+
the following <template/>:
|
|
279
302
|
|
|
280
303
|
- <if condition="<subtitle/> is not empty">
|
|
281
|
-
Set <raw-title>⧉ ASE: <title/>: <subtitle
|
|
304
|
+
Set <raw-title>⧉ ASE: <title/>: <subtitle/></raw-title>.
|
|
282
305
|
Set <render-title>⧉ ASE: **`<title/>`**: `<subtitle/>`</render-title>.
|
|
283
306
|
</if>
|
|
284
307
|
<else>
|
|
285
|
-
Set <raw-title>⧉ ASE: <title
|
|
308
|
+
Set <raw-title>⧉ ASE: <title/></raw-title>.
|
|
286
309
|
Set <render-title>⧉ ASE: **`<title/>`**</render-title>.
|
|
287
310
|
</else>
|
|
288
|
-
- Set <raw-title-len/> to the number of characters in
|
|
289
|
-
|
|
290
|
-
- Set <
|
|
311
|
+
- Set <raw-title-len/> to the number of characters in the visible
|
|
312
|
+
un-styled text <raw-title/>.
|
|
313
|
+
- Set <bar/> to the `─` character repeated exactly max(0, 67 - <raw-title-len/>)
|
|
314
|
+
times -- clamped to zero so an over-long title never yields a negative
|
|
315
|
+
count -- the very same bar-width rule as `<ase-tpl-head/>` and
|
|
316
|
+
`<ase-tpl-foot/>`, so equal visible text yields equal total width.
|
|
317
|
+
- Set <body/> to <content/> with all line-starts prefixed with `│ `.
|
|
291
318
|
|
|
292
319
|
<template>
|
|
293
320
|
|
|
@@ -324,7 +351,8 @@ Template Patterns
|
|
|
324
351
|
<template>🟠</template>
|
|
325
352
|
|
|
326
353
|
- 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
|
|
354
|
+
(where <ws/> = ` ` x max(0, <width/> - length("<text/>")), i.e., <ws/> is
|
|
355
|
+
the ` ` character repeated max(0, <width/> - length("<text/>")) times --
|
|
356
|
+
clamped to zero so an over-long text never yields a negative count):
|
|
329
357
|
|
|
330
358
|
<template><text/><ws/></template>
|
package/plugin/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.
|
|
9
|
+
"version": "0.9.14",
|
|
10
10
|
"license": "GPL-3.0-only",
|
|
11
11
|
"author": {
|
|
12
12
|
"name": "Dr. Ralf S. Engelschall",
|
|
@@ -375,13 +375,19 @@ interface quality, quality attributes, and architecture governance.
|
|
|
375
375
|
- *Focal aspect*: <focal-aspect/> - <focal-state/>
|
|
376
376
|
- *In tension with*: <partner-list/>
|
|
377
377
|
|
|
378
|
-
**RECOMMENDED**: lean toward *<
|
|
378
|
+
**RECOMMENDED**: lean toward *<lean-toward/>*
|
|
379
379
|
*Reason*: <rationale/>
|
|
380
380
|
*Implies*:
|
|
381
|
-
- <partner-aspect
|
|
382
|
-
-
|
|
381
|
+
- <partner-aspect/>: <partner-implication/>
|
|
382
|
+
- ...
|
|
383
383
|
</template>
|
|
384
384
|
|
|
385
|
+
For each partner in <partner-list/>, repeat the `*Implies*` line,
|
|
386
|
+
set <partner-aspect/> to the partner aspect, and set
|
|
387
|
+
<partner-implication/> to its brief implication. Set <lean-toward/>
|
|
388
|
+
to the aspect direction the recommendation favors (the *focal
|
|
389
|
+
aspect* or the *partners*).
|
|
390
|
+
|
|
385
391
|
Hints:
|
|
386
392
|
|
|
387
393
|
- For the final results, do *not* output anything else,
|
|
@@ -393,9 +399,13 @@ interface quality, quality attributes, and architecture governance.
|
|
|
393
399
|
DEPENDENCY-DIRECTION`).
|
|
394
400
|
|
|
395
401
|
- The <focal-aspect/> is the aspect that participates in
|
|
396
|
-
*all* tensions of the cluster.
|
|
397
|
-
|
|
398
|
-
|
|
402
|
+
*all* tensions of the cluster. In a size-2 cluster both
|
|
403
|
+
aspects participate equally in the single tension, so this
|
|
404
|
+
rule cannot disambiguate; instead pick the focal aspect by
|
|
405
|
+
the first applicable tiebreaker: (1) the aspect whose
|
|
406
|
+
direction is more constrained by the detected style; else
|
|
407
|
+
(2) the aspect carrying the *higher* finding severity; else
|
|
408
|
+
(3) the aspect listed *first* in the tension matrix pair.
|
|
399
409
|
|
|
400
410
|
- *Brevity and precision*: all free-form placeholders
|
|
401
411
|
(<description/>, <focal-state/>, partner-implications)
|
|
@@ -429,13 +439,16 @@ interface quality, quality attributes, and architecture governance.
|
|
|
429
439
|
for the same aspect, and never emit both halves of a
|
|
430
440
|
tension pair as separate PROBLEMs.
|
|
431
441
|
|
|
432
|
-
- *Additionally*,
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
442
|
+
- *Additionally*, persist all reported findings in a *single*
|
|
443
|
+
`ase_kv_batch` call to the `ase` MCP server with `transactional`
|
|
444
|
+
set to `true`. The `commands` parameter array of this call
|
|
445
|
+
starts with one `{ command: "clear", prefix: "ase-issue-" }`
|
|
446
|
+
entry (which removes only the previously persisted `ase-issue-*`
|
|
447
|
+
keys, leaving any unrelated keys in the shared store intact),
|
|
448
|
+
followed by one `{ command: "set", key: "ase-issue-P<n/>", val:
|
|
449
|
+
"<title/>: <description/>" }` entry per reported PROBLEM and one
|
|
450
|
+
`{ command: "set", key: "ase-issue-T<n/>", val: "<title/>:
|
|
451
|
+
<description/>" }` entry per reported TRADEOFF.
|
|
439
452
|
</step>
|
|
440
453
|
|
|
441
454
|
4. <step id="STEP 4: Give Final Hint">
|