@rse/ase 0.9.50 → 0.9.52
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-hook.js +9 -13
- package/dst/ase-statusline.js +30 -4
- package/dst/ase-task.js +7 -2
- package/package.json +7 -7
- 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-code-lint.md +21 -1
- package/plugin/agents/ase-meta-proximity.md +133 -0
- package/plugin/etc/stx.conf +2 -2
- package/plugin/meta/ase-common-dissect.md +110 -0
- package/plugin/meta/ase-common-task.md +5 -3
- package/plugin/meta/ase-control.md +53 -0
- package/plugin/meta/ase-format-task.md +6 -0
- package/plugin/meta/ase-skill.md +8 -8
- package/plugin/package.json +2 -2
- package/plugin/skills/ase-arch-analyze/SKILL.md +23 -12
- package/plugin/skills/ase-arch-analyze/help.md +16 -0
- package/plugin/skills/ase-arch-discover/SKILL.md +2 -2
- package/plugin/skills/ase-code-analyze/SKILL.md +33 -16
- package/plugin/skills/ase-code-analyze/help.md +19 -2
- package/plugin/skills/ase-code-craft/SKILL.md +2 -2
- package/plugin/skills/ase-code-dissect/SKILL.md +380 -0
- package/plugin/skills/ase-code-dissect/help.md +121 -0
- package/plugin/skills/ase-code-explain/SKILL.md +2 -2
- package/plugin/skills/ase-code-insight/SKILL.md +2 -2
- package/plugin/skills/ase-code-lint/SKILL.md +43 -12
- package/plugin/skills/ase-code-lint/help.md +43 -1
- package/plugin/skills/ase-code-refactor/SKILL.md +2 -2
- package/plugin/skills/ase-code-resolve/SKILL.md +2 -2
- package/plugin/skills/ase-docs-distill/SKILL.md +2 -2
- package/plugin/skills/ase-docs-proofread/SKILL.md +2 -2
- package/plugin/skills/ase-help-intent/SKILL.md +2 -2
- package/plugin/skills/ase-help-skill/SKILL.md +2 -2
- package/plugin/skills/ase-help-skill/catalog.md +4 -0
- package/plugin/skills/ase-meta-brainstorm/SKILL.md +2 -2
- package/plugin/skills/ase-meta-changelog/SKILL.md +2 -2
- package/plugin/skills/ase-meta-chat/SKILL.md +2 -2
- package/plugin/skills/ase-meta-commit/SKILL.md +2 -2
- package/plugin/skills/ase-meta-config/SKILL.md +2 -2
- package/plugin/skills/ase-meta-diaboli/SKILL.md +2 -2
- package/plugin/skills/ase-meta-diff/SKILL.md +2 -2
- package/plugin/skills/ase-meta-eli5/SKILL.md +2 -2
- package/plugin/skills/ase-meta-eli5/help.md +1 -1
- package/plugin/skills/ase-meta-evaluate/SKILL.md +2 -2
- package/plugin/skills/ase-meta-proximity/SKILL.md +51 -92
- package/plugin/skills/ase-meta-proximity/help.md +11 -10
- package/plugin/skills/ase-meta-quorum/SKILL.md +2 -2
- package/plugin/skills/ase-meta-quotes/SKILL.md +214 -0
- package/plugin/skills/ase-meta-quotes/help.md +109 -0
- package/plugin/skills/ase-meta-review/SKILL.md +2 -2
- package/plugin/skills/ase-meta-review/help.md +4 -3
- package/plugin/skills/ase-meta-search/SKILL.md +2 -2
- package/plugin/skills/ase-meta-steelman/SKILL.md +2 -2
- package/plugin/skills/ase-meta-why/SKILL.md +2 -2
- package/plugin/skills/ase-meta-workflow/SKILL.md +378 -0
- package/plugin/skills/ase-meta-workflow/help.md +117 -0
- package/plugin/skills/ase-meta-workflow/sample.md +70 -0
- package/plugin/skills/ase-meta-workflow/workflow.txt +97 -0
- package/plugin/skills/ase-sync-export/SKILL.md +2 -2
- package/plugin/skills/ase-sync-import/SKILL.md +2 -2
- package/plugin/skills/ase-sync-reconcile/SKILL.md +2 -2
- package/plugin/skills/ase-task-condense/SKILL.md +26 -6
- package/plugin/skills/ase-task-delete/SKILL.md +2 -2
- package/plugin/skills/ase-task-dissect/SKILL.md +299 -0
- package/plugin/skills/ase-task-dissect/help.md +114 -0
- package/plugin/skills/ase-task-edit/SKILL.md +6 -4
- package/plugin/skills/ase-task-grill/SKILL.md +6 -4
- package/plugin/skills/ase-task-id/SKILL.md +2 -2
- package/plugin/skills/ase-task-implement/SKILL.md +2 -2
- package/plugin/skills/ase-task-list/SKILL.md +2 -2
- package/plugin/skills/ase-task-preflight/SKILL.md +2 -2
- package/plugin/skills/ase-task-reboot/SKILL.md +12 -6
- package/plugin/skills/ase-task-rename/SKILL.md +2 -2
- package/plugin/skills/ase-task-view/SKILL.md +2 -2
package/dst/ase-hook.js
CHANGED
|
@@ -145,12 +145,9 @@ export default class HookCommand {
|
|
|
145
145
|
pluginRootVars = ["PLUGIN_ROOT", "CLAUDE_PLUGIN_ROOT"];
|
|
146
146
|
else
|
|
147
147
|
pluginRootVars = ["CLAUDE_PLUGIN_ROOT"];
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
pluginRoot = process.env[pluginRootVar];
|
|
152
|
-
break;
|
|
153
|
-
}
|
|
148
|
+
const pluginRoot = pluginRootVars
|
|
149
|
+
.map((varName) => process.env[varName] ?? "")
|
|
150
|
+
.find((value) => value !== "") ?? "";
|
|
154
151
|
if (pluginRoot === "")
|
|
155
152
|
throw new Error(`${pluginRootVars.join("/")} environment variable is not set`);
|
|
156
153
|
return pluginRoot;
|
|
@@ -254,7 +251,7 @@ export default class HookCommand {
|
|
|
254
251
|
const guidance = setting("agent.guidance", "ASE_GUIDANCE_LEVEL", "normal");
|
|
255
252
|
const boxing = setting("project.boxing", "ASE_PROJECT_BOXING", "white");
|
|
256
253
|
/* determine headless mode */
|
|
257
|
-
const headless =
|
|
254
|
+
const headless = process.env.ASE_HEADLESS === "true" ? "true" : "false";
|
|
258
255
|
/* provide ASE information to Anthropic Claude Code CLI shell commands
|
|
259
256
|
(Anthropic Claude Code CLI only -- GitHub Copilot CLI has no equivalent mechanism) */
|
|
260
257
|
const envFile = tool === "claude" ? (process.env.CLAUDE_ENV_FILE ?? "") : "";
|
|
@@ -300,15 +297,14 @@ export default class HookCommand {
|
|
|
300
297
|
"systemMessage" field for this -- GitHub Copilot CLI has no equivalent);
|
|
301
298
|
the trailing help hint is emitted only if the guidance level asks for it */
|
|
302
299
|
const banner = "\n" +
|
|
303
|
-
`\n⧉ ASE: ⎈ version: ${versionCurrentPlugin}${versionHint !== "" ? " " + versionHint.
|
|
300
|
+
`\n⧉ ASE: ⎈ version: ${versionCurrentPlugin}${versionHint !== "" ? " " + versionHint.replace(/\*/g, "") : ""}` +
|
|
304
301
|
`\n⧉ ASE: ※ user: ${userId}, ⚑ project: ${projectId}` +
|
|
305
302
|
`\n⧉ ASE: ◉ task: ${taskId}, ⏻ session: ${sessionId}` +
|
|
306
303
|
`\n⧉ ASE: ☯ persona: ${persona}, ▶ guidance: ${guidance}, ▢ boxing: ${boxing}` +
|
|
307
304
|
(guidance === "normal" || guidance === "verbose" ?
|
|
308
305
|
"\n" +
|
|
309
306
|
"\n⧉ ASE: ▷ hint: use \"/ase-help-intent <intent-description>\" for skill command proposal" +
|
|
310
|
-
"\n⧉ ASE: ▷ hint: use \"/ase-help-skill [<skill-name>]\" for skill catalog or skill manpage" : "")
|
|
311
|
-
"\n";
|
|
307
|
+
"\n⧉ ASE: ▷ hint: use \"/ase-help-skill [<skill-name>]\" for skill catalog or skill manpage" : "");
|
|
312
308
|
/* inject markdown into session context.
|
|
313
309
|
Anthropic Claude Code CLI and OpenAI Codex CLI expect the context nested in
|
|
314
310
|
"hookSpecificOutput"; GitHub Copilot CLI expects a flat top-level
|
|
@@ -434,10 +430,10 @@ export default class HookCommand {
|
|
|
434
430
|
tools, but the decision logic is shared by the "pre-tool-use" and
|
|
435
431
|
"permission-request" handlers. */
|
|
436
432
|
decideApproval(tool, spec, input) {
|
|
437
|
-
const
|
|
438
|
-
input[spec.toolNameField] : "";
|
|
439
|
-
let toolInput = {};
|
|
433
|
+
const rawName = input[spec.toolNameField];
|
|
440
434
|
const rawInput = input[spec.toolInputField];
|
|
435
|
+
const toolName = typeof rawName === "string" ? rawName : "";
|
|
436
|
+
let toolInput = {};
|
|
441
437
|
if (spec.toolInputIsString && typeof rawInput === "string")
|
|
442
438
|
toolInput = this.parseJSON(rawInput, toolInputSchema);
|
|
443
439
|
else if (!spec.toolInputIsString && typeof rawInput === "object" && rawInput !== null) {
|
package/dst/ase-statusline.js
CHANGED
|
@@ -159,6 +159,23 @@ const probeMemory = () => {
|
|
|
159
159
|
return { used: 0, total: 0 };
|
|
160
160
|
}
|
|
161
161
|
};
|
|
162
|
+
/* set of reasoning effort levels GitHub Copilot CLI offers in its effort picker */
|
|
163
|
+
const EFFORTS = new Set([
|
|
164
|
+
"low", "medium", "high", "xhigh", "max"
|
|
165
|
+
]);
|
|
166
|
+
/* split a GitHub Copilot CLI "model.display_name" into its plain model name and its
|
|
167
|
+
reasoning effort: Copilot CLI renders the display name as the model label, followed
|
|
168
|
+
by the optional request multiplier, the optional reasoning effort and the optional
|
|
169
|
+
context tier, all separated by " · " (e.g. "gpt-5.4 (2x) · high · 1M context"), so
|
|
170
|
+
only a segment matching a known effort level is taken as the effort */
|
|
171
|
+
const splitCopilotModel = (display) => {
|
|
172
|
+
const parts = display.split(" · ");
|
|
173
|
+
const effort = parts.filter((part) => EFFORTS.has(part.toLowerCase()));
|
|
174
|
+
const name = parts.filter((part) => !EFFORTS.has(part.toLowerCase()));
|
|
175
|
+
if (effort.length === 0)
|
|
176
|
+
return { name: display, effort: "" };
|
|
177
|
+
return { name: name.join(" · "), effort: effort[0].toLowerCase() };
|
|
178
|
+
};
|
|
162
179
|
/* memoize a zero-argument function, computing its value at most once on first use */
|
|
163
180
|
const memoize = (fn) => {
|
|
164
181
|
let cache = null;
|
|
@@ -286,6 +303,15 @@ export default class StatuslineCommand {
|
|
|
286
303
|
}
|
|
287
304
|
return { taskId, persona, guidance };
|
|
288
305
|
});
|
|
306
|
+
const getModel = memoize(() => {
|
|
307
|
+
const display = data.model?.display_name ?? "";
|
|
308
|
+
/* under GitHub Copilot CLI the reasoning effort is only available as
|
|
309
|
+
a segment of the display name, so split it off again and let the
|
|
310
|
+
regular "effort" field of Anthropic Claude Code CLI still win */
|
|
311
|
+
const split = tool === "copilot" && display !== "" ?
|
|
312
|
+
splitCopilotModel(display) : { name: display, effort: "" };
|
|
313
|
+
return { name: split.name, effort: data.effort?.level ?? split.effort };
|
|
314
|
+
});
|
|
289
315
|
const getGit = memoize(() => probeGit(data.workspace?.current_dir ?? ""));
|
|
290
316
|
const getMem = memoize(() => probeMemory());
|
|
291
317
|
/* identifier to renderer map: each callback fetches its own information
|
|
@@ -308,12 +334,12 @@ export default class StatuslineCommand {
|
|
|
308
334
|
s: () => emit(`${prefix("⏻", "session")}${c.bold(getSession())}`),
|
|
309
335
|
/* ==== MODEL ==== */
|
|
310
336
|
m: () => {
|
|
311
|
-
const
|
|
312
|
-
emit(`${prefix("⚙", "model")}${c.bold(
|
|
337
|
+
const { name } = getModel();
|
|
338
|
+
emit(`${prefix("⚙", "model")}${c.bold(name)}`);
|
|
313
339
|
},
|
|
314
340
|
e: () => {
|
|
315
|
-
const effort =
|
|
316
|
-
emit(`${prefix("⚒", "effort")}${c.bold(effort)}`);
|
|
341
|
+
const { effort } = getModel();
|
|
342
|
+
emit(`${prefix("⚒", "effort")}${c.bold(effort !== "" ? effort : "unknown")}`);
|
|
317
343
|
},
|
|
318
344
|
t: () => {
|
|
319
345
|
const thinking = data.thinking?.enabled === true ? "yes" : "no";
|
package/dst/ase-task.js
CHANGED
|
@@ -451,7 +451,8 @@ export class TaskMCP {
|
|
|
451
451
|
mcp.registerTool("ase_task_save", {
|
|
452
452
|
title: "ASE task save",
|
|
453
453
|
description: "Persist a task as `text` under `id`. " +
|
|
454
|
-
"Overwrites any existing task for the same `id`."
|
|
454
|
+
"Overwrites any existing task for the same `id`. " +
|
|
455
|
+
"Returns the persisted task as `text`, prepared for improved rendering.",
|
|
455
456
|
inputSchema: {
|
|
456
457
|
id: z.string()
|
|
457
458
|
.describe("task identifier (allowed characters: A-Z, a-z, 0-9, '_', '-')"),
|
|
@@ -461,8 +462,12 @@ export class TaskMCP {
|
|
|
461
462
|
}, async (args) => {
|
|
462
463
|
try {
|
|
463
464
|
Task.save(this.log, args.id, args.text);
|
|
465
|
+
/* return the prepared content, so a caller reusing the
|
|
466
|
+
just-saved plan instead of re-loading it still receives
|
|
467
|
+
the rendering-prepared variant */
|
|
468
|
+
const text = Markdown.prepare(args.text);
|
|
464
469
|
return {
|
|
465
|
-
content: [{ type: "text", text
|
|
470
|
+
content: [{ type: "text", text }]
|
|
466
471
|
};
|
|
467
472
|
}
|
|
468
473
|
catch (err) {
|
package/package.json
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"homepage": "https://ase.tools",
|
|
7
7
|
"repository": { "url": "git+https://github.com/rse/ase.git", "type": "git" },
|
|
8
8
|
"bugs": { "url": "https://github.com/rse/ase/issues" },
|
|
9
|
-
"version": "0.9.
|
|
9
|
+
"version": "0.9.52",
|
|
10
10
|
"license": "Apache-2.0",
|
|
11
11
|
"author": {
|
|
12
12
|
"name": "Dr. Ralf S. Engelschall",
|
|
@@ -23,14 +23,14 @@
|
|
|
23
23
|
"eslint-plugin-promise": "7.3.0",
|
|
24
24
|
"eslint-plugin-import": "2.32.0",
|
|
25
25
|
"neostandard": "0.13.0",
|
|
26
|
-
"globals": "17.
|
|
26
|
+
"globals": "17.8.0",
|
|
27
27
|
"typescript": "6.0.3",
|
|
28
28
|
|
|
29
29
|
"@rse/stx": "1.1.6",
|
|
30
30
|
"nodemon": "3.1.14",
|
|
31
31
|
"shx": "0.4.0",
|
|
32
32
|
|
|
33
|
-
"@types/node": "26.1.
|
|
33
|
+
"@types/node": "26.1.2",
|
|
34
34
|
"@types/luxon": "3.7.2",
|
|
35
35
|
"@types/which": "3.0.4",
|
|
36
36
|
"@types/update-notifier": "6.0.8",
|
|
@@ -42,18 +42,18 @@
|
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
44
|
"commander": "15.0.0",
|
|
45
|
-
"@dotenvx/dotenvx": "2.
|
|
45
|
+
"@dotenvx/dotenvx": "2.19.1",
|
|
46
46
|
"yaml": "2.9.0",
|
|
47
47
|
"valibot": "1.4.2",
|
|
48
|
-
"execa": "10.0.
|
|
48
|
+
"execa": "10.0.1",
|
|
49
49
|
"mkdirp": "3.0.1",
|
|
50
50
|
"@hapi/hapi": "21.4.10",
|
|
51
51
|
"beautiful-mermaid": "1.1.3",
|
|
52
52
|
"cli-table3": "0.6.5",
|
|
53
|
-
"chalk": "
|
|
53
|
+
"chalk": "6.0.0",
|
|
54
54
|
"pretty-ms": "9.3.0",
|
|
55
55
|
"luxon": "3.7.2",
|
|
56
|
-
"@modelcontextprotocol/sdk": "1.
|
|
56
|
+
"@modelcontextprotocol/sdk": "1.30.0",
|
|
57
57
|
"json-asty": "1.3.4",
|
|
58
58
|
"zod": "4.4.3",
|
|
59
59
|
"which": "7.0.0",
|
|
@@ -13,6 +13,10 @@ Workflow
|
|
|
13
13
|
--------
|
|
14
14
|
|
|
15
15
|
1. Set the requested context: <context>$ARGUMENTS</context>.
|
|
16
|
+
The *first* whitespace-separated token of <context/> is the
|
|
17
|
+
comma-separated *aspect set* <aspects/> (a non-empty subset of the
|
|
18
|
+
aspect ids `A01`...`A20`). The *remaining* tokens are the source
|
|
19
|
+
code files to check.
|
|
16
20
|
|
|
17
21
|
2. Use the `Read` tool to read all source code files referenced by
|
|
18
22
|
<context/>, plus all *related* source code files needed to really
|
|
@@ -25,7 +29,9 @@ Workflow
|
|
|
25
29
|
4. Set <problems/> to empty.
|
|
26
30
|
Then check the read source code for the following aspects (each
|
|
27
31
|
aspect is uniquely identified by its `aspect` id `A01 - XXX`...`A20
|
|
28
|
-
- XXX`)
|
|
32
|
+
- XXX`), but *strictly limited* to those aspects whose id is
|
|
33
|
+
contained in the aspect set <aspects/> -- all other aspects are
|
|
34
|
+
*not* checked and their problems are *never* reported:
|
|
29
35
|
|
|
30
36
|
- **A01 - FORMATTING**:
|
|
31
37
|
Check for inconsistently formatted code and badly vertically
|
|
@@ -95,6 +101,20 @@ Workflow
|
|
|
95
101
|
site as close as possible. For R4, prefer *parameterization*
|
|
96
102
|
(table-driven, strategy map) over inheritance.
|
|
97
103
|
|
|
104
|
+
**PAYOFF GATE**: *Before* reporting any redundancy, draft the
|
|
105
|
+
solution diff and count its lines. The removed lines *MUST* be at
|
|
106
|
+
least *twice* the added lines (ratio >= 2:1, i.e. a net reduction
|
|
107
|
+
of at least 50%), where the added lines include the *entire*
|
|
108
|
+
extracted construct (signature, body, closing lines, comments,
|
|
109
|
+
type annotations) plus all replacing call sites. A break-even
|
|
110
|
+
proposal (e.g. 8 removed, 8 added) or any proposal below the 2:1
|
|
111
|
+
ratio *MUST* be *silently dropped* and *MUST* *NOT* be reported --
|
|
112
|
+
it merely relocates code instead of reducing it. Do *not* game
|
|
113
|
+
the ratio by compressing the extracted construct into unnatural
|
|
114
|
+
formatting or by omitting comments the code base style requires.
|
|
115
|
+
Two duplicated occurrences of a short block rarely pass this gate;
|
|
116
|
+
three or more occurrences usually do.
|
|
117
|
+
|
|
98
118
|
- **A07 - PATTERNS**:
|
|
99
119
|
Check for broken design patterns, broken conventions, or broken
|
|
100
120
|
best practices.
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ase-meta-proximity
|
|
3
|
+
description: "Determine the Conceptual Proximity of a Topic"
|
|
4
|
+
effort: high
|
|
5
|
+
tools:
|
|
6
|
+
- "Agent"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
@../meta/ase-control.md
|
|
10
|
+
|
|
11
|
+
<define name="gather-facts">
|
|
12
|
+
<if condition="<ground/> is equal `true`">
|
|
13
|
+
Use the `ase-meta-search` skill in a sub-agent to gather facts with
|
|
14
|
+
the following tool call and store the returned facts in the placeholder
|
|
15
|
+
named `<arg2/>`:
|
|
16
|
+
|
|
17
|
+
`Agent(
|
|
18
|
+
description: "Query Web Search Service",
|
|
19
|
+
subagent_type: "ase:ase-meta-search",
|
|
20
|
+
prompt: "Search the Internet/Web and gather facts about <arg1/>",
|
|
21
|
+
run_in_background: false
|
|
22
|
+
)`
|
|
23
|
+
|
|
24
|
+
<if condition="the placeholder named `<arg2/>` contains no usable facts">
|
|
25
|
+
Set the placeholder named `<arg2/>` to empty, so the determination below
|
|
26
|
+
silently falls back to model knowledge. You *MUST* *NOT* output any
|
|
27
|
+
warning, because the caller expects the labeled list of step 4 as the
|
|
28
|
+
*only* output.
|
|
29
|
+
</if>
|
|
30
|
+
</if>
|
|
31
|
+
<else>
|
|
32
|
+
Use the model's world knowledge and determine facts about <arg1/> and
|
|
33
|
+
store those facts in the placeholder named `<arg2/>`.
|
|
34
|
+
</else>
|
|
35
|
+
</define>
|
|
36
|
+
|
|
37
|
+
1. Set <args>$ARGUMENTS</args>, the single whitespace-separated string.
|
|
38
|
+
|
|
39
|
+
<if condition="the *first* token of <args/> is equal `GROUND`">
|
|
40
|
+
Set <ground>true</ground> (grounding requested) and set <topic/>
|
|
41
|
+
to the *second and all following* tokens of <args/>.
|
|
42
|
+
</if>
|
|
43
|
+
<else>
|
|
44
|
+
Set <ground>false</ground> (no grounding requested) and set
|
|
45
|
+
<topic/> to *all* tokens of <args/>.
|
|
46
|
+
</else>
|
|
47
|
+
|
|
48
|
+
You *MUST* *NOT* output anything related to this step.
|
|
49
|
+
|
|
50
|
+
2. *Determine Topic*:
|
|
51
|
+
|
|
52
|
+
Determine the canonical name of the central *topic* which is stored
|
|
53
|
+
in <topic/>.
|
|
54
|
+
|
|
55
|
+
<expand name="gather-facts"
|
|
56
|
+
arg1="the following topic: <topic/>"
|
|
57
|
+
arg2="facts-topic"></expand>
|
|
58
|
+
|
|
59
|
+
Ground the determination of the canonical name of the topic <topic/>
|
|
60
|
+
in the facts of <facts-topic/> and do not contradict them. Update
|
|
61
|
+
<topic/> accordingly.
|
|
62
|
+
|
|
63
|
+
You *MUST* *NOT* output anything related to this step.
|
|
64
|
+
|
|
65
|
+
3. *Determine Proximity*:
|
|
66
|
+
|
|
67
|
+
Determine the *conceptual proximity* of the current <topic/> along
|
|
68
|
+
three *dimensions* in parallel:
|
|
69
|
+
|
|
70
|
+
- **PARENT**:
|
|
71
|
+
|
|
72
|
+
The single most relevant *parent* topic (the broader topic that
|
|
73
|
+
<topic/> is a specialization of), which will be stored in
|
|
74
|
+
<parent/>.
|
|
75
|
+
|
|
76
|
+
<expand name="gather-facts"
|
|
77
|
+
arg1="the PARENT topic (the broader topic that the given topic is a specialization of) of the following topic: <topic/>"
|
|
78
|
+
arg2="facts-parent"></expand>
|
|
79
|
+
|
|
80
|
+
Ground the determination of the canonical name of the parent
|
|
81
|
+
topic <parent/> in the facts of <facts-parent/> and do not
|
|
82
|
+
contradict them.
|
|
83
|
+
|
|
84
|
+
- **SIBLINGS**:
|
|
85
|
+
|
|
86
|
+
The *four* most relevant *sibling* topics (topics on the same
|
|
87
|
+
level that share the same parent), which will be stored in
|
|
88
|
+
<sibling-1/> to <sibling-4/>.
|
|
89
|
+
|
|
90
|
+
<expand name="gather-facts"
|
|
91
|
+
arg1="the SIBLING topics (topics on the same level that share the same parent) of the following topic: <topic/>"
|
|
92
|
+
arg2="facts-siblings"></expand>
|
|
93
|
+
|
|
94
|
+
Ground the determination of the canonical names of the most
|
|
95
|
+
relevant sibling topics <sibling-1/> to <sibling-4/> in the facts
|
|
96
|
+
of <facts-siblings/> and do not contradict them.
|
|
97
|
+
|
|
98
|
+
- **CHILDREN**:
|
|
99
|
+
|
|
100
|
+
The *four* most relevant *child* topics (narrower topics that
|
|
101
|
+
are specializations of <topic/>), stored in <child-1/> to
|
|
102
|
+
<child-4/>.
|
|
103
|
+
|
|
104
|
+
<expand name="gather-facts"
|
|
105
|
+
arg1="the CHILDREN topics (narrower topics that are specializations) of the following topic: <topic/>"
|
|
106
|
+
arg2="facts-children"></expand>
|
|
107
|
+
|
|
108
|
+
Ground the determination of the canonical names of the most
|
|
109
|
+
relevant child topics <child-1/> to <child-4/> in the facts of
|
|
110
|
+
<facts-children/> and do not contradict them.
|
|
111
|
+
|
|
112
|
+
You *MUST* determine *exactly* one parent, *exactly* four siblings,
|
|
113
|
+
and *exactly* four children. All nine proximity topics *MUST* be
|
|
114
|
+
*distinct* from each other and *MUST* *NOT* be <topic/> itself or a
|
|
115
|
+
mere synonym or spelling variant of it. You *MUST* *NOT* output
|
|
116
|
+
anything related to this step.
|
|
117
|
+
|
|
118
|
+
4. Return *exclusively* the following <template/> (no prose, no
|
|
119
|
+
preamble, no summary, and no Markdown formatting):
|
|
120
|
+
|
|
121
|
+
<template>
|
|
122
|
+
TOPIC: <topic/>
|
|
123
|
+
PARENT: <parent/>
|
|
124
|
+
SIBLING: <sibling-1/>
|
|
125
|
+
SIBLING: <sibling-2/>
|
|
126
|
+
SIBLING: <sibling-3/>
|
|
127
|
+
SIBLING: <sibling-4/>
|
|
128
|
+
CHILD: <child-1/>
|
|
129
|
+
CHILD: <child-2/>
|
|
130
|
+
CHILD: <child-3/>
|
|
131
|
+
CHILD: <child-4/>
|
|
132
|
+
</template>
|
|
133
|
+
|
package/plugin/etc/stx.conf
CHANGED
|
@@ -12,9 +12,9 @@ lint
|
|
|
12
12
|
# [plugin] build project
|
|
13
13
|
build : lint
|
|
14
14
|
( for name in $(cd skills; ls -1 | grep -v ase-help-intent | sort); do
|
|
15
|
-
echo "<
|
|
15
|
+
echo "<purpose name=\"$name\">"
|
|
16
16
|
cat skills/$name/help.md | sed -e '/^## SEE ALSO/,$d'
|
|
17
|
-
echo "</
|
|
17
|
+
echo "</purpose>"
|
|
18
18
|
done
|
|
19
19
|
) >skills/ase-help-intent/data.md
|
|
20
20
|
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
|
|
2
|
+
Dissect Skill Common Steps
|
|
3
|
+
==========================
|
|
4
|
+
|
|
5
|
+
<define name="dissect-derive">
|
|
6
|
+
|
|
7
|
+
*Dissect* <content/> into *cohesive parts* by strictly honoring the
|
|
8
|
+
following ruleset:
|
|
9
|
+
|
|
10
|
+
1. *Separate domain-wise and logically*: every part *MUST* be a
|
|
11
|
+
*self-contained* unit of work with a *single*, coherent purpose (one
|
|
12
|
+
domain, one concern, one logical change), so it can be implemented,
|
|
13
|
+
reviewed, and committed entirely *on its own*. A *technical* split
|
|
14
|
+
-- one part per file, per directory, per file type, or per technical
|
|
15
|
+
layer -- is usually *not* the obvious and intended one: files are
|
|
16
|
+
merely *where* the change lands, while a part is defined by *what*
|
|
17
|
+
it achieves. Cut along the *semantics* first, and let a file-wise
|
|
18
|
+
boundary result only when it *coincides* with a domain boundary.
|
|
19
|
+
|
|
20
|
+
2. *Bound the part count*: derive at least *2* and at most
|
|
21
|
+
*<getopt-option-max-parts/>* parts. Prefer *fewer* and *larger*
|
|
22
|
+
cohesive parts over *many* and *tiny* ones.
|
|
23
|
+
|
|
24
|
+
3. *Assign totally and disjointly*: *every* input element of the epic
|
|
25
|
+
*MUST* be assigned to *exactly one* part -- no input element is
|
|
26
|
+
dropped, and no input element occurs in two parts. An input element
|
|
27
|
+
which itself spans *multiple* domains or concerns *MAY* be *split*
|
|
28
|
+
into two or more *sub-elements*, which are then assigned like
|
|
29
|
+
ordinary input elements, provided the sub-elements *together* cover
|
|
30
|
+
the original element *completely*, *never* overlap, and each one
|
|
31
|
+
stays *self-contained* in the input form the calling skill defines.
|
|
32
|
+
Split *only* when rule 1 forces it: an input element whose content
|
|
33
|
+
fits a *single* part stays *unsplit*.
|
|
34
|
+
|
|
35
|
+
4. *Keep mutually dependent elements together*: input elements which
|
|
36
|
+
only make sense *together* -- they reference each other, one is the
|
|
37
|
+
precondition of the other, or splitting them would leave a part
|
|
38
|
+
broken -- *MUST* land in the *same* part.
|
|
39
|
+
|
|
40
|
+
5. *Never invent*: parts are formed *exclusively* from the input
|
|
41
|
+
elements of the epic. Do *not* add scope, do *not* re-interpret the
|
|
42
|
+
input elements, and do *not* re-word them beyond what a part-local
|
|
43
|
+
summary requires.
|
|
44
|
+
|
|
45
|
+
6. *Slug and identify every part*: per part derive a <feature-slug/>
|
|
46
|
+
from its scope, matching the regexp `^[a-z][a-z0-9-]{0,23}$` and
|
|
47
|
+
*unique* across all parts, and then set
|
|
48
|
+
<part-id><arg3/>-<feature-slug/></part-id>, where <arg3/> is the
|
|
49
|
+
*id prefix* the calling skill passed in.
|
|
50
|
+
|
|
51
|
+
7. *Order for implementation*: order the parts so that a part *never*
|
|
52
|
+
depends on a later one, and number them consecutively as <part-no/>,
|
|
53
|
+
starting at `1`.
|
|
54
|
+
|
|
55
|
+
8. *Honor the dissection hint*:
|
|
56
|
+
<if condition="<arg2/> is not empty">
|
|
57
|
+
Set <hint><arg2/></hint>. The user explicitly told *how* the epic
|
|
58
|
+
should be split -- e.g. which input elements belong together, along
|
|
59
|
+
which axis to cut, or how many parts to aim at -- so you *MUST*
|
|
60
|
+
follow this <hint/> as closely as possible and let it *override* the
|
|
61
|
+
default grouping of rule 1. It *MUST NOT* override the rules 2-7,
|
|
62
|
+
though: the part count stays bounded, the assignment stays total and
|
|
63
|
+
disjoint, mutually dependent elements stay together, nothing is
|
|
64
|
+
invented, every part stays uniquely slugged, and the order stays
|
|
65
|
+
dependency-free. If the <hint/> conflicts with one of these rules,
|
|
66
|
+
honor the rule and follow the <hint/> only as far as the rule
|
|
67
|
+
permits.
|
|
68
|
+
</if>
|
|
69
|
+
<else>
|
|
70
|
+
No dissection hint was given, so the grouping follows the rules 1-7
|
|
71
|
+
alone. Do not output anything.
|
|
72
|
+
</else>
|
|
73
|
+
|
|
74
|
+
Per part, additionally derive an *ultra brief* <scope/> (*what* the part
|
|
75
|
+
covers) and an *ultra brief* <rationale/> (*why* exactly these input
|
|
76
|
+
elements form *one* cohesive part). Store the resulting parts in
|
|
77
|
+
<parts/> and their number in <n/>.
|
|
78
|
+
|
|
79
|
+
<if condition="fewer than 2 cohesive parts exist">
|
|
80
|
+
The epic is *not* dissectable, because it carries a *single* cohesive
|
|
81
|
+
purpose (or too few input elements) and splitting it would only produce
|
|
82
|
+
artificial fragments. Only output the following <template/> and then
|
|
83
|
+
immediately *STOP* processing the entire current skill:
|
|
84
|
+
|
|
85
|
+
<template>
|
|
86
|
+
⧉ **ASE**: ✪ skill: **<arg1/>**, ▶ status: **epic not dissectable**
|
|
87
|
+
</template>
|
|
88
|
+
</if>
|
|
89
|
+
|
|
90
|
+
</define>
|
|
91
|
+
|
|
92
|
+
<define name="dissect-report">
|
|
93
|
+
|
|
94
|
+
Report the derived <parts/> with the following <template/>, emitting
|
|
95
|
+
*one* table row per part in <parts/>, in their derived order. Keep
|
|
96
|
+
<scope/> and <rationale/> each to *one* ultra brief sentence, align all
|
|
97
|
+
column edges of the table, and do *not* output any further explanation:
|
|
98
|
+
|
|
99
|
+
<template>
|
|
100
|
+
<ase-tpl-head title="DISSECTION" subtitle="<arg1/>">
|
|
101
|
+
|
|
102
|
+
| Part | Id | Scope | Rationale |
|
|
103
|
+
| --------------- | ------------ | -------- | ------------ |
|
|
104
|
+
| **P<part-no/>** | `<part-id/>` | <scope/> | <rationale/> |
|
|
105
|
+
| [...] | [...] | [...] | [...] |
|
|
106
|
+
|
|
107
|
+
<ase-tpl-foot title="DISSECTION" subtitle="<arg1/>">
|
|
108
|
+
</template>
|
|
109
|
+
|
|
110
|
+
</define>
|
|
@@ -65,9 +65,11 @@ Task Skill Common Steps
|
|
|
65
65
|
*and* a `ase_task_save(id: '<ase-task-id/>', ...)` tool call
|
|
66
66
|
exists earlier in the current session
|
|
67
67
|
">
|
|
68
|
-
Set <text/> to the `text`
|
|
69
|
-
`ase_task_save(id: '<ase-task-id/>', ...)` tool call
|
|
70
|
-
|
|
68
|
+
Set <text/> to the `text` *output* field of the most recent
|
|
69
|
+
`ase_task_save(id: '<ase-task-id/>', ...)` tool call -- this is
|
|
70
|
+
the rendering-prepared plan content and *MUST NOT* be confused
|
|
71
|
+
with the `text` *argument* passed into that call -- *without*
|
|
72
|
+
calling `ase_task_load` again. Set <status>plan
|
|
71
73
|
reused</status>. Do not output anything.
|
|
72
74
|
</if>
|
|
73
75
|
<else>
|
|
@@ -95,3 +95,56 @@ Control Flow Constructs
|
|
|
95
95
|
is finished and no further repetitions are performed. This construct
|
|
96
96
|
is expanded into nothing. Do not output anything.
|
|
97
97
|
|
|
98
|
+
- *IMPORTANT*: You *MUST* honor the following control flow construct:
|
|
99
|
+
<agent <attr/>="<value/>" [...]><agent-body/></agent>:
|
|
100
|
+
|
|
101
|
+
This specifies the *invocation* of a *sub-agent* through the
|
|
102
|
+
`Agent` tool. Every XML attribute is passed *verbatim* as the
|
|
103
|
+
identically named parameter of the `Agent` tool (e.g. `description`,
|
|
104
|
+
`subagent_type`, `run_in_background`, `isolation`, `model`), and
|
|
105
|
+
<agent-body/> is passed as its `prompt` parameter.
|
|
106
|
+
|
|
107
|
+
The *sole exception* is the *reserved* attribute `result="<var/>"`,
|
|
108
|
+
which is *not* passed on but instead *binds* the result returned
|
|
109
|
+
by the sub-agent to the placeholder `<<var/>/>`. This construct is
|
|
110
|
+
expanded to the result returned by the sub-agent if `result` is
|
|
111
|
+
*absent*, or into nothing if `result` is *present*. Do not output
|
|
112
|
+
anything else.
|
|
113
|
+
|
|
114
|
+
- *IMPORTANT*: You *MUST* honor the following control flow construct:
|
|
115
|
+
<agent-consolidation [group=<agent-group/>]/>
|
|
116
|
+
|
|
117
|
+
This specifies the merging of all the Git WorkTrees created by the
|
|
118
|
+
<agent/> calls with either are identified with the unique group
|
|
119
|
+
<agent-group/> or all <agent/> calls in the last <parallel/> section
|
|
120
|
+
of the context. After merging a single Git WorkTree, remove the Git
|
|
121
|
+
WorkTree.
|
|
122
|
+
|
|
123
|
+
- *IMPORTANT*: You *MUST* honor the following control flow construct:
|
|
124
|
+
<skill name="<id/>" [args="<args/>"] [result="<var/>"]/>:
|
|
125
|
+
|
|
126
|
+
This specifies the *invocation* of another *skill* through the
|
|
127
|
+
`Skill` tool, with its `skill` parameter set to <id/> and its `args`
|
|
128
|
+
parameter set to <args/> (or to the empty string if the `args`
|
|
129
|
+
attribute is absent).
|
|
130
|
+
|
|
131
|
+
The *reserved* attribute `result="<var/>"` *binds* the result
|
|
132
|
+
returned by the skill to the placeholder `<<var/>/>`, exactly
|
|
133
|
+
as for <agent/>. This construct is *always* *self-closing*: a
|
|
134
|
+
*body-bearing* `<skill>` element is *never* an invocation. This
|
|
135
|
+
construct is expanded to the result returned by the skill if
|
|
136
|
+
`result` is *absent*, or into nothing if `result` is *present*. Do
|
|
137
|
+
not output anything else.
|
|
138
|
+
|
|
139
|
+
- *IMPORTANT*: You *MUST* honor the following control flow construct:
|
|
140
|
+
<parallel><parallel-body/></parallel>:
|
|
141
|
+
|
|
142
|
+
This specifies a <parallel-body/> whose <agent/> and <skill/>
|
|
143
|
+
invocations are *all* dispatched *concurrently*: you *MUST* emit
|
|
144
|
+
them *in one single message* instead of one per turn, and this
|
|
145
|
+
construct is finished only once *all* of them have returned. If two
|
|
146
|
+
or more of these invocations bind the *same* `result` name, the
|
|
147
|
+
corresponding placeholder carries an *array* of their results, in
|
|
148
|
+
the order of their occurrence in <parallel-body/>. This construct is
|
|
149
|
+
expanded to its <parallel-body/>. Do not output anything else.
|
|
150
|
+
|
|
@@ -70,3 +70,9 @@ You *MUST* honor the following hints on this *task* format:
|
|
|
70
70
|
after about 100 characters per line for better subsequent
|
|
71
71
|
manual editing.
|
|
72
72
|
|
|
73
|
+
- You *MUST* *NEVER* break a line *inside* an inline code span
|
|
74
|
+
<template>`<code/>`</template>, as a code span split across two
|
|
75
|
+
lines renders badly. Instead, break the line *before* its opening
|
|
76
|
+
backtick or *after* its closing backtick, even if this means
|
|
77
|
+
breaking the line noticeably earlier than after 100 characters.
|
|
78
|
+
|
package/plugin/meta/ase-skill.md
CHANGED
|
@@ -209,18 +209,18 @@ MCP Tool Calls
|
|
|
209
209
|
Skill Identification
|
|
210
210
|
--------------------
|
|
211
211
|
|
|
212
|
-
- *IMPORTANT*: Set <
|
|
212
|
+
- *IMPORTANT*: Set <purpose></purpose> (set to empty)
|
|
213
213
|
and <skill-name></skill-name> (set name to empty).
|
|
214
214
|
|
|
215
|
-
In case <
|
|
216
|
-
name="<name/>"><body/></
|
|
217
|
-
(set skill name to name), and then
|
|
218
|
-
to `-h` or `--help`) *AND*
|
|
219
|
-
or `verbose`))) you *MUST*
|
|
220
|
-
<template/>:
|
|
215
|
+
In case <purpose/> later becomes *not* empty by defining it as
|
|
216
|
+
<purpose name="<name/>"><body/></purpose>, set
|
|
217
|
+
<skill-name><name/></skill-name> (set skill name to name), and then
|
|
218
|
+
(but only if ((`$1` is *NOT* equal to `-h` or `--help`) *AND*
|
|
219
|
+
(<ase-guidance-level/> is equal to `normal` or `verbose`))) you *MUST*
|
|
220
|
+
once output the following output <template/>:
|
|
221
221
|
|
|
222
222
|
<template>
|
|
223
|
-
⧉ **ASE**: ✪ skill: **<skill-name/>**, ✦ purpose: **<
|
|
223
|
+
⧉ **ASE**: ✪ skill: **<skill-name/>**, ✦ purpose: **<purpose/>**, ▶ status: **skill started**
|
|
224
224
|
</template>
|
|
225
225
|
|
|
226
226
|
Later (but only if ((`$1` is *NOT* equal to `-h` or `--help`) *AND*
|
package/plugin/package.json
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"homepage": "https://ase.tools",
|
|
7
7
|
"repository": { "url": "git+https://github.com/rse/ase.git", "type": "git" },
|
|
8
8
|
"bugs": { "url": "https://github.com/rse/ase/issues" },
|
|
9
|
-
"version": "0.9.
|
|
9
|
+
"version": "0.9.52",
|
|
10
10
|
"license": "Apache-2.0",
|
|
11
11
|
"author": {
|
|
12
12
|
"name": "Dr. Ralf S. Engelschall",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"devDependencies": {
|
|
17
17
|
"@rse/stx": "1.1.6",
|
|
18
18
|
"markdownlint": "0.41.1",
|
|
19
|
-
"markdownlint-cli2": "0.23.
|
|
19
|
+
"markdownlint-cli2": "0.23.2",
|
|
20
20
|
"eslint": "10.8.0",
|
|
21
21
|
"@eslint/markdown": "8.0.3",
|
|
22
22
|
"eslint-markdown": "0.12.1"
|