@rse/ase 0.0.37 → 0.0.38
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-hello.js +4 -4
- package/dst/ase-setup.js +73 -2
- package/package.json +1 -1
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/.github/plugin/plugin.json +1 -1
- package/plugin/package.json +1 -1
- package/plugin/skills/ase-code-craft/SKILL.md +15 -4
- package/plugin/skills/ase-code-refactor/SKILL.md +15 -4
- package/plugin/skills/ase-code-resolve/SKILL.md +23 -11
- package/plugin/skills/ase-meta-evaluate/SKILL.md +9 -5
package/dst/ase-hello.js
CHANGED
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
** Licensed under GPL 3.0 <https://spdx.org/licenses/GPL-3.0-only>
|
|
5
5
|
*/
|
|
6
6
|
import { Chalk } from "chalk";
|
|
7
|
-
/* forced-color chalk instance: stdout
|
|
8
|
-
auto-detection would yield level 0; force level 1 to keep
|
|
9
|
-
emitting ANSI sequences as
|
|
7
|
+
/* forced-color chalk instance: stdout is a pipe under Claude Code,
|
|
8
|
+
so chalk auto-detection would yield level 0; force level 1 to keep
|
|
9
|
+
emitting ANSI sequences as the original implementation did */
|
|
10
10
|
const c = new Chalk({ level: 1 });
|
|
11
11
|
/* command-line handling */
|
|
12
12
|
export default class HelloCommand {
|
|
@@ -20,7 +20,7 @@ export default class HelloCommand {
|
|
|
20
20
|
.command("hello")
|
|
21
21
|
.description("print a colored greeting message")
|
|
22
22
|
.option("-s, --subject <name>", "subject to greet", "Universe")
|
|
23
|
-
.action((opts) => {
|
|
23
|
+
.action(async (opts) => {
|
|
24
24
|
process.stdout.write(`${c.red(`${opts.subject} World!`)}\n`);
|
|
25
25
|
});
|
|
26
26
|
}
|
package/dst/ase-setup.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
** Copyright (c) 2025-2026 Dr. Ralf S. Engelschall <rse@engelschall.com>
|
|
4
4
|
** Licensed under GPL 3.0 <https://spdx.org/licenses/GPL-3.0-only>
|
|
5
5
|
*/
|
|
6
|
+
import fs from "node:fs/promises";
|
|
6
7
|
import path from "node:path";
|
|
7
8
|
import { fileURLToPath } from "node:url";
|
|
8
9
|
import { execa } from "execa";
|
|
@@ -24,6 +25,74 @@ export default class SetupCommand {
|
|
|
24
25
|
throw new Error(`mandatory tool "${tool}" not found in $PATH`);
|
|
25
26
|
});
|
|
26
27
|
}
|
|
28
|
+
/* determine whether a global "npm" operation requires "sudo" by
|
|
29
|
+
checking whether the npm global install root is writable by the
|
|
30
|
+
current user; on Windows or when already running as root, no
|
|
31
|
+
elevation is needed */
|
|
32
|
+
async npmGlobalNeedsSudo() {
|
|
33
|
+
/* Windows has no "sudo" concept here */
|
|
34
|
+
if (process.platform === "win32")
|
|
35
|
+
return false;
|
|
36
|
+
/* already running as root */
|
|
37
|
+
const getuid = process.getuid;
|
|
38
|
+
if (typeof getuid === "function" && getuid.call(process) === 0)
|
|
39
|
+
return false;
|
|
40
|
+
/* determine the npm global prefix and probe writability of the
|
|
41
|
+
directories that "npm -g" actually mutates */
|
|
42
|
+
let prefix = "";
|
|
43
|
+
try {
|
|
44
|
+
const result = await execa("npm", ["prefix", "-g"], { stdio: "pipe" });
|
|
45
|
+
prefix = result.stdout.trim();
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
/* if we cannot determine the prefix, fall back to "no sudo" */
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
if (prefix === "")
|
|
52
|
+
return false;
|
|
53
|
+
const candidates = [
|
|
54
|
+
prefix,
|
|
55
|
+
path.join(prefix, "bin"),
|
|
56
|
+
path.join(prefix, "lib", "node_modules")
|
|
57
|
+
];
|
|
58
|
+
for (const dir of candidates) {
|
|
59
|
+
try {
|
|
60
|
+
await fs.access(dir, fs.constants.W_OK);
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
/* directory exists but not writable, or does not exist
|
|
64
|
+
inside a non-writable parent: require sudo */
|
|
65
|
+
try {
|
|
66
|
+
await fs.access(dir, fs.constants.F_OK);
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
/* directory does not exist: check parent writability */
|
|
71
|
+
try {
|
|
72
|
+
await fs.access(path.dirname(dir), fs.constants.W_OK);
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
/* build the (cmd, args) pair for an "npm" invocation, prefixing
|
|
83
|
+
with "sudo" when necessary for global operations */
|
|
84
|
+
async npmCmd(args, global) {
|
|
85
|
+
if (global && await this.npmGlobalNeedsSudo()) {
|
|
86
|
+
const sudo = await which("sudo").catch(() => "");
|
|
87
|
+
if (sudo !== "") {
|
|
88
|
+
this.log.write("info", "setup: npm global install root not writable: using \"sudo\"");
|
|
89
|
+
return { cmd: "sudo", args: ["npm", ...args] };
|
|
90
|
+
}
|
|
91
|
+
this.log.write("warning", "setup: npm global install root is not writable by current user " +
|
|
92
|
+
"and \"sudo\" not found in $PATH: attempting without elevation");
|
|
93
|
+
}
|
|
94
|
+
return { cmd: "npm", args };
|
|
95
|
+
}
|
|
27
96
|
/* run a sub-process, suppressing output on success and emitting it on failure */
|
|
28
97
|
async run(cmd, args, opts = {}) {
|
|
29
98
|
const { cwd, quiet = false, retries = 1, ignoreError } = opts;
|
|
@@ -118,7 +187,8 @@ export default class SetupCommand {
|
|
|
118
187
|
}
|
|
119
188
|
/* update ASE CLI tool */
|
|
120
189
|
this.log.write("info", `setup: update: updating ASE CLI tool: ${current} -> ${latest}`);
|
|
121
|
-
await this.
|
|
190
|
+
const updateCmd = await this.npmCmd(["update", "-g", "@rse/ase"], true);
|
|
191
|
+
await this.run(updateCmd.cmd, updateCmd.args);
|
|
122
192
|
/* update ASE plugin */
|
|
123
193
|
this.log.write("info", `setup: update: updating ASE ${spec.label} plugin`);
|
|
124
194
|
await this.run(spec.cli, ["plugin", "marketplace", "update", "ase"]);
|
|
@@ -165,7 +235,8 @@ export default class SetupCommand {
|
|
|
165
235
|
/* uninstall ASE CLI tool (non-development only) */
|
|
166
236
|
if (!dev) {
|
|
167
237
|
this.log.write("info", "setup: uninstall: uninstalling ASE CLI tool (origin: remote)");
|
|
168
|
-
await this.
|
|
238
|
+
const uninstallCmd = await this.npmCmd(["uninstall", "-g", "@rse/ase"], true);
|
|
239
|
+
await this.run(uninstallCmd.cmd, uninstallCmd.args);
|
|
169
240
|
}
|
|
170
241
|
return 0;
|
|
171
242
|
}
|
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.0.
|
|
9
|
+
"version": "0.0.38",
|
|
10
10
|
"license": "GPL-3.0-only",
|
|
11
11
|
"author": {
|
|
12
12
|
"name": "Dr. Ralf S. Engelschall",
|
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.0.
|
|
9
|
+
"version": "0.0.38",
|
|
10
10
|
"license": "GPL-3.0-only",
|
|
11
11
|
"author": {
|
|
12
12
|
"name": "Dr. Ralf S. Engelschall",
|
|
@@ -84,19 +84,30 @@ permitted way to persist artifacts is via `task_save(...)`.
|
|
|
84
84
|
|
|
85
85
|
Then set <feature/> to the response of the user.
|
|
86
86
|
|
|
87
|
-
4.
|
|
87
|
+
4. <if condition="
|
|
88
|
+
<ase-task-id/> is equal `default` and
|
|
89
|
+
<feature/> is not empty
|
|
90
|
+
">
|
|
91
|
+
Set <ase-task-id/> to a unique task id, derived from <feature/>,
|
|
92
|
+
which consists of two lower-case words concatenated with a
|
|
93
|
+
`-` character. Then call the `task_id(id: <ase-task-id/>,
|
|
94
|
+
session: <ase-session-id/>)` tool from the `ase` MCP service to
|
|
95
|
+
implicitly switch the task.
|
|
96
|
+
</if>
|
|
97
|
+
|
|
98
|
+
5. Report the task and feature with the following <template/>:
|
|
88
99
|
|
|
89
100
|
<template>
|
|
90
101
|
⧉ **ASE**: ◉ task: **<ase-task-id/>**
|
|
91
102
|
⧉ **ASE**: ⇌ feature: **<feature/>**
|
|
92
103
|
</template>
|
|
93
104
|
|
|
94
|
-
|
|
105
|
+
6. Figure out what the requested <feature/> to be crafted is about.
|
|
95
106
|
|
|
96
|
-
|
|
107
|
+
7. Ask the user for clarification if the goal of this crafting is too
|
|
97
108
|
unclear.
|
|
98
109
|
|
|
99
|
-
|
|
110
|
+
8. Do not output anything in this step, except you asked the user.
|
|
100
111
|
|
|
101
112
|
2. **Investigate Code Base**:
|
|
102
113
|
|
|
@@ -84,19 +84,30 @@ permitted way to persist artifacts is via `task_save(...)`.
|
|
|
84
84
|
|
|
85
85
|
Then set <request/> to the response of the user.
|
|
86
86
|
|
|
87
|
-
4.
|
|
87
|
+
4. <if condition="
|
|
88
|
+
<ase-task-id/> is equal `default` and
|
|
89
|
+
<request/> is not empty
|
|
90
|
+
">
|
|
91
|
+
Set <ase-task-id/> to a unique task id, derived from <request/>,
|
|
92
|
+
which consists of two lower-case words concatenated with a
|
|
93
|
+
`-` character. Then call the `task_id(id: <ase-task-id/>,
|
|
94
|
+
session: <ase-session-id/>)` tool from the `ase` MCP service to
|
|
95
|
+
implicitly switch the task.
|
|
96
|
+
</if>
|
|
97
|
+
|
|
98
|
+
5. Report the task and request with the following <template/>:
|
|
88
99
|
|
|
89
100
|
<template>
|
|
90
101
|
⧉ **ASE**: ◉ task: **<ase-task-id/>**
|
|
91
102
|
⧉ **ASE**: ⇌ request: **<request/>**
|
|
92
103
|
</template>
|
|
93
104
|
|
|
94
|
-
|
|
105
|
+
6. Figure out what the artifact refactoring <request/> is about.
|
|
95
106
|
|
|
96
|
-
|
|
107
|
+
7. Ask the user for clarification if the goal of this refactoring is
|
|
97
108
|
too unclear.
|
|
98
109
|
|
|
99
|
-
|
|
110
|
+
8. Do not output anything in this step, except you asked the user.
|
|
100
111
|
|
|
101
112
|
2. **Investigate Code Base**:
|
|
102
113
|
|
|
@@ -56,12 +56,13 @@ permitted way to persist artifacts is via `task_save(...)`.
|
|
|
56
56
|
1. **Reason About Problem**:
|
|
57
57
|
|
|
58
58
|
1. If <problem/> matches the regexp `^[PT]\d+$` (i.e. a bare issue
|
|
59
|
-
identifier like `P1`, `P2`, `T1`, `T2`, ...),
|
|
60
|
-
<problem-id><problem/></problem-id
|
|
61
|
-
<ase-task-id
|
|
62
|
-
|
|
63
|
-
`
|
|
64
|
-
|
|
59
|
+
identifier like `P1`, `P2`, `T1`, `T2`, ...),
|
|
60
|
+
set <problem-id><problem/></problem-id> and
|
|
61
|
+
<ase-task-id><problem/></ase-task-id>, call the `task_id(id:
|
|
62
|
+
<ase-task-id/>, session: <ase-session-id/>)` tool from the
|
|
63
|
+
`ase` MCP service to implicitly switch the task, and then
|
|
64
|
+
call the `kv_get(key: "ase-issue-<problem-id/>")` tool of
|
|
65
|
+
the `ase` MCP service to retrieve the previously persisted
|
|
65
66
|
problem description. If the returned `text` is non-empty, set
|
|
66
67
|
<problem><text/></problem>, otherwise complain to the user that
|
|
67
68
|
no analyzer result exists for <problem-id/> and stop processing.
|
|
@@ -95,21 +96,32 @@ permitted way to persist artifacts is via `task_save(...)`.
|
|
|
95
96
|
|
|
96
97
|
Then set <problem/> to the response of the user.
|
|
97
98
|
|
|
98
|
-
5.
|
|
99
|
+
5. <if condition="
|
|
100
|
+
<ase-task-id/> is equal `default` and
|
|
101
|
+
<problem/> is not empty
|
|
102
|
+
">
|
|
103
|
+
Set <ase-task-id/> to a unique task id, derived from <problem/>,
|
|
104
|
+
which consists of two lower-case words concatenated with a
|
|
105
|
+
`-` character. Then call the `task_id(id: <ase-task-id/>,
|
|
106
|
+
session: <ase-session-id/>)` tool from the `ase` MCP service to
|
|
107
|
+
implicitly switch the task.
|
|
108
|
+
</if>
|
|
109
|
+
|
|
110
|
+
6. Report the task and problem with the following <template/>:
|
|
99
111
|
|
|
100
112
|
<template>
|
|
101
113
|
⧉ **ASE**: ◉ task: **<ase-task-id/>**
|
|
102
114
|
⧉ **ASE**: ⇌ problem: **<problem/>**
|
|
103
115
|
</template>
|
|
104
116
|
|
|
105
|
-
|
|
117
|
+
7. Figure out what the requested <problem/> is about.
|
|
106
118
|
|
|
107
|
-
|
|
119
|
+
8. Ask the user for clarification if the goal of this resolution is
|
|
108
120
|
too unclear.
|
|
109
121
|
|
|
110
|
-
|
|
122
|
+
9. Do not output anything in this step, except you asked the user.
|
|
111
123
|
|
|
112
|
-
|
|
124
|
+
10. Investigate and *figure out details* related to this problem.
|
|
113
125
|
Report those details with the following <template/>:
|
|
114
126
|
|
|
115
127
|
<template>
|
|
@@ -21,8 +21,10 @@ Evaluate Alternatives
|
|
|
21
21
|
Evaluate Alternatives
|
|
22
22
|
</skill>
|
|
23
23
|
|
|
24
|
+
<role>
|
|
24
25
|
Your role is an experienced, *expert-level assistant*,
|
|
25
26
|
specialized in *evaluating alternatives*.
|
|
27
|
+
</role>
|
|
26
28
|
|
|
27
29
|
<objective>
|
|
28
30
|
*Evaluate* *alternatives* through a weighted
|
|
@@ -73,10 +75,11 @@ multi-*criteria* decision matrix.
|
|
|
73
75
|
over) is its single most distinguishing perspective, and remember
|
|
74
76
|
this as an <info-K/> (K=1-N) formatted like `<type/>: <hint/>` where
|
|
75
77
|
<type/> is one of `USP`, `Crux`, or `Gotcha` and <hint/> is a 1-6
|
|
76
|
-
word hint.
|
|
78
|
+
word hint. Do not output anything.
|
|
77
79
|
|
|
78
80
|
- For the set of alternatives, decide what the 1-6 word long
|
|
79
81
|
name of the *class of alternatives* <class-of-alternatives/> is.
|
|
82
|
+
Do not output anything.
|
|
80
83
|
|
|
81
84
|
- For each alternative <alternative-K/> (K=1-N), decide whether
|
|
82
85
|
it is a genuine member of <class-of-alternatives/>. If any
|
|
@@ -178,16 +181,16 @@ multi-*criteria* decision matrix.
|
|
|
178
181
|
- The best alternative <alternative-K/> (K=1-N) is the alternative
|
|
179
182
|
whose *raw, unrounded* <rating-K/> (i.e. the product-sum from STEP
|
|
180
183
|
4, *before* the display-only rounding) is the maximum rating value
|
|
181
|
-
across all alternatives.
|
|
184
|
+
across all alternatives. Do not output anything.
|
|
182
185
|
|
|
183
186
|
- The second best alternative <alternative-X/> (X=1-N, X != K) is
|
|
184
187
|
the alternative whose *raw, unrounded* <rating-X/> is the second
|
|
185
|
-
largest rating value across all alternatives.
|
|
188
|
+
largest rating value across all alternatives. Do not output anything.
|
|
186
189
|
|
|
187
190
|
- If multiple alternatives share the second-largest raw rating, pick
|
|
188
191
|
any one of them as <alternative-X/>; the resulting <distance/> and
|
|
189
192
|
<percentage/> are unaffected by the choice, so the downstream output
|
|
190
|
-
is deterministic.
|
|
193
|
+
is deterministic. Do not output anything.
|
|
191
194
|
|
|
192
195
|
- Determine rating distance <distance/> between <alternative-K/> and
|
|
193
196
|
<alternative-X/> from their *raw, unrounded* ratings by calculating:
|
|
@@ -203,6 +206,7 @@ multi-*criteria* decision matrix.
|
|
|
203
206
|
(so a true zero tie with <distance/> = 0 falls into the
|
|
204
207
|
*MULTIPLE BEST* branch below, and a non-zero gap with zero
|
|
205
208
|
best falls into the *small distance* branch below).
|
|
209
|
+
Do not output anything.
|
|
206
210
|
|
|
207
211
|
- By construction, <rating-K/> is the maximum rating across
|
|
208
212
|
all alternatives, so <distance/> >= 0 always holds; using
|
|
@@ -210,7 +214,7 @@ multi-*criteria* decision matrix.
|
|
|
210
214
|
regimes. Note that when <rating-K/> itself is negative, the
|
|
211
215
|
denominator anchors to a poor best rating and small gaps can
|
|
212
216
|
appear large; the all-negative regime is surfaced as a dedicated
|
|
213
|
-
warning branch below.
|
|
217
|
+
warning branch below. Do not output anything.
|
|
214
218
|
|
|
215
219
|
- If <percentage/> is less than 0.01 (i.e. <distance/> is
|
|
216
220
|
effectively zero relative to abs(<rating-K/>)), stop the flow after
|