@rse/ase 1.0.7 → 2.0.1
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-api.d.ts +184 -0
- package/dst/ase-agent-definition-api.js +6 -0
- package/dst/ase-agent-definition-builtin/condenser.js +42 -0
- package/dst/ase-agent-definition-builtin/editor.js +45 -0
- package/dst/ase-agent-definition-builtin/estimator.js +98 -0
- package/dst/ase-agent-definition-builtin/implementer.js +121 -0
- package/dst/ase-agent-definition-builtin/integrator.js +56 -0
- package/dst/ase-agent-definition-builtin/qualifier.js +61 -0
- package/dst/ase-agent-definition-builtin/rebooter.js +41 -0
- package/dst/ase-agent-definition-builtin/researcher.js +77 -0
- package/dst/ase-agent-definition-core.js +827 -0
- package/dst/ase-agent-fleet.js +772 -0
- package/dst/ase-agent-process.js +232 -0
- package/dst/ase-agent-relay-client.js +509 -0
- package/dst/ase-agent-relay-core.js +213 -0
- package/dst/ase-agent-relay-server-bind.js +242 -0
- package/dst/ase-agent-relay-server-cli.js +50 -0
- package/dst/ase-agent-runtime-claim.js +189 -0
- package/dst/ase-agent-runtime-engine.js +1100 -0
- package/dst/ase-agent-runtime-exec.js +275 -0
- package/dst/ase-agent-runtime-phase.js +581 -0
- package/dst/ase-agent-runtime-request.js +272 -0
- package/dst/ase-agent-runtime-tool.js +207 -0
- package/dst/ase-agent-runtime.js +1316 -0
- package/dst/ase-agent.js +65 -0
- package/dst/ase-artifact.js +6 -5
- package/dst/ase-config-core.js +465 -0
- package/dst/ase-config-schema.js +357 -0
- package/dst/ase-config-scope.js +172 -0
- package/dst/ase-config.js +25 -585
- package/dst/ase-hook.js +228 -111
- package/dst/ase-lib-daemon-cli.js +130 -0
- package/dst/ase-lib-hash.js +20 -0
- package/dst/{ase-log.js → ase-lib-log.js} +40 -7
- package/dst/ase-lib-server-bind.js +115 -0
- package/dst/ase-lib-server-cli.js +474 -0
- package/dst/{ase-table.js → ase-lib-table.js} +1 -1
- package/dst/{ase-version.js → ase-lib-version.js} +8 -1
- package/dst/ase-man.js +96 -0
- package/dst/ase-mcp.js +166 -13
- package/dst/{ase-getopt.js → ase-service-getopt.js} +82 -80
- package/dst/{ase-markdown.js → ase-service-markdown.js} +18 -11
- package/dst/ase-service-otel.js +1246 -0
- package/dst/{ase-skills.js → ase-service-skills.js} +29 -64
- package/dst/ase-service-state.js +101 -0
- package/dst/ase-service.js +269 -81
- package/dst/ase-setup-common.js +141 -0
- package/dst/ase-setup-mcp.js +359 -0
- package/dst/ase-setup-settings.js +837 -0
- package/dst/ase-setup.js +113 -869
- package/dst/ase-spec.js +31 -19
- package/dst/ase-statusline.js +108 -43
- package/dst/ase-task-board-core.js +739 -0
- package/dst/ase-task-board-filter.js +127 -0
- package/dst/ase-task-board-flow.js +237 -0
- package/dst/ase-task-board-graph.js +497 -0
- package/dst/ase-task-board-stats.js +263 -0
- package/dst/ase-task-board-tui-control.js +775 -0
- package/dst/ase-task-board-tui-model.js +1008 -0
- package/dst/ase-task-board-tui-popup.js +626 -0
- package/dst/ase-task-board-tui-style.js +106 -0
- package/dst/ase-task-board-tui-view.js +847 -0
- package/dst/ase-task-board-tui.js +189 -0
- package/dst/ase-task-board-web-client.css +1 -0
- package/dst/ase-task-board-web-client.html +20 -0
- package/dst/ase-task-board-web-client.js +81 -0
- package/dst/ase-task-board-web-server.js +823 -0
- package/dst/ase-task-board.js +134 -0
- package/dst/ase-task-format.js +757 -0
- package/dst/ase-task-request.js +208 -0
- package/dst/ase-task-store-client.js +495 -0
- package/dst/ase-task-store-core.js +804 -0
- package/dst/ase-task-store-issues.js +237 -0
- package/dst/ase-task-store-plugin-api.js +6 -0
- package/dst/ase-task-store-plugin-ase.js +484 -0
- package/dst/ase-task-store-plugin-delegate.js +137 -0
- package/dst/ase-task-store-plugin-gitea.js +666 -0
- package/dst/ase-task-store-plugin-github.js +696 -0
- package/dst/ase-task-store-plugin-gitlab.js +668 -0
- package/dst/ase-task-store-server-bind.js +538 -0
- package/dst/ase-task-store-server-cli.js +154 -0
- package/dst/ase-task.js +1335 -357
- package/dst/{ase-compat.js → ase-util-compat.js} +2 -2
- package/dst/{ase-diagram.js → ase-util-diagram.js} +107 -32
- package/dst/{ase-meta.js → ase-util-meta.js} +2 -2
- package/dst/{ase-metric.js → ase-util-metric.js} +2 -2
- package/dst/{ase-mint.js → ase-util-mint.js} +19 -12
- package/dst/{ase-worktree.js → ase-util-worktree.js} +30 -19
- package/dst/ase-util.js +20 -0
- package/dst/ase.js +108 -32
- package/dst/man/ase-agent-adhoc.1 +515 -0
- package/dst/man/ase-agent-condenser.1 +193 -0
- package/dst/man/ase-agent-editor.1 +212 -0
- package/dst/man/ase-agent-estimator.1 +214 -0
- package/dst/man/ase-agent-fleet.1 +185 -0
- package/dst/man/ase-agent-implementer.1 +233 -0
- package/dst/man/ase-agent-integrator.1 +213 -0
- package/dst/man/ase-agent-qualifier.1 +214 -0
- package/dst/man/ase-agent-rebooter.1 +193 -0
- package/dst/man/ase-agent-relay.1 +128 -0
- package/dst/man/ase-agent-researcher.1 +217 -0
- package/dst/man/ase-agent.1 +264 -0
- package/dst/man/ase-artifact-list.1 +38 -0
- package/dst/man/ase-artifact-name.1 +39 -0
- package/dst/man/ase-artifact.1 +56 -0
- package/dst/man/ase-config-delete.1 +45 -0
- package/dst/man/ase-config-edit.1 +48 -0
- package/dst/man/ase-config-get.1 +46 -0
- package/dst/man/ase-config-init.1 +60 -0
- package/dst/man/ase-config-list.1 +42 -0
- package/dst/man/ase-config-set.1 +52 -0
- package/dst/man/ase-config.1 +231 -0
- package/dst/man/ase-hook-permission-request.1 +36 -0
- package/dst/man/ase-hook-pre-tool-use.1 +59 -0
- package/dst/man/ase-hook-session-end.1 +47 -0
- package/dst/man/ase-hook-session-persona.1 +37 -0
- package/dst/man/ase-hook-session-start.1 +81 -0
- package/dst/man/ase-hook-stop.1 +34 -0
- package/dst/man/ase-hook-user-prompt-submit.1 +34 -0
- package/dst/man/ase-hook.1 +51 -0
- package/dst/man/ase-man.1 +67 -0
- package/dst/man/ase-mcp.1 +61 -0
- package/dst/man/ase-service-log.1 +43 -0
- package/dst/man/ase-service-send.1 +47 -0
- package/dst/man/ase-service-start.1 +54 -0
- package/dst/man/ase-service-status.1 +46 -0
- package/dst/man/ase-service-stop.1 +37 -0
- package/dst/man/ase-service.1 +85 -0
- package/dst/man/ase-setup-disable.1 +44 -0
- package/dst/man/ase-setup-enable.1 +45 -0
- package/dst/man/ase-setup-install.1 +73 -0
- package/dst/man/ase-setup-mcp.1 +124 -0
- package/dst/man/ase-setup-status.1 +60 -0
- package/dst/man/ase-setup-statusline.1 +92 -0
- package/dst/man/ase-setup-telemetry.1 +92 -0
- package/dst/man/ase-setup-uninstall.1 +59 -0
- package/dst/man/ase-setup-update.1 +64 -0
- package/dst/man/ase-setup.1 +93 -0
- package/dst/man/ase-spec-export.1 +62 -0
- package/dst/man/ase-spec-lint.1 +40 -0
- package/dst/man/ase-spec-preview.1 +40 -0
- package/dst/man/ase-spec.1 +46 -0
- package/dst/man/ase-statusline.1 +189 -0
- package/dst/man/ase-task-assign.1 +71 -0
- package/dst/man/ase-task-board.1 +384 -0
- package/dst/man/ase-task-delete.1 +35 -0
- package/dst/man/ase-task-edit.1 +46 -0
- package/dst/man/ase-task-idscheme.1 +65 -0
- package/dst/man/ase-task-lifecycle.1 +57 -0
- package/dst/man/ase-task-list.1 +47 -0
- package/dst/man/ase-task-load.1 +36 -0
- package/dst/man/ase-task-newid.1 +61 -0
- package/dst/man/ase-task-purge.1 +37 -0
- package/dst/man/ase-task-rename.1 +44 -0
- package/dst/man/ase-task-request.1 +61 -0
- package/dst/man/ase-task-save.1 +48 -0
- package/dst/man/ase-task-status.1 +55 -0
- package/dst/man/ase-task-store.1 +194 -0
- package/dst/man/ase-task-view.1 +40 -0
- package/dst/man/ase-task.1 +160 -0
- package/dst/man/ase-util-compat.1 +25 -0
- package/dst/man/ase-util-diagram.1 +76 -0
- package/dst/man/ase-util-meta.1 +45 -0
- package/dst/man/ase-util-metric.1 +54 -0
- package/dst/man/ase-util-mint.1 +59 -0
- package/dst/man/ase-util-worktree.1 +72 -0
- package/dst/man/ase-util.1 +50 -0
- package/dst/man/ase.1 +124 -0
- package/package.json +81 -21
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/.codex-plugin/plugin.json +1 -1
- package/plugin/.github/plugin/plugin.json +1 -1
- package/plugin/agents/ase-meta-diagram.md +12 -8
- package/plugin/agents/ase-repo-review.md +322 -0
- package/plugin/hooks/hooks-codex.json +5 -0
- package/plugin/hooks/hooks-copilot.json +5 -0
- package/plugin/hooks/hooks.json +8 -0
- package/plugin/meta/ase-common-approach.md +117 -0
- package/plugin/meta/ase-common-changeset.md +256 -0
- package/plugin/meta/ase-common-code.md +10 -173
- package/plugin/meta/ase-common-grill.md +317 -0
- package/plugin/meta/ase-common-resolve.md +305 -0
- package/plugin/meta/ase-common-task.md +83 -4
- package/plugin/meta/ase-constitution.md +0 -2
- package/plugin/meta/ase-format-specbook.md +208 -25
- package/plugin/meta/ase-format-specbook.yaml +242 -851
- package/plugin/meta/ase-format-task.md +669 -125
- package/plugin/meta/ase-persona.md +3 -4
- package/plugin/meta/ase-skill.md +9 -0
- package/plugin/mods/ase-mods.ts +409 -0
- package/plugin/mods/claude-code.d.ts +13417 -0
- package/plugin/skills/ase-arch-analyze/SKILL.md +1 -1
- package/plugin/skills/ase-arch-analyze/help.md +2 -2
- package/plugin/skills/ase-code-analyze/SKILL.md +59 -8
- package/plugin/skills/ase-code-analyze/help.md +29 -4
- package/plugin/skills/ase-code-edit/SKILL.md +107 -181
- package/plugin/skills/ase-code-edit/help.md +118 -31
- package/plugin/skills/ase-code-lint/SKILL.md +64 -13
- package/plugin/skills/ase-code-lint/help.md +32 -2
- package/plugin/skills/ase-docs-proofread/SKILL.md +4 -4
- package/plugin/skills/ase-docs-proofread/help.md +1 -1
- package/plugin/skills/ase-docs-refine/SKILL.md +4 -4
- package/plugin/skills/ase-docs-shorten/SKILL.md +4 -4
- package/plugin/skills/ase-help-intent/data.md +2164 -1087
- package/plugin/skills/ase-help-intent/help.md +1 -1
- package/plugin/skills/ase-help-skill/catalog.md +12 -9
- package/plugin/skills/ase-meta-brainstorm/SKILL.md +1 -1
- package/plugin/skills/ase-meta-config/SKILL.md +3 -4
- package/plugin/skills/ase-meta-config/help.md +31 -10
- package/plugin/skills/ase-meta-mint/SKILL.md +5 -5
- package/plugin/skills/ase-meta-mint/help.md +10 -5
- package/plugin/skills/ase-meta-why/help.md +1 -1
- package/plugin/skills/ase-meta-workflow/SKILL.md +7 -7
- package/plugin/skills/ase-meta-workflow/help.md +4 -4
- package/plugin/skills/ase-meta-workflow/sample.md +3 -3
- package/plugin/skills/ase-meta-workflow/workflow.txt +22 -18
- package/plugin/skills/{ase-meta-changelog → ase-repo-changelog}/SKILL.md +4 -3
- package/plugin/skills/{ase-meta-changelog → ase-repo-changelog}/help.md +5 -5
- package/plugin/skills/{ase-meta-commit → ase-repo-commit}/SKILL.md +6 -6
- package/plugin/skills/{ase-meta-commit → ase-repo-commit}/help.md +5 -5
- package/plugin/skills/{ase-meta-diff → ase-repo-diff}/SKILL.md +6 -6
- package/plugin/skills/{ase-meta-diff → ase-repo-diff}/help.md +8 -8
- package/plugin/skills/{ase-code-dissect → ase-repo-dissect}/SKILL.md +19 -19
- package/plugin/skills/{ase-code-dissect → ase-repo-dissect}/help.md +10 -12
- package/plugin/skills/ase-repo-merge/SKILL.md +346 -0
- package/plugin/skills/ase-repo-merge/help.md +107 -0
- package/plugin/skills/ase-repo-resolve/SKILL.md +158 -0
- package/plugin/skills/ase-repo-resolve/help.md +102 -0
- package/plugin/skills/ase-repo-review/SKILL.md +406 -0
- package/plugin/skills/ase-repo-review/help.md +181 -0
- package/plugin/skills/ase-spec-edit/SKILL.md +117 -183
- package/plugin/skills/ase-spec-edit/help.md +107 -26
- package/plugin/skills/ase-sync-reconcile/help.md +1 -1
- package/plugin/skills/ase-task-assign/SKILL.md +111 -0
- package/plugin/skills/ase-task-assign/help.md +119 -0
- package/plugin/skills/ase-task-condense/SKILL.md +21 -21
- package/plugin/skills/ase-task-condense/help.md +12 -10
- package/plugin/skills/ase-task-delete/SKILL.md +1 -1
- package/plugin/skills/ase-task-dissect/SKILL.md +71 -48
- package/plugin/skills/ase-task-dissect/help.md +10 -9
- package/plugin/skills/ase-task-edit/SKILL.md +379 -94
- package/plugin/skills/ase-task-edit/help.md +95 -22
- package/plugin/skills/ase-task-estimate/SKILL.md +492 -0
- package/plugin/skills/ase-task-estimate/help.md +158 -0
- package/plugin/skills/ase-task-grill/SKILL.md +246 -138
- package/plugin/skills/ase-task-grill/help.md +129 -26
- package/plugin/skills/ase-task-id/SKILL.md +8 -1
- package/plugin/skills/ase-task-id/help.md +6 -3
- package/plugin/skills/ase-task-implement/SKILL.md +535 -145
- package/plugin/skills/ase-task-implement/help.md +138 -47
- package/plugin/skills/ase-task-integrate/SKILL.md +549 -0
- package/plugin/skills/ase-task-integrate/help.md +187 -0
- package/plugin/skills/ase-task-list/SKILL.md +55 -23
- package/plugin/skills/ase-task-list/help.md +45 -21
- package/plugin/skills/ase-task-reboot/SKILL.md +84 -43
- package/plugin/skills/ase-task-reboot/help.md +28 -8
- package/plugin/skills/ase-task-rename/SKILL.md +10 -2
- package/plugin/skills/ase-task-research/SKILL.md +386 -0
- package/plugin/skills/ase-task-research/help.md +102 -0
- package/plugin/skills/ase-task-status/SKILL.md +137 -0
- package/plugin/skills/ase-task-status/help.md +80 -0
- package/plugin/skills/ase-task-view/SKILL.md +49 -24
- package/plugin/skills/ase-task-view/help.md +19 -9
- package/plugin/agents/ase-meta-review.md +0 -187
- package/plugin/skills/ase-code-craft/SKILL.md +0 -264
- package/plugin/skills/ase-code-craft/help.md +0 -122
- package/plugin/skills/ase-code-refactor/SKILL.md +0 -232
- package/plugin/skills/ase-code-refactor/help.md +0 -109
- package/plugin/skills/ase-code-resolve/SKILL.md +0 -289
- package/plugin/skills/ase-code-resolve/help.md +0 -116
- package/plugin/skills/ase-meta-review/SKILL.md +0 -210
- package/plugin/skills/ase-meta-review/help.md +0 -96
- package/plugin/skills/ase-task-preflight/SKILL.md +0 -166
- package/plugin/skills/ase-task-preflight/help.md +0 -82
- /package/dst/{ase-ignore.js → ase-lib-ignore.js} +0 -0
- /package/dst/{ase-stdio.js → ase-lib-stdio.js} +0 -0
- /package/dst/{ase-kv.js → ase-service-kv.js} +0 -0
- /package/dst/{ase-sleep.js → ase-service-sleep.js} +0 -0
- /package/dst/{ase-timestamp.js → ase-service-timestamp.js} +0 -0
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
** Copyright (c) 2025-2026 Dr. Ralf S. Engelschall <rse@engelschall.com>
|
|
4
4
|
** Licensed under Apache 2.0 <https://spdx.org/licenses/Apache-2.0>
|
|
5
5
|
*/
|
|
6
|
-
import { writeStdout } from "./ase-stdio.js";
|
|
6
|
+
import { writeStdout } from "./ase-lib-stdio.js";
|
|
7
7
|
/* the canonical expected values for every ase-meta-compat probe,
|
|
8
8
|
keyed by "<category>/<probe-name>" as used in the skill */
|
|
9
9
|
const EXPECTED = {
|
|
@@ -39,7 +39,7 @@ const EXPECTED = {
|
|
|
39
39
|
};
|
|
40
40
|
/* format the expected values as "<id>: <value>\n" lines */
|
|
41
41
|
const formatExpected = () => Object.entries(EXPECTED).map(([id, value]) => `${id}: ${value}`).join("\n") + "\n";
|
|
42
|
-
/* CLI command "ase compat" */
|
|
42
|
+
/* CLI command "ase util compat" */
|
|
43
43
|
export default class CompatCommand {
|
|
44
44
|
register(program) {
|
|
45
45
|
program
|
|
@@ -5,9 +5,8 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import fs from "node:fs";
|
|
7
7
|
import { InvalidArgumentError } from "commander";
|
|
8
|
-
import { renderMermaidASCII, renderMermaidSVG } from "beautiful-mermaid";
|
|
9
8
|
import { z } from "zod";
|
|
10
|
-
import { readStdin } from "./ase-stdio.js";
|
|
9
|
+
import { readStdin } from "./ase-lib-stdio.js";
|
|
11
10
|
/* custom argument parser for Commander: non-negative integer */
|
|
12
11
|
const parseInteger = (name) => (value) => {
|
|
13
12
|
const n = Number.parseInt(value, 10);
|
|
@@ -21,12 +20,34 @@ const parseColorMode = (name) => (value) => {
|
|
|
21
20
|
throw new InvalidArgumentError(`${name} must be "none", "ansi16", or "ansi256"`);
|
|
22
21
|
return value;
|
|
23
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
|
+
};
|
|
24
29
|
/* custom argument parser for Commander: output format */
|
|
25
30
|
const parseFormat = (name) => (value) => {
|
|
26
31
|
if (value !== "ascii" && value !== "svg")
|
|
27
32
|
throw new InvalidArgumentError(`${name} must be "ascii" or "svg"`);
|
|
28
33
|
return value;
|
|
29
34
|
};
|
|
35
|
+
/* the D2 compiler, created on first use only (as it spins up the
|
|
36
|
+
WebAssembly build of D2 in a worker thread, which keeps the process
|
|
37
|
+
alive until the compiler is disposed) */
|
|
38
|
+
let d2 = null;
|
|
39
|
+
/* turn a D2 compile failure (a JSON-encoded list of errors) into a message */
|
|
40
|
+
const d2Error = (err) => {
|
|
41
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
42
|
+
try {
|
|
43
|
+
return JSON.parse(message)
|
|
44
|
+
.map((error) => error.errmsg.replace(/^index:/, "line "))
|
|
45
|
+
.join("; ");
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return message;
|
|
49
|
+
}
|
|
50
|
+
};
|
|
30
51
|
/* scan a CSI escape sequence starting at line[i] (where line[i]===ESC and
|
|
31
52
|
line[i+1]==="["); return the index just past the terminating letter, or
|
|
32
53
|
-1 if the sequence is unterminated within the line */
|
|
@@ -141,19 +162,48 @@ export class Diagram {
|
|
|
141
162
|
}
|
|
142
163
|
return mode;
|
|
143
164
|
}
|
|
144
|
-
/*
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
165
|
+
/* dispose the D2 compiler (if any), so its worker thread no longer
|
|
166
|
+
keeps the process alive (used by the short-lived CLI only) */
|
|
167
|
+
static async dispose() {
|
|
168
|
+
if (d2 === null)
|
|
169
|
+
return;
|
|
170
|
+
const compiler = d2;
|
|
171
|
+
d2 = null;
|
|
172
|
+
await (await compiler).dispose();
|
|
173
|
+
}
|
|
174
|
+
/* render a D2 source string as Unicode/ASCII art or SVG document
|
|
175
|
+
("@d2lang/d2" is loaded on first use only; the ANSI "colorMode"
|
|
176
|
+
and the node margins/padding are not supported by D2) */
|
|
177
|
+
static async renderD2(src, opts) {
|
|
178
|
+
d2 ??= import("@d2lang/d2").then((module) => new module.D2()).catch((err) => {
|
|
179
|
+
d2 = null;
|
|
180
|
+
throw err;
|
|
181
|
+
});
|
|
182
|
+
const compiler = await d2;
|
|
183
|
+
try {
|
|
184
|
+
const result = await compiler.compile(src);
|
|
185
|
+
return await compiler.render(result.diagram, {
|
|
186
|
+
...result.renderOptions,
|
|
187
|
+
ascii: opts.format === "ascii",
|
|
188
|
+
asciiMode: opts.ascii ? "standard" : "extended"
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
catch (err) {
|
|
192
|
+
throw new Error(d2Error(err), { cause: err });
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
/* render a Mermaid source string as Unicode/ASCII art or SVG document
|
|
196
|
+
("beautiful-mermaid" is loaded on first use only) */
|
|
197
|
+
static async renderMermaid(src, opts) {
|
|
198
|
+
const { renderMermaidASCII, renderMermaidSVG } = await import("beautiful-mermaid");
|
|
148
199
|
/* render as a self-contained SVG document using the library's
|
|
149
|
-
themed defaults (the ANSI "colorMode"
|
|
150
|
-
clipping below are meaningful only for ASCII art) */
|
|
200
|
+
themed defaults (the ANSI "colorMode" is meaningful only for ASCII art) */
|
|
151
201
|
if (opts.format === "svg")
|
|
152
202
|
return renderMermaidSVG(src);
|
|
153
203
|
/* determine theme colors (gray shades once colors are enabled) */
|
|
154
204
|
const colored = opts.colorMode !== "none";
|
|
155
205
|
/* create diagram rendering */
|
|
156
|
-
|
|
206
|
+
return renderMermaidASCII(src, {
|
|
157
207
|
useAscii: opts.ascii,
|
|
158
208
|
paddingX: opts.nodeMarginX,
|
|
159
209
|
paddingY: opts.nodeMarginY,
|
|
@@ -168,6 +218,24 @@ export class Diagram {
|
|
|
168
218
|
corner: colored ? "#707070" : "#000000"
|
|
169
219
|
}
|
|
170
220
|
});
|
|
221
|
+
}
|
|
222
|
+
/* pure rendering helper: turn a Mermaid or D2 source string plus
|
|
223
|
+
options into a rendered Unicode/ASCII diagram string, or an SVG
|
|
224
|
+
document string when "svg" format is requested. Throws on render
|
|
225
|
+
failure. (the terminal clipping is meaningful only for ASCII art) */
|
|
226
|
+
static async render(src, opts) {
|
|
227
|
+
/* create diagram rendering */
|
|
228
|
+
let out = opts.lang === "d2" ?
|
|
229
|
+
await Diagram.renderD2(src, opts) :
|
|
230
|
+
await Diagram.renderMermaid(src, opts);
|
|
231
|
+
if (opts.format === "svg")
|
|
232
|
+
return out;
|
|
233
|
+
/* determine language-specific regeneration hints */
|
|
234
|
+
const lang = opts.lang === "d2" ? "D2" : "Mermaid";
|
|
235
|
+
const portrait = opts.lang === "d2" ?
|
|
236
|
+
"(\"direction: down\", top-to-bottom) over landscape (\"direction: right\"/\"left\"/\"up\")" :
|
|
237
|
+
"(\"flowchart TB\", top-to-bottom) over landscape (\"LR\"/\"RL\"/\"BT\")";
|
|
238
|
+
const nesting = opts.lang === "d2" ? "nested container" : "nested subgraph";
|
|
171
239
|
/* optionally clip diagram rendering */
|
|
172
240
|
const termWidth = opts.terminalWidth;
|
|
173
241
|
const termHeight = opts.terminalHeight;
|
|
@@ -182,19 +250,19 @@ export class Diagram {
|
|
|
182
250
|
const widest = lines.reduce((m, l) => Math.max(m, visibleWidth(l)), 0);
|
|
183
251
|
if (widest > maxWidth)
|
|
184
252
|
widthWarn =
|
|
185
|
-
`ase diagram: WARNING: rendered diagram width ${widest} exceeds budget ${maxWidth}; ` +
|
|
186
|
-
|
|
253
|
+
`ase util diagram: WARNING: rendered diagram width ${widest} exceeds budget ${maxWidth}; ` +
|
|
254
|
+
`rightmost content was clipped. Please regenerate the ${lang} source to fit ` +
|
|
187
255
|
`within ${maxWidth} chars by preferring a portrait orientation ` +
|
|
188
|
-
|
|
256
|
+
`${portrait}, ` +
|
|
189
257
|
"reducing siblings per row, abbreviating node labels, or restructuring " +
|
|
190
|
-
|
|
258
|
+
`into ${nesting} hierarchies.`;
|
|
191
259
|
lines = lines.map((l) => truncateAnsiLine(l, maxWidth));
|
|
192
260
|
}
|
|
193
261
|
if (maxHeight > 0 && lines.length > maxHeight) {
|
|
194
262
|
const overflow = lines.length - maxHeight;
|
|
195
263
|
heightWarn =
|
|
196
|
-
`ase diagram: WARNING: rendered diagram height ${lines.length} exceeds budget ${maxHeight}; ` +
|
|
197
|
-
`bottom ${overflow} line(s) were clipped. Please regenerate the
|
|
264
|
+
`ase util diagram: WARNING: rendered diagram height ${lines.length} exceeds budget ${maxHeight}; ` +
|
|
265
|
+
`bottom ${overflow} line(s) were clipped. Please regenerate the ${lang} source to fit ` +
|
|
198
266
|
`within ${maxHeight} lines by reducing depth or splitting into multiple diagrams.`;
|
|
199
267
|
lines = lines.slice(0, maxHeight);
|
|
200
268
|
}
|
|
@@ -217,20 +285,21 @@ export default class DiagramCommand {
|
|
|
217
285
|
register(program) {
|
|
218
286
|
program
|
|
219
287
|
.command("diagram")
|
|
220
|
-
.description("Render Mermaid diagram specification as Unicode/ASCII art or SVG")
|
|
221
|
-
.option("-i, --input <file>", "read
|
|
288
|
+
.description("Render Mermaid or D2 diagram specification as Unicode/ASCII art or SVG")
|
|
289
|
+
.option("-i, --input <file>", "read diagram source from file instead of stdin")
|
|
290
|
+
.option("-l, --lang <lang>", "diagram language (\"mermaid\" or \"d2\")", parseLang("--lang"), "mermaid")
|
|
222
291
|
.option("-f, --format <format>", "output format (\"ascii\" or \"svg\")", parseFormat("--format"), "ascii")
|
|
223
292
|
.option("-a, --ascii", "emit plain ASCII (+-|) instead of Unicode box-drawing", false)
|
|
224
|
-
.option("-c, --color-mode <mode>", "force color mode (\"none\", \"ansi16\", or \"ansi256\")", parseColorMode("--color-mode"), Diagram.detectColorMode())
|
|
225
|
-
.option("--node-margin-x <n>", "horizontal margin between nodes of <n> characters", parseInteger("--node-margin-x"), 3)
|
|
226
|
-
.option("--node-margin-y <n>", "vertical margin between nodes of <n> lines", parseInteger("--node-margin-y"), 3)
|
|
227
|
-
.option("--node-padding <n>", "horizontal and vertical inner node padding with <n> characters", parseInteger("--node-padding"), 1)
|
|
293
|
+
.option("-c, --color-mode <mode>", "force color mode (\"none\", \"ansi16\", or \"ansi256\") (Mermaid only)", parseColorMode("--color-mode"), Diagram.detectColorMode())
|
|
294
|
+
.option("--node-margin-x <n>", "horizontal margin between nodes of <n> characters (Mermaid only)", parseInteger("--node-margin-x"), 3)
|
|
295
|
+
.option("--node-margin-y <n>", "vertical margin between nodes of <n> lines (Mermaid only)", parseInteger("--node-margin-y"), 3)
|
|
296
|
+
.option("--node-padding <n>", "horizontal and vertical inner node padding with <n> characters (Mermaid only)", parseInteger("--node-padding"), 1)
|
|
228
297
|
.option("--diagram-clip-x <n>", "extra horizontal clipping of diagram to terminal width minus <n> characters", parseInteger("--diagram-clip-x"), 0)
|
|
229
298
|
.option("--diagram-clip-y <n>", "extra vertical clipping of diagram to terminal height minus <n> lines", parseInteger("--diagram-clip-y"), 0)
|
|
230
299
|
.option("--terminal-width <n>", "width of terminal of <n> characters (for diagram clipping)", parseInteger("--terminal-width"), Diagram.detectTermWidth())
|
|
231
300
|
.option("--terminal-height <n>", "height of terminal of <n> lines (for diagram clipping)", parseInteger("--terminal-height"), Diagram.detectTermHeight())
|
|
232
301
|
.action(async (opts) => {
|
|
233
|
-
/* fetch
|
|
302
|
+
/* fetch diagram specification from file or stdin */
|
|
234
303
|
let src;
|
|
235
304
|
if (opts.input !== undefined) {
|
|
236
305
|
try {
|
|
@@ -245,19 +314,22 @@ export default class DiagramCommand {
|
|
|
245
314
|
else
|
|
246
315
|
src = await readStdin();
|
|
247
316
|
if (src.trim() === "") {
|
|
248
|
-
this.log.write("error", "diagram: empty
|
|
317
|
+
this.log.write("error", "diagram: empty diagram specification");
|
|
249
318
|
process.exit(1);
|
|
250
319
|
}
|
|
251
320
|
/* create diagram rendering */
|
|
252
321
|
let out;
|
|
253
322
|
try {
|
|
254
|
-
out = Diagram.render(src, opts);
|
|
323
|
+
out = await Diagram.render(src, opts);
|
|
255
324
|
}
|
|
256
325
|
catch (err) {
|
|
257
326
|
const message = err instanceof Error ? err.message : String(err);
|
|
258
327
|
this.log.write("error", `diagram: render failed: ${message}`);
|
|
259
328
|
process.exit(1);
|
|
260
329
|
}
|
|
330
|
+
finally {
|
|
331
|
+
await Diagram.dispose();
|
|
332
|
+
}
|
|
261
333
|
/* output diagram rendering */
|
|
262
334
|
process.stdout.write(out);
|
|
263
335
|
if (!out.endsWith("\n"))
|
|
@@ -270,7 +342,7 @@ export class DiagramMCP {
|
|
|
270
342
|
register(mcp) {
|
|
271
343
|
mcp.registerTool("ase_diagram", {
|
|
272
344
|
title: "ASE diagram render",
|
|
273
|
-
description: "Render a Mermaid diagram as Unicode/ASCII art or SVG. " +
|
|
345
|
+
description: "Render a Mermaid or D2 diagram as Unicode/ASCII art or SVG. " +
|
|
274
346
|
"Use for visualizing " +
|
|
275
347
|
"structure/layout/components/dependencies as a Flowchart, " +
|
|
276
348
|
"control-flow/branching/concurrency as a Flowchart, " +
|
|
@@ -279,23 +351,26 @@ export class DiagramMCP {
|
|
|
279
351
|
"data-structure/classes/methods as a UML Class Diagram, " +
|
|
280
352
|
"data-model/entities/relationships as an ER Diagram, or " +
|
|
281
353
|
"metrics/distributions/time-series as an XY-Chart. " +
|
|
282
|
-
"Pass the
|
|
354
|
+
"Pass the diagram specification as `diagram` and its language as `lang` " +
|
|
355
|
+
"(\"mermaid\" by default, or \"d2\"). " +
|
|
283
356
|
"Returns the rendered art (or SVG document, for `format` \"svg\") as `text`.",
|
|
284
357
|
inputSchema: {
|
|
285
358
|
diagram: z.string()
|
|
286
|
-
.describe("Mermaid diagram specification"),
|
|
359
|
+
.describe("Mermaid or D2 diagram specification"),
|
|
360
|
+
lang: z.enum(["mermaid", "d2"]).default("mermaid")
|
|
361
|
+
.describe("diagram language: \"mermaid\" for Mermaid, \"d2\" for D2"),
|
|
287
362
|
format: z.enum(["ascii", "svg"]).default("ascii")
|
|
288
363
|
.describe("output format: \"ascii\" for Unicode/ASCII art, \"svg\" for an SVG document"),
|
|
289
364
|
ascii: z.boolean().default(false)
|
|
290
365
|
.describe("emit plain ASCII (+-|) instead of Unicode box-drawing characters"),
|
|
291
366
|
colorMode: z.enum(["none", "ansi16", "ansi256"]).default("none")
|
|
292
|
-
.describe("color mode for ANSI escape sequences in the rendered output"),
|
|
367
|
+
.describe("color mode for ANSI escape sequences in the rendered output (Mermaid only)"),
|
|
293
368
|
nodeMarginX: z.number().int().min(0).default(3)
|
|
294
|
-
.describe("horizontal margin between nodes, in characters"),
|
|
369
|
+
.describe("horizontal margin between nodes, in characters (Mermaid only)"),
|
|
295
370
|
nodeMarginY: z.number().int().min(0).default(3)
|
|
296
|
-
.describe("vertical margin between nodes, in lines"),
|
|
371
|
+
.describe("vertical margin between nodes, in lines (Mermaid only)"),
|
|
297
372
|
nodePadding: z.number().int().min(0).default(1)
|
|
298
|
-
.describe("inner horizontal and vertical padding within each node, in characters"),
|
|
373
|
+
.describe("inner horizontal and vertical padding within each node, in characters (Mermaid only)"),
|
|
299
374
|
diagramClipX: z.number().int().min(0).default(0)
|
|
300
375
|
.describe("extra horizontal clipping: subtract this many characters from `terminalWidth`"),
|
|
301
376
|
diagramClipY: z.number().int().min(0).default(0)
|
|
@@ -307,7 +382,7 @@ export class DiagramMCP {
|
|
|
307
382
|
}
|
|
308
383
|
}, async (args) => {
|
|
309
384
|
try {
|
|
310
|
-
const out = Diagram.render(args.diagram, args);
|
|
385
|
+
const out = await Diagram.render(args.diagram, args);
|
|
311
386
|
return {
|
|
312
387
|
content: [{ type: "text", text: out }]
|
|
313
388
|
};
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import path from "node:path";
|
|
7
7
|
import fs from "node:fs";
|
|
8
8
|
import { fileURLToPath } from "node:url";
|
|
9
|
-
import { writeStdout } from "./ase-stdio.js";
|
|
9
|
+
import { writeStdout } from "./ase-lib-stdio.js";
|
|
10
10
|
/* reusable functionality: resolve and read plugin "meta/" files */
|
|
11
11
|
export class Meta {
|
|
12
12
|
/* determine the plugin "meta/" directory; the build process copies
|
|
@@ -45,7 +45,7 @@ export class Meta {
|
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
|
-
/* CLI command "ase meta" */
|
|
48
|
+
/* CLI command "ase util meta" */
|
|
49
49
|
export default class MetaCommand {
|
|
50
50
|
log;
|
|
51
51
|
constructor(log) {
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import fs from "node:fs";
|
|
7
7
|
import { z } from "zod";
|
|
8
|
-
import { writeStdout } from "./ase-stdio.js";
|
|
8
|
+
import { writeStdout } from "./ase-lib-stdio.js";
|
|
9
9
|
/* measure the metrics of the text "content", where "words" are the
|
|
10
10
|
whitespace-separated tokens, "lines" count a trailing line without a
|
|
11
11
|
final newline as a full line, "chars" are Unicode characters (code
|
|
@@ -42,7 +42,7 @@ export const measureInput = (file, text) => {
|
|
|
42
42
|
else
|
|
43
43
|
throw new Error("metric: either \"file\" or \"text\" has to be given");
|
|
44
44
|
};
|
|
45
|
-
/* CLI command "ase metric" */
|
|
45
|
+
/* CLI command "ase util metric" */
|
|
46
46
|
export default class MetricCommand {
|
|
47
47
|
/* register commands */
|
|
48
48
|
register(program) {
|
|
@@ -7,21 +7,22 @@ import { createHash } from "node:crypto";
|
|
|
7
7
|
import { Option } from "commander";
|
|
8
8
|
import { z } from "zod";
|
|
9
9
|
import UUID from "pure-uuid";
|
|
10
|
-
import { writeStdout } from "./ase-stdio.js";
|
|
10
|
+
import { writeStdout } from "./ase-lib-stdio.js";
|
|
11
|
+
import { nanoid } from "./ase-lib-hash.js";
|
|
11
12
|
/* the fixed ASE namespace UUID, itself a UUID V5 over the ASE home URL
|
|
12
13
|
within the standard URL namespace, so that all hint-derived UUIDs
|
|
13
14
|
stay stable over time and disjoint from those of other applications */
|
|
14
15
|
const NAMESPACE = new UUID(5, "ns:URL", "https://ase.tools").format("std");
|
|
15
16
|
/* mint "count" identifiers of "type" out of "hint": an empty hint
|
|
16
17
|
yields "count" random UUIDs (V4), while a non-empty hint yields
|
|
17
|
-
exactly one deterministic hash (UUID V5, SHA-1), as hashing is a
|
|
18
|
+
exactly one deterministic hash (UUID V5, SHA-1, NanoId), as hashing is a
|
|
18
19
|
pure function of the hint and hence cannot produce distinct results
|
|
19
20
|
for it -- a larger count is clamped and reported back as a warning */
|
|
20
21
|
export const mint = (type, hint, count) => {
|
|
21
22
|
if (!Number.isInteger(count) || count < 1)
|
|
22
23
|
throw new Error("mint: count has to be a positive integer");
|
|
23
|
-
if (type
|
|
24
|
-
throw new Error(
|
|
24
|
+
if (type !== "uuid" && hint === "")
|
|
25
|
+
throw new Error(`mint: type "${type}" requires a non-empty hint`);
|
|
25
26
|
let warning = "";
|
|
26
27
|
if (hint !== "" && count > 1) {
|
|
27
28
|
warning = `WARNING: type "${type}" is deterministic for a non-empty hint, ` +
|
|
@@ -34,27 +35,29 @@ export const mint = (type, hint, count) => {
|
|
|
34
35
|
ids.push(hint === "" ?
|
|
35
36
|
new UUID(4).format("std") :
|
|
36
37
|
new UUID(5, NAMESPACE, hint).format("std"));
|
|
37
|
-
else
|
|
38
|
+
else if (type === "sha1")
|
|
38
39
|
ids.push(createHash("sha1").update(hint).digest("hex"));
|
|
40
|
+
else
|
|
41
|
+
ids.push(nanoid(hint));
|
|
39
42
|
}
|
|
40
43
|
return { ids, warning };
|
|
41
44
|
};
|
|
42
|
-
/* CLI command "ase mint" */
|
|
45
|
+
/* CLI command "ase util mint" */
|
|
43
46
|
export default class MintCommand {
|
|
44
47
|
/* register commands */
|
|
45
48
|
register(program) {
|
|
46
49
|
program
|
|
47
50
|
.command("mint")
|
|
48
|
-
.description("Mint hash-derived identifiers (UUID, SHA-1) out of a hint")
|
|
51
|
+
.description("Mint hash-derived identifiers (UUID, SHA-1, NanoId) out of a hint")
|
|
49
52
|
.addOption(new Option("-t, --type <type>", "identifier type")
|
|
50
|
-
.choices(["uuid", "sha1"]).default("uuid"))
|
|
53
|
+
.choices(["uuid", "sha1", "nanoid"]).default("uuid"))
|
|
51
54
|
.option("-c, --count <count>", "number of identifiers to mint (empty hint only)", "1")
|
|
52
55
|
.argument("[hint...]", "hint the identifiers are derived from")
|
|
53
56
|
.action(async (hint, opts) => {
|
|
54
57
|
const count = Number(opts.count);
|
|
55
58
|
const result = mint(opts.type, hint.join(" "), count);
|
|
56
59
|
if (result.warning !== "")
|
|
57
|
-
process.stderr.write(`ase mint: ${result.warning}\n`);
|
|
60
|
+
process.stderr.write(`ase util mint: ${result.warning}\n`);
|
|
58
61
|
await writeStdout(`${result.ids.join("\n")}\n`);
|
|
59
62
|
});
|
|
60
63
|
}
|
|
@@ -69,15 +72,19 @@ export class MintMCP {
|
|
|
69
72
|
"is derived from the hint, or a random UUID V4 if the hint is empty. " +
|
|
70
73
|
"For `type` `sha1`, the 40-character hexadecimal SHA-1 digest of the hint " +
|
|
71
74
|
"is derived, which requires a non-empty hint. " +
|
|
75
|
+
"For `type` `nanoid`, a 10-character, NanoId-style base62 hash of the hint " +
|
|
76
|
+
"(the SHA-1 digest, base62-encoded and truncated) is derived, which requires " +
|
|
77
|
+
"a non-empty hint, too. " +
|
|
72
78
|
"Pass `count` to mint more than one random UUID V4 at once, which is " +
|
|
73
79
|
"possible for an empty hint only, as hashing a non-empty hint is " +
|
|
74
80
|
"deterministic and hence always yields exactly one identifier. " +
|
|
75
81
|
"Returns the minted identifiers as `text`, one per line, optionally " +
|
|
76
82
|
"preceded by a line starting with `WARNING:`.",
|
|
77
83
|
inputSchema: {
|
|
78
|
-
type: z.enum(["uuid", "sha1"]).default("uuid")
|
|
79
|
-
.describe("identifier type: `uuid` (UUID V5, or V4 for an empty hint)
|
|
80
|
-
"`sha1` (SHA-1 hexadecimal digest),
|
|
84
|
+
type: z.enum(["uuid", "sha1", "nanoid"]).default("uuid")
|
|
85
|
+
.describe("identifier type: `uuid` (UUID V5, or V4 for an empty hint), " +
|
|
86
|
+
"`sha1` (SHA-1 hexadecimal digest), or `nanoid` (NanoId-style base62 hash), " +
|
|
87
|
+
"default `uuid`"),
|
|
81
88
|
hint: z.string().default("")
|
|
82
89
|
.describe("free-text hint the identifiers are derived from " +
|
|
83
90
|
"(an empty hint is allowed for `uuid` only)"),
|
|
@@ -7,10 +7,13 @@ import path from "node:path";
|
|
|
7
7
|
import fs from "node:fs";
|
|
8
8
|
import { execaSync } from "execa";
|
|
9
9
|
import { z } from "zod";
|
|
10
|
-
import { writeStdout } from "./ase-stdio.js";
|
|
10
|
+
import { writeStdout } from "./ase-lib-stdio.js";
|
|
11
11
|
/* the repository-root-relative path components of the base directory
|
|
12
12
|
which holds all ASE-managed Git worktrees */
|
|
13
13
|
const baseComponents = [".ase", "worktree"];
|
|
14
|
+
/* the extra path component of the base directory holding the temporary
|
|
15
|
+
worktrees: as ids never contain ".", it is disjoint from all regular ids */
|
|
16
|
+
const tempComponent = ".temp";
|
|
14
17
|
/* reusable functionality: safe resolution of the ASE worktree
|
|
15
18
|
directories under <repo-root>/.ase/worktree/<id> */
|
|
16
19
|
export class Worktree {
|
|
@@ -23,12 +26,12 @@ export class Worktree {
|
|
|
23
26
|
throw new Error("worktree: id must match [A-Za-z0-9_-]+");
|
|
24
27
|
}
|
|
25
28
|
/* determine the fully resolved top-level directory of the Git
|
|
26
|
-
working tree, as a Git worktree can only be
|
|
27
|
-
inside one */
|
|
28
|
-
static repoRoot() {
|
|
29
|
+
working tree of a directory, as a Git worktree can only be
|
|
30
|
+
created from inside one */
|
|
31
|
+
static repoRoot(cwd = process.cwd()) {
|
|
29
32
|
let top = "";
|
|
30
33
|
try {
|
|
31
|
-
top = execaSync("git", ["rev-parse", "--show-toplevel"], { stderr: "ignore" }).stdout.trim();
|
|
34
|
+
top = execaSync("git", ["rev-parse", "--show-toplevel"], { cwd, stderr: "ignore" }).stdout.trim();
|
|
32
35
|
}
|
|
33
36
|
catch {
|
|
34
37
|
/* not inside a Git working tree */
|
|
@@ -64,9 +67,9 @@ export class Worktree {
|
|
|
64
67
|
/* resolve the base directory holding all ASE worktrees, asserting
|
|
65
68
|
that every path component below the repository root is a real
|
|
66
69
|
directory; the base directory is created on demand only */
|
|
67
|
-
static baseDir(create = false) {
|
|
68
|
-
let dir = Worktree.repoRoot();
|
|
69
|
-
for (const component of baseComponents) {
|
|
70
|
+
static baseDir(create = false, temp = false, cwd = process.cwd()) {
|
|
71
|
+
let dir = Worktree.repoRoot(cwd);
|
|
72
|
+
for (const component of temp ? [...baseComponents, tempComponent] : baseComponents) {
|
|
70
73
|
dir = path.join(dir, component);
|
|
71
74
|
Worktree.assertRealDir(dir);
|
|
72
75
|
}
|
|
@@ -79,18 +82,18 @@ export class Worktree {
|
|
|
79
82
|
/* resolve the worktree directory of a single id; the leaf itself is
|
|
80
83
|
created by "git worktree add" and hence only has to be free of an
|
|
81
84
|
aliasing entry left behind by an earlier run */
|
|
82
|
-
static dir(id, create = false) {
|
|
85
|
+
static dir(id, create = false, temp = false, cwd = process.cwd()) {
|
|
83
86
|
Worktree.validateId(id);
|
|
84
|
-
const dir = path.join(Worktree.baseDir(create), id);
|
|
87
|
+
const dir = path.join(Worktree.baseDir(create, temp, cwd), id);
|
|
85
88
|
Worktree.assertRealDir(dir);
|
|
86
89
|
return dir;
|
|
87
90
|
}
|
|
88
91
|
}
|
|
89
|
-
/* CLI command "ase worktree" */
|
|
92
|
+
/* CLI command "ase util worktree" */
|
|
90
93
|
export default class WorktreeCommand {
|
|
91
94
|
/* register commands */
|
|
92
95
|
register(program) {
|
|
93
|
-
/* register CLI
|
|
96
|
+
/* register CLI sub-command "ase util worktree" */
|
|
94
97
|
const worktree = program
|
|
95
98
|
.command("worktree")
|
|
96
99
|
.description("Safely resolve the ASE worktree directories under <repo-root>/.ase/worktree")
|
|
@@ -98,22 +101,24 @@ export default class WorktreeCommand {
|
|
|
98
101
|
worktree.outputHelp();
|
|
99
102
|
process.exit(1);
|
|
100
103
|
});
|
|
101
|
-
/* register CLI sub-command "ase worktree base" */
|
|
104
|
+
/* register CLI sub-sub-command "ase util worktree base" */
|
|
102
105
|
worktree
|
|
103
106
|
.command("base")
|
|
104
107
|
.description("Print the validated base directory holding all ASE worktrees")
|
|
105
108
|
.option("-c, --create", "create the base directory if it does not exist yet")
|
|
109
|
+
.option("-t, --temp", "use the base directory of the temporary worktrees")
|
|
106
110
|
.action(async (opts) => {
|
|
107
|
-
await writeStdout(`${Worktree.baseDir(opts.create ?? false)}\n`);
|
|
111
|
+
await writeStdout(`${Worktree.baseDir(opts.create ?? false, opts.temp ?? false)}\n`);
|
|
108
112
|
});
|
|
109
|
-
/* register CLI sub-command "ase worktree path" */
|
|
113
|
+
/* register CLI sub-sub-command "ase util worktree path" */
|
|
110
114
|
worktree
|
|
111
115
|
.command("path")
|
|
112
116
|
.description("Print the validated worktree directory of a single <id>")
|
|
113
117
|
.argument("<id>", "Worktree identifier")
|
|
114
118
|
.option("-c, --create", "create the base directory if it does not exist yet")
|
|
119
|
+
.option("-t, --temp", "resolve the id below the base directory of the temporary worktrees")
|
|
115
120
|
.action(async (id, opts) => {
|
|
116
|
-
await writeStdout(`${Worktree.dir(id, opts.create ?? false)}\n`);
|
|
121
|
+
await writeStdout(`${Worktree.dir(id, opts.create ?? false, opts.temp ?? false)}\n`);
|
|
117
122
|
});
|
|
118
123
|
}
|
|
119
124
|
}
|
|
@@ -135,6 +140,9 @@ export class WorktreeMCP {
|
|
|
135
140
|
"link, through a non-directory, or out of the repository, which `git worktree " +
|
|
136
141
|
"add` would otherwise silently follow and thereby write outside the repository. " +
|
|
137
142
|
"Set `create` to `true` to also create the base directory. " +
|
|
143
|
+
"Set `temp` to `true` for a *temporary* worktree, which is a worktree the caller " +
|
|
144
|
+
"may remove forcibly: it is then resolved below `<repo-root>/.ase/worktree/.temp` " +
|
|
145
|
+
"instead, a namespace disjoint from all regular worktrees. " +
|
|
138
146
|
"Fails with an error if the path is unsafe or the current directory is not a " +
|
|
139
147
|
"Git working tree; in that case you MUST NOT create the worktree at all.",
|
|
140
148
|
inputSchema: {
|
|
@@ -142,14 +150,17 @@ export class WorktreeMCP {
|
|
|
142
150
|
.describe("worktree identifier (allowed characters: A-Z, a-z, 0-9, '_', '-'); " +
|
|
143
151
|
"if omitted, the base directory holding all ASE worktrees is returned"),
|
|
144
152
|
create: z.boolean().optional()
|
|
145
|
-
.describe("if true, create the base directory if it does not exist yet (default: false)")
|
|
153
|
+
.describe("if true, create the base directory if it does not exist yet (default: false)"),
|
|
154
|
+
temp: z.boolean().optional()
|
|
155
|
+
.describe("if true, resolve below the base directory of the temporary worktrees (default: false)")
|
|
146
156
|
}
|
|
147
157
|
}, async (args) => {
|
|
148
158
|
try {
|
|
149
159
|
const create = args.create ?? false;
|
|
160
|
+
const temp = args.temp ?? false;
|
|
150
161
|
const text = args.id !== undefined ?
|
|
151
|
-
Worktree.dir(args.id, create) :
|
|
152
|
-
Worktree.baseDir(create);
|
|
162
|
+
Worktree.dir(args.id, create, temp) :
|
|
163
|
+
Worktree.baseDir(create, temp);
|
|
153
164
|
return {
|
|
154
165
|
content: [{ type: "text", text }]
|
|
155
166
|
};
|
package/dst/ase-util.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
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
|
+
/* CLI command "ase util" */
|
|
7
|
+
export default class UtilCommand {
|
|
8
|
+
/* register command */
|
|
9
|
+
register(program) {
|
|
10
|
+
/* register CLI top-level command "ase util" */
|
|
11
|
+
const util = program
|
|
12
|
+
.command("util")
|
|
13
|
+
.description("Utility commands (meta, compat, diagram, worktree, mint, metric)")
|
|
14
|
+
.action(() => {
|
|
15
|
+
util.outputHelp();
|
|
16
|
+
process.exit(1);
|
|
17
|
+
});
|
|
18
|
+
return util;
|
|
19
|
+
}
|
|
20
|
+
}
|