@rse/ase 0.9.36 → 0.9.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-hook.js +8 -1
- package/dst/ase-setup.js +261 -0
- package/package.json +5 -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-constitution.md +1 -1
- package/plugin/meta/ase-dialog.md +4 -2
- package/plugin/meta/ase-skill.md +50 -0
- package/plugin/package.json +1 -1
- package/plugin/skills/ase-arch-analyze/SKILL.md +16 -0
- package/plugin/skills/ase-code-analyze/SKILL.md +27 -8
- package/plugin/skills/ase-code-craft/SKILL.md +6 -3
- package/plugin/skills/ase-code-explain/SKILL.md +29 -0
- package/plugin/skills/ase-code-insight/SKILL.md +15 -0
- package/plugin/skills/ase-code-lint/SKILL.md +89 -16
- package/plugin/skills/ase-code-refactor/SKILL.md +6 -3
- package/plugin/skills/ase-code-resolve/SKILL.md +6 -3
- package/plugin/skills/ase-docs-proofread/SKILL.md +36 -2
- package/plugin/skills/ase-meta-changelog/SKILL.md +31 -6
- package/plugin/skills/ase-meta-changelog/help.md +7 -4
- package/plugin/skills/ase-meta-diff/SKILL.md +21 -3
- package/plugin/skills/ase-meta-review/SKILL.md +27 -7
package/dst/ase-hook.js
CHANGED
|
@@ -250,6 +250,11 @@ export default class HookCommand {
|
|
|
250
250
|
const val = cfg.get("agent.persona");
|
|
251
251
|
if (typeof val === "string")
|
|
252
252
|
persona = val;
|
|
253
|
+
/* determine project boxing transparency */
|
|
254
|
+
let boxing = process.env.ASE_PROJECT_BOXING ?? "white";
|
|
255
|
+
const valBoxing = cfg.get("project.boxing");
|
|
256
|
+
if (typeof valBoxing === "string")
|
|
257
|
+
boxing = valBoxing;
|
|
253
258
|
/* determine headless mode */
|
|
254
259
|
const headless = (process.env.ASE_HEADLESS ?? "false") === "true" ? "true" : "false";
|
|
255
260
|
/* provide ASE information to Anthropic Claude Code CLI shell commands
|
|
@@ -260,6 +265,7 @@ export default class HookCommand {
|
|
|
260
265
|
`export ASE_PLUGIN_ROOT=${quote([pluginRoot])}\n` +
|
|
261
266
|
`export ASE_USER_ID=${quote([userId])}\n` +
|
|
262
267
|
`export ASE_PROJECT_ID=${quote([projectId])}\n` +
|
|
268
|
+
`export ASE_PROJECT_BOXING=${quote([boxing])}\n` +
|
|
263
269
|
`export ASE_TASK_ID=${quote([taskId])}\n` +
|
|
264
270
|
`export ASE_SESSION_ID=${quote([sessionId])}\n` +
|
|
265
271
|
`export ASE_HEADLESS=${quote([headless])}\n` +
|
|
@@ -274,6 +280,7 @@ export default class HookCommand {
|
|
|
274
280
|
`<ase-persona-style>${persona}</ase-persona-style>\n` +
|
|
275
281
|
`<ase-user-id>${userId}</ase-user-id>\n` +
|
|
276
282
|
`<ase-project-id>${projectId}</ase-project-id>\n` +
|
|
283
|
+
`<ase-project-boxing>${boxing}</ase-project-boxing>\n` +
|
|
277
284
|
`<ase-task-id>${taskId}</ase-task-id>\n` +
|
|
278
285
|
`<ase-session-id>${sessionId}</ase-session-id>\n` +
|
|
279
286
|
`<ase-headless>${headless}</ase-headless>\n` +
|
|
@@ -289,7 +296,7 @@ export default class HookCommand {
|
|
|
289
296
|
const banner = `\n⧉ ASE: ⎈ version: ${versionCurrentPlugin}${versionHint !== "" ? " " + versionHint.replaceAll(/\*/g, "") : ""}` +
|
|
290
297
|
`\n⧉ ASE: ※ user: ${userId}, ⚑ project: ${projectId}` +
|
|
291
298
|
`\n⧉ ASE: ◉ task: ${taskId}, ⏻ session: ${sessionId}` +
|
|
292
|
-
`\n⧉ ASE: ☯ persona: ${persona}`;
|
|
299
|
+
`\n⧉ ASE: ☯ persona: ${persona}, ▢ boxing: ${boxing}`;
|
|
293
300
|
/* inject markdown into session context.
|
|
294
301
|
Anthropic Claude Code CLI and OpenAI Codex CLI expect the context nested in
|
|
295
302
|
"hookSpecificOutput"; GitHub Copilot CLI expects a flat top-level
|
package/dst/ase-setup.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
** Licensed under Apache 2.0 <https://spdx.org/licenses/Apache-2.0>
|
|
5
5
|
*/
|
|
6
6
|
import fs from "node:fs/promises";
|
|
7
|
+
import os from "node:os";
|
|
7
8
|
import path from "node:path";
|
|
8
9
|
import { fileURLToPath } from "node:url";
|
|
9
10
|
import { execa } from "execa";
|
|
@@ -11,6 +12,9 @@ import which from "which";
|
|
|
11
12
|
import * as dotenvx from "@dotenvx/dotenvx";
|
|
12
13
|
import Table from "cli-table3";
|
|
13
14
|
import chalk from "chalk";
|
|
15
|
+
import writeFileAtomic from "write-file-atomic";
|
|
16
|
+
import { mkdirp } from "mkdirp";
|
|
17
|
+
import JsonAsty from "json-asty";
|
|
14
18
|
import Version from "./ase-version.js";
|
|
15
19
|
const toolSpecs = {
|
|
16
20
|
"claude": { cli: "claude", label: "Anthropic Claude Code CLI", pInstall: "install", pRemove: "uninstall", pUpdate: "update" },
|
|
@@ -567,6 +571,226 @@ export default class SetupCommand {
|
|
|
567
571
|
}
|
|
568
572
|
}
|
|
569
573
|
];
|
|
574
|
+
/* the default "ase statusline" format lines used when the user does
|
|
575
|
+
not override them with positional arguments to "activate" */
|
|
576
|
+
statuslineFormatDflt = [
|
|
577
|
+
"<blue>%u</blue> <red>%p</red> <black>%T</black> %s",
|
|
578
|
+
"%m %e %t",
|
|
579
|
+
"%P %c"
|
|
580
|
+
];
|
|
581
|
+
/* resolve the tool settings file for a given installation scope */
|
|
582
|
+
statuslineSettingsFile(tool, scope) {
|
|
583
|
+
if (tool === "copilot") {
|
|
584
|
+
const home = process.env.COPILOT_HOME ?? "";
|
|
585
|
+
const base = home !== "" ? home : path.join(os.homedir(), ".copilot");
|
|
586
|
+
return path.join(base, "settings.json");
|
|
587
|
+
}
|
|
588
|
+
else if (scope === "project")
|
|
589
|
+
return path.join(process.cwd(), ".claude", "settings.json");
|
|
590
|
+
else if (scope === "local")
|
|
591
|
+
return path.join(process.cwd(), ".claude", "settings.local.json");
|
|
592
|
+
else
|
|
593
|
+
return path.join(os.homedir(), ".claude", "settings.json");
|
|
594
|
+
}
|
|
595
|
+
/* reject the statusline operation for tools without a scriptable
|
|
596
|
+
statusline mechanism (only the OpenAI Codex CLI lacks one) */
|
|
597
|
+
requireStatuslineTool(tool) {
|
|
598
|
+
if (tool === "codex")
|
|
599
|
+
throw new Error("statusline configuration is not supported for --tool codex " +
|
|
600
|
+
`(the ${toolSpecs[tool].label} has no scriptable statusline mechanism)`);
|
|
601
|
+
}
|
|
602
|
+
/* reject a non-default --scope for the GitHub Copilot CLI, which has a
|
|
603
|
+
single per-user settings file and thus no scope concept */
|
|
604
|
+
requireStatuslineScope(tool, scope) {
|
|
605
|
+
if (tool === "copilot" && scope !== "user")
|
|
606
|
+
throw new Error("--scope is only supported for --tool claude " +
|
|
607
|
+
`(the ${toolSpecs[tool].label} has a single per-user settings file)`);
|
|
608
|
+
}
|
|
609
|
+
/* build the "ase statusline ..." command string from the activate
|
|
610
|
+
options and the effective format lines */
|
|
611
|
+
statuslineCommand(opts, format) {
|
|
612
|
+
const parts = ["ase", "statusline", "-w", String(opts.width), "-m", String(opts.margin)];
|
|
613
|
+
if (!opts.icons)
|
|
614
|
+
parts.push("--no-icons");
|
|
615
|
+
if (!opts.labels)
|
|
616
|
+
parts.push("--no-labels");
|
|
617
|
+
const lines = format.length > 0 ? format : this.statuslineFormatDflt;
|
|
618
|
+
for (const line of lines)
|
|
619
|
+
parts.push(`'${line.replace(/'/g, "'\\''")}'`);
|
|
620
|
+
return parts.join(" ");
|
|
621
|
+
}
|
|
622
|
+
/* determine whether an existing "statusLine" value object is owned by us */
|
|
623
|
+
statuslineIsOwned(member) {
|
|
624
|
+
const obj = member.query("/ * [ pos() == 2 ]")[0];
|
|
625
|
+
if (obj === undefined)
|
|
626
|
+
return false;
|
|
627
|
+
for (const m of obj.query("/ member")) {
|
|
628
|
+
const key = m.query("/ string [ pos() == 1 ]")[0];
|
|
629
|
+
if (key !== undefined && key.get("value") === "command") {
|
|
630
|
+
const val = m.query("/ string [ pos() == 2 ]")[0];
|
|
631
|
+
const cmd = val !== undefined ? String(val.get("value") ?? "") : "";
|
|
632
|
+
return cmd.startsWith("ase statusline");
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
return false;
|
|
636
|
+
}
|
|
637
|
+
/* locate the top-level "statusLine" member node within the root object */
|
|
638
|
+
statuslineFindMember(root) {
|
|
639
|
+
for (const m of root.query("/ member")) {
|
|
640
|
+
const key = m.query("/ string [ pos() == 1 ]")[0];
|
|
641
|
+
if (key !== undefined && key.get("value") === "statusLine")
|
|
642
|
+
return m;
|
|
643
|
+
}
|
|
644
|
+
return undefined;
|
|
645
|
+
}
|
|
646
|
+
/* build the "statusLine" member subtree natively inside the target
|
|
647
|
+
AST, reproducing the exact whitespace tokens json-asty emits for a
|
|
648
|
+
canonically 4-space-indented settings.json */
|
|
649
|
+
statuslineBuildMember(root, command) {
|
|
650
|
+
const strMember = (key, val, epilog) => {
|
|
651
|
+
const k = root.create("string").set({ body: JSON.stringify(key), value: key, epilog: ": " });
|
|
652
|
+
const v = root.create("string").set({ body: JSON.stringify(val), value: val });
|
|
653
|
+
const m = root.create("member");
|
|
654
|
+
if (epilog !== undefined)
|
|
655
|
+
m.set({ epilog });
|
|
656
|
+
return m.add(k, v);
|
|
657
|
+
};
|
|
658
|
+
const numMember = (key, val, epilog) => {
|
|
659
|
+
const k = root.create("string").set({ body: JSON.stringify(key), value: key, epilog: ": " });
|
|
660
|
+
const v = root.create("number").set({ body: String(val), value: val });
|
|
661
|
+
const m = root.create("member");
|
|
662
|
+
if (epilog !== undefined)
|
|
663
|
+
m.set({ epilog });
|
|
664
|
+
return m.add(k, v);
|
|
665
|
+
};
|
|
666
|
+
const obj = root.create("object").set({ prolog: "{\n ", epilog: "\n }\n" });
|
|
667
|
+
obj.add(strMember("type", "command", ",\n "), strMember("command", command, ",\n "), numMember("padding", 0));
|
|
668
|
+
const key = root.create("string").set({
|
|
669
|
+
body: JSON.stringify("statusLine"),
|
|
670
|
+
value: "statusLine",
|
|
671
|
+
epilog: ": "
|
|
672
|
+
});
|
|
673
|
+
return root.create("member").add(key, obj);
|
|
674
|
+
}
|
|
675
|
+
/* normalize the previous-last member so a following ",\n " comma reads cleanly */
|
|
676
|
+
statuslineMakeNonLast(member) {
|
|
677
|
+
const val = member.query("/ * [ pos() == 2 ]")[0];
|
|
678
|
+
if (val !== undefined) {
|
|
679
|
+
const ep = val.get("epilog");
|
|
680
|
+
if (typeof ep === "string" && ep.endsWith("\n"))
|
|
681
|
+
val.set({ epilog: ep.replace(/\n$/, "") });
|
|
682
|
+
}
|
|
683
|
+
member.set({ epilog: ",\n " });
|
|
684
|
+
}
|
|
685
|
+
/* read a settings.json file into a JSON-ASTy AST */
|
|
686
|
+
async statuslineReadAst(file) {
|
|
687
|
+
let text = "";
|
|
688
|
+
try {
|
|
689
|
+
text = await fs.readFile(file, "utf8");
|
|
690
|
+
}
|
|
691
|
+
catch {
|
|
692
|
+
/* missing file: start from an empty object */
|
|
693
|
+
}
|
|
694
|
+
if (text.trim() === "")
|
|
695
|
+
text = "{}";
|
|
696
|
+
return JsonAsty.parse(text);
|
|
697
|
+
}
|
|
698
|
+
/* write a JSON-ASTy AST back to a settings.json file */
|
|
699
|
+
async statuslineWriteAst(file, root) {
|
|
700
|
+
await mkdirp(path.dirname(file));
|
|
701
|
+
const text = JsonAsty.unparse(root);
|
|
702
|
+
writeFileAtomic.sync(file, text, { encoding: "utf8" });
|
|
703
|
+
}
|
|
704
|
+
/* handler for "ase setup statusline activate" */
|
|
705
|
+
async doStatuslineActivate(tool, scope, opts, format) {
|
|
706
|
+
this.requireStatuslineTool(tool);
|
|
707
|
+
this.requireStatuslineScope(tool, scope);
|
|
708
|
+
const file = this.statuslineSettingsFile(tool, scope);
|
|
709
|
+
const command = this.statuslineCommand(opts, format);
|
|
710
|
+
const root = await this.statuslineReadAst(file);
|
|
711
|
+
const existing = this.statuslineFindMember(root);
|
|
712
|
+
if (existing !== undefined) {
|
|
713
|
+
/* preserve a foreign, hand-crafted statusLine: skip and warn */
|
|
714
|
+
if (!this.statuslineIsOwned(existing)) {
|
|
715
|
+
this.log.write("warning", "setup: statusline: activate: a non-ASE \"statusLine\" " +
|
|
716
|
+
`is already present in ${file}: preserving it (skipped)`);
|
|
717
|
+
return 0;
|
|
718
|
+
}
|
|
719
|
+
/* replace the value object in place, preserving its epilog */
|
|
720
|
+
const valNew = this.statuslineBuildMember(root, command).query("/ object")[0];
|
|
721
|
+
const valOld = existing.query("/ * [ pos() == 2 ]")[0];
|
|
722
|
+
valNew.set({ epilog: valOld.get("epilog") });
|
|
723
|
+
existing.del(valOld).add(valNew);
|
|
724
|
+
this.log.write("info", `setup: statusline: activate: updating ASE "statusLine" in ${file}`);
|
|
725
|
+
}
|
|
726
|
+
else {
|
|
727
|
+
/* insert a fresh statusLine member */
|
|
728
|
+
const members = root.query("/ member");
|
|
729
|
+
const member = this.statuslineBuildMember(root, command);
|
|
730
|
+
if (members.length === 0) {
|
|
731
|
+
root.set({ prolog: "{\n ", epilog: "}\n" });
|
|
732
|
+
root.add(member);
|
|
733
|
+
}
|
|
734
|
+
else {
|
|
735
|
+
root.set({ epilog: "}\n" });
|
|
736
|
+
this.statuslineMakeNonLast(members[members.length - 1]);
|
|
737
|
+
root.add(member);
|
|
738
|
+
}
|
|
739
|
+
this.log.write("info", `setup: statusline: activate: adding ASE "statusLine" to ${file}`);
|
|
740
|
+
}
|
|
741
|
+
await this.statuslineWriteAst(file, root);
|
|
742
|
+
return 0;
|
|
743
|
+
}
|
|
744
|
+
/* handler for "ase setup statusline deactivate" */
|
|
745
|
+
async doStatuslineDeactivate(tool, scope) {
|
|
746
|
+
this.requireStatuslineTool(tool);
|
|
747
|
+
this.requireStatuslineScope(tool, scope);
|
|
748
|
+
const file = this.statuslineSettingsFile(tool, scope);
|
|
749
|
+
/* a missing settings file means nothing to remove */
|
|
750
|
+
try {
|
|
751
|
+
await fs.access(file);
|
|
752
|
+
}
|
|
753
|
+
catch {
|
|
754
|
+
this.log.write("info", `setup: statusline: deactivate: no settings file ${file} (skipped)`);
|
|
755
|
+
return 0;
|
|
756
|
+
}
|
|
757
|
+
/* read file */
|
|
758
|
+
const root = await this.statuslineReadAst(file);
|
|
759
|
+
const target = this.statuslineFindMember(root);
|
|
760
|
+
if (target === undefined) {
|
|
761
|
+
this.log.write("info", `setup: statusline: deactivate: no "statusLine" in ${file} (skipped)`);
|
|
762
|
+
return 0;
|
|
763
|
+
}
|
|
764
|
+
/* preserve a foreign, hand-crafted statusLine: skip and warn */
|
|
765
|
+
if (!this.statuslineIsOwned(target)) {
|
|
766
|
+
this.log.write("warning", "setup: statusline: deactivate: a non-ASE \"statusLine\" " +
|
|
767
|
+
`is present in ${file}: preserving it (skipped)`);
|
|
768
|
+
return 0;
|
|
769
|
+
}
|
|
770
|
+
/* remove the member and repair the whitespace at the seam */
|
|
771
|
+
const members = root.query("/ member");
|
|
772
|
+
const wasLast = members[members.length - 1] === target;
|
|
773
|
+
root.del(target);
|
|
774
|
+
if (wasLast) {
|
|
775
|
+
if (members.length > 1) {
|
|
776
|
+
/* promote the new last member: strip its comma epilog and
|
|
777
|
+
restore the pre-"}" newline into the root epilog when the
|
|
778
|
+
new-last value is a scalar (a container value carries the
|
|
779
|
+
newline in its own epilog already) */
|
|
780
|
+
const newLast = members[members.length - 2];
|
|
781
|
+
newLast.set({ epilog: undefined });
|
|
782
|
+
const val = newLast.query("/ * [ pos() == 2 ]")[0];
|
|
783
|
+
const ep = val !== undefined ? val.get("epilog") : undefined;
|
|
784
|
+
if (!(typeof ep === "string" && ep.endsWith("\n")))
|
|
785
|
+
root.set({ epilog: "\n}\n" });
|
|
786
|
+
}
|
|
787
|
+
else
|
|
788
|
+
root.set({ epilog: "}\n" });
|
|
789
|
+
}
|
|
790
|
+
await this.statuslineWriteAst(file, root);
|
|
791
|
+
this.log.write("info", `setup: statusline: deactivate: removing ASE "statusLine" from ${file}`);
|
|
792
|
+
return 0;
|
|
793
|
+
}
|
|
570
794
|
/* parse and validate the --tool option */
|
|
571
795
|
parseTool(value) {
|
|
572
796
|
if (value !== "claude" && value !== "copilot" && value !== "codex")
|
|
@@ -683,5 +907,42 @@ export default class SetupCommand {
|
|
|
683
907
|
.action(async (servers, opts) => {
|
|
684
908
|
process.exit(await this.doMcp("deactivate", this.parseTool(opts.tool), servers ?? "all", this.parseScope(opts.scope)));
|
|
685
909
|
});
|
|
910
|
+
/* parser for the non-negative integer "ase setup statusline" options */
|
|
911
|
+
const parseNonNeg = (name) => (value) => {
|
|
912
|
+
const n = Number.parseInt(value, 10);
|
|
913
|
+
if (!Number.isFinite(n) || n < 0)
|
|
914
|
+
throw new Error(`invalid --${name} value: "${value}" (expected a non-negative integer)`);
|
|
915
|
+
return n;
|
|
916
|
+
};
|
|
917
|
+
/* register CLI sub-command "ase setup statusline" */
|
|
918
|
+
const statuslineCmd = setupCmd
|
|
919
|
+
.command("statusline")
|
|
920
|
+
.description("activate or deactivate the ASE statusline for a tool")
|
|
921
|
+
.action(() => {
|
|
922
|
+
statuslineCmd.outputHelp();
|
|
923
|
+
process.exit(1);
|
|
924
|
+
});
|
|
925
|
+
/* register CLI sub-command "ase setup statusline activate" */
|
|
926
|
+
statuslineCmd
|
|
927
|
+
.command("activate [format...]")
|
|
928
|
+
.description("activate the ASE statusline (optionally with custom format lines)")
|
|
929
|
+
.option("-t, --tool <tool>", "target tool (\"claude\" or \"copilot\"; \"codex\" is unsupported)", toolDflt)
|
|
930
|
+
.option("-s, --scope <scope>", "target scope (\"user\", \"project\", or \"local\")", "user")
|
|
931
|
+
.option("-w, --width <n>", "force terminal width to <n> characters (0 = auto-detect via /dev/tty)", parseNonNeg("width"), 0)
|
|
932
|
+
.option("-m, --margin <n>", "reduce maximum used terminal width by <n> characters on each side", parseNonNeg("margin"), 2)
|
|
933
|
+
.option("--no-icons", "disable icons in placeholder rendering")
|
|
934
|
+
.option("--no-labels", "disable labels in front of bold values")
|
|
935
|
+
.action(async (format, opts) => {
|
|
936
|
+
process.exit(await this.doStatuslineActivate(this.parseTool(opts.tool), this.parseScope(opts.scope), { width: opts.width, margin: opts.margin, icons: opts.icons, labels: opts.labels }, format ?? []));
|
|
937
|
+
});
|
|
938
|
+
/* register CLI sub-command "ase setup statusline deactivate" */
|
|
939
|
+
statuslineCmd
|
|
940
|
+
.command("deactivate")
|
|
941
|
+
.description("deactivate the ASE statusline")
|
|
942
|
+
.option("-t, --tool <tool>", "target tool (\"claude\" or \"copilot\"; \"codex\" is unsupported)", toolDflt)
|
|
943
|
+
.option("-s, --scope <scope>", "target scope (\"user\", \"project\", or \"local\")", "user")
|
|
944
|
+
.action(async (opts) => {
|
|
945
|
+
process.exit(await this.doStatuslineDeactivate(this.parseTool(opts.tool), this.parseScope(opts.scope)));
|
|
946
|
+
});
|
|
686
947
|
}
|
|
687
948
|
}
|
package/package.json
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"homepage": "http://github.com/rse/ase",
|
|
7
7
|
"repository": { "url": "git+https://github.com/rse/ase.git", "type": "git" },
|
|
8
8
|
"bugs": { "url": "http://github.com/rse/ase/issues" },
|
|
9
|
-
"version": "0.9.
|
|
9
|
+
"version": "0.9.38",
|
|
10
10
|
"license": "Apache-2.0",
|
|
11
11
|
"author": {
|
|
12
12
|
"name": "Dr. Ralf S. Engelschall",
|
|
@@ -54,6 +54,7 @@
|
|
|
54
54
|
"pretty-ms": "9.3.0",
|
|
55
55
|
"luxon": "3.7.2",
|
|
56
56
|
"@modelcontextprotocol/sdk": "1.29.0",
|
|
57
|
+
"json-asty": "1.3.2",
|
|
57
58
|
"zod": "4.4.3",
|
|
58
59
|
"which": "7.0.0",
|
|
59
60
|
"update-notifier": "7.3.1",
|
|
@@ -65,6 +66,9 @@
|
|
|
65
66
|
"ofetch": "1.5.1",
|
|
66
67
|
"picomatch": "4.0.5"
|
|
67
68
|
},
|
|
69
|
+
"allowScripts": {
|
|
70
|
+
"es5-ext": true
|
|
71
|
+
},
|
|
68
72
|
"engines": {
|
|
69
73
|
"npm": ">=10.0.0",
|
|
70
74
|
"node": ">=22.0.0"
|
|
@@ -16,7 +16,7 @@ any skill flow:
|
|
|
16
16
|
⧉ **ASE**: ⎈ version: **<ase-version/>** <ase-version-hint/>
|
|
17
17
|
⧉ **ASE**: ※ user: **<ase-user-id/>**, ⚑ project: **<ase-project-id/>**
|
|
18
18
|
⧉ **ASE**: ◉ task: **<ase-task-id/>**, ⏻ session: **<ase-session-id/>**
|
|
19
|
-
⧉ **ASE**: ☯ persona: **<ase-persona-style/>**
|
|
19
|
+
⧉ **ASE**: ☯ persona: **<ase-persona-style/>**, ▢ boxing: **<ase-project-boxing/>**
|
|
20
20
|
</template>
|
|
21
21
|
|
|
22
22
|
Prohibitions
|
|
@@ -56,12 +56,14 @@ following procedure:
|
|
|
56
56
|
If this line exists, parse it according to the format `<label/>: <description/>`.
|
|
57
57
|
Set <n/> to <n/> + 1 (increment entry count).
|
|
58
58
|
Set <label-key/> to `<ase-tpl-key digit="<n/>"/>`.
|
|
59
|
-
Set <label-text/> to
|
|
59
|
+
Set <label-text/> to `**<label/>:**`.
|
|
60
|
+
Set <label-pad/> to `<ase-tpl-pad width="<width/>" text="<label/>:"/>` with
|
|
61
|
+
the leading `<label/>:` text removed, i.e. only the trailing padding spaces.
|
|
60
62
|
Append an entry to <text/>:
|
|
61
63
|
|
|
62
64
|
<text>
|
|
63
65
|
<text/>
|
|
64
|
-
<ase-tpl-boxline><label-key/> ▶
|
|
66
|
+
<ase-tpl-boxline><label-key/> ▶ <label-text/><label-pad/> <description/></ase-tpl-boxline>
|
|
65
67
|
</text>
|
|
66
68
|
|
|
67
69
|
<if condition="<keys/> is empty">
|
package/plugin/meta/ase-skill.md
CHANGED
|
@@ -243,9 +243,58 @@ Skill Identification
|
|
|
243
243
|
steps at the end of a skill beside the explicit outputs via any
|
|
244
244
|
<template/>.
|
|
245
245
|
|
|
246
|
+
Artifact Boxing Transparency
|
|
247
|
+
----------------------------
|
|
248
|
+
|
|
249
|
+
- *IMPORTANT*: The *boxing* of a project (indicated by
|
|
250
|
+
<ase-project-boxing/> configuration) classifies how *transparent*
|
|
251
|
+
its *source artifacts* (specification, architecture, source code,
|
|
252
|
+
documentation, infrastructure, task plan, and other artifacts) are,
|
|
253
|
+
and thus how *deeply* you *MUST* inspect or produce them and how
|
|
254
|
+
*much* of their internals you *MUST* surface.
|
|
255
|
+
|
|
256
|
+
- *IMPORTANT*: Boxing modulates only the *work depth* (inspection and
|
|
257
|
+
production thoroughness) and the *output visibility* (surfaced
|
|
258
|
+
content and findings) of *artifact-touching* skills, per the three
|
|
259
|
+
lists below. It *MUST* *NOT* alter the *communication style*
|
|
260
|
+
(governed exclusively by the persona), and it *MUST* *NOT* apply to
|
|
261
|
+
skills that neither read, critique, nor write any project source
|
|
262
|
+
artifact.
|
|
263
|
+
|
|
264
|
+
- If <ase-project-boxing/> is `white`:
|
|
265
|
+
- Transparency: *fully*
|
|
266
|
+
- Work depth: inspect *fully*, produce *thoroughly*
|
|
267
|
+
- Findings surfaced: *all*
|
|
268
|
+
- Internals exposed: *full* (complete diffs, exhaustive rationale)
|
|
269
|
+
|
|
270
|
+
- If <ase-project-boxing/> is `grey`:
|
|
271
|
+
- Transparency: *partially*
|
|
272
|
+
- Work depth: inspect *significant* parts, produce *reasonably*
|
|
273
|
+
- Findings surfaced: *essentials*, summarize rest
|
|
274
|
+
- Internals exposed: *key* only (essential hunks, condensed rationale), summarize rest
|
|
275
|
+
|
|
276
|
+
- If <ase-project-boxing/> is `black`:
|
|
277
|
+
- Transparency: *none*
|
|
278
|
+
- Work depth: *minimum* work to satisfy the request
|
|
279
|
+
- Findings surfaced: *none* (report only the *outcome*)
|
|
280
|
+
- Internals exposed: *none* (no diffs, no code, no per-artifact explanation)
|
|
281
|
+
|
|
282
|
+
- *IMPORTANT*: Precedence rule: skill's *explicit* `black` branches
|
|
283
|
+
deterministically skip or suppress and *win* over the implicit decisions
|
|
284
|
+
above. Where no such branches exist, the decisions above apply.
|
|
285
|
+
|
|
246
286
|
Template Patterns
|
|
247
287
|
-----------------
|
|
248
288
|
|
|
289
|
+
- *IMPORTANT*: In every `<template/>` below you *MUST* reproduce all
|
|
290
|
+
box-drawing and decorative glyphs *verbatim*, character-for-character,
|
|
291
|
+
exactly as written. This especially includes the corner and edge
|
|
292
|
+
characters `╭`, `╰`, and `│`, the shoulder character `━`, the bar
|
|
293
|
+
character `─`, and the trailing dotted character `┈`. You *MUST* *NOT*
|
|
294
|
+
substitute visually similar ASCII fallbacks (e.g. `+`, `|`, `-`) or
|
|
295
|
+
other Unicode look-alikes, and you *MUST* *NOT* drop, add, or reorder
|
|
296
|
+
any of these glyphs.
|
|
297
|
+
|
|
249
298
|
- When `<ase-tpl-head/>` (no title attribute) should be expanded, use:
|
|
250
299
|
|
|
251
300
|
<template>
|
|
@@ -360,3 +409,4 @@ Template Patterns
|
|
|
360
409
|
clamped to zero so an over-long text never yields a negative count):
|
|
361
410
|
|
|
362
411
|
<template><text/><ws/></template>
|
|
412
|
+
|
package/plugin/package.json
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"homepage": "http://github.com/rse/ase",
|
|
7
7
|
"repository": { "url": "git+https://github.com/rse/ase.git", "type": "git" },
|
|
8
8
|
"bugs": { "url": "http://github.com/rse/ase/issues" },
|
|
9
|
-
"version": "0.9.
|
|
9
|
+
"version": "0.9.38",
|
|
10
10
|
"license": "Apache-2.0",
|
|
11
11
|
"author": {
|
|
12
12
|
"name": "Dr. Ralf S. Engelschall",
|
|
@@ -121,6 +121,22 @@ interface quality, quality attributes, and architecture governance.
|
|
|
121
121
|
|
|
122
122
|
<flow>
|
|
123
123
|
1. <step id="STEP 1: Investigate Code Base">
|
|
124
|
+
|
|
125
|
+
<if condition="<ase-project-boxing/> is equal `black`">
|
|
126
|
+
|
|
127
|
+
The project source artifacts are classified as a *black box*, so
|
|
128
|
+
the user does *not* want the architecture inspected or its findings
|
|
129
|
+
surfaced. *Skip* the entire investigation and reporting: do *not*
|
|
130
|
+
invoke any `Agent` tool and do *not* read any source, only output
|
|
131
|
+
the following <template/> and then *SKIP* the remaining steps STEP 2
|
|
132
|
+
through STEP 4:
|
|
133
|
+
|
|
134
|
+
<template>
|
|
135
|
+
<ase-tpl-bullet-normal/> **ARCHITECTURE ANALYSIS**: *suppressed* (`project.boxing` is `black`)
|
|
136
|
+
</template>
|
|
137
|
+
|
|
138
|
+
</if>
|
|
139
|
+
|
|
124
140
|
Investigate the code from an *architectural* perspective. If the
|
|
125
141
|
code base is large, you *MUST* use the `Agent` tool (not inline
|
|
126
142
|
work) to create multiple sub-agents to split the investigation
|
|
@@ -54,6 +54,20 @@ problems in *performance* and *efficiency*, or problems in *security*.
|
|
|
54
54
|
|
|
55
55
|
2. <step id="STEP 2: Investigate Code Base">
|
|
56
56
|
|
|
57
|
+
<if condition="<ase-project-boxing/> is equal `black`">
|
|
58
|
+
|
|
59
|
+
The project source artifacts are classified as a *black box*, so
|
|
60
|
+
the user does *not* want them inspected or their problems surfaced.
|
|
61
|
+
*Skip* the entire investigation and analysis: do *not* invoke any
|
|
62
|
+
`Glob` or `Agent` tool and do *not* read any source, only output
|
|
63
|
+
the following <template/> and then *SKIP* the remaining step STEP 3:
|
|
64
|
+
|
|
65
|
+
<template>
|
|
66
|
+
<ase-tpl-bullet-normal/> **CODE ANALYSIS**: *suppressed* (`project.boxing` is `black`)
|
|
67
|
+
</template>
|
|
68
|
+
|
|
69
|
+
</if>
|
|
70
|
+
|
|
57
71
|
First, use the following <template/> to give a hint on this step:
|
|
58
72
|
|
|
59
73
|
<template>
|
|
@@ -109,14 +123,19 @@ problems in *performance* and *efficiency*, or problems in *security*.
|
|
|
109
123
|
|
|
110
124
|
3. <step id="STEP 3: Show Results">
|
|
111
125
|
|
|
112
|
-
Before reporting,
|
|
113
|
-
|
|
114
|
-
`LOW
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
126
|
+
Before reporting, determine the *effective severity floor* <floor/>:
|
|
127
|
+
define the ordinal rank `LOW`=1, `MEDIUM`=2, `HIGH`=3, start from
|
|
128
|
+
<floor><getopt-option-severity/></floor> (default `LOW`), and - if
|
|
129
|
+
<ase-project-boxing/> is equal `grey` - raise <floor/> to `MEDIUM`
|
|
130
|
+
whenever its current rank is below `rank(MEDIUM)` (grey boxing
|
|
131
|
+
surfaces only *material* findings of severity `MEDIUM` and above).
|
|
132
|
+
|
|
133
|
+
Then *apply the effective severity floor* <floor/>: *Keep* a detected
|
|
134
|
+
problem if and only if its `severity` field is `ACCEPTED` *or*
|
|
135
|
+
`rank(severity)` is greater than or equal to `rank(<floor/>)`;
|
|
136
|
+
*silently drop* all other problems (they are neither reported nor
|
|
137
|
+
persisted). With the default floor `LOW`, all problems are kept.
|
|
138
|
+
`ACCEPTED` problems are *never* dropped.
|
|
120
139
|
|
|
121
140
|
Then renumber the surviving problems contiguously as `P<n/>` with
|
|
122
141
|
<n/> = 1, 2, ... in the original ordering. If *all* problems are
|
|
@@ -140,8 +140,11 @@ permitted way to persist artifacts is via `ase_task_save(...)`.
|
|
|
140
140
|
You *MUST* perform the following sub-steps *internally* and *without
|
|
141
141
|
any output* until and including the recommendation decision. Only
|
|
142
142
|
sub-steps 4-6 below are allowed to produce output, and only if
|
|
143
|
-
<getopt-option-auto/> is equal `false
|
|
144
|
-
|
|
143
|
+
<getopt-option-auto/> is equal `false` *and* <ase-project-boxing/>
|
|
144
|
+
is *not* equal `black`.
|
|
145
|
+
|
|
146
|
+
If <getopt-option-auto/> is equal `true` or <ase-project-boxing/> is
|
|
147
|
+
equal `black`, *skip* the reporting sub-steps 4-6 entirely (perform
|
|
145
148
|
no output at all) to speed up processing.
|
|
146
149
|
|
|
147
150
|
1. *Propose* corresponding *feature approach*, including optionally,
|
|
@@ -187,7 +190,7 @@ permitted way to persist artifacts is via `ase_task_save(...)`.
|
|
|
187
190
|
<ase-tpl-foot title="APPROACHES"/>
|
|
188
191
|
</template>
|
|
189
192
|
|
|
190
|
-
7. <if condition="<getopt-option-auto/> is not equal `true`">
|
|
193
|
+
7. <if condition="<getopt-option-auto/> is not equal `true` and <ase-project-boxing/> is not equal `black`">
|
|
191
194
|
|
|
192
195
|
In the following, you *MUST* *NOT* use your built-in
|
|
193
196
|
<user-dialog-tool/> tool! Instead, you *MUST* just show a
|
|
@@ -43,6 +43,23 @@ code and *explain* it in a *brief*, *standardized*, and *concise* way.
|
|
|
43
43
|
Second, explain *WHY* the code does it (*rationale*).
|
|
44
44
|
|
|
45
45
|
Keep your explanations *brief* and *concise*.
|
|
46
|
+
|
|
47
|
+
<if condition="<ase-project-boxing/> is equal `black`">
|
|
48
|
+
|
|
49
|
+
The project source artifacts are classified as a *black box*, so the
|
|
50
|
+
user wants only the *minimal* surface explanation. Output *only* the
|
|
51
|
+
*WHAT* block (omit the *WHY* block) with the following <template/>:
|
|
52
|
+
|
|
53
|
+
<template>
|
|
54
|
+
<ase-tpl-bullet-normal/> **WHAT** (You should know what):
|
|
55
|
+
- [...]
|
|
56
|
+
- [...]
|
|
57
|
+
- [...]
|
|
58
|
+
</template>
|
|
59
|
+
|
|
60
|
+
</if>
|
|
61
|
+
<else>
|
|
62
|
+
|
|
46
63
|
Output the result with the following <template/>:
|
|
47
64
|
|
|
48
65
|
<template>
|
|
@@ -56,9 +73,21 @@ code and *explain* it in a *brief*, *standardized*, and *concise* way.
|
|
|
56
73
|
- [...]
|
|
57
74
|
- [...]
|
|
58
75
|
</template>
|
|
76
|
+
|
|
77
|
+
</else>
|
|
59
78
|
</step>
|
|
60
79
|
|
|
61
80
|
3. <step id="STEP 3: ANALOGY and DIAGRAM">
|
|
81
|
+
|
|
82
|
+
<if condition="<ase-project-boxing/> is equal `black`">
|
|
83
|
+
|
|
84
|
+
The project source artifacts are classified as a *black box*, so
|
|
85
|
+
deeper elaboration is *not* wanted. *Skip* this STEP 3 and the
|
|
86
|
+
following STEP 4 entirely: do *not* output any ANALOGY, DIAGRAM,
|
|
87
|
+
CRUXES, or GOTCHAS, and do *not* dispatch any diagram rendering.
|
|
88
|
+
|
|
89
|
+
</if>
|
|
90
|
+
|
|
62
91
|
**Give insights with ANALOGY and DIAGRAM**.
|
|
63
92
|
|
|
64
93
|
First, give an analogy by comparing the code to something from
|
|
@@ -34,6 +34,21 @@ Give *insights* into the project through the source code of <getopt-arguments/>.
|
|
|
34
34
|
|
|
35
35
|
<flow>
|
|
36
36
|
1. <step id="STEP 1: PROJECT ABSTRACT">
|
|
37
|
+
|
|
38
|
+
<if condition="<ase-project-boxing/> is equal `black`">
|
|
39
|
+
|
|
40
|
+
The project source artifacts are classified as a *black box*, so the
|
|
41
|
+
user does *not* want them inspected or their internals surfaced.
|
|
42
|
+
*Skip* the entire insight gathering: do *not* read any source, only
|
|
43
|
+
output the following <template/> and then *SKIP* the remaining steps
|
|
44
|
+
STEP 2 through STEP 4:
|
|
45
|
+
|
|
46
|
+
<template>
|
|
47
|
+
<ase-tpl-bullet-normal/> **PROJECT INSIGHT**: *suppressed* (`project.boxing` is `black`)
|
|
48
|
+
</template>
|
|
49
|
+
|
|
50
|
+
</if>
|
|
51
|
+
|
|
37
52
|
Determine an <abstract/> summary of this project.
|
|
38
53
|
For this, check a potentially existing `README.*` file
|
|
39
54
|
or scan the source files and figure it out indirectly.
|
|
@@ -33,6 +33,21 @@ related to a set of code quality aspects.
|
|
|
33
33
|
|
|
34
34
|
1. <step id="STEP 1: Investigation">
|
|
35
35
|
|
|
36
|
+
<if condition="<ase-project-boxing/> is equal `black`">
|
|
37
|
+
|
|
38
|
+
The project source artifacts are classified as a *black box*, so
|
|
39
|
+
the user does *not* want them inspected or their problems surfaced.
|
|
40
|
+
*Skip* the entire investigation and reporting: do *not* invoke any
|
|
41
|
+
`Glob` or `Agent` tool and do *not* read any source, only output
|
|
42
|
+
the following <template/> and then *SKIP* the remaining steps STEP 2
|
|
43
|
+
and STEP 3:
|
|
44
|
+
|
|
45
|
+
<template>
|
|
46
|
+
<ase-tpl-bullet-normal/> **LINT**: *suppressed* (`project.boxing` is `black`)
|
|
47
|
+
</template>
|
|
48
|
+
|
|
49
|
+
</if>
|
|
50
|
+
|
|
36
51
|
First, use the following <template/> to give a hint on this step:
|
|
37
52
|
|
|
38
53
|
<template>
|
|
@@ -76,13 +91,18 @@ related to a set of code quality aspects.
|
|
|
76
91
|
sort the list by `file` and then numerically by `line`, and set
|
|
77
92
|
<problems/> to that list.
|
|
78
93
|
|
|
79
|
-
Then
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
94
|
+
Then determine the *effective severity floor* <floor/>: define the
|
|
95
|
+
ordinal rank `LOW`=1, `MEDIUM`=2, `HIGH`=3, start from
|
|
96
|
+
<floor><getopt-option-severity/></floor> (default `LOW`), and - if
|
|
97
|
+
<ase-project-boxing/> is equal `grey` - raise <floor/> to `MEDIUM`
|
|
98
|
+
whenever its current rank is below `rank(MEDIUM)` (grey boxing
|
|
99
|
+
surfaces only *material* findings of severity `MEDIUM` and above).
|
|
100
|
+
|
|
101
|
+
Then *apply the effective severity floor* <floor/>: *Keep* a problem
|
|
102
|
+
in <problems/> if and only if its `severity` field is `ACCEPTED` *or*
|
|
103
|
+
`rank(severity)` is greater than or equal to `rank(<floor/>)`;
|
|
104
|
+
*silently drop* all other problems. With the default floor `LOW`, all
|
|
105
|
+
problems are kept. `ACCEPTED` problems are *never* dropped.
|
|
86
106
|
|
|
87
107
|
You *MUST* *NOT* output anything else in this step 1.
|
|
88
108
|
|
|
@@ -145,6 +165,7 @@ related to a set of code quality aspects.
|
|
|
145
165
|
|
|
146
166
|
2. Set <context></context> (set to empty).
|
|
147
167
|
Set <diff></diff> (set to empty).
|
|
168
|
+
Set <diff-condensed></diff-condensed> (set to empty).
|
|
148
169
|
|
|
149
170
|
3. Iterate over the change set:
|
|
150
171
|
|
|
@@ -153,7 +174,9 @@ related to a set of code quality aspects.
|
|
|
153
174
|
1. Set <file/> to the `file` field of <item/>.
|
|
154
175
|
Set <change-hunks/> to the `change-hunks` field of <item/>.
|
|
155
176
|
|
|
156
|
-
|
|
177
|
+
Unless <ase-project-boxing/> is equal `grey` (where the
|
|
178
|
+
full unified diff is suppressed and this per-file header is
|
|
179
|
+
unused), set <diff-file/> to the following <template/>:
|
|
157
180
|
|
|
158
181
|
<template>
|
|
159
182
|
--- <file/> (original)
|
|
@@ -170,11 +193,18 @@ related to a set of code quality aspects.
|
|
|
170
193
|
Set <new-text/> to the `new_text` field of <item/>.
|
|
171
194
|
Set <context-after/> to the `context_after` field of <item/>.
|
|
172
195
|
|
|
173
|
-
2.
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
196
|
+
2. *Skip* this substep entirely when <ase-project-boxing/>
|
|
197
|
+
is equal `grey` - the full unified diff is suppressed
|
|
198
|
+
there, so none of the <hunk-body/>, <old-count/>,
|
|
199
|
+
<new-count/>, <old-start/>, or <new-start/> values
|
|
200
|
+
below are consumed (substep 4 builds only the condensed
|
|
201
|
+
one-liner instead).
|
|
202
|
+
|
|
203
|
+
Otherwise, determine the hunk *body* as an ordered list
|
|
204
|
+
of lines, each carrying a one-character prefix (` ` for
|
|
205
|
+
context, `-` for old-side, `+` for new-side). Build it
|
|
206
|
+
by concatenating, in order and *skipping any part that
|
|
207
|
+
is empty*:
|
|
178
208
|
|
|
179
209
|
- one ` `-prefixed line for *each* line of
|
|
180
210
|
<context-before/> (if non-empty),
|
|
@@ -217,7 +247,27 @@ related to a set of code quality aspects.
|
|
|
217
247
|
|
|
218
248
|
<template>`<file/>`:<line/></template>
|
|
219
249
|
|
|
220
|
-
4.
|
|
250
|
+
4. <if condition="<ase-project-boxing/> is equal `grey`">
|
|
251
|
+
|
|
252
|
+
The full unified diff is *suppressed* under grey boxing
|
|
253
|
+
(see substep 5 below), so *skip* the full-diff append
|
|
254
|
+
and instead build only a *condensed* one-line
|
|
255
|
+
representation of this hunk: determine <old-snippet/>
|
|
256
|
+
as the *single-line* collapse of <old-text/> (join its
|
|
257
|
+
lines with ` ⏎ `, or `∅` when <old-text/> is empty for
|
|
258
|
+
a pure insertion) and <new-snippet/> as the same
|
|
259
|
+
collapse of <new-text/> (or `∅` when empty for a pure
|
|
260
|
+
deletion). Then append the following <template/> to
|
|
261
|
+
<diff-condensed/> as a new line:
|
|
262
|
+
|
|
263
|
+
<template>
|
|
264
|
+
<ase-tpl-bullet-signal/> `<file/>`:<line/>: `<old-snippet/>` → `<new-snippet/>`
|
|
265
|
+
</template>
|
|
266
|
+
|
|
267
|
+
</if>
|
|
268
|
+
<else>
|
|
269
|
+
|
|
270
|
+
Append the following <template/> to <diff-file/>,
|
|
221
271
|
emitting <hunk-body/> verbatim (one already-prefixed
|
|
222
272
|
line per line, with no extra blank or space-only lines):
|
|
223
273
|
|
|
@@ -226,9 +276,12 @@ related to a set of code quality aspects.
|
|
|
226
276
|
<hunk-body/>
|
|
227
277
|
</template>
|
|
228
278
|
|
|
279
|
+
</else>
|
|
280
|
+
|
|
229
281
|
</for>
|
|
230
282
|
|
|
231
|
-
3.
|
|
283
|
+
3. Unless <ase-project-boxing/> is equal `grey` (where
|
|
284
|
+
<diff-file/> is unused), append <diff-file/> to <diff/>.
|
|
232
285
|
|
|
233
286
|
</for>
|
|
234
287
|
|
|
@@ -241,7 +294,25 @@ related to a set of code quality aspects.
|
|
|
241
294
|
|
|
242
295
|
</template>
|
|
243
296
|
|
|
244
|
-
5. <if condition="<getopt-option-auto/> is not 'true'">
|
|
297
|
+
5. <if condition="<getopt-option-auto/> is not 'true' and <ase-project-boxing/> is not equal `black`">
|
|
298
|
+
|
|
299
|
+
<if condition="<ase-project-boxing/> is equal `grey`">
|
|
300
|
+
|
|
301
|
+
The project source artifacts are classified as a *grey box*, so
|
|
302
|
+
the user does *not* want the full artifact internals surfaced:
|
|
303
|
+
*suppress* the full unified diff and instead show only the
|
|
304
|
+
*condensed* one-line-per-hunk representation. Report the
|
|
305
|
+
solution with the following <template/>:
|
|
306
|
+
|
|
307
|
+
<template>
|
|
308
|
+
<ase-tpl-bullet-normal/> **<aspect/> SOLUTION**:
|
|
309
|
+
|
|
310
|
+
<diff-condensed/>
|
|
311
|
+
|
|
312
|
+
</template>
|
|
313
|
+
|
|
314
|
+
</if>
|
|
315
|
+
<else>
|
|
245
316
|
|
|
246
317
|
Report the solution with the following <template/>:
|
|
247
318
|
|
|
@@ -254,6 +325,8 @@ related to a set of code quality aspects.
|
|
|
254
325
|
|
|
255
326
|
</template>
|
|
256
327
|
|
|
328
|
+
</else>
|
|
329
|
+
|
|
257
330
|
</if>
|
|
258
331
|
<else>
|
|
259
332
|
|
|
@@ -140,8 +140,11 @@ permitted way to persist artifacts is via `ase_task_save(...)`.
|
|
|
140
140
|
You *MUST* perform the following sub-steps *internally* and *without
|
|
141
141
|
any output* until and including the recommendation decision. Only
|
|
142
142
|
sub-steps 4-6 below are allowed to produce output, and only if
|
|
143
|
-
<getopt-option-auto/> is equal `false
|
|
144
|
-
|
|
143
|
+
<getopt-option-auto/> is equal `false` *and* <ase-project-boxing/>
|
|
144
|
+
is *not* equal `black`.
|
|
145
|
+
|
|
146
|
+
If <getopt-option-auto/> is equal `true` or <ase-project-boxing/> is
|
|
147
|
+
equal `black`, *skip* the reporting sub-steps 4-6 entirely (perform
|
|
145
148
|
no output at all) to speed up processing.
|
|
146
149
|
|
|
147
150
|
1. *Propose* corresponding *refactoring approach*, including
|
|
@@ -187,7 +190,7 @@ permitted way to persist artifacts is via `ase_task_save(...)`.
|
|
|
187
190
|
<ase-tpl-foot title="APPROACHES"/>
|
|
188
191
|
</template>
|
|
189
192
|
|
|
190
|
-
7. <if condition="<getopt-option-auto/> is not `true`">
|
|
193
|
+
7. <if condition="<getopt-option-auto/> is not equal `true` and <ase-project-boxing/> is not equal `black`">
|
|
191
194
|
|
|
192
195
|
In the following, you *MUST* *NOT* use your built-in
|
|
193
196
|
<user-dialog-tool/> tool! Instead, you *MUST* just show a
|
|
@@ -194,8 +194,11 @@ permitted way to persist artifacts is via `ase_task_save(...)`.
|
|
|
194
194
|
You *MUST* perform the following sub-steps *internally* and *without
|
|
195
195
|
any output* until and including the recommendation decision. Only
|
|
196
196
|
sub-steps 4-6 below are allowed to produce output, and only if
|
|
197
|
-
<getopt-option-auto/> is equal `false
|
|
198
|
-
|
|
197
|
+
<getopt-option-auto/> is equal `false` *and* <ase-project-boxing/>
|
|
198
|
+
is *not* equal `black`.
|
|
199
|
+
|
|
200
|
+
If <getopt-option-auto/> is equal `true` or <ase-project-boxing/> is
|
|
201
|
+
equal `black`, *skip* the reporting sub-steps 4-6 entirely (perform
|
|
199
202
|
no output at all) to speed up processing.
|
|
200
203
|
|
|
201
204
|
1. *Propose* corresponding *resolution approach*, including optionally,
|
|
@@ -241,7 +244,7 @@ permitted way to persist artifacts is via `ase_task_save(...)`.
|
|
|
241
244
|
<ase-tpl-foot title="APPROACHES"/>
|
|
242
245
|
</template>
|
|
243
246
|
|
|
244
|
-
7. <if condition="<getopt-option-auto/> is not `true`">
|
|
247
|
+
7. <if condition="<getopt-option-auto/> is not equal `true` and <ase-project-boxing/> is not equal `black`">
|
|
245
248
|
|
|
246
249
|
In the following, you *MUST* *NOT* use your built-in
|
|
247
250
|
<user-dialog-tool/> tool! Instead, you *MUST* just show a
|
|
@@ -33,6 +33,21 @@ Analyze documents for spelling, punctuation, or grammar errors
|
|
|
33
33
|
|
|
34
34
|
1. <step id="STEP 1: Investigation">
|
|
35
35
|
|
|
36
|
+
<if condition="<ase-project-boxing/> is equal `black`">
|
|
37
|
+
|
|
38
|
+
The project source artifacts are classified as a *black box*, so
|
|
39
|
+
the user does *not* want them inspected or their problems surfaced.
|
|
40
|
+
*Skip* the entire investigation and reporting: do *not* invoke any
|
|
41
|
+
`Glob` or `Agent` tool and do *not* read any document, only output
|
|
42
|
+
the following <template/> and then *SKIP* the remaining steps STEP 2
|
|
43
|
+
and STEP 3:
|
|
44
|
+
|
|
45
|
+
<template>
|
|
46
|
+
<ase-tpl-bullet-normal/> **PROOFREAD**: *suppressed* (`project.boxing` is `black`)
|
|
47
|
+
</template>
|
|
48
|
+
|
|
49
|
+
</if>
|
|
50
|
+
|
|
36
51
|
First, use the following <template/> to give a hint on this step:
|
|
37
52
|
|
|
38
53
|
<template>
|
|
@@ -141,7 +156,26 @@ Analyze documents for spelling, punctuation, or grammar errors
|
|
|
141
156
|
<description/>
|
|
142
157
|
</template>
|
|
143
158
|
|
|
144
|
-
3. <if condition="<getopt-option-auto/> is not 'true'">
|
|
159
|
+
3. <if condition="<getopt-option-auto/> is not 'true' and <ase-project-boxing/> is equal `grey`">
|
|
160
|
+
|
|
161
|
+
The project source artifacts are classified as a *grey box*, so
|
|
162
|
+
the user does *not* want the full artifact internals surfaced:
|
|
163
|
+
*suppress* the full unified diff and instead show only a
|
|
164
|
+
*condensed* one-line representation. Determine <old-snippet/>
|
|
165
|
+
as the *single-line* collapse of <old-text/> (join its lines
|
|
166
|
+
with ` ⏎ `, or `∅` when <old-text/> is empty for a pure
|
|
167
|
+
insertion) and <new-snippet/> as the same collapse of
|
|
168
|
+
<new-text/> (or `∅` when empty for a pure deletion). Then
|
|
169
|
+
report the correction with the following <template/>:
|
|
170
|
+
|
|
171
|
+
<template>
|
|
172
|
+
|
|
173
|
+
<ase-tpl-bullet-normal/> **<type/> CORRECTION**: `<old-snippet/>` → `<new-snippet/>`
|
|
174
|
+
|
|
175
|
+
</template>
|
|
176
|
+
|
|
177
|
+
</if>
|
|
178
|
+
<elseif condition="<getopt-option-auto/> is not 'true'">
|
|
145
179
|
|
|
146
180
|
Determine the hunk *body* as an ordered list of lines, each
|
|
147
181
|
carrying a one-character prefix (` ` for context, `-` for
|
|
@@ -195,7 +229,7 @@ Analyze documents for spelling, punctuation, or grammar errors
|
|
|
195
229
|
|
|
196
230
|
</template>
|
|
197
231
|
|
|
198
|
-
</
|
|
232
|
+
</elseif>
|
|
199
233
|
|
|
200
234
|
4. <if condition="<getopt-option-auto/> is not 'true'">
|
|
201
235
|
|
|
@@ -38,9 +38,12 @@ Format
|
|
|
38
38
|
The *ChangeLog* file is a Markdown formatted file named `CHANGELOG.md`,
|
|
39
39
|
and contains sections with headers in the style `N.M.K (YYYY-MM-DD)`.
|
|
40
40
|
|
|
41
|
-
Each *ChangeLog* entry is always formatted as
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
Each *ChangeLog* entry is always formatted as...
|
|
42
|
+
|
|
43
|
+
`<change-type/> [<artifact-kind/>]: <summary/>`
|
|
44
|
+
|
|
45
|
+
...where the <change-type/> is one of the following tags and their usual
|
|
46
|
+
related changes:
|
|
44
47
|
|
|
45
48
|
- `FEATURE`: new functionality or configuration
|
|
46
49
|
- `IMPROVEMENT`: improved functionality or configuration
|
|
@@ -49,9 +52,21 @@ changes:
|
|
|
49
52
|
- `CLEANUP`: cleaned up functionality or configuration
|
|
50
53
|
- `REFACTOR`: refactored functionality or configuration
|
|
51
54
|
|
|
55
|
+
The <artifact-kind/> is one or more of the following *artifact* tags,
|
|
56
|
+
classifying which kind of artifact the change primarily touches. If
|
|
57
|
+
multiple artifact kinds apply, comma-separate them
|
|
58
|
+
(e.g. `[arch, code]`):
|
|
59
|
+
|
|
60
|
+
- `spec`: requirement/specification artifacts
|
|
61
|
+
- `arch`: architecture/design artifacts
|
|
62
|
+
- `code`: source code artifacts
|
|
63
|
+
- `docs`: documentation artifacts
|
|
64
|
+
- `infr`: infrastructure/build/tooling artifacts
|
|
65
|
+
- `othr`: any other artifacts
|
|
66
|
+
|
|
52
67
|
The <summary/> is not longer than about 60-80 characters. The
|
|
53
68
|
*ChangeLog* entries for a single product release version are also always
|
|
54
|
-
grouped and sorted according to the above <
|
|
69
|
+
grouped and sorted according to the above <change-type/> list.
|
|
55
70
|
|
|
56
71
|
Processing
|
|
57
72
|
----------
|
|
@@ -123,6 +138,16 @@ Processing
|
|
|
123
138
|
For each Git commit, reduce the Git commit messages to a single
|
|
124
139
|
short <summary/> sentence, not longer than 60-80 characters.
|
|
125
140
|
|
|
141
|
+
For each entry, also determine the <artifact-kind/> *artifact kind*
|
|
142
|
+
tag(s) from the paths of the changed files. To classify a changed
|
|
143
|
+
file to its artifact class, call the `ase_artifact_list(kind: [
|
|
144
|
+
... ])` tool of the `ase` MCP server *once*, passing the `kind`
|
|
145
|
+
tokens (`spec`, `arch`, `code`, `docs`, `infr`, `othr`), and read
|
|
146
|
+
the returned `artifacts` array of `{ kind, files }` objects to match
|
|
147
|
+
each changed file to its kind. Map the matched lower-cased kind back
|
|
148
|
+
to its upper-cased <artifact-kind/> tag, and comma-separate multiple
|
|
149
|
+
tags when more than one artifact class applies.
|
|
150
|
+
|
|
126
151
|
If a <summary/> is too short or especially is not comprehensible
|
|
127
152
|
enough because of too little context information, add some essential
|
|
128
153
|
context, especially references to the class/module/package, etc.
|
|
@@ -144,11 +169,11 @@ Processing
|
|
|
144
169
|
Without immediately modifying the `CHANGELOG.md` file, *consolidate*
|
|
145
170
|
the entries in the first (most recent) section only, by summarizing
|
|
146
171
|
and merging closely related entries. Perform the entry consolidation
|
|
147
|
-
per <
|
|
172
|
+
per <change-type/> group only.
|
|
148
173
|
|
|
149
174
|
Without immediately modifying the `CHANGELOG.md` file, *sort* the
|
|
150
175
|
entries in the first (most recent) section only. Instead of the
|
|
151
|
-
chronological commit order, group the entries by the <
|
|
176
|
+
chronological commit order, group the entries by the <change-type/>s.
|
|
152
177
|
|
|
153
178
|
</step>
|
|
154
179
|
|
|
@@ -15,10 +15,13 @@ The `ase-meta-changelog` skill helps to *complete*, *consolidate*, and
|
|
|
15
15
|
file, based on the underlying *Git* commits and the currently staged
|
|
16
16
|
changes in the Git *index*.
|
|
17
17
|
|
|
18
|
-
Each entry is formatted as `<
|
|
19
|
-
one of `FEATURE`, `IMPROVEMENT`, `BUGFIX`,
|
|
20
|
-
`
|
|
21
|
-
|
|
18
|
+
Each entry is formatted as `<change-type> [<artifact-kind>]: <summary>`
|
|
19
|
+
where *change-type* is one of `FEATURE`, `IMPROVEMENT`, `BUGFIX`,
|
|
20
|
+
`UPDATE`, `CLEANUP`, or `REFACTOR`, and *artifact-kind* is one or more
|
|
21
|
+
comma-separated *artifact class* tags out of `spec`, `arch`, `code`,
|
|
22
|
+
`docs`, `infr`, or `othr`. Entries are grouped and sorted by this
|
|
23
|
+
prefix. The date in the section header is also updated to the current
|
|
24
|
+
date.
|
|
22
25
|
|
|
23
26
|
## EXAMPLES
|
|
24
27
|
|
|
@@ -123,10 +123,28 @@ Procedure
|
|
|
123
123
|
*not* output any further explanation.
|
|
124
124
|
</if>
|
|
125
125
|
|
|
126
|
+
4. <if condition="
|
|
127
|
+
<ase-project-boxing/> is equal `black` and
|
|
128
|
+
(<getopt-option-coherence/> is equal `true` or
|
|
129
|
+
<getopt-option-risk/> is equal `true` or
|
|
130
|
+
<getopt-option-blast/> is equal `true`)
|
|
131
|
+
">
|
|
132
|
+
The project source artifacts are classified as a *black box*, so
|
|
133
|
+
the user does *not* want the staged changes scrutinized or their
|
|
134
|
+
coherence, risk, and blast-radius findings surfaced. The
|
|
135
|
+
requested scrutiny of STEP 3 through STEP 5 is therefore
|
|
136
|
+
suppressed: only output the following <template/> and then *SKIP*
|
|
137
|
+
the remaining steps STEP 3 through STEP 5:
|
|
138
|
+
|
|
139
|
+
<template>
|
|
140
|
+
<ase-tpl-bullet-normal/> **DIFF SCRUTINY**: *suppressed* (`project.boxing` is `black`)
|
|
141
|
+
</template>
|
|
142
|
+
</if>
|
|
143
|
+
|
|
126
144
|
</step>
|
|
127
145
|
|
|
128
146
|
3. <step id="STEP 3: Assess Intent Coherence"
|
|
129
|
-
condition="<getopt-option-coherence/> is equal `true` and <diff/> is NOT empty">
|
|
147
|
+
condition="<getopt-option-coherence/> is equal `true` and <diff/> is NOT empty and <ase-project-boxing/> is not equal `black`">
|
|
130
148
|
|
|
131
149
|
1. From the *same* captured <diff/> and <stat/>, *reconstruct the
|
|
132
150
|
single intended change* as a thesis - the one logical, coherent purpose
|
|
@@ -203,7 +221,7 @@ Procedure
|
|
|
203
221
|
</step>
|
|
204
222
|
|
|
205
223
|
4. <step id="STEP 4: Score Against Risk Rubric"
|
|
206
|
-
condition="<getopt-option-risk/> is equal `true` and <diff/> is NOT empty">
|
|
224
|
+
condition="<getopt-option-risk/> is equal `true` and <diff/> is NOT empty and <ase-project-boxing/> is not equal `black`">
|
|
207
225
|
|
|
208
226
|
1. Score the *same* captured <diff/> and <stat/> information
|
|
209
227
|
against the four-axis rubric below. Each axis is scored on an
|
|
@@ -275,7 +293,7 @@ Procedure
|
|
|
275
293
|
</step>
|
|
276
294
|
|
|
277
295
|
5. <step id="STEP 5: Render Blast-Radius Map"
|
|
278
|
-
condition="<getopt-option-blast/> is equal `true` and <diff/> is NOT empty">
|
|
296
|
+
condition="<getopt-option-blast/> is equal `true` and <diff/> is NOT empty and <ase-project-boxing/> is not equal `black`">
|
|
279
297
|
|
|
280
298
|
1. From the *same* captured <diff/> and <stat/>, *extract the
|
|
281
299
|
touched modules* - the distinct changed source files (or their
|
|
@@ -67,6 +67,19 @@ Procedure
|
|
|
67
67
|
|
|
68
68
|
2. <step id="STEP 2: Review Investigation">
|
|
69
69
|
|
|
70
|
+
<if condition="<ase-project-boxing/> is equal `black`">
|
|
71
|
+
|
|
72
|
+
The project source artifacts are classified as a *black box*, so
|
|
73
|
+
the user does *not* want the staged changes scrutinized or their
|
|
74
|
+
findings surfaced. *Skip* the entire review investigation: do
|
|
75
|
+
*not* invoke the `Agent` tool and do *not* read any change, set
|
|
76
|
+
<findings/> to the *empty* list, set <verdict/> to `SKIPPED (boxing:
|
|
77
|
+
black)`, set <summary/> to a *one-line* neutral restatement of the
|
|
78
|
+
change intent derived solely from STEP 1, and proceed *directly* to
|
|
79
|
+
STEP 3.
|
|
80
|
+
|
|
81
|
+
</if>
|
|
82
|
+
|
|
70
83
|
First, use the following <template/> to give a hint on this step:
|
|
71
84
|
|
|
72
85
|
<template>
|
|
@@ -102,13 +115,20 @@ Procedure
|
|
|
102
115
|
severity floor below, so the floor only affects which findings are
|
|
103
116
|
*rendered*, never the verdict.
|
|
104
117
|
|
|
105
|
-
Then
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
118
|
+
Then determine the *effective severity floor* <floor/>: define the
|
|
119
|
+
ordinal rank `LOW`=1, `MEDIUM`=2, `HIGH`=3, start from
|
|
120
|
+
<floor><getopt-option-severity/></floor> (default `LOW`), and - if
|
|
121
|
+
<ase-project-boxing/> is equal `grey` - raise <floor/> to `MEDIUM`
|
|
122
|
+
whenever its current rank is below `rank(MEDIUM)` (grey boxing
|
|
123
|
+
surfaces only *material* findings of severity `MEDIUM` and above).
|
|
124
|
+
The floor affects only which findings are *rendered*, never the
|
|
125
|
+
<verdict/> derived above.
|
|
126
|
+
|
|
127
|
+
Then *apply the effective severity floor* <floor/>: *Keep* a finding
|
|
128
|
+
in <findings/> if and only if its `severity` field is `ACCEPTED` *or*
|
|
129
|
+
`rank(severity)` is greater than or equal to `rank(<floor/>)`;
|
|
130
|
+
*silently drop* all other findings. With the default floor `LOW`, all
|
|
131
|
+
findings are kept. `ACCEPTED` findings are *never* dropped.
|
|
112
132
|
|
|
113
133
|
You *MUST* *NOT* output anything else in this STEP 2.
|
|
114
134
|
|