@rse/ase 2.0.1 → 2.0.3
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-agent-definition-core.js +111 -87
- package/dst/ase-agent-fleet.js +1 -1
- package/dst/ase-agent-runtime-claim.js +5 -3
- package/dst/ase-agent-runtime-engine.js +1 -1
- package/dst/ase-agent-runtime-phase.js +1 -1
- package/dst/ase-agent-runtime-request.js +1 -1
- package/dst/ase-agent-runtime.js +3 -5
- package/dst/ase-artifact.js +3 -3
- package/dst/ase-config-core.js +2 -16
- package/dst/ase-config-schema.js +1 -3
- package/dst/ase-config.js +4 -1
- package/dst/ase-hook.js +14 -19
- package/dst/ase-lib-daemon-cli.js +117 -4
- package/dst/ase-lib-server-cli.js +10 -10
- package/dst/ase-mcp.js +4 -4
- package/dst/ase-service-getopt.js +2 -2
- package/dst/ase-service-otel.js +4 -4
- package/dst/ase-service-skills.js +5 -15
- package/dst/ase-service.js +87 -210
- package/dst/ase-setup-common.js +1 -2
- package/dst/ase-setup-settings.js +6 -9
- package/dst/ase-setup.js +2 -3
- package/dst/ase-statusline.js +170 -170
- package/dst/ase-task-board-core.js +1 -1
- package/dst/ase-task-board-flow.js +7 -6
- package/dst/ase-task-board-graph.js +5 -4
- package/dst/ase-task-board-tui-control.js +51 -45
- package/dst/ase-task-board-tui-model.js +195 -181
- package/dst/ase-task-board-tui-popup.js +2 -3
- package/dst/ase-task-board-tui-view.js +88 -79
- package/dst/ase-task-board-web-client.css +1 -1
- package/dst/ase-task-board-web-client.js +2 -2
- package/dst/ase-task-board-web-server.js +4 -27
- package/dst/ase-task-board.js +1 -1
- package/dst/ase-task-format.js +1 -1
- package/dst/ase-task-store-client.js +17 -5
- package/dst/ase-task-store-core.js +5 -7
- package/dst/ase-task-store-issues.js +91 -0
- package/dst/ase-task-store-plugin-ase.js +7 -3
- package/dst/ase-task-store-plugin-gitea.js +11 -97
- package/dst/ase-task-store-plugin-github.js +5 -77
- package/dst/ase-task-store-plugin-gitlab.js +4 -83
- package/dst/ase-task.js +51 -23
- package/dst/ase-util-compat.js +1 -1
- package/dst/ase-util-diagram.js +16 -42
- package/dst/ase.js +5 -5
- package/dst/man/ase-agent-adhoc.1 +1 -1
- package/dst/man/ase-agent-condenser.1 +1 -1
- package/dst/man/ase-agent-editor.1 +1 -1
- package/dst/man/ase-agent-estimator.1 +1 -1
- package/dst/man/ase-agent-fleet.1 +1 -1
- package/dst/man/ase-agent-implementer.1 +1 -1
- package/dst/man/ase-agent-integrator.1 +1 -1
- package/dst/man/ase-agent-qualifier.1 +1 -1
- package/dst/man/ase-agent-rebooter.1 +1 -1
- package/dst/man/ase-agent-relay.1 +1 -1
- package/dst/man/ase-agent-researcher.1 +1 -1
- package/dst/man/ase-agent.1 +1 -1
- package/dst/man/ase-artifact-list.1 +1 -1
- package/dst/man/ase-artifact-name.1 +1 -1
- package/dst/man/ase-artifact.1 +1 -1
- package/dst/man/ase-config-delete.1 +1 -1
- package/dst/man/ase-config-edit.1 +1 -1
- package/dst/man/ase-config-get.1 +1 -1
- package/dst/man/ase-config-init.1 +1 -1
- package/dst/man/ase-config-list.1 +1 -1
- package/dst/man/ase-config-set.1 +1 -1
- package/dst/man/ase-config.1 +1 -1
- package/dst/man/ase-hook-permission-request.1 +1 -1
- package/dst/man/ase-hook-pre-tool-use.1 +1 -1
- package/dst/man/ase-hook-session-end.1 +1 -1
- package/dst/man/ase-hook-session-persona.1 +1 -1
- package/dst/man/ase-hook-session-start.1 +1 -1
- package/dst/man/ase-hook-stop.1 +1 -1
- package/dst/man/ase-hook-user-prompt-submit.1 +1 -1
- package/dst/man/ase-hook.1 +1 -1
- package/dst/man/ase-man.1 +1 -1
- package/dst/man/ase-mcp.1 +1 -1
- package/dst/man/ase-service-log.1 +1 -1
- package/dst/man/ase-service-send.1 +1 -1
- package/dst/man/ase-service-start.1 +1 -1
- package/dst/man/ase-service-status.1 +1 -1
- package/dst/man/ase-service-stop.1 +1 -1
- package/dst/man/ase-service.1 +1 -1
- package/dst/man/ase-setup-disable.1 +1 -1
- package/dst/man/ase-setup-enable.1 +1 -1
- package/dst/man/ase-setup-install.1 +1 -1
- package/dst/man/ase-setup-mcp.1 +1 -1
- package/dst/man/ase-setup-status.1 +1 -1
- package/dst/man/ase-setup-statusline.1 +1 -1
- package/dst/man/ase-setup-telemetry.1 +1 -1
- package/dst/man/ase-setup-uninstall.1 +1 -1
- package/dst/man/ase-setup-update.1 +1 -1
- package/dst/man/ase-setup.1 +1 -1
- package/dst/man/ase-spec-export.1 +1 -1
- package/dst/man/ase-spec-lint.1 +1 -1
- package/dst/man/ase-spec-preview.1 +1 -1
- package/dst/man/ase-spec.1 +1 -1
- package/dst/man/ase-statusline.1 +1 -1
- package/dst/man/ase-task-assign.1 +1 -1
- package/dst/man/ase-task-board.1 +3 -3
- package/dst/man/ase-task-delete.1 +1 -1
- package/dst/man/ase-task-edit.1 +1 -1
- package/dst/man/ase-task-idscheme.1 +1 -1
- package/dst/man/ase-task-lifecycle.1 +1 -1
- package/dst/man/ase-task-list.1 +1 -1
- package/dst/man/ase-task-load.1 +1 -1
- package/dst/man/ase-task-newid.1 +1 -1
- package/dst/man/ase-task-purge.1 +1 -1
- package/dst/man/ase-task-rename.1 +1 -1
- package/dst/man/ase-task-request.1 +1 -1
- package/dst/man/ase-task-save.1 +1 -1
- package/dst/man/ase-task-status.1 +1 -1
- package/dst/man/ase-task-store.1 +1 -1
- package/dst/man/ase-task-view.1 +1 -1
- package/dst/man/ase-task.1 +1 -1
- package/dst/man/ase-util-compat.1 +1 -1
- package/dst/man/ase-util-diagram.1 +1 -1
- package/dst/man/ase-util-meta.1 +1 -1
- package/dst/man/ase-util-metric.1 +1 -1
- package/dst/man/ase-util-mint.1 +1 -1
- package/dst/man/ase-util-worktree.1 +1 -1
- package/dst/man/ase-util.1 +1 -1
- package/dst/man/ase.1 +1 -1
- package/package.json +1 -1
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/.codex-plugin/plugin.json +1 -1
- package/plugin/.github/plugin/plugin.json +1 -1
- package/plugin/meta/ase-common-resolve.md +2 -2
- package/plugin/meta/ase-skill.md +7 -0
- package/plugin/mods/ase-mods.ts +16 -12
- package/plugin/skills/ase-arch-analyze/SKILL.md +3 -1
- package/plugin/skills/ase-code-analyze/SKILL.md +26 -10
- package/plugin/skills/ase-code-analyze/help.md +11 -6
- package/plugin/skills/ase-code-edit/SKILL.md +5 -4
- package/plugin/skills/ase-code-edit/help.md +1 -1
- package/plugin/skills/ase-code-lint/SKILL.md +52 -27
- package/plugin/skills/ase-code-lint/help.md +10 -5
- package/plugin/skills/ase-help-intent/data.md +60 -30
- package/plugin/skills/ase-help-skill/help.md +3 -4
- package/plugin/skills/ase-meta-quorum/SKILL.md +9 -0
- package/plugin/skills/ase-meta-quorum/help.md +5 -3
- package/plugin/skills/ase-meta-workflow/sample.md +5 -3
- package/plugin/skills/ase-repo-changelog/SKILL.md +8 -9
- package/plugin/skills/ase-repo-changelog/help.md +2 -2
- package/plugin/skills/ase-repo-review/SKILL.md +5 -3
- package/plugin/skills/ase-repo-review/help.md +3 -1
- package/plugin/skills/ase-spec-edit/SKILL.md +2 -1
- package/plugin/skills/ase-spec-edit/help.md +2 -1
- package/plugin/skills/ase-sync-reconcile/help.md +4 -4
- package/plugin/skills/ase-task-dissect/SKILL.md +10 -6
- package/plugin/skills/ase-task-grill/help.md +1 -1
- package/plugin/skills/ase-task-implement/SKILL.md +58 -1
- package/plugin/skills/ase-task-implement/help.md +16 -0
- package/plugin/skills/ase-task-list/help.md +2 -2
|
@@ -38,10 +38,8 @@ const live = (issue) => (issue.issue_type ?? "issue") === "issue" && !issue.labe
|
|
|
38
38
|
"Created"/"Modified" onto the issue timestamps, any other key (including "Group",
|
|
39
39
|
as GitLab has no parent issues) onto "ase:<key>:<value>" labels, and the attachments
|
|
40
40
|
onto the issue notes */
|
|
41
|
-
class GitLabTaskStoragePlugin {
|
|
42
|
-
ctx;
|
|
41
|
+
class GitLabTaskStoragePlugin extends TaskIssues.IssueTaskStoragePlugin {
|
|
43
42
|
name = "gitlab";
|
|
44
|
-
url;
|
|
45
43
|
token;
|
|
46
44
|
source;
|
|
47
45
|
issues;
|
|
@@ -51,13 +49,6 @@ class GitLabTaskStoragePlugin {
|
|
|
51
49
|
milestones;
|
|
52
50
|
members;
|
|
53
51
|
users;
|
|
54
|
-
repos = new Map();
|
|
55
|
-
poll;
|
|
56
|
-
listener = null;
|
|
57
|
-
timer = null;
|
|
58
|
-
polling = false;
|
|
59
|
-
opened = now();
|
|
60
|
-
polls = new Map();
|
|
61
52
|
registry = new LRUCache({ max: 64, ttl: 60 * 1000 });
|
|
62
53
|
latest = new Map();
|
|
63
54
|
titles = new Map();
|
|
@@ -67,7 +58,7 @@ class GitLabTaskStoragePlugin {
|
|
|
67
58
|
recent = new Map();
|
|
68
59
|
loads = new LRUCache({ max: 256, ttl: 2 * 1000 });
|
|
69
60
|
constructor(ctx) {
|
|
70
|
-
|
|
61
|
+
super(ctx, "projects", now);
|
|
71
62
|
const options = ctx.options;
|
|
72
63
|
const token = options.token ?? process.env.GITLAB_TOKEN ?? "";
|
|
73
64
|
if (typeof token !== "string" || token === "")
|
|
@@ -132,27 +123,6 @@ class GitLabTaskStoragePlugin {
|
|
|
132
123
|
}
|
|
133
124
|
});
|
|
134
125
|
}
|
|
135
|
-
/* the storage lifecycle: polling for changes while opened and observed
|
|
136
|
-
(without keeping the process alive) */
|
|
137
|
-
async open() {
|
|
138
|
-
this.opened = now();
|
|
139
|
-
if (this.poll > 0 && this.listener !== null) {
|
|
140
|
-
this.timer = setInterval(() => {
|
|
141
|
-
this.pollAll().catch(() => { });
|
|
142
|
-
}, this.poll * 1000);
|
|
143
|
-
this.timer.unref();
|
|
144
|
-
}
|
|
145
|
-
this.ctx.log("debug", `opened ${this.repos.size} projects on ${this.url} (polling every ${this.poll}s)`);
|
|
146
|
-
}
|
|
147
|
-
async close() {
|
|
148
|
-
if (this.timer !== null)
|
|
149
|
-
clearInterval(this.timer);
|
|
150
|
-
this.timer = null;
|
|
151
|
-
}
|
|
152
|
-
/* observe the changes of the issues made outside of this plugin instance */
|
|
153
|
-
watch(listener) {
|
|
154
|
-
this.listener = listener;
|
|
155
|
-
}
|
|
156
126
|
/* ==== project registry ==== */
|
|
157
127
|
/* the GitLab project path of a project */
|
|
158
128
|
repo(prjId) {
|
|
@@ -224,15 +194,6 @@ class GitLabTaskStoragePlugin {
|
|
|
224
194
|
this.latest.set(path, { etag: r.etag, number, at: Date.now() });
|
|
225
195
|
return number;
|
|
226
196
|
}
|
|
227
|
-
async projectList() {
|
|
228
|
-
const out = [];
|
|
229
|
-
for (const prjId of this.repos.keys()) {
|
|
230
|
-
const entry = await this.projectGet(prjId);
|
|
231
|
-
if (entry !== null)
|
|
232
|
-
out.push(entry);
|
|
233
|
-
}
|
|
234
|
-
return out;
|
|
235
|
-
}
|
|
236
197
|
/* get a project, with the highest issue number as the sequence number high-water
|
|
237
198
|
mark, so the next allocated task id is the one of the next created issue */
|
|
238
199
|
async projectGet(prjId) {
|
|
@@ -279,14 +240,7 @@ class GitLabTaskStoragePlugin {
|
|
|
279
240
|
const key = `${path}#${issue.iid}@${issue.updated_at}`;
|
|
280
241
|
if (fresh)
|
|
281
242
|
this.linked.delete(key);
|
|
282
|
-
|
|
283
|
-
if (links === undefined) {
|
|
284
|
-
links = this.links.all(path, issue.iid).then((data) => data);
|
|
285
|
-
this.linked.set(key, links);
|
|
286
|
-
links.catch(() => {
|
|
287
|
-
this.linked.delete(key);
|
|
288
|
-
});
|
|
289
|
-
}
|
|
243
|
+
const links = TaskIssues.memoize(this.linked, key, () => this.links.all(path, issue.iid).then((data) => data));
|
|
290
244
|
return (await links).filter((link) => link.link_type === "is_blocked_by" && link.project_id === issue.project_id);
|
|
291
245
|
}
|
|
292
246
|
/* the (non-system) notes of an issue */
|
|
@@ -490,11 +444,7 @@ class GitLabTaskStoragePlugin {
|
|
|
490
444
|
own write or detected change of the issue), as e.g. the boards load the plan
|
|
491
445
|
and its attachments in separate operations */
|
|
492
446
|
load(prjId, path, n) {
|
|
493
|
-
|
|
494
|
-
const cached = this.loads.get(key);
|
|
495
|
-
if (cached !== undefined)
|
|
496
|
-
return cached;
|
|
497
|
-
const load = (async () => {
|
|
447
|
+
return TaskIssues.memoize(this.loads, `${prjId}#${n}`, async () => {
|
|
498
448
|
const [issue, notes] = await Promise.all([
|
|
499
449
|
this.fetch(path, n),
|
|
500
450
|
n === 0 ? [] : found(this.comments(path, n))
|
|
@@ -502,12 +452,7 @@ class GitLabTaskStoragePlugin {
|
|
|
502
452
|
if (issue === null)
|
|
503
453
|
return null;
|
|
504
454
|
return { issue, after: await this.blockers(path, issue), notes: notes ?? [] };
|
|
505
|
-
})();
|
|
506
|
-
this.loads.set(key, load);
|
|
507
|
-
load.catch(() => {
|
|
508
|
-
this.loads.delete(key);
|
|
509
455
|
});
|
|
510
|
-
return load;
|
|
511
456
|
}
|
|
512
457
|
/* ==== task plans ==== */
|
|
513
458
|
async taskList(prjId) {
|
|
@@ -596,30 +541,6 @@ class GitLabTaskStoragePlugin {
|
|
|
596
541
|
throw new Error(`task "${oldId}" cannot be renamed to "${newId}", as task ids are GitLab issue numbers`);
|
|
597
542
|
}
|
|
598
543
|
/* ==== change detection ==== */
|
|
599
|
-
/* the change detection state of a project (starting at the opening time) */
|
|
600
|
-
pollState(prjId) {
|
|
601
|
-
let state = this.polls.get(prjId);
|
|
602
|
-
if (state === undefined) {
|
|
603
|
-
state = { since: this.opened, seen: new Map() };
|
|
604
|
-
this.polls.set(prjId, state);
|
|
605
|
-
}
|
|
606
|
-
return state;
|
|
607
|
-
}
|
|
608
|
-
/* poll all registered projects, never overlapping itself */
|
|
609
|
-
async pollAll() {
|
|
610
|
-
if (this.polling)
|
|
611
|
-
return;
|
|
612
|
-
this.polling = true;
|
|
613
|
-
try {
|
|
614
|
-
for (const prjId of this.repos.keys())
|
|
615
|
-
await this.pollProject(prjId).catch((err) => {
|
|
616
|
-
this.ctx.log("warning", `polling project "${prjId}" failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
617
|
-
});
|
|
618
|
-
}
|
|
619
|
-
finally {
|
|
620
|
-
this.polling = false;
|
|
621
|
-
}
|
|
622
|
-
}
|
|
623
544
|
/* poll the issues of a project updated since the last poll, conditionally via
|
|
624
545
|
the entity tag of the last poll (a "304" answer still counts against the rate
|
|
625
546
|
limit of GitLab), and report the issues not seen at their update time yet: as
|
package/dst/ase-task.js
CHANGED
|
@@ -341,7 +341,7 @@ export class Task {
|
|
|
341
341
|
try {
|
|
342
342
|
url = new URL(store.value);
|
|
343
343
|
}
|
|
344
|
-
catch
|
|
344
|
+
catch {
|
|
345
345
|
throw unsupported();
|
|
346
346
|
}
|
|
347
347
|
if (url.hostname === "" || url.port === "" || url.username !== "" || url.password !== ""
|
|
@@ -444,21 +444,12 @@ export class Task {
|
|
|
444
444
|
tag: Core.taskTag(plan)
|
|
445
445
|
};
|
|
446
446
|
}
|
|
447
|
-
/* save a task as text under the given id
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
the entity tag of the just-saved plan, and the text of the just-saved plan
|
|
454
|
-
(as sent, re-serialized from its parsed form, i.e., before any
|
|
455
|
-
normalization by the task store, and with its elided attachment
|
|
456
|
-
payloads still elided, while they are restored from the stored
|
|
457
|
-
plan for the save itself); the entity tag
|
|
458
|
-
is the one the task store reports for the plan as stored, and only on a
|
|
459
|
-
task store server predating this report the one of the plan as sent (which
|
|
460
|
-
never is the one of a plan saved by somebody else in the meantime, so a
|
|
461
|
-
conditional save based on it at worst is refused spuriously) */
|
|
447
|
+
/* save a task as text under the given id, throwing on a "Status:" unknown to or not
|
|
448
|
+
reachable in the task lifecycle model, on a conditional save (with an entity tag) a
|
|
449
|
+
problem 412 on a concurrent change, and on a create-only save an error if the task
|
|
450
|
+
exists; elided attachment payloads are restored from the stored plan; returns the
|
|
451
|
+
id scheme warning (else empty), the entity tag of the saved plan (as reported by the
|
|
452
|
+
task store, else of the plan as sent), and the text of the plan as sent */
|
|
462
453
|
static async save(log, id, text, tag, create = false) {
|
|
463
454
|
if (typeof text !== "string")
|
|
464
455
|
throw new Error("task: text must be a string");
|
|
@@ -993,6 +984,17 @@ export default class TaskCommand {
|
|
|
993
984
|
process.exit(0);
|
|
994
985
|
}
|
|
995
986
|
});
|
|
987
|
+
/* register the further CLI sub-commands */
|
|
988
|
+
this.registerRequestCommands(task);
|
|
989
|
+
this.registerPlanCommands(task);
|
|
990
|
+
this.registerProjectCommands(task);
|
|
991
|
+
/* register CLI sub-command group "ase task store" */
|
|
992
|
+
new TaskStoreCommand(this.log).register(task);
|
|
993
|
+
/* provide "ase task" command for further sub-commands */
|
|
994
|
+
return task;
|
|
995
|
+
}
|
|
996
|
+
/* register the CLI sub-commands requesting and assigning a task */
|
|
997
|
+
registerRequestCommands(task) {
|
|
996
998
|
/* register CLI sub-command "ase task request" */
|
|
997
999
|
task
|
|
998
1000
|
.command("request")
|
|
@@ -1049,6 +1051,9 @@ export default class TaskCommand {
|
|
|
1049
1051
|
}
|
|
1050
1052
|
process.exit(0);
|
|
1051
1053
|
});
|
|
1054
|
+
}
|
|
1055
|
+
/* register the CLI sub-commands loading, viewing, editing, saving, deleting, and renaming a task */
|
|
1056
|
+
registerPlanCommands(task) {
|
|
1052
1057
|
/* register CLI sub-command "ase task load" */
|
|
1053
1058
|
task
|
|
1054
1059
|
.command("load")
|
|
@@ -1130,6 +1135,9 @@ export default class TaskCommand {
|
|
|
1130
1135
|
this.log.write("info", `task: no task "${oldId}" to rename`);
|
|
1131
1136
|
process.exit(result !== null ? 0 : 1);
|
|
1132
1137
|
});
|
|
1138
|
+
}
|
|
1139
|
+
/* register the CLI sub-commands of the task ids, the purging, and the project settings */
|
|
1140
|
+
registerProjectCommands(task) {
|
|
1133
1141
|
/* register CLI sub-command "ase task newid" */
|
|
1134
1142
|
task
|
|
1135
1143
|
.command("newid")
|
|
@@ -1197,10 +1205,6 @@ export default class TaskCommand {
|
|
|
1197
1205
|
process.exit(0);
|
|
1198
1206
|
}
|
|
1199
1207
|
});
|
|
1200
|
-
/* register CLI sub-command group "ase task store" */
|
|
1201
|
-
new TaskStoreCommand(this.log).register(task);
|
|
1202
|
-
/* provide "ase task" command for further sub-commands */
|
|
1203
|
-
return task;
|
|
1204
1208
|
}
|
|
1205
1209
|
}
|
|
1206
1210
|
/* render a caught error as an MCP tool error result */
|
|
@@ -1264,9 +1268,8 @@ export class TaskMCP {
|
|
|
1264
1268
|
try {
|
|
1265
1269
|
const verbose = args.verbose ?? false;
|
|
1266
1270
|
const items = await Task.list(this.log);
|
|
1267
|
-
const tasks = verbose ?
|
|
1268
|
-
items.map((
|
|
1269
|
-
items.map((item) => ({ id: item.id, status: item.status, title: item.title }));
|
|
1271
|
+
const tasks = verbose ? items :
|
|
1272
|
+
items.map(({ id, status, title }) => ({ id, status, title }));
|
|
1270
1273
|
const result = { tasks };
|
|
1271
1274
|
return {
|
|
1272
1275
|
structuredContent: result,
|
|
@@ -1277,6 +1280,16 @@ export class TaskMCP {
|
|
|
1277
1280
|
return mcpError(err);
|
|
1278
1281
|
}
|
|
1279
1282
|
});
|
|
1283
|
+
/* register the further MCP tools */
|
|
1284
|
+
this.registerLoadTool(mcp);
|
|
1285
|
+
this.registerSaveTool(mcp);
|
|
1286
|
+
this.registerPlanTools(mcp);
|
|
1287
|
+
this.registerStatusTools(mcp);
|
|
1288
|
+
this.registerAssignTool(mcp);
|
|
1289
|
+
this.registerIdTools(mcp);
|
|
1290
|
+
}
|
|
1291
|
+
/* register the MCP tool loading a task plan */
|
|
1292
|
+
registerLoadTool(mcp) {
|
|
1280
1293
|
/* task load */
|
|
1281
1294
|
mcp.registerTool("ase_task_load", {
|
|
1282
1295
|
title: "ASE task load",
|
|
@@ -1332,6 +1345,9 @@ export class TaskMCP {
|
|
|
1332
1345
|
return mcpError(err);
|
|
1333
1346
|
}
|
|
1334
1347
|
});
|
|
1348
|
+
}
|
|
1349
|
+
/* register the MCP tool saving a task plan */
|
|
1350
|
+
registerSaveTool(mcp) {
|
|
1335
1351
|
/* task save */
|
|
1336
1352
|
mcp.registerTool("ase_task_save", {
|
|
1337
1353
|
title: "ASE task save",
|
|
@@ -1408,6 +1424,9 @@ export class TaskMCP {
|
|
|
1408
1424
|
return mcpError(err);
|
|
1409
1425
|
}
|
|
1410
1426
|
});
|
|
1427
|
+
}
|
|
1428
|
+
/* register the MCP tools reading an attachment of, deleting, and renaming a task plan */
|
|
1429
|
+
registerPlanTools(mcp) {
|
|
1411
1430
|
/* task attachment */
|
|
1412
1431
|
mcp.registerTool("ase_task_attachment", {
|
|
1413
1432
|
title: "ASE task attachment",
|
|
@@ -1482,6 +1501,9 @@ export class TaskMCP {
|
|
|
1482
1501
|
return mcpError(err);
|
|
1483
1502
|
}
|
|
1484
1503
|
});
|
|
1504
|
+
}
|
|
1505
|
+
/* register the MCP tools getting/setting the status of and requesting the processing of a task plan */
|
|
1506
|
+
registerStatusTools(mcp) {
|
|
1485
1507
|
/* task status get/set */
|
|
1486
1508
|
mcp.registerTool("ase_task_status", {
|
|
1487
1509
|
title: "ASE task status get/set",
|
|
@@ -1539,6 +1561,9 @@ export class TaskMCP {
|
|
|
1539
1561
|
return mcpError(err);
|
|
1540
1562
|
}
|
|
1541
1563
|
});
|
|
1564
|
+
}
|
|
1565
|
+
/* register the MCP tool assigning a task plan (with AI usage accounting) */
|
|
1566
|
+
registerAssignTool(mcp) {
|
|
1542
1567
|
/* task assignment (with AI usage accounting) */
|
|
1543
1568
|
mcp.registerTool("ase_task_assign", {
|
|
1544
1569
|
title: "ASE task assignment",
|
|
@@ -1586,6 +1611,9 @@ export class TaskMCP {
|
|
|
1586
1611
|
return mcpError(err);
|
|
1587
1612
|
}
|
|
1588
1613
|
});
|
|
1614
|
+
}
|
|
1615
|
+
/* register the MCP tools generating task ids and getting/setting the active task id */
|
|
1616
|
+
registerIdTools(mcp) {
|
|
1589
1617
|
/* task id generation */
|
|
1590
1618
|
mcp.registerTool("ase_task_newid", {
|
|
1591
1619
|
title: "ASE task id generation",
|
package/dst/ase-util-compat.js
CHANGED
|
@@ -50,7 +50,7 @@ export default class CompatCommand {
|
|
|
50
50
|
});
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
|
-
/* MCP tool "ase_compat"
|
|
53
|
+
/* MCP tool "ase_compat" -- lets the skill call this without a Bash tool */
|
|
54
54
|
export class CompatMCP {
|
|
55
55
|
register(mcp) {
|
|
56
56
|
mcp.registerTool("ase_compat", {
|
package/dst/ase-util-diagram.js
CHANGED
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
** Licensed under Apache 2.0 <https://spdx.org/licenses/Apache-2.0>
|
|
5
5
|
*/
|
|
6
6
|
import fs from "node:fs";
|
|
7
|
-
import { InvalidArgumentError } from "commander";
|
|
7
|
+
import { InvalidArgumentError, Option } from "commander";
|
|
8
8
|
import { z } from "zod";
|
|
9
|
-
import { readStdin } from "./ase-lib-stdio.js";
|
|
9
|
+
import { readStdin, writeStdout } from "./ase-lib-stdio.js";
|
|
10
10
|
/* custom argument parser for Commander: non-negative integer */
|
|
11
11
|
const parseInteger = (name) => (value) => {
|
|
12
12
|
const n = Number.parseInt(value, 10);
|
|
@@ -14,24 +14,6 @@ const parseInteger = (name) => (value) => {
|
|
|
14
14
|
throw new InvalidArgumentError(`${name} must be a non-negative integer`);
|
|
15
15
|
return n;
|
|
16
16
|
};
|
|
17
|
-
/* custom argument parser for Commander: color mode */
|
|
18
|
-
const parseColorMode = (name) => (value) => {
|
|
19
|
-
if (value !== "none" && value !== "ansi16" && value !== "ansi256")
|
|
20
|
-
throw new InvalidArgumentError(`${name} must be "none", "ansi16", or "ansi256"`);
|
|
21
|
-
return value;
|
|
22
|
-
};
|
|
23
|
-
/* custom argument parser for Commander: diagram language */
|
|
24
|
-
const parseLang = (name) => (value) => {
|
|
25
|
-
if (value !== "mermaid" && value !== "d2")
|
|
26
|
-
throw new InvalidArgumentError(`${name} must be "mermaid" or "d2"`);
|
|
27
|
-
return value;
|
|
28
|
-
};
|
|
29
|
-
/* custom argument parser for Commander: output format */
|
|
30
|
-
const parseFormat = (name) => (value) => {
|
|
31
|
-
if (value !== "ascii" && value !== "svg")
|
|
32
|
-
throw new InvalidArgumentError(`${name} must be "ascii" or "svg"`);
|
|
33
|
-
return value;
|
|
34
|
-
};
|
|
35
17
|
/* the D2 compiler, created on first use only (as it spins up the
|
|
36
18
|
WebAssembly build of D2 in a worker thread, which keeps the process
|
|
37
19
|
alive until the compiler is disposed) */
|
|
@@ -115,8 +97,9 @@ const visibleWidth = (line) => {
|
|
|
115
97
|
}
|
|
116
98
|
return visible;
|
|
117
99
|
};
|
|
118
|
-
/* reusable functionality: Mermaid diagram rendering as Unicode/ASCII art */
|
|
100
|
+
/* reusable functionality: Mermaid and D2 diagram rendering as Unicode/ASCII art or SVG */
|
|
119
101
|
export class Diagram {
|
|
102
|
+
/* detect a terminal dimension from an environment variable, else from stdout (0 if unknown) */
|
|
120
103
|
static detectTermDimension(envVar, stdoutProp) {
|
|
121
104
|
let value = 0;
|
|
122
105
|
/* attempt 1: query environment variable */
|
|
@@ -144,23 +127,13 @@ export class Diagram {
|
|
|
144
127
|
}
|
|
145
128
|
/* detect terminal color capability */
|
|
146
129
|
static detectColorMode() {
|
|
147
|
-
let mode = "none";
|
|
148
|
-
let explicit = false;
|
|
149
130
|
/* attempt 1: query environment variable (explicitly) */
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
explicit = true;
|
|
154
|
-
}
|
|
131
|
+
const env = process.env.ASE_TERM_COLORS;
|
|
132
|
+
if (env === "none" || env === "ansi16" || env === "ansi256")
|
|
133
|
+
return env;
|
|
155
134
|
/* attempt 2: query stdout */
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
if (depth >= 8)
|
|
159
|
-
mode = "ansi256";
|
|
160
|
-
else if (depth >= 4)
|
|
161
|
-
mode = "ansi16";
|
|
162
|
-
}
|
|
163
|
-
return mode;
|
|
135
|
+
const depth = process.stdout.isTTY ? process.stdout.getColorDepth() : 0;
|
|
136
|
+
return depth >= 8 ? "ansi256" : depth >= 4 ? "ansi16" : "none";
|
|
164
137
|
}
|
|
165
138
|
/* dispose the D2 compiler (if any), so its worker thread no longer
|
|
166
139
|
keeps the process alive (used by the short-lived CLI only) */
|
|
@@ -287,10 +260,13 @@ export default class DiagramCommand {
|
|
|
287
260
|
.command("diagram")
|
|
288
261
|
.description("Render Mermaid or D2 diagram specification as Unicode/ASCII art or SVG")
|
|
289
262
|
.option("-i, --input <file>", "read diagram source from file instead of stdin")
|
|
290
|
-
.
|
|
291
|
-
.
|
|
263
|
+
.addOption(new Option("-l, --lang <lang>", "diagram language")
|
|
264
|
+
.choices(["mermaid", "d2"]).default("mermaid"))
|
|
265
|
+
.addOption(new Option("-f, --format <format>", "output format")
|
|
266
|
+
.choices(["ascii", "svg"]).default("ascii"))
|
|
292
267
|
.option("-a, --ascii", "emit plain ASCII (+-|) instead of Unicode box-drawing", false)
|
|
293
|
-
.
|
|
268
|
+
.addOption(new Option("-c, --color-mode <mode>", "force color mode (Mermaid only)")
|
|
269
|
+
.choices(["none", "ansi16", "ansi256"]).default(Diagram.detectColorMode()))
|
|
294
270
|
.option("--node-margin-x <n>", "horizontal margin between nodes of <n> characters (Mermaid only)", parseInteger("--node-margin-x"), 3)
|
|
295
271
|
.option("--node-margin-y <n>", "vertical margin between nodes of <n> lines (Mermaid only)", parseInteger("--node-margin-y"), 3)
|
|
296
272
|
.option("--node-padding <n>", "horizontal and vertical inner node padding with <n> characters (Mermaid only)", parseInteger("--node-padding"), 1)
|
|
@@ -331,9 +307,7 @@ export default class DiagramCommand {
|
|
|
331
307
|
await Diagram.dispose();
|
|
332
308
|
}
|
|
333
309
|
/* output diagram rendering */
|
|
334
|
-
|
|
335
|
-
if (!out.endsWith("\n"))
|
|
336
|
-
process.stdout.write("\n");
|
|
310
|
+
await writeStdout(out.endsWith("\n") ? out : `${out}\n`);
|
|
337
311
|
});
|
|
338
312
|
}
|
|
339
313
|
}
|
package/dst/ase.js
CHANGED
|
@@ -112,9 +112,9 @@ const main = async () => {
|
|
|
112
112
|
the command line actually addresses; when no sub-command matches
|
|
113
113
|
at all, all of them are registered, as only then Commander can
|
|
114
114
|
render the complete sub-command overview of a help or a typo */
|
|
115
|
-
const register = async (
|
|
116
|
-
const parent = await commands[
|
|
117
|
-
const subs = subCommands[
|
|
115
|
+
const register = async (top) => {
|
|
116
|
+
const parent = await commands[top](program);
|
|
117
|
+
const subs = subCommands[top];
|
|
118
118
|
if (subs === undefined || !(parent instanceof Command))
|
|
119
119
|
return;
|
|
120
120
|
const wanted = Object.keys(subs).filter((sub) => rest.includes(sub));
|
|
@@ -133,10 +133,10 @@ const main = async () => {
|
|
|
133
133
|
answered by the program itself and hence needs no command module,
|
|
134
134
|
while an unknown command and any help request need all of them */
|
|
135
135
|
if (Object.hasOwn(commands, name))
|
|
136
|
-
await register(name
|
|
136
|
+
await register(name);
|
|
137
137
|
else if (!(name === "" && version))
|
|
138
138
|
for (const command of Object.keys(commands))
|
|
139
|
-
await register(command
|
|
139
|
+
await register(command);
|
|
140
140
|
/* parse program arguments */
|
|
141
141
|
await program.parseAsync(process.argv);
|
|
142
142
|
/* gracefully terminate */
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
.TH "ASE-AGENT-ADHOC" "1" "October 2026" "2.0.
|
|
1
|
+
.TH "ASE-AGENT-ADHOC" "1" "October 2026" "2.0.3" "Agentic Software Engineering (ASE)"
|
|
2
2
|
.SH "NAME"
|
|
3
3
|
\fBase-agent-adhoc\fR - Run an Ad-Hoc Agent of a Definition Given by Options
|
|
4
4
|
.SH "SYNOPSIS"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
.TH "ASE-AGENT-IMPLEMENTER" "1" "October 2026" "2.0.
|
|
1
|
+
.TH "ASE-AGENT-IMPLEMENTER" "1" "October 2026" "2.0.3" "Agentic Software Engineering (ASE)"
|
|
2
2
|
.SH "NAME"
|
|
3
3
|
\fBase-agent-implementer\fR - Implementation Phase Agent
|
|
4
4
|
.SH "SYNOPSIS"
|
package/dst/man/ase-agent.1
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
.TH "ASE-ARTIFACT-LIST" "1" "October 2026" "2.0.
|
|
1
|
+
.TH "ASE-ARTIFACT-LIST" "1" "October 2026" "2.0.3" "Agentic Software Engineering (ASE)"
|
|
2
2
|
.SH "NAME"
|
|
3
3
|
\fBase-artifact-list\fR - Resolve Artifact Kinds to Project-Relative File Paths
|
|
4
4
|
.SH "SYNOPSIS"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
.TH "ASE-ARTIFACT-NAME" "1" "October 2026" "2.0.
|
|
1
|
+
.TH "ASE-ARTIFACT-NAME" "1" "October 2026" "2.0.3" "Agentic Software Engineering (ASE)"
|
|
2
2
|
.SH "NAME"
|
|
3
3
|
\fBase-artifact-name\fR - Resolve a Filename within an Artifact Kind
|
|
4
4
|
.SH "SYNOPSIS"
|
package/dst/man/ase-artifact.1
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
.TH "ASE-CONFIG-EDIT" "1" "October 2026" "2.0.
|
|
1
|
+
.TH "ASE-CONFIG-EDIT" "1" "October 2026" "2.0.3" "Agentic Software Engineering (ASE)"
|
|
2
2
|
.SH "NAME"
|
|
3
3
|
\fBase-config-edit\fR - Edit the Configuration File with an Editor
|
|
4
4
|
.SH "SYNOPSIS"
|
package/dst/man/ase-config-get.1
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
.TH "ASE-CONFIG-INIT" "1" "October 2026" "2.0.
|
|
1
|
+
.TH "ASE-CONFIG-INIT" "1" "October 2026" "2.0.3" "Agentic Software Engineering (ASE)"
|
|
2
2
|
.SH "NAME"
|
|
3
3
|
\fBase-config-init\fR - Initialize Configuration with Preset Values
|
|
4
4
|
.SH "SYNOPSIS"
|
package/dst/man/ase-config-set.1
CHANGED
package/dst/man/ase-config.1
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
.TH "ASE-HOOK-PERMISSION-REQUEST" "1" "October 2026" "2.0.
|
|
1
|
+
.TH "ASE-HOOK-PERMISSION-REQUEST" "1" "October 2026" "2.0.3" "Agentic Software Engineering (ASE)"
|
|
2
2
|
.SH "NAME"
|
|
3
3
|
\fBase-hook-permission-request\fR - Handle the PermissionRequest Hook Event
|
|
4
4
|
.SH "SYNOPSIS"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
.TH "ASE-HOOK-PRE-TOOL-USE" "1" "October 2026" "2.0.
|
|
1
|
+
.TH "ASE-HOOK-PRE-TOOL-USE" "1" "October 2026" "2.0.3" "Agentic Software Engineering (ASE)"
|
|
2
2
|
.SH "NAME"
|
|
3
3
|
\fBase-hook-pre-tool-use\fR - Handle the PreToolUse Hook Event
|
|
4
4
|
.SH "SYNOPSIS"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
.TH "ASE-HOOK-SESSION-END" "1" "October 2026" "2.0.
|
|
1
|
+
.TH "ASE-HOOK-SESSION-END" "1" "October 2026" "2.0.3" "Agentic Software Engineering (ASE)"
|
|
2
2
|
.SH "NAME"
|
|
3
3
|
\fBase-hook-session-end\fR - Handle the SessionEnd Hook Event
|
|
4
4
|
.SH "SYNOPSIS"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
.TH "ASE-HOOK-SESSION-PERSONA" "1" "October 2026" "2.0.
|
|
1
|
+
.TH "ASE-HOOK-SESSION-PERSONA" "1" "October 2026" "2.0.3" "Agentic Software Engineering (ASE)"
|
|
2
2
|
.SH "NAME"
|
|
3
3
|
\fBase-hook-session-persona\fR - Handle the SessionStart Hook Event for the Persona
|
|
4
4
|
.SH "SYNOPSIS"
|