@rse/ase 0.9.56 → 0.9.58
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-config.js +72 -31
- package/dst/ase-getopt.js +3 -1
- package/dst/ase-hook.js +5 -3
- package/dst/ase-markdown.js +7 -4
- package/dst/ase-service.js +3 -1
- package/dst/ase-sleep.js +26 -0
- package/dst/ase-task.js +1 -0
- 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/meta/ase-common-code.md +4 -0
- package/plugin/meta/ase-common-task.md +17 -0
- package/plugin/meta/ase-constitution.md +4 -0
- package/plugin/meta/ase-control.md +21 -0
- package/plugin/meta/ase-format-arch.md +0 -14
- package/plugin/meta/ase-format-meta.md +15 -2
- package/plugin/meta/ase-format-spec.md +0 -14
- package/plugin/meta/ase-skill.md +3 -1
- package/plugin/package.json +1 -1
- package/plugin/skills/ase-arch-analyze/SKILL.md +1 -1
- package/plugin/skills/ase-arch-discover/SKILL.md +1 -1
- package/plugin/skills/ase-code-craft/SKILL.md +44 -4
- package/plugin/skills/ase-code-craft/help.md +15 -4
- package/plugin/skills/ase-code-refactor/SKILL.md +44 -4
- package/plugin/skills/ase-code-refactor/help.md +15 -4
- package/plugin/skills/ase-code-resolve/SKILL.md +55 -19
- package/plugin/skills/ase-code-resolve/help.md +15 -4
- package/plugin/skills/ase-meta-changelog/SKILL.md +1 -0
- package/plugin/skills/ase-meta-chat/SKILL.md +9 -0
- package/plugin/skills/ase-meta-config/help.md +2 -1
- package/plugin/skills/ase-task-preflight/SKILL.md +4 -26
- package/plugin/skills/ase-task-reboot/SKILL.md +6 -39
package/dst/ase-config.js
CHANGED
|
@@ -124,27 +124,33 @@ const gitToplevel = () => {
|
|
|
124
124
|
gitToplevelCache.set(cwd, top);
|
|
125
125
|
return top === "" ? null : top;
|
|
126
126
|
};
|
|
127
|
-
/*
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
127
|
+
/* determine the project root directory, i.e. either the top-level
|
|
128
|
+
directory of the Git working tree or the nearest directory at or
|
|
129
|
+
above cwd which carries a ".ase" directory */
|
|
130
|
+
const projectRoot = () => {
|
|
131
|
+
const top = gitToplevel();
|
|
132
|
+
if (top !== null)
|
|
133
|
+
return top;
|
|
132
134
|
let dir = fs.realpathSync(process.cwd());
|
|
133
135
|
for (;;) {
|
|
134
136
|
if (fs.existsSync(path.join(dir, ".ase")))
|
|
135
|
-
return
|
|
137
|
+
return dir;
|
|
136
138
|
const parent = path.dirname(dir);
|
|
137
139
|
if (parent === dir)
|
|
138
|
-
return
|
|
140
|
+
return null;
|
|
139
141
|
dir = parent;
|
|
140
142
|
}
|
|
141
143
|
};
|
|
144
|
+
/* detect whether a project context exists, i.e. either we are inside
|
|
145
|
+
a Git working tree or a ".ase" directory is present at or above cwd */
|
|
146
|
+
const hasProjectContext = () => projectRoot() !== null;
|
|
142
147
|
/* parse a raw "--scope" option value into a canonical Scope chain;
|
|
143
148
|
accepts a comma-separated list of terms in any order. The "user"
|
|
144
149
|
term is always implicitly added at the bottom of the chain; the
|
|
145
150
|
"project" term is implicitly added only when a project context
|
|
146
|
-
exists (Git repository or ".ase" directory at or above cwd)
|
|
147
|
-
|
|
151
|
+
exists (Git repository or ".ase" directory at or above cwd) and it
|
|
152
|
+
stays weaker than the strongest explicitly requested term, and an
|
|
153
|
+
explicit "project" term requires that same context */
|
|
148
154
|
export const parseScope = (value) => {
|
|
149
155
|
const projectActive = hasProjectContext();
|
|
150
156
|
const input = (value === undefined || value === "") ?
|
|
@@ -162,7 +168,11 @@ export const parseScope = (value) => {
|
|
|
162
168
|
if (seen.has("project") && !projectActive)
|
|
163
169
|
throw new Error("invalid --scope: \"project\" requires a project context " +
|
|
164
170
|
"(a Git repository or a \".ase\" directory at or above the current directory)");
|
|
165
|
-
|
|
171
|
+
/* the strongest term of the chain is the write target, so an implicitly
|
|
172
|
+
added "project" term must never outrank the strongest explicitly
|
|
173
|
+
requested term, as this would silently retarget the caller's request */
|
|
174
|
+
const rankMax = Math.max(...terms.map((t) => scopeRank(t.kind)));
|
|
175
|
+
if (!seen.has("project") && projectActive && rankMax > scopeRank("project"))
|
|
166
176
|
terms.unshift({ kind: "project" });
|
|
167
177
|
if (!seen.has("user"))
|
|
168
178
|
terms.unshift({ kind: "user" });
|
|
@@ -210,6 +220,7 @@ export class Config {
|
|
|
210
220
|
log;
|
|
211
221
|
docs;
|
|
212
222
|
target;
|
|
223
|
+
pruned;
|
|
213
224
|
/* creation */
|
|
214
225
|
constructor(name, schema, log, scope = [{ kind: "user" }, { kind: "project" }]) {
|
|
215
226
|
if (scope.length === 0)
|
|
@@ -222,6 +233,7 @@ export class Config {
|
|
|
222
233
|
this.filename = this.resolveFilename(name, tgt);
|
|
223
234
|
this.docs = [{ scope: tgt, filename: this.filename, doc: new Document() }];
|
|
224
235
|
this.target = 0;
|
|
236
|
+
this.pruned = [];
|
|
225
237
|
}
|
|
226
238
|
/* render a scope term as a short textual label */
|
|
227
239
|
static scopeLabel(term) {
|
|
@@ -252,16 +264,13 @@ export class Config {
|
|
|
252
264
|
return path.join(this.userConfigDir(), `${name}.yaml`);
|
|
253
265
|
else if (term.kind === "project") {
|
|
254
266
|
const rel = path.join(".ase", `${name}.yaml`);
|
|
255
|
-
const
|
|
256
|
-
const
|
|
257
|
-
|
|
258
|
-
this.findUpward(cwd, top, rel) :
|
|
259
|
-
(fs.existsSync(path.join(cwd, rel)) ? path.join(cwd, rel) : null);
|
|
260
|
-
return found ?? path.join(top ?? cwd, rel);
|
|
267
|
+
const root = projectRoot() ?? process.cwd();
|
|
268
|
+
const found = this.findUpward(process.cwd(), root, rel);
|
|
269
|
+
return found ?? path.join(root, rel);
|
|
261
270
|
}
|
|
262
271
|
else if (term.kind === "task") {
|
|
263
|
-
const
|
|
264
|
-
return path.join(
|
|
272
|
+
const root = projectRoot() ?? process.cwd();
|
|
273
|
+
return path.join(root, ".ase", "task", term.id, `${name}.yaml`);
|
|
265
274
|
}
|
|
266
275
|
else
|
|
267
276
|
return path.join(os.homedir(), ".ase", "session", term.id, `${name}.yaml`);
|
|
@@ -290,6 +299,7 @@ export class Config {
|
|
|
290
299
|
read(mode = "lenient") {
|
|
291
300
|
const chain = this.scope;
|
|
292
301
|
const docs = [];
|
|
302
|
+
this.pruned = [];
|
|
293
303
|
for (let i = 0; i < chain.length; i++) {
|
|
294
304
|
const sc = chain[i];
|
|
295
305
|
if (sc.kind === "default") {
|
|
@@ -321,6 +331,8 @@ export class Config {
|
|
|
321
331
|
if (perDocMode === "strict")
|
|
322
332
|
throw new Error(msg);
|
|
323
333
|
this.log.write("warning", msg);
|
|
334
|
+
if (isTarget)
|
|
335
|
+
this.pruned.push(`unparsable YAML (${doc.errors[0].message.split("\n")[0]})`);
|
|
324
336
|
doc = new Document();
|
|
325
337
|
}
|
|
326
338
|
docs.push({ scope: sc, filename, doc });
|
|
@@ -330,7 +342,9 @@ export class Config {
|
|
|
330
342
|
for (let i = 0; i < docs.length; i++) {
|
|
331
343
|
const isTarget = (i === this.target);
|
|
332
344
|
const perDocMode = isTarget ? mode : "lenient";
|
|
333
|
-
this.validateDoc(docs[i].doc, docs[i].filename, perDocMode);
|
|
345
|
+
const removed = this.validateDoc(docs[i].doc, docs[i].filename, perDocMode);
|
|
346
|
+
if (isTarget)
|
|
347
|
+
this.pruned.push(...removed);
|
|
334
348
|
}
|
|
335
349
|
}
|
|
336
350
|
/* acquire a cross-process advisory lock on the target scope's file,
|
|
@@ -355,18 +369,28 @@ export class Config {
|
|
|
355
369
|
const td = this.docs[this.target];
|
|
356
370
|
if (td.scope.kind === "default")
|
|
357
371
|
throw new Error("internal error: \"default\" scope is not writable");
|
|
372
|
+
/* a lenient read physically removes the invalid content from the in-memory
|
|
373
|
+
target document, so writing that document back would silently erase the
|
|
374
|
+
very same content from the file on disk */
|
|
375
|
+
if (this.pruned.length > 0)
|
|
376
|
+
throw new Error(`refusing to overwrite ${td.filename}: it carries invalid content ` +
|
|
377
|
+
`(${this.pruned.join(", ")}) which was skipped on reading and hence would be ` +
|
|
378
|
+
"lost on writing -- repair the file first");
|
|
358
379
|
this.validateDoc(td.doc, td.filename, "strict");
|
|
359
380
|
fs.mkdirSync(path.dirname(td.filename), { recursive: true });
|
|
360
381
|
writeFileAtomic.sync(td.filename, td.doc.toString({ indent: 4 }), { encoding: "utf8" });
|
|
361
382
|
}
|
|
362
|
-
/* validate a single YAML document against the optional schema
|
|
383
|
+
/* validate a single YAML document against the optional schema; in "strict"
|
|
384
|
+
mode all invalid entries are reported as a thrown error, in "lenient" mode
|
|
385
|
+
they are removed from the document and their dotted paths are returned */
|
|
363
386
|
validateDoc(doc, filename, mode = "strict") {
|
|
364
387
|
if (this.schema === null)
|
|
365
|
-
return;
|
|
388
|
+
return [];
|
|
389
|
+
const removed = [];
|
|
366
390
|
for (;;) {
|
|
367
391
|
const result = v.safeParse(this.schema, doc.toJS());
|
|
368
392
|
if (result.success)
|
|
369
|
-
return;
|
|
393
|
+
return removed;
|
|
370
394
|
if (mode === "strict") {
|
|
371
395
|
const issues = result.issues.map((i) => {
|
|
372
396
|
const dotPath = (i.path ?? []).map((p) => String(p.key)).join(".");
|
|
@@ -374,19 +398,20 @@ export class Config {
|
|
|
374
398
|
}).join("; ");
|
|
375
399
|
throw new Error(`invalid configuration in ${filename}: ${issues}`);
|
|
376
400
|
}
|
|
377
|
-
|
|
401
|
+
const before = removed.length;
|
|
378
402
|
for (const i of result.issues) {
|
|
379
403
|
const segs = (i.path ?? []).map((p) => String(p.key));
|
|
380
404
|
const dotPath = segs.join(".");
|
|
381
405
|
this.log.write("warning", `invalid entry in ${filename}: ${dotPath ? `${dotPath}: ` : ""}${i.message}`);
|
|
382
|
-
if (segs.length > 0)
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
406
|
+
if (segs.length > 0 && doc.deleteIn(segs))
|
|
407
|
+
removed.push(dotPath);
|
|
408
|
+
/* issues at the document root and issues whose stringified path does not
|
|
409
|
+
address a deletable node (e.g. a non-string YAML key like "404:", which
|
|
410
|
+
"toJS" stringifies) cannot be removed; processing continues with the
|
|
411
|
+
remaining issues */
|
|
387
412
|
}
|
|
388
|
-
if (
|
|
389
|
-
return;
|
|
413
|
+
if (removed.length === before)
|
|
414
|
+
return removed;
|
|
390
415
|
}
|
|
391
416
|
}
|
|
392
417
|
/* enumerate all full dotted leaf paths from the attached valibot schema */
|
|
@@ -444,6 +469,21 @@ export class Config {
|
|
|
444
469
|
}
|
|
445
470
|
return undefined;
|
|
446
471
|
}
|
|
472
|
+
/* retrieve the explicitly configured value at a dotted key, i.e. the same
|
|
473
|
+
cascade as "get", but skipping the built-in "default" scope layer, so
|
|
474
|
+
callers can distinguish a deliberately configured value from a merely
|
|
475
|
+
preset one */
|
|
476
|
+
getExplicit(key) {
|
|
477
|
+
const segs = this.resolveKey(key).split(".");
|
|
478
|
+
for (let i = this.docs.length - 1; i >= 0; i--) {
|
|
479
|
+
if (this.docs[i].scope.kind === "default")
|
|
480
|
+
continue;
|
|
481
|
+
const node = this.docs[i].doc.getIn(segs);
|
|
482
|
+
if (node !== undefined)
|
|
483
|
+
return node;
|
|
484
|
+
}
|
|
485
|
+
return undefined;
|
|
486
|
+
}
|
|
447
487
|
/* enumerate the effective leaf entries across the full scope chain;
|
|
448
488
|
each returned entry identifies the originating scope */
|
|
449
489
|
entries() {
|
|
@@ -551,7 +591,8 @@ export default class ConfigCommand {
|
|
|
551
591
|
.option("--scope <scope>", "configuration scope chain: comma-separated list of \"user\", \"project\", " +
|
|
552
592
|
"\"task:<id>\", and/or \"session:<id>\" terms (e.g. \"task:N,session:M\"); " +
|
|
553
593
|
"\"user\" is always implicitly included and \"project\" is implicitly " +
|
|
554
|
-
"included whenever a project context (Git repo or upward \".ase\" directory) exists"
|
|
594
|
+
"included whenever a project context (Git repo or upward \".ase\" directory) exists, " +
|
|
595
|
+
"but never above the strongest explicitly requested term")
|
|
555
596
|
.description("manage ASE configuration")
|
|
556
597
|
.action(() => {
|
|
557
598
|
configCmd.outputHelp();
|
package/dst/ase-getopt.js
CHANGED
|
@@ -7,7 +7,7 @@ import { z } from "zod";
|
|
|
7
7
|
import { Command, Option } from "commander";
|
|
8
8
|
import { parse as shParse, quote as shQuote } from "shell-quote";
|
|
9
9
|
/* tokenize a raw input string into [start,end) token ranges, preserving
|
|
10
|
-
the quoting so the original text can later be sliced verbatim */
|
|
10
|
+
the quoting and escaping so the original text can later be sliced verbatim */
|
|
11
11
|
const tokenizeRanges = (input) => {
|
|
12
12
|
const ranges = [];
|
|
13
13
|
let i = 0;
|
|
@@ -30,6 +30,8 @@ const tokenizeRanges = (input) => {
|
|
|
30
30
|
if (i < input.length)
|
|
31
31
|
i++;
|
|
32
32
|
}
|
|
33
|
+
else if (ch === "\\" && i + 1 < input.length)
|
|
34
|
+
i += 2;
|
|
33
35
|
else
|
|
34
36
|
i++;
|
|
35
37
|
}
|
package/dst/ase-hook.js
CHANGED
|
@@ -240,10 +240,12 @@ export default class HookCommand {
|
|
|
240
240
|
const projectId = path.basename(projectDir);
|
|
241
241
|
/* determine user id */
|
|
242
242
|
const userId = process.env.USER ?? process.env.LOGNAME ?? "unknown";
|
|
243
|
-
/* helper function: determine a setting from the
|
|
244
|
-
falling back to an environment variable and a default
|
|
243
|
+
/* helper function: determine a setting from the explicitly configured
|
|
244
|
+
scopes, falling back to an environment variable and a default; the
|
|
245
|
+
built-in "default" scope layer is deliberately skipped, as its preset
|
|
246
|
+
value is always present and would hence shadow the environment variable */
|
|
245
247
|
const setting = (key, envVar, dflt) => {
|
|
246
|
-
const val = cfg.
|
|
248
|
+
const val = cfg.getExplicit(key);
|
|
247
249
|
return typeof val === "string" ? val : (process.env[envVar] ?? dflt);
|
|
248
250
|
};
|
|
249
251
|
/* determine agent persona style, agent guidance level, and project boxing transparency */
|
package/dst/ase-markdown.js
CHANGED
|
@@ -19,9 +19,12 @@ export class Markdown {
|
|
|
19
19
|
/* segment the input line-wise into alternating non-fenced and
|
|
20
20
|
fenced regions: a fenced code block opens with a line whose first
|
|
21
21
|
non-whitespace content is a run of 3+ backticks or tildes and
|
|
22
|
-
closes with a matching-or-longer run of the same marker;
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
closes with a matching-or-longer run of the same marker; for a
|
|
23
|
+
backtick fence the info string trailing the run must not carry any
|
|
24
|
+
further backtick, so an inline code span delimited by a run of 3+
|
|
25
|
+
backticks never opens a fence; fenced regions are emitted verbatim
|
|
26
|
+
while only non-fenced regions are handed to the rewriting passes
|
|
27
|
+
below */
|
|
25
28
|
const lines = text.split("\n");
|
|
26
29
|
let result = "";
|
|
27
30
|
let buf = "";
|
|
@@ -37,7 +40,7 @@ export class Markdown {
|
|
|
37
40
|
for (let li = 0; li < lines.length; li++) {
|
|
38
41
|
const line = lines[li];
|
|
39
42
|
const nl = li < lines.length - 1 ? "\n" : "";
|
|
40
|
-
const m = line.match(/^\s*(`{3,}|~{3,})/);
|
|
43
|
+
const m = line.match(/^\s*(`{3,}(?![^`]*`)|~{3,})/);
|
|
41
44
|
if (!inFence && m) {
|
|
42
45
|
/* a fence-opening line: flush the pending non-fenced buffer,
|
|
43
46
|
enter fenced mode, and emit the opener verbatim */
|
package/dst/ase-service.js
CHANGED
|
@@ -24,6 +24,7 @@ import { MarkdownMCP } from "./ase-markdown.js";
|
|
|
24
24
|
import { ArtifactMCP } from "./ase-artifact.js";
|
|
25
25
|
import { KVMCP } from "./ase-kv.js";
|
|
26
26
|
import { TimestampMCP } from "./ase-timestamp.js";
|
|
27
|
+
import { SleepMCP } from "./ase-sleep.js";
|
|
27
28
|
import { GetoptMCP } from "./ase-getopt.js";
|
|
28
29
|
import { SkillsMCP } from "./ase-skills.js";
|
|
29
30
|
import pkg from "../package.json" with { type: "json" };
|
|
@@ -268,6 +269,7 @@ export default class ServiceCommand {
|
|
|
268
269
|
new ArtifactMCP(this.log).register(mcp);
|
|
269
270
|
new KVMCP().register(mcp);
|
|
270
271
|
new TimestampMCP().register(mcp);
|
|
272
|
+
new SleepMCP().register(mcp);
|
|
271
273
|
new GetoptMCP().register(mcp);
|
|
272
274
|
new SkillsMCP().register(mcp);
|
|
273
275
|
new ConfigMCP(this.log).register(mcp);
|
|
@@ -439,7 +441,7 @@ export default class ServiceCommand {
|
|
|
439
441
|
return await new Promise(() => { });
|
|
440
442
|
}
|
|
441
443
|
if (port !== null) {
|
|
442
|
-
const match = await probe(port, ctx.projectId);
|
|
444
|
+
const match = await probe(port, ctx.projectId).catch(() => null);
|
|
443
445
|
if (match === true) {
|
|
444
446
|
this.log.write("info", `service: already running on port ${port}`);
|
|
445
447
|
return 0;
|
package/dst/ase-sleep.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/*
|
|
2
|
+
** Agentic Software Engineering (ASE)
|
|
3
|
+
** Copyright (c) 2025-2026 Dr. Ralf S. Engelschall <rse@engelschall.com>
|
|
4
|
+
** Licensed under Apache 2.0 <https://spdx.org/licenses/Apache-2.0>
|
|
5
|
+
*/
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
/* MCP registration entry point for sleep tool */
|
|
8
|
+
export class SleepMCP {
|
|
9
|
+
register(mcp) {
|
|
10
|
+
mcp.registerTool("ase_sleep", {
|
|
11
|
+
title: "ASE sleep",
|
|
12
|
+
description: "Wait once for `duration` seconds and then return. " +
|
|
13
|
+
"The duration can be fractional (e.g. `1.5`). " +
|
|
14
|
+
"Returns `OK: slept <duration> seconds` as `text` after the duration elapsed.",
|
|
15
|
+
inputSchema: {
|
|
16
|
+
duration: z.number().positive().max(3600)
|
|
17
|
+
.describe("wait duration in seconds (fractional values allowed, at most 3600)")
|
|
18
|
+
}
|
|
19
|
+
}, async (args) => {
|
|
20
|
+
await new Promise((resolve) => setTimeout(resolve, args.duration * 1000));
|
|
21
|
+
return {
|
|
22
|
+
content: [{ type: "text", text: `OK: slept ${args.duration} seconds` }]
|
|
23
|
+
};
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
}
|
package/dst/ase-task.js
CHANGED
|
@@ -334,6 +334,7 @@ export class Task {
|
|
|
334
334
|
/* set the active task id for a given session */
|
|
335
335
|
static setId(log, session, id) {
|
|
336
336
|
Task.validateSession(session);
|
|
337
|
+
Task.validateId(id);
|
|
337
338
|
const scope = parseScope(`session:${session}`);
|
|
338
339
|
const cfg = new Config("config", configSchema, log, scope);
|
|
339
340
|
cfg.lock(() => {
|
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.58",
|
|
10
10
|
"license": "Apache-2.0",
|
|
11
11
|
"author": {
|
|
12
12
|
"name": "Dr. Ralf S. Engelschall",
|
|
@@ -194,4 +194,8 @@ Set <args>--int-reuse-task</args>.
|
|
|
194
194
|
Then call the tool `Skill(skill: "ase:ase-task-edit", args: "<args/>")`.
|
|
195
195
|
</else>
|
|
196
196
|
|
|
197
|
+
6. In every branch above which invoked the `Skill` tool, you *MUST*
|
|
198
|
+
immediately stop processing the current skill once the `Skill`
|
|
199
|
+
tool was used.
|
|
200
|
+
|
|
197
201
|
</define>
|
|
@@ -156,3 +156,20 @@ related to this MCP call except the following <template/>:
|
|
|
156
156
|
</expand>
|
|
157
157
|
|
|
158
158
|
</define>
|
|
159
|
+
|
|
160
|
+
<define name="task-next-handoff">
|
|
161
|
+
|
|
162
|
+
Set <args>--int-reuse-task</args>.
|
|
163
|
+
<if condition="<getopt-option-next/> is not equal `none`">
|
|
164
|
+
Set <args><args/> --next <getopt-option-next/></args>
|
|
165
|
+
</if>
|
|
166
|
+
Only output the following <template/> and then call the tool
|
|
167
|
+
`Skill(skill: "ase:<arg1/>", args: "<args/>")` to invoke the
|
|
168
|
+
`ase:<arg1/>` skill to continue with the updated plan. Immediately
|
|
169
|
+
stop processing the current skill once the `Skill` tool was used.
|
|
170
|
+
|
|
171
|
+
<template>
|
|
172
|
+
⧉ **ASE**: ◉ task: **<ase-task-id/>**, ✪ plan: **<words/>** words, ▶ status: **<arg2/>**
|
|
173
|
+
</template>
|
|
174
|
+
|
|
175
|
+
</define>
|
|
@@ -31,6 +31,10 @@ which boosts you to an expert-level Software Engineering AI agent.
|
|
|
31
31
|
- Place a *blank line before any comment line*,
|
|
32
32
|
but not when it is the first line of a block or an end-of-line comment.
|
|
33
33
|
- Keep code and comment *formatting exactly as in the existing code*.
|
|
34
|
+
- Keep comments *brief*: target *1-2 lines*, only as an exception use up to *4 lines*,
|
|
35
|
+
and only for *very complex algorithms* go up to at most *8 lines*.
|
|
36
|
+
If an existing comment is already at its limit and still has to be expanded,
|
|
37
|
+
first *compact* its wording before adding new content.
|
|
34
38
|
- Use *regular comments* `/* [...] */` instead of end-of-line comments `// [...]`.
|
|
35
39
|
- Use *two leading/trailing spaces within comments* as in `/* [...] */`.
|
|
36
40
|
- Always use *parentheses around arrow function parameters*, even for a single parameter.
|
|
@@ -95,6 +95,27 @@ 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
|
+
<sleep duration="<sleep-duration/>"/>:
|
|
100
|
+
|
|
101
|
+
This specifies a single *wait* of <sleep-duration/> seconds
|
|
102
|
+
(fractional values like `1.5` are allowed): call the
|
|
103
|
+
`ase_sleep(duration: <sleep-duration/>)` tool of the `ase` MCP
|
|
104
|
+
server, which returns once the duration has elapsed. This construct
|
|
105
|
+
is expanded into nothing. Do not output anything.
|
|
106
|
+
|
|
107
|
+
- *IMPORTANT*: You *MUST* honor the following control flow construct:
|
|
108
|
+
<await condition="<await-condition/>" [interval="<await-interval/>"]><await-body/></await>:
|
|
109
|
+
|
|
110
|
+
This specifies an <await-body/> whose execution *waits* until
|
|
111
|
+
<await-condition/> is met: if <await-condition/> is met, the
|
|
112
|
+
<await-body/> is executed once and the construct is finished. If
|
|
113
|
+
<await-condition/> is *not* met, wait for <await-interval/> seconds
|
|
114
|
+
(default: `60`) via the `ase_sleep(duration: <await-interval/>)`
|
|
115
|
+
tool of the `ase` MCP server and then *start over* by re-evaluating
|
|
116
|
+
<await-condition/>. This construct is expanded to its
|
|
117
|
+
<await-body/>. Do not output anything else.
|
|
118
|
+
|
|
98
119
|
- *IMPORTANT*: You *MUST* honor the following control flow construct:
|
|
99
120
|
<agent <attr/>="<value/>" [...]><agent-body/></agent>:
|
|
100
121
|
|
|
@@ -18,20 +18,6 @@ at `01`) according to the order of the **Artifact** list below, and with
|
|
|
18
18
|
Pascal-casing each word (upper-casing its first letter) and using `-`
|
|
19
19
|
characters instead of spaces (e.g. `Context-View`).
|
|
20
20
|
|
|
21
|
-
Each **Artifact** file *MUST* begin with a single blank line before its
|
|
22
|
-
`#` heading and end with a single blank line after its last content line
|
|
23
|
-
(followed by the trailing newline), mirroring the blank lines shown
|
|
24
|
-
inside the `<format>` blocks below.
|
|
25
|
-
|
|
26
|
-
Each **Artifact** contains two timestamps: the <timestamp-created/>
|
|
27
|
-
is the timestamp when this **Artifact** was created. The
|
|
28
|
-
<timestamp-modified/> is the timestamp when this **Artifact** was last
|
|
29
|
-
modified. Both use an ISO-style format value. The value of both can be
|
|
30
|
-
determined by a call to the `ase_timestamp(format: "yyyy-LL-dd HH:mm")`
|
|
31
|
-
tool of the `ase` MCP server, using the `text` field of its response.
|
|
32
|
-
Whenever an **Artifact** is updated, the <timestamp-modified/> *MUST* be
|
|
33
|
-
updated, too.
|
|
34
|
-
|
|
35
21
|
The **Artifact Set** **Architecture (ARCH)** consists of the following
|
|
36
22
|
distinct **Artifact**s (listed under their <artifact-name/> and their
|
|
37
23
|
<artifact-id/>):
|
|
@@ -51,8 +51,7 @@ Artifact Meta Information
|
|
|
51
51
|
name (for stable ordering) and is *not* part of the **Artifact**'s
|
|
52
52
|
or its **Aspect**s' identifiers.
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
blank line. All its lines should be kept below 140 characters,
|
|
54
|
+
All lines of an **Artifact** should be kept below 140 characters,
|
|
56
55
|
whenever possible by line-breaking with newlines after about 120
|
|
57
56
|
characters per line.
|
|
58
57
|
|
|
@@ -64,6 +63,20 @@ Artifact Meta Information
|
|
|
64
63
|
characters and in total not longer than 30 characters). An example
|
|
65
64
|
is `user-login`.
|
|
66
65
|
|
|
66
|
+
Each **Artifact** file *MUST* begin with a single blank line before its
|
|
67
|
+
`#` heading and end with a single blank line after its last content line
|
|
68
|
+
(followed by the trailing newline), mirroring the blank lines shown
|
|
69
|
+
inside the `<format>` blocks below.
|
|
70
|
+
|
|
71
|
+
Each **Artifact** contains two timestamps: the <timestamp-created/>
|
|
72
|
+
is the timestamp when this **Artifact** was created. The
|
|
73
|
+
<timestamp-modified/> is the timestamp when this **Artifact** was last
|
|
74
|
+
modified. Both use an ISO-style format value. The value of both can be
|
|
75
|
+
determined by a call to the `ase_timestamp(format: "yyyy-LL-dd HH:mm")`
|
|
76
|
+
tool of the `ase` MCP server, using the `text` field of its response.
|
|
77
|
+
Whenever an **Artifact** is updated, the <timestamp-modified/> *MUST* be
|
|
78
|
+
updated, too.
|
|
79
|
+
|
|
67
80
|
An **Artifact** *MAY* additionally declare an **Export** -- a derived,
|
|
68
81
|
ready-to-consume rendering of (part of) its content, materialized as a
|
|
69
82
|
*side-by-side* file next to the **Artifact** itself. An **Artifact**
|
|
@@ -18,20 +18,6 @@ at `01`) according to the order of the **Artifact** list below, and with
|
|
|
18
18
|
Pascal-casing each word (upper-casing its first letter) and using `-`
|
|
19
19
|
characters instead of spaces (e.g. `Customer-Journey`).
|
|
20
20
|
|
|
21
|
-
Each **Artifact** file *MUST* begin with a single blank line before its
|
|
22
|
-
`#` heading and end with a single blank line after its last content line
|
|
23
|
-
(followed by the trailing newline), mirroring the blank lines shown
|
|
24
|
-
inside the `<format>` blocks below.
|
|
25
|
-
|
|
26
|
-
Each **Artifact** contains two timestamps: the <timestamp-created/>
|
|
27
|
-
is the timestamp when this **Artifact** was created. The
|
|
28
|
-
<timestamp-modified/> is the timestamp when this **Artifact** was last
|
|
29
|
-
modified. Both use an ISO-style format value. The value of both can be
|
|
30
|
-
determined by a call to the `ase_timestamp(format: "yyyy-LL-dd HH:mm")`
|
|
31
|
-
tool of the `ase` MCP server, using the `text` field of its response.
|
|
32
|
-
Whenever an **Artifact** is updated, the <timestamp-modified/> *MUST* be
|
|
33
|
-
updated, too.
|
|
34
|
-
|
|
35
21
|
The **Artifact Set** **Specification (SPEC)** consists of the following
|
|
36
22
|
distinct **Artifact**s (listed under their <artifact-name/> and their
|
|
37
23
|
<artifact-id/>):
|
package/plugin/meta/ase-skill.md
CHANGED
|
@@ -292,8 +292,10 @@ Artifact Boxing Transparency
|
|
|
292
292
|
- Internals exposed: *none* (no diffs, no code, no per-artifact explanation)
|
|
293
293
|
|
|
294
294
|
- *IMPORTANT*: Precedence rule: a skill's *explicit* `black` branches
|
|
295
|
+
and a skill's *explicit* output suppression instructions
|
|
295
296
|
deterministically skip or suppress and *win* over the implicit decisions
|
|
296
|
-
above. Where no such branches exist, the decisions
|
|
297
|
+
above. Where no such branches or instructions exist, the decisions
|
|
298
|
+
above apply.
|
|
297
299
|
|
|
298
300
|
Guidance Hint Level
|
|
299
301
|
-------------------
|
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.58",
|
|
10
10
|
"license": "Apache-2.0",
|
|
11
11
|
"author": {
|
|
12
12
|
"name": "Dr. Ralf S. Engelschall",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: ase-arch-analyze
|
|
3
|
-
argument-hint: "[--help|-h] <source-reference>"
|
|
3
|
+
argument-hint: "[--help|-h] [--prefix|-P=<prefix>] <source-reference>"
|
|
4
4
|
description: Review software architecture, including package cohesion and inter-package coupling
|
|
5
5
|
user-invocable: true
|
|
6
6
|
disable-model-invocation: false
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: ase-code-craft
|
|
3
|
-
argument-hint: "[--help|-h] [--auto|-a] [--dry|-d] [--quick|-Q] [--next|-n <option>[,...]] [<task-id>:] <feature>"
|
|
3
|
+
argument-hint: "[--help|-h] [--auto|-a] [--dry|-d] [--direct|-D] [--quick|-Q] [--next|-n <option>[,...]] [<task-id>:] <feature>"
|
|
4
4
|
description: >
|
|
5
5
|
Craft Source Code:
|
|
6
6
|
Use when user wants to "create", "add", or "craft" a new feature from scratch.
|
|
@@ -10,6 +10,7 @@ effort: xhigh
|
|
|
10
10
|
allowed-tools:
|
|
11
11
|
- "Skill"
|
|
12
12
|
- "Agent"
|
|
13
|
+
- "Read"
|
|
13
14
|
---
|
|
14
15
|
|
|
15
16
|
@${CLAUDE_SKILL_DIR}/../../meta/ase-control.md
|
|
@@ -23,7 +24,7 @@ Craft Source Code
|
|
|
23
24
|
|
|
24
25
|
<expand name="getopt"
|
|
25
26
|
arg1="ase-code-craft"
|
|
26
|
-
arg2="--auto|-a --dry|-d --quick|-Q --next|-n=(none|DONE|EDIT|GRILL|PREFLIGHT|IMPLEMENT)...">
|
|
27
|
+
arg2="--auto|-a --dry|-d --direct|-D --quick|-Q --next|-n=(none|DONE|EDIT|GRILL|PREFLIGHT|IMPLEMENT)...">
|
|
27
28
|
$ARGUMENTS
|
|
28
29
|
</expand>
|
|
29
30
|
|
|
@@ -45,9 +46,18 @@ From scratch *craft* the following feature:
|
|
|
45
46
|
Procedure
|
|
46
47
|
---------
|
|
47
48
|
|
|
49
|
+
<if condition="<getopt-option-direct/> is not equal to 'true'">
|
|
48
50
|
You *MUST* *NOT* call `Edit`, `Write`, `NotebookEdit`, or any
|
|
49
51
|
filesystem-modifying tool during this entire skill. The *only*
|
|
50
52
|
permitted way to persist artifacts is via `ase_task_save(...)`.
|
|
53
|
+
</if>
|
|
54
|
+
<else>
|
|
55
|
+
The `--direct`/`-D` mode applies the crafting *in place*, so STEP 4
|
|
56
|
+
below *requires* `Edit` and `Write` to modify the affected artifacts.
|
|
57
|
+
Every modification *MUST* still stay restricted to the artifacts the
|
|
58
|
+
crafting actually demands, and you *MUST* *NOT* call
|
|
59
|
+
`ase_task_save(...)`, as no task plan is composed at all.
|
|
60
|
+
</else>
|
|
51
61
|
|
|
52
62
|
<flow>
|
|
53
63
|
|
|
@@ -136,13 +146,41 @@ permitted way to persist artifacts is via `ase_task_save(...)`.
|
|
|
136
146
|
|
|
137
147
|
</step>
|
|
138
148
|
|
|
139
|
-
4. <
|
|
149
|
+
4. <if condition="<getopt-option-direct/> is equal to 'true'">
|
|
150
|
+
|
|
151
|
+
<step id="STEP 4: Direct Feature Crafting">
|
|
152
|
+
|
|
153
|
+
1. Directly craft the <feature/> by modifying the affected
|
|
154
|
+
*artifacts* with a corresponding, complete *change set*,
|
|
155
|
+
based on your gathered knowledge about the code base and your
|
|
156
|
+
internalized crafting tenets. Also, if a CHANGELOG.md
|
|
157
|
+
file exists, make an appropriate entry there, too.
|
|
158
|
+
|
|
159
|
+
2. Output only the following <template/>:
|
|
160
|
+
|
|
161
|
+
<template>
|
|
162
|
+
⧉ **ASE**: ◉ task: **<ase-task-id/>**, ▶ status: **changes directly applied**
|
|
163
|
+
</template>
|
|
164
|
+
|
|
165
|
+
3. Then *IMMEDIATELY* *STOP* all further skill processing. You
|
|
166
|
+
*MUST* *NOT* output anything else in this STEP 4 or after it --
|
|
167
|
+
*independent* of <ase-project-boxing/>, whose exposure rules
|
|
168
|
+
are explicitly *overridden* here. Especially, do not output a
|
|
169
|
+
change summary, a list of modified artifacts, a rationale, or
|
|
170
|
+
a unified diff of the changes.
|
|
171
|
+
|
|
172
|
+
</step>
|
|
173
|
+
|
|
174
|
+
</if>
|
|
175
|
+
<else>
|
|
176
|
+
|
|
177
|
+
<step id="STEP 4: Choose Feature Crafting Approaches">
|
|
140
178
|
|
|
141
179
|
<expand name="code-approaches" arg1="feature" arg2="crafting"></expand>
|
|
142
180
|
|
|
143
181
|
</step>
|
|
144
182
|
|
|
145
|
-
|
|
183
|
+
<step id="STEP 5: Compose Feature Crafting Plan">
|
|
146
184
|
|
|
147
185
|
1. *Compose a feature plan* for the chosen feature A<n/> by
|
|
148
186
|
closely aligning to the existing architecture and the existing
|
|
@@ -187,4 +225,6 @@ permitted way to persist artifacts is via `ase_task_save(...)`.
|
|
|
187
225
|
|
|
188
226
|
</step>
|
|
189
227
|
|
|
228
|
+
</else>
|
|
229
|
+
|
|
190
230
|
</flow>
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
[`--help`|`-h`]
|
|
10
10
|
[`--auto`|`-a`]
|
|
11
11
|
[`--dry`|`-d`]
|
|
12
|
+
[`--direct`|`-D`]
|
|
12
13
|
[`--quick`|`-Q`]
|
|
13
14
|
[`--next`|`-n` *option*[,...]]
|
|
14
15
|
[*task-id*:] *feature*
|
|
@@ -22,10 +23,11 @@ investigating the existing code base, internalizing crafting tenets
|
|
|
22
23
|
preferred approach, and composing a corresponding *task plan* aligned
|
|
23
24
|
with the existing architecture.
|
|
24
25
|
|
|
25
|
-
|
|
26
|
-
plan via `ase_task_save` and then hands off to
|
|
27
|
-
`ase-task-preflight`, or `ase-task-implement`, as
|
|
28
|
-
`--next`.
|
|
26
|
+
By default the skill does *not* directly modify source files. It
|
|
27
|
+
persists the plan via `ase_task_save` and then hands off to
|
|
28
|
+
`ase-task-edit`, `ase-task-preflight`, or `ase-task-implement`, as
|
|
29
|
+
selected by `--next`. Only under `--direct` it skips the plan
|
|
30
|
+
entirely and applies the change set to the affected artifacts itself.
|
|
29
31
|
|
|
30
32
|
## OPTIONS
|
|
31
33
|
|
|
@@ -40,6 +42,15 @@ plan via `ase_task_save` and then hands off to `ase-task-edit`,
|
|
|
40
42
|
type-checker, or program execution) once the source files have
|
|
41
43
|
been modified.
|
|
42
44
|
|
|
45
|
+
`--direct`|`-D`:
|
|
46
|
+
Craft the feature *immediately* and *in place*: skip the
|
|
47
|
+
feature approaches, the interactive dialog, and the entire task
|
|
48
|
+
plan ceremony, and directly apply the complete change set to the
|
|
49
|
+
affected artifacts, including a corresponding entry in an existing
|
|
50
|
+
`CHANGELOG.md` file. In this mode `--auto`, `--dry`, `--quick`, and
|
|
51
|
+
`--next` have no effect, as neither approaches are proposed nor a
|
|
52
|
+
plan is composed.
|
|
53
|
+
|
|
43
54
|
`--quick`|`-Q`:
|
|
44
55
|
Shorthand alias for `-a -d -n IMPLEMENT,DELETE`: automatically pick
|
|
45
56
|
the recommended feature approach, compose the plan *without* the
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: ase-code-refactor
|
|
3
|
-
argument-hint: "[--help|-h] [--auto|-a] [--dry|-d] [--quick|-Q] [--next|-n <option>[,...]] [<task-id>:] <request>"
|
|
3
|
+
argument-hint: "[--help|-h] [--auto|-a] [--dry|-d] [--direct|-D] [--quick|-Q] [--next|-n <option>[,...]] [<task-id>:] <request>"
|
|
4
4
|
description: >
|
|
5
5
|
Refactor Code:
|
|
6
6
|
Use when user wants to "refactor" or "change" the code base.
|
|
@@ -10,6 +10,7 @@ effort: xhigh
|
|
|
10
10
|
allowed-tools:
|
|
11
11
|
- "Skill"
|
|
12
12
|
- "Agent"
|
|
13
|
+
- "Read"
|
|
13
14
|
---
|
|
14
15
|
|
|
15
16
|
@${CLAUDE_SKILL_DIR}/../../meta/ase-control.md
|
|
@@ -23,7 +24,7 @@ Refactor Source Code
|
|
|
23
24
|
|
|
24
25
|
<expand name="getopt"
|
|
25
26
|
arg1="ase-code-refactor"
|
|
26
|
-
arg2="--auto|-a --dry|-d --quick|-Q --next|-n=(none|DONE|EDIT|GRILL|PREFLIGHT|IMPLEMENT)...">
|
|
27
|
+
arg2="--auto|-a --dry|-d --direct|-D --quick|-Q --next|-n=(none|DONE|EDIT|GRILL|PREFLIGHT|IMPLEMENT)...">
|
|
27
28
|
$ARGUMENTS
|
|
28
29
|
</expand>
|
|
29
30
|
|
|
@@ -45,9 +46,18 @@ to `true`, <getopt-option-dry/> to `true`, and <getopt-option-next/> to
|
|
|
45
46
|
Procedure
|
|
46
47
|
---------
|
|
47
48
|
|
|
49
|
+
<if condition="<getopt-option-direct/> is not equal to 'true'">
|
|
48
50
|
You *MUST* *NOT* call `Edit`, `Write`, `NotebookEdit`, or any
|
|
49
51
|
filesystem-modifying tool during this entire skill. The *only*
|
|
50
52
|
permitted way to persist artifacts is via `ase_task_save(...)`.
|
|
53
|
+
</if>
|
|
54
|
+
<else>
|
|
55
|
+
The `--direct`/`-D` mode applies the refactoring *in place*, so STEP 4
|
|
56
|
+
below *requires* `Edit` and `Write` to modify the affected artifacts.
|
|
57
|
+
Every modification *MUST* still stay restricted to the artifacts the
|
|
58
|
+
refactoring actually demands, and you *MUST* *NOT* call
|
|
59
|
+
`ase_task_save(...)`, as no task plan is composed at all.
|
|
60
|
+
</else>
|
|
51
61
|
|
|
52
62
|
<flow>
|
|
53
63
|
|
|
@@ -136,13 +146,41 @@ permitted way to persist artifacts is via `ase_task_save(...)`.
|
|
|
136
146
|
|
|
137
147
|
</step>
|
|
138
148
|
|
|
139
|
-
4. <
|
|
149
|
+
4. <if condition="<getopt-option-direct/> is equal to 'true'">
|
|
150
|
+
|
|
151
|
+
<step id="STEP 4: Direct Refactoring">
|
|
152
|
+
|
|
153
|
+
1. Directly apply the refactoring <request/> by modifying the
|
|
154
|
+
affected *artifacts* with a corresponding, complete *change set*,
|
|
155
|
+
based on your gathered knowledge about the code base and your
|
|
156
|
+
internalized refactoring tenets. Also, if a CHANGELOG.md
|
|
157
|
+
file exists, make an appropriate entry there, too.
|
|
158
|
+
|
|
159
|
+
2. Output only the following <template/>:
|
|
160
|
+
|
|
161
|
+
<template>
|
|
162
|
+
⧉ **ASE**: ◉ task: **<ase-task-id/>**, ▶ status: **changes directly applied**
|
|
163
|
+
</template>
|
|
164
|
+
|
|
165
|
+
3. Then *IMMEDIATELY* *STOP* all further skill processing. You
|
|
166
|
+
*MUST* *NOT* output anything else in this STEP 4 or after it --
|
|
167
|
+
*independent* of <ase-project-boxing/>, whose exposure rules
|
|
168
|
+
are explicitly *overridden* here. Especially, do not output a
|
|
169
|
+
change summary, a list of modified artifacts, a rationale, or
|
|
170
|
+
a unified diff of the changes.
|
|
171
|
+
|
|
172
|
+
</step>
|
|
173
|
+
|
|
174
|
+
</if>
|
|
175
|
+
<else>
|
|
176
|
+
|
|
177
|
+
<step id="STEP 4: Choose Refactoring Approaches">
|
|
140
178
|
|
|
141
179
|
<expand name="code-approaches" arg1="refactoring" arg2="refactoring"></expand>
|
|
142
180
|
|
|
143
181
|
</step>
|
|
144
182
|
|
|
145
|
-
|
|
183
|
+
<step id="STEP 5: Compose Refactoring Plan">
|
|
146
184
|
|
|
147
185
|
1. *Compose a refactoring plan* for the chosen refactoring A<n/> by
|
|
148
186
|
closely aligning to the existing architecture and the existing
|
|
@@ -187,5 +225,7 @@ permitted way to persist artifacts is via `ase_task_save(...)`.
|
|
|
187
225
|
|
|
188
226
|
</step>
|
|
189
227
|
|
|
228
|
+
</else>
|
|
229
|
+
|
|
190
230
|
</flow>
|
|
191
231
|
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
[`--help`|`-h`]
|
|
10
10
|
[`--auto`|`-a`]
|
|
11
11
|
[`--dry`|`-d`]
|
|
12
|
+
[`--direct`|`-D`]
|
|
12
13
|
[`--quick`|`-Q`]
|
|
13
14
|
[`--next`|`-n` *option*[,...]]
|
|
14
15
|
[*task-id*:] *request*
|
|
@@ -22,10 +23,11 @@ clear interfaces, ...), proposing one or more *refactoring approaches*
|
|
|
22
23
|
with pros and cons, letting the user pick the preferred approach,
|
|
23
24
|
and composing a corresponding *task plan*.
|
|
24
25
|
|
|
25
|
-
|
|
26
|
-
plan via `ase_task_save` and then hands off to
|
|
27
|
-
`ase-task-preflight`, or `ase-task-implement`, as
|
|
28
|
-
`--next`.
|
|
26
|
+
By default the skill does *not* directly modify source files. It
|
|
27
|
+
persists the plan via `ase_task_save` and then hands off to
|
|
28
|
+
`ase-task-edit`, `ase-task-preflight`, or `ase-task-implement`, as
|
|
29
|
+
selected by `--next`. Only under `--direct` it skips the plan
|
|
30
|
+
entirely and applies the change set to the affected artifacts itself.
|
|
29
31
|
|
|
30
32
|
## OPTIONS
|
|
31
33
|
|
|
@@ -40,6 +42,15 @@ plan via `ase_task_save` and then hands off to `ase-task-edit`,
|
|
|
40
42
|
type-checker, or program execution) once the source files have
|
|
41
43
|
been modified.
|
|
42
44
|
|
|
45
|
+
`--direct`|`-D`:
|
|
46
|
+
Apply the refactoring *immediately* and *in place*: skip the
|
|
47
|
+
refactoring approaches, the interactive dialog, and the entire task
|
|
48
|
+
plan ceremony, and directly apply the complete change set to the
|
|
49
|
+
affected artifacts, including a corresponding entry in an existing
|
|
50
|
+
`CHANGELOG.md` file. In this mode `--auto`, `--dry`, `--quick`, and
|
|
51
|
+
`--next` have no effect, as neither approaches are proposed nor a
|
|
52
|
+
plan is composed.
|
|
53
|
+
|
|
43
54
|
`--quick`|`-Q`:
|
|
44
55
|
Shorthand alias for `-a -d -n IMPLEMENT,DELETE`: automatically pick
|
|
45
56
|
the recommended refactoring approach, compose the plan *without* the
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: ase-code-resolve
|
|
3
|
-
argument-hint: "[--help|-h] [--auto|-a] [--dry|-d] [--quick|-Q] [--next|-n <option>[,...]] [<task-id>:] <problem>"
|
|
3
|
+
argument-hint: "[--help|-h] [--auto|-a] [--dry|-d] [--direct|-D] [--quick|-Q] [--next|-n <option>[,...]] [<task-id>:] <problem>"
|
|
4
4
|
description: >
|
|
5
5
|
Resolve Problem:
|
|
6
6
|
Use when user wants to "bugfix" or "fix" code or "resolve" a problem.
|
|
@@ -10,6 +10,7 @@ effort: xhigh
|
|
|
10
10
|
allowed-tools:
|
|
11
11
|
- "Skill"
|
|
12
12
|
- "Agent"
|
|
13
|
+
- "Read"
|
|
13
14
|
---
|
|
14
15
|
|
|
15
16
|
@${CLAUDE_SKILL_DIR}/../../meta/ase-control.md
|
|
@@ -23,7 +24,7 @@ Resolve Problem
|
|
|
23
24
|
|
|
24
25
|
<expand name="getopt"
|
|
25
26
|
arg1="ase-code-resolve"
|
|
26
|
-
arg2="--auto|-a --dry|-d --quick|-Q --next|-n=(none|DONE|EDIT|GRILL|PREFLIGHT|IMPLEMENT)...">
|
|
27
|
+
arg2="--auto|-a --dry|-d --direct|-D --quick|-Q --next|-n=(none|DONE|EDIT|GRILL|PREFLIGHT|IMPLEMENT)...">
|
|
27
28
|
$ARGUMENTS
|
|
28
29
|
</expand>
|
|
29
30
|
|
|
@@ -45,9 +46,18 @@ to `true`, <getopt-option-dry/> to `true`, and <getopt-option-next/> to
|
|
|
45
46
|
Procedure
|
|
46
47
|
---------
|
|
47
48
|
|
|
49
|
+
<if condition="<getopt-option-direct/> is not equal to 'true'">
|
|
48
50
|
You *MUST* *NOT* call `Edit`, `Write`, `NotebookEdit`, or any
|
|
49
51
|
filesystem-modifying tool during this entire skill. The *only*
|
|
50
52
|
permitted way to persist artifacts is via `ase_task_save(...)`.
|
|
53
|
+
</if>
|
|
54
|
+
<else>
|
|
55
|
+
The `--direct`/`-D` mode applies the resolution *in place*, so STEP 4
|
|
56
|
+
below *requires* `Edit` and `Write` to modify the affected artifacts.
|
|
57
|
+
Every modification *MUST* still stay restricted to the artifacts the
|
|
58
|
+
resolution actually demands, and you *MUST* *NOT* call
|
|
59
|
+
`ase_task_save(...)`, as no task plan is composed at all.
|
|
60
|
+
</else>
|
|
51
61
|
|
|
52
62
|
<flow>
|
|
53
63
|
|
|
@@ -120,14 +130,19 @@ permitted way to persist artifacts is via `ase_task_save(...)`.
|
|
|
120
130
|
⧉ **ASE**: ⇌ problem: **<problem/>**
|
|
121
131
|
</template>
|
|
122
132
|
|
|
123
|
-
|
|
133
|
+
</step>
|
|
134
|
+
|
|
135
|
+
2. <step id="STEP 2: Investigate Code Base">
|
|
124
136
|
|
|
125
|
-
|
|
126
|
-
|
|
137
|
+
1. Check the existing source files for all code which is related to the
|
|
138
|
+
requested <problem/> resolution.
|
|
127
139
|
|
|
128
|
-
|
|
140
|
+
2. Check the architecture of the existing code base to understand the
|
|
141
|
+
overall structures and dynamics.
|
|
129
142
|
|
|
130
|
-
|
|
143
|
+
3. Investigate and *figure out details* related to this problem.
|
|
144
|
+
|
|
145
|
+
<if condition="<getopt-option-direct/> is not equal to 'true'">
|
|
131
146
|
Report those details with the following <template/>:
|
|
132
147
|
|
|
133
148
|
<template>
|
|
@@ -165,38 +180,57 @@ permitted way to persist artifacts is via `ase_task_save(...)`.
|
|
|
165
180
|
run_in_background: false)`, reproducing its
|
|
166
181
|
returned fenced code block verbatim. Omit <optional-diagram/>
|
|
167
182
|
entirely for simple or purely local situations.
|
|
183
|
+
</if>
|
|
184
|
+
|
|
185
|
+
4. Do not output anything else in this STEP 2.
|
|
168
186
|
|
|
169
187
|
</step>
|
|
170
188
|
|
|
171
|
-
|
|
189
|
+
3. <step id="STEP 3: Internalize Problem Resolution Tenets">
|
|
172
190
|
|
|
173
|
-
1.
|
|
174
|
-
requested <problem/> resolution.
|
|
191
|
+
1. <task-kind>RESOLVING</task-kind>
|
|
175
192
|
|
|
176
|
-
2.
|
|
177
|
-
overall structures and dynamics.
|
|
193
|
+
2. <expand name="code-tenets" arg1="<task-kind/>"></expand>
|
|
178
194
|
|
|
179
|
-
3. Do not output anything in this STEP
|
|
195
|
+
3. Do not output anything in this STEP 3.
|
|
180
196
|
|
|
181
197
|
</step>
|
|
182
198
|
|
|
183
|
-
|
|
199
|
+
4. <if condition="<getopt-option-direct/> is equal to 'true'">
|
|
184
200
|
|
|
185
|
-
|
|
201
|
+
<step id="STEP 4: Direct Problem Resolution">
|
|
186
202
|
|
|
187
|
-
|
|
203
|
+
1. Directly resolve the <problem/> by modifying the affected
|
|
204
|
+
*artifacts* with a corresponding, complete *change set*,
|
|
205
|
+
based on your gathered knowledge about the code base and your
|
|
206
|
+
internalized problem resolution tenets. Also, if a CHANGELOG.md
|
|
207
|
+
file exists, make an appropriate entry there, too.
|
|
188
208
|
|
|
189
|
-
|
|
209
|
+
2. Output only the following <template/>:
|
|
210
|
+
|
|
211
|
+
<template>
|
|
212
|
+
⧉ **ASE**: ◉ task: **<ase-task-id/>**, ▶ status: **changes directly applied**
|
|
213
|
+
</template>
|
|
214
|
+
|
|
215
|
+
3. Then *IMMEDIATELY* *STOP* all further skill processing. You
|
|
216
|
+
*MUST* *NOT* output anything else in this STEP 4 or after it --
|
|
217
|
+
*independent* of <ase-project-boxing/>, whose exposure rules
|
|
218
|
+
are explicitly *overridden* here. Especially, do not output a
|
|
219
|
+
change summary, a list of modified artifacts, a rationale, or
|
|
220
|
+
a unified diff of the changes.
|
|
190
221
|
|
|
191
222
|
</step>
|
|
192
223
|
|
|
193
|
-
|
|
224
|
+
</if>
|
|
225
|
+
<else>
|
|
226
|
+
|
|
227
|
+
<step id="STEP 4: Choose Problem Resolution Approaches">
|
|
194
228
|
|
|
195
229
|
<expand name="code-approaches" arg1="resolution" arg2="resolution"></expand>
|
|
196
230
|
|
|
197
231
|
</step>
|
|
198
232
|
|
|
199
|
-
|
|
233
|
+
<step id="STEP 5: Compose Problem Resolution Plan">
|
|
200
234
|
|
|
201
235
|
1. *Compose a plan* with code references, a precise description of the
|
|
202
236
|
problem, the chosen resolution approach, a preview of the *unified
|
|
@@ -248,5 +282,7 @@ permitted way to persist artifacts is via `ase_task_save(...)`.
|
|
|
248
282
|
|
|
249
283
|
</step>
|
|
250
284
|
|
|
285
|
+
</else>
|
|
286
|
+
|
|
251
287
|
</flow>
|
|
252
288
|
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
[`--help`|`-h`]
|
|
10
10
|
[`--auto`|`-a`]
|
|
11
11
|
[`--dry`|`-d`]
|
|
12
|
+
[`--direct`|`-D`]
|
|
12
13
|
[`--quick`|`-Q`]
|
|
13
14
|
[`--next`|`-n` *option*[,...]]
|
|
14
15
|
[*task-id*:] *problem*
|
|
@@ -27,10 +28,11 @@ or `T1`) previously produced by `ase-code-analyze` or
|
|
|
27
28
|
`ase-arch-analyze` and persisted in the `ase` MCP key/value store
|
|
28
29
|
under `ase-issue-<id>`.
|
|
29
30
|
|
|
30
|
-
|
|
31
|
-
plan via `ase_task_save` and then hands off to
|
|
32
|
-
`ase-task-preflight`, or `ase-task-implement`, as
|
|
33
|
-
`--next`.
|
|
31
|
+
By default the skill does *not* directly modify source files. It
|
|
32
|
+
persists the plan via `ase_task_save` and then hands off to
|
|
33
|
+
`ase-task-edit`, `ase-task-preflight`, or `ase-task-implement`, as
|
|
34
|
+
selected by `--next`. Only under `--direct` it skips the plan
|
|
35
|
+
entirely and applies the change set to the affected artifacts itself.
|
|
34
36
|
|
|
35
37
|
## OPTIONS
|
|
36
38
|
|
|
@@ -45,6 +47,15 @@ plan via `ase_task_save` and then hands off to `ase-task-edit`,
|
|
|
45
47
|
type-checker, or program execution) once the source files have
|
|
46
48
|
been modified.
|
|
47
49
|
|
|
50
|
+
`--direct`|`-D`:
|
|
51
|
+
Resolve the problem *immediately* and *in place*: skip the
|
|
52
|
+
resolution approaches, the interactive dialog, and the entire task
|
|
53
|
+
plan ceremony, and directly apply the complete change set to the
|
|
54
|
+
affected artifacts, including a corresponding entry in an existing
|
|
55
|
+
`CHANGELOG.md` file. In this mode `--auto`, `--dry`, `--quick`, and
|
|
56
|
+
`--next` have no effect, as neither approaches are proposed nor a
|
|
57
|
+
plan is composed.
|
|
58
|
+
|
|
48
59
|
`--quick`|`-Q`:
|
|
49
60
|
Shorthand alias for `-a -d -n IMPLEMENT,DELETE`: automatically pick
|
|
50
61
|
the recommended resolution approach, compose the plan *without* the
|
|
@@ -28,6 +28,15 @@ Query Foreign LLM for Chat
|
|
|
28
28
|
Query foreign LLM for: <query><getopt-arguments/></query>
|
|
29
29
|
</objective>
|
|
30
30
|
|
|
31
|
+
<if condition="<query/> is empty">
|
|
32
|
+
Only output the following <template/> and then immediately *STOP*
|
|
33
|
+
processing the entire current skill:
|
|
34
|
+
|
|
35
|
+
<template>
|
|
36
|
+
⧉ **ASE**: ✪ skill: **ase-meta-chat**, ▶ ERROR: expected a `<query>` argument
|
|
37
|
+
</template>
|
|
38
|
+
</if>
|
|
39
|
+
|
|
31
40
|
1. You *MUST* *NOT* output anything in this step.
|
|
32
41
|
Just call the underlying agent with the following tool:
|
|
33
42
|
|
|
@@ -78,7 +78,8 @@ preset-bootstrapping operation that stays a shell concern next to
|
|
|
78
78
|
`user`, `project`, `task:`*id*, and/or `session:`*id* terms, in any
|
|
79
79
|
order and at most one term per kind. The `user` term is always
|
|
80
80
|
implicitly added at the bottom of the chain, and `project` is
|
|
81
|
-
implicitly added whenever a project context exists
|
|
81
|
+
implicitly added whenever a project context exists, but never above
|
|
82
|
+
the strongest explicitly requested term. If the option is
|
|
82
83
|
omitted, the chain of the *current session* (`session:`*id*) is used,
|
|
83
84
|
so that reads see the full `user` -> `project` -> `session` cascade
|
|
84
85
|
and writes -- including those to the session-only keys `agent.task`
|
|
@@ -143,32 +143,10 @@ Procedure
|
|
|
143
143
|
</template>
|
|
144
144
|
|
|
145
145
|
- If <result/> is `EDIT`:
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
Set <args><args/> --next <getopt-option-next/></args>
|
|
149
|
-
</if>
|
|
150
|
-
Only output the following <template/> and then call the
|
|
151
|
-
tool `Skill(skill: "ase:ase-task-edit", args: "<args/>")`
|
|
152
|
-
to invoke the `ase:ase-task-edit` skill in order to *edit*
|
|
153
|
-
the updated plan. Immediately stop processing the current
|
|
154
|
-
skill once the `Skill` tool was used.
|
|
155
|
-
|
|
156
|
-
<template>
|
|
157
|
-
⧉ **ASE**: ◉ task: **<ase-task-id/>**, ✪ plan: **<words/>** words, ▶ status: **plan updated -- hand-off to edit**
|
|
158
|
-
</template>
|
|
146
|
+
<expand name="task-next-handoff" arg1="ase-task-edit"
|
|
147
|
+
arg2="plan updated -- hand-off to edit"></expand>
|
|
159
148
|
|
|
160
149
|
- If <result/> is `IMPLEMENT`:
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
Set <args><args/> --next <getopt-option-next/></args>
|
|
164
|
-
</if>
|
|
165
|
-
Only output the following <template/> and then call the
|
|
166
|
-
tool `Skill(skill: "ase:ase-task-implement", args: "<args/>")`
|
|
167
|
-
to invoke the `ase:ase-task-implement` skill in order to
|
|
168
|
-
*implement* the updated plan. Immediately stop processing
|
|
169
|
-
the current skill once the `Skill` tool was used.
|
|
170
|
-
|
|
171
|
-
<template>
|
|
172
|
-
⧉ **ASE**: ◉ task: **<ase-task-id/>**, ✪ plan: **<words/>** words, ▶ status: **plan updated -- hand-off to implementation**
|
|
173
|
-
</template>
|
|
150
|
+
<expand name="task-next-handoff" arg1="ase-task-implement"
|
|
151
|
+
arg2="plan updated -- hand-off to implementation"></expand>
|
|
174
152
|
|
|
@@ -143,47 +143,14 @@ Procedure
|
|
|
143
143
|
</template>
|
|
144
144
|
|
|
145
145
|
- If <result/> is `EDIT`:
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
Set <args><args/> --next <getopt-option-next/></args>
|
|
149
|
-
</if>
|
|
150
|
-
Only output the following <template/> and then call the
|
|
151
|
-
tool `Skill(skill: "ase:ase-task-edit", args: "<args/>")`
|
|
152
|
-
to invoke the `ase:ase-task-edit` skill in order to *edit*
|
|
153
|
-
the updated plan. Immediately stop processing the current
|
|
154
|
-
skill once the `Skill` tool was used.
|
|
155
|
-
|
|
156
|
-
<template>
|
|
157
|
-
⧉ **ASE**: ◉ task: **<ase-task-id/>**, ✪ plan: **<words/>** words, ▶ status: **plan rebooted -- hand-off to edit**
|
|
158
|
-
</template>
|
|
146
|
+
<expand name="task-next-handoff" arg1="ase-task-edit"
|
|
147
|
+
arg2="plan rebooted -- hand-off to edit"></expand>
|
|
159
148
|
|
|
160
149
|
- If <result/> is `IMPLEMENT`:
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
Set <args><args/> --next <getopt-option-next/></args>
|
|
164
|
-
</if>
|
|
165
|
-
Only output the following <template/> and then call the
|
|
166
|
-
tool `Skill(skill: "ase:ase-task-implement", args: "<args/>")`
|
|
167
|
-
to invoke the `ase:ase-task-implement` skill in order to
|
|
168
|
-
*implement* the updated plan. Immediately stop processing
|
|
169
|
-
the current skill once the `Skill` tool was used.
|
|
170
|
-
|
|
171
|
-
<template>
|
|
172
|
-
⧉ **ASE**: ◉ task: **<ase-task-id/>**, ✪ plan: **<words/>** words, ▶ status: **plan rebooted -- hand-off to implementation**
|
|
173
|
-
</template>
|
|
150
|
+
<expand name="task-next-handoff" arg1="ase-task-implement"
|
|
151
|
+
arg2="plan rebooted -- hand-off to implementation"></expand>
|
|
174
152
|
|
|
175
153
|
- If <result/> is `PREFLIGHT`:
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
Set <args><args/> --next <getopt-option-next/></args>
|
|
179
|
-
</if>
|
|
180
|
-
Only output the following <template/> and then call the
|
|
181
|
-
tool `Skill(skill: "ase:ase-task-preflight", args: "<args/>")`
|
|
182
|
-
to invoke the `ase:ase-task-preflight` skill in order to
|
|
183
|
-
*preflight* the updated plan. Immediately stop processing
|
|
184
|
-
the current skill once the `Skill` tool was used.
|
|
185
|
-
|
|
186
|
-
<template>
|
|
187
|
-
⧉ **ASE**: ◉ task: **<ase-task-id/>**, ✪ plan: **<words/>** words, ▶ status: **plan rebooted -- hand-off to pre-flight**
|
|
188
|
-
</template>
|
|
154
|
+
<expand name="task-next-handoff" arg1="ase-task-preflight"
|
|
155
|
+
arg2="plan rebooted -- hand-off to pre-flight"></expand>
|
|
189
156
|
|