@rse/ase 0.0.15 → 0.0.16

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-setup.js CHANGED
@@ -3,16 +3,129 @@
3
3
  ** Copyright (c) 2025-2026 Dr. Ralf S. Engelschall <rse@engelschall.com>
4
4
  ** Licensed under GPL 3.0 <https://spdx.org/licenses/GPL-3.0-only>
5
5
  */
6
- const registerSetupCommand = (program) => {
7
- program
8
- .command("setup")
9
- .description("Setup ASE")
10
- .action((_opts, cmd) => {
11
- const debug = Boolean(cmd.optsWithGlobals().debug);
12
- if (debug)
13
- console.log("DEBUG: setup command");
14
- console.log("Setup ASE...");
15
- /* TODO: implement setup logic */
16
- });
17
- };
18
- export default registerSetupCommand;
6
+ import path from "node:path";
7
+ import { fileURLToPath } from "node:url";
8
+ import { execa } from "execa";
9
+ import pkg from "../package.json" with { type: "json" };
10
+ /* CLI command "ase setup" */
11
+ export default class SetupCommand {
12
+ log;
13
+ constructor(log) {
14
+ this.log = log;
15
+ }
16
+ /* run a sub-process with inherited stdio so users see live output */
17
+ async run(cmd, args, cwd) {
18
+ this.log.write("info", `setup: running: $ ${cmd} ${args.join(" ")}` +
19
+ (cwd !== undefined ? ` (cwd: ${cwd})` : ""));
20
+ await execa(cmd, args, { stdio: "inherit", cwd });
21
+ }
22
+ /* capture stdout of a sub-process */
23
+ async capture(cmd, args, cwd) {
24
+ this.log.write("info", `setup: running: $ ${cmd} ${args.join(" ")}` +
25
+ (cwd !== undefined ? ` (cwd: ${cwd})` : ""));
26
+ const r = await execa(cmd, args, { stdio: ["ignore", "pipe", "pipe"], cwd });
27
+ return r.stdout.trim();
28
+ }
29
+ /* handler for "ase setup install" */
30
+ async doInstall(dev) {
31
+ this.log.write("info", `setup: install${dev ? "[dev]" : ""}: ` +
32
+ `installing ASE Claude Code plugin (origin: ${dev ? "local" : "remote"})`);
33
+ const source = dev ? process.cwd() : "rse/ase";
34
+ await this.run("claude", ["plugin", "marketplace", "add", source]);
35
+ await this.run("claude", ["plugin", "install", "ase@ase"]);
36
+ return 0;
37
+ }
38
+ /* handler for "ase setup update" */
39
+ async doUpdate(force, dev) {
40
+ if (dev) {
41
+ /* update ASE CLI Tool */
42
+ this.log.write("info", "setup: update[dev]: re-build ASE CLI tool (origin: local)");
43
+ const tooldir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
44
+ await this.run("npm", ["install"], tooldir);
45
+ await this.run("npm", ["start", "build"], tooldir);
46
+ /* in development mode the local plugin files are already current
47
+ but there is no version change in the plugin manifest,
48
+ so just re-install the plugin to let Claude Code update its copy */
49
+ this.log.write("info", "setup: update[dev]: re-install ASE Claude Code plugin (origin: local)");
50
+ await this.run("claude", ["plugin", "uninstall", "ase@ase"]);
51
+ await this.run("claude", ["plugin", "install", "ase@ase"]);
52
+ }
53
+ else {
54
+ /* perform NPM version check */
55
+ const current = pkg.version;
56
+ let latest = "";
57
+ try {
58
+ latest = await this.capture("npm", ["view", "@rse/ase", "version"]);
59
+ }
60
+ catch (err) {
61
+ const message = err instanceof Error ? err.message : String(err);
62
+ this.log.write("warning", `setup: update: failed to query latest ASE version: ${message}`);
63
+ }
64
+ if (!force && latest !== "" && latest === current) {
65
+ this.log.write("info", `setup: update: ASE already at latest version ${current}`);
66
+ return 0;
67
+ }
68
+ /* update ASE CLI tool */
69
+ this.log.write("info", `setup: update: updating ASE CLI tool: ${current} -> ${latest}`);
70
+ await this.run("npm", ["update", "-g", "@rse/ase"]);
71
+ /* update ASE Claude Code plugin */
72
+ this.log.write("info", "setup: update: updating ASE Claude Code plugin");
73
+ await this.run("claude", ["plugin", "marketplace", "update", "ase"]);
74
+ await this.run("claude", ["plugin", "update", "ase@ase"]);
75
+ }
76
+ return 0;
77
+ }
78
+ /* handler for "ase setup uninstall" */
79
+ async doUninstall(dev) {
80
+ /* uninstall ASE Claude Code plugin */
81
+ this.log.write("info", `setup: uninstall${dev ? "[dev]" : ""}: ` +
82
+ `uninstalling ASE Claude Code plugin (origin: ${dev ? "local" : "remote"})`);
83
+ await this.run("claude", ["plugin", "uninstall", "ase@ase"]);
84
+ await this.run("claude", ["plugin", "marketplace", "remove", "ase"]);
85
+ /* uninstall ASE CLI tool (non-development only) */
86
+ if (!dev) {
87
+ this.log.write("info", "setup: uninstall: uninstalling ASE CLI tool (origin: remote)");
88
+ await this.run("npm", ["uninstall", "-g", "@rse/ase"]);
89
+ }
90
+ return 0;
91
+ }
92
+ /* register commands */
93
+ register(program) {
94
+ /* default for --dev derived from ASE_SETUP_DEV environment variable */
95
+ const envDev = process.env.ASE_SETUP_DEV ?? "";
96
+ const devDflt = envDev !== "" && envDev !== "0" && envDev.toLowerCase() !== "false";
97
+ /* register CLI top-level command "ase setup" */
98
+ const setupCmd = program
99
+ .command("setup")
100
+ .description("install, update, or uninstall the ASE tool and plugin")
101
+ .action(() => {
102
+ setupCmd.outputHelp();
103
+ process.exit(1);
104
+ });
105
+ /* register CLI sub-command "ase setup install" */
106
+ setupCmd
107
+ .command("install")
108
+ .description("install the ASE Claude Code plugin")
109
+ .option("-d, --dev", "use local working copy instead of remote repository", devDflt)
110
+ .action(async (opts) => {
111
+ process.exit(await this.doInstall(opts.dev));
112
+ });
113
+ /* register CLI sub-command "ase setup update" */
114
+ setupCmd
115
+ .command("update")
116
+ .description("update the ASE tool and the ASE Claude Code plugin")
117
+ .option("-f, --force", "always perform the update, even if already at latest version", false)
118
+ .option("-d, --dev", "use local working copy instead of remote repository", devDflt)
119
+ .action(async (opts) => {
120
+ process.exit(await this.doUpdate(opts.force, opts.dev));
121
+ });
122
+ /* register CLI sub-command "ase setup uninstall" */
123
+ setupCmd
124
+ .command("uninstall")
125
+ .description("uninstall the ASE Claude Code plugin and the ASE tool")
126
+ .option("-d, --dev", "use local working copy instead of remote repository", devDflt)
127
+ .action(async (opts) => {
128
+ process.exit(await this.doUninstall(opts.dev));
129
+ });
130
+ }
131
+ }
package/dst/ase.js CHANGED
@@ -11,6 +11,7 @@ import ServiceCommand from "./ase-service.js";
11
11
  import MCPCommand from "./ase-mcp.js";
12
12
  import HookCommand from "./ase-hook.js";
13
13
  import DiagramCommand from "./ase-diagram.js";
14
+ import SetupCommand from "./ase-setup.js";
14
15
  import pkg from "../package.json" with { type: "json" };
15
16
  /* globally initialize logger */
16
17
  const log = new Log("ase", "warning", "-");
@@ -26,7 +27,7 @@ const main = async () => {
26
27
  .usage("<command> [options]")
27
28
  .version(`ASE ${pkg.version}`, "-V, --version", "show version information")
28
29
  .addOption(new Option("-l, --log-level <level>", "log level")
29
- .choices(["error", "warning", "info", "debug"]).default("warning"))
30
+ .choices(["error", "warning", "info", "debug"]).default("info"))
30
31
  .option("-L, --log-file <file>", "log file path, or \"-\" for stdout", "-")
31
32
  .showHelpAfterError()
32
33
  .enablePositionalOptions()
@@ -44,6 +45,7 @@ const main = async () => {
44
45
  new MCPCommand(log).register(program);
45
46
  new HookCommand(log).register(program);
46
47
  new DiagramCommand(log).register(program);
48
+ new SetupCommand(log).register(program);
47
49
  /* parse program arguments */
48
50
  await program.parseAsync(process.argv);
49
51
  /* gracefully terminate */
package/package.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "homepage": "http://github.com/rse/ase",
7
7
  "repository": { "url": "git+https://github.com/rse/ase.git", "type": "git" },
8
8
  "bugs": { "url": "http://github.com/rse/ase/issues" },
9
- "version": "0.0.15",
9
+ "version": "0.0.16",
10
10
  "license": "GPL-3.0-only",
11
11
  "author": {
12
12
  "name": "Dr. Ralf S. Engelschall",
@@ -36,7 +36,7 @@
36
36
  },
37
37
  "dependencies": {
38
38
  "commander": "14.0.3",
39
- "yaml": "2.8.3",
39
+ "yaml": "2.8.4",
40
40
  "valibot": "1.3.1",
41
41
  "execa": "9.6.1",
42
42
  "mkdirp": "3.0.1",
@@ -1,34 +0,0 @@
1
- /*
2
- ** Agentic Software Engineering (ASE)
3
- ** Copyright (c) 2025-2026 Dr. Ralf S. Engelschall <rse@engelschall.com>
4
- ** Licensed under GPL 3.0 <https://spdx.org/licenses/GPL-3.0-only>
5
- */
6
- /* create agent command module */
7
- export const createAgentCommandModule = (category, description, subCommands) => {
8
- /* create sub-command handler */
9
- const createSubCommandHandler = (subCommand) => {
10
- return (_opts, cmd) => {
11
- const opts = cmd.optsWithGlobals();
12
- if (opts.debug)
13
- console.log(`DEBUG: agent ${category} ${subCommand} command`);
14
- if (opts.verbose)
15
- console.log(`VERBOSE: executing agent ${category} ${subCommand}...`);
16
- console.log(`Executing agent ${category} ${subCommand}...`);
17
- /* TODO: implement agent ${category} sub-command logic */
18
- };
19
- };
20
- return (parent) => {
21
- const agent = parent
22
- .command(`${category}`)
23
- .description(`Execute ${description} agent operations`)
24
- .option("-v, --verbose", "Enable verbose output", false);
25
- /* register all sub-commands */
26
- for (const subCmd of subCommands) {
27
- agent
28
- .command(subCmd)
29
- .description(`Execute agent ${category} ${subCmd} operation`)
30
- .action(createSubCommandHandler(subCmd));
31
- }
32
- return agent;
33
- };
34
- };
@@ -1,40 +0,0 @@
1
- /*
2
- ** Agentic Software Engineering (ASE)
3
- ** Copyright (c) 2025-2026 Dr. Ralf S. Engelschall <rse@engelschall.com>
4
- ** Licensed under GPL 3.0 <https://spdx.org/licenses/GPL-3.0-only>
5
- */
6
- /* biz sub-commands */
7
- const bizSubCommands = [
8
- "understand",
9
- "ideate",
10
- "explore",
11
- "specify"
12
- ];
13
- /* create sub-command handler */
14
- const createSubCommandHandler = (subCommand) => {
15
- return (_opts, cmd) => {
16
- const opts = cmd.optsWithGlobals();
17
- if (opts.debug)
18
- console.log(`DEBUG: agent biz ${subCommand} command`);
19
- if (opts.verbose)
20
- console.log(`VERBOSE: executing agent biz ${subCommand}...`);
21
- console.log(`Executing agent biz ${subCommand}...`);
22
- /* TODO: implement agent biz sub-command logic */
23
- };
24
- };
25
- /* register biz command on the given parent */
26
- const registerBizCommand = (parent) => {
27
- const biz = parent
28
- .command("biz")
29
- .description("Execute business agent operations")
30
- .option("-v, --verbose", "Enable verbose output", false);
31
- /* register all sub-commands */
32
- for (const subCmd of bizSubCommands) {
33
- biz
34
- .command(subCmd)
35
- .description(`Execute agent biz ${subCmd} operation`)
36
- .action(createSubCommandHandler(subCmd));
37
- }
38
- return biz;
39
- };
40
- export default registerBizCommand;
@@ -1,40 +0,0 @@
1
- /*
2
- ** Agentic Software Engineering (ASE)
3
- ** Copyright (c) 2025-2026 Dr. Ralf S. Engelschall <rse@engelschall.com>
4
- ** Licensed under GPL 3.0 <https://spdx.org/licenses/GPL-3.0-only>
5
- */
6
- /* dev sub-commands */
7
- const devSubCommands = [
8
- "design",
9
- "implement",
10
- "build",
11
- "verify"
12
- ];
13
- /* create sub-command handler */
14
- const createSubCommandHandler = (subCommand) => {
15
- return (_opts, cmd) => {
16
- const opts = cmd.optsWithGlobals();
17
- if (opts.debug)
18
- console.log(`DEBUG: agent dev ${subCommand} command`);
19
- if (opts.verbose)
20
- console.log(`VERBOSE: executing agent dev ${subCommand}...`);
21
- console.log(`Executing agent dev ${subCommand}...`);
22
- /* TODO: implement agent dev sub-command logic */
23
- };
24
- };
25
- /* register dev command on the given parent */
26
- const registerDevCommand = (parent) => {
27
- const dev = parent
28
- .command("dev")
29
- .description("Execute development agent operations")
30
- .option("-v, --verbose", "Enable verbose output", false);
31
- /* register all sub-commands */
32
- for (const subCmd of devSubCommands) {
33
- dev
34
- .command(subCmd)
35
- .description(`Execute agent dev ${subCmd} operation`)
36
- .action(createSubCommandHandler(subCmd));
37
- }
38
- return dev;
39
- };
40
- export default registerDevCommand;
@@ -1,40 +0,0 @@
1
- /*
2
- ** Agentic Software Engineering (ASE)
3
- ** Copyright (c) 2025-2026 Dr. Ralf S. Engelschall <rse@engelschall.com>
4
- ** Licensed under GPL 3.0 <https://spdx.org/licenses/GPL-3.0-only>
5
- */
6
- /* ops sub-commands */
7
- const opsSubCommands = [
8
- "deploy",
9
- "integrate",
10
- "operate",
11
- "monitor"
12
- ];
13
- /* create sub-command handler */
14
- const createSubCommandHandler = (subCommand) => {
15
- return (_opts, cmd) => {
16
- const opts = cmd.optsWithGlobals();
17
- if (opts.debug)
18
- console.log(`DEBUG: agent ops ${subCommand} command`);
19
- if (opts.verbose)
20
- console.log(`VERBOSE: executing agent ops ${subCommand}...`);
21
- console.log(`Executing agent ops ${subCommand}...`);
22
- /* TODO: implement agent ops sub-command logic */
23
- };
24
- };
25
- /* register ops command on the given parent */
26
- const registerOpsCommand = (parent) => {
27
- const ops = parent
28
- .command("ops")
29
- .description("Execute operations agent operations")
30
- .option("-v, --verbose", "Enable verbose output", false);
31
- /* register all sub-commands */
32
- for (const subCmd of opsSubCommands) {
33
- ops
34
- .command(subCmd)
35
- .description(`Execute agent ops ${subCmd} operation`)
36
- .action(createSubCommandHandler(subCmd));
37
- }
38
- return ops;
39
- };
40
- export default registerOpsCommand;
@@ -1,40 +0,0 @@
1
- /*
2
- ** Agentic Software Engineering (ASE)
3
- ** Copyright (c) 2025-2026 Dr. Ralf S. Engelschall <rse@engelschall.com>
4
- ** Licensed under GPL 3.0 <https://spdx.org/licenses/GPL-3.0-only>
5
- */
6
- /* prd sub-commands */
7
- const prdSubCommands = [
8
- "envision",
9
- "configure",
10
- "release",
11
- "rollout"
12
- ];
13
- /* create sub-command handler */
14
- const createSubCommandHandler = (subCommand) => {
15
- return (_opts, cmd) => {
16
- const opts = cmd.optsWithGlobals();
17
- if (opts.debug)
18
- console.log(`DEBUG: agent prd ${subCommand} command`);
19
- if (opts.verbose)
20
- console.log(`VERBOSE: executing agent prd ${subCommand}...`);
21
- console.log(`Executing agent prd ${subCommand}...`);
22
- /* TODO: implement agent prd sub-command logic */
23
- };
24
- };
25
- /* register prd command on the given parent */
26
- const registerPrdCommand = (parent) => {
27
- const prd = parent
28
- .command("prd")
29
- .description("Execute production agent operations")
30
- .option("-v, --verbose", "Enable verbose output", false);
31
- /* register all sub-commands */
32
- for (const subCmd of prdSubCommands) {
33
- prd
34
- .command(subCmd)
35
- .description(`Execute agent prd ${subCmd} operation`)
36
- .action(createSubCommandHandler(subCmd));
37
- }
38
- return prd;
39
- };
40
- export default registerPrdCommand;
@@ -1,40 +0,0 @@
1
- /*
2
- ** Agentic Software Engineering (ASE)
3
- ** Copyright (c) 2025-2026 Dr. Ralf S. Engelschall <rse@engelschall.com>
4
- ** Licensed under GPL 3.0 <https://spdx.org/licenses/GPL-3.0-only>
5
- */
6
- /* prj sub-commands */
7
- const prjSubCommands = [
8
- "initiate",
9
- "define",
10
- "plan",
11
- "steer"
12
- ];
13
- /* create sub-command handler */
14
- const createSubCommandHandler = (subCommand) => {
15
- return (_opts, cmd) => {
16
- const opts = cmd.optsWithGlobals();
17
- if (opts.debug)
18
- console.log(`DEBUG: agent prj ${subCommand} command`);
19
- if (opts.verbose)
20
- console.log(`VERBOSE: executing agent prj ${subCommand}...`);
21
- console.log(`Executing agent prj ${subCommand}...`);
22
- /* TODO: implement agent prj sub-command logic */
23
- };
24
- };
25
- /* register prj command on the given parent */
26
- const registerPrjCommand = (parent) => {
27
- const prj = parent
28
- .command("prj")
29
- .description("Execute project agent operations")
30
- .option("-v, --verbose", "Enable verbose output", false);
31
- /* register all sub-commands */
32
- for (const subCmd of prjSubCommands) {
33
- prj
34
- .command(subCmd)
35
- .description(`Execute agent prj ${subCmd} operation`)
36
- .action(createSubCommandHandler(subCmd));
37
- }
38
- return prj;
39
- };
40
- export default registerPrjCommand;
package/dst/ase-agent.js DELETED
@@ -1,25 +0,0 @@
1
- /*
2
- ** Agentic Software Engineering (ASE)
3
- ** Copyright (c) 2025-2026 Dr. Ralf S. Engelschall <rse@engelschall.com>
4
- ** Licensed under GPL 3.0 <https://spdx.org/licenses/GPL-3.0-only>
5
- */
6
- import registerBizCommand from "./ase-agent-biz.js";
7
- import registerDevCommand from "./ase-agent-dev.js";
8
- import registerOpsCommand from "./ase-agent-ops.js";
9
- import registerPrdCommand from "./ase-agent-prd.js";
10
- import registerPrjCommand from "./ase-agent-prj.js";
11
- /* register agent command on the given program */
12
- const registerAgentCommand = (program) => {
13
- const agent = program
14
- .command("agent")
15
- .description("Execute agent operations")
16
- .option("-v, --verbose", "Enable verbose output", false);
17
- /* register all agent sub-commands */
18
- registerBizCommand(agent);
19
- registerDevCommand(agent);
20
- registerOpsCommand(agent);
21
- registerPrdCommand(agent);
22
- registerPrjCommand(agent);
23
- return agent;
24
- };
25
- export default registerAgentCommand;
package/dst/ase-init.js DELETED
@@ -1,19 +0,0 @@
1
- /*
2
- ** Agentic Software Engineering (ASE)
3
- ** Copyright (c) 2025-2026 Dr. Ralf S. Engelschall <rse@engelschall.com>
4
- ** Licensed under GPL 3.0 <https://spdx.org/licenses/GPL-3.0-only>
5
- */
6
- const initCommand = {
7
- command: "init",
8
- describe: "Initialize ASE configuration",
9
- builder: (yargs) => {
10
- return yargs;
11
- },
12
- handler: (argv) => {
13
- if (argv.debug)
14
- console.log("DEBUG: init command");
15
- console.log("Initializing ASE configuration...");
16
- /* TODO: implement initialization logic */
17
- }
18
- };
19
- export default initCommand;
@@ -1,78 +0,0 @@
1
- /*
2
- ** Agentic Software Engineering (ASE)
3
- ** Copyright (c) 2025-2026 Dr. Ralf S. Engelschall <rse@engelschall.com>
4
- ** Licensed under GPL 3.0 <https://spdx.org/licenses/GPL-3.0-only>
5
- */
6
- import path from "node:path";
7
- import fs from "node:fs";
8
- import { execa } from "execa";
9
- import { mkdirp } from "mkdirp";
10
- const configCommand = {
11
- command: "meta-plan <subcommand>",
12
- describe: "Manage plans",
13
- builder: (yargs) => {
14
- return yargs
15
- .command({
16
- command: "init",
17
- describe: "ensure plan directory exists",
18
- handler: async () => {
19
- const { stdout: root } = await execa("git", ["rev-parse", "--show-toplevel"]);
20
- const planDir = `${root}/.plan/`;
21
- if (!fs.existsSync(planDir))
22
- await mkdirp(planDir);
23
- }
24
- })
25
- .command({
26
- command: "load <id>",
27
- describe: "load a plan",
28
- builder: (yargs) => yargs.positional("id", {
29
- type: "string",
30
- describe: "plan identifier"
31
- }),
32
- handler: async (argv) => {
33
- const { stdout: root } = await execa("git", ["rev-parse", "--show-toplevel"]);
34
- const planDir = `${root}/.plan/`;
35
- const planFile = path.join(planDir, `${argv.id}.md`);
36
- const text = fs.existsSync(planFile) ? fs.readFileSync(planFile, "utf8") : "";
37
- process.stdout.write(text);
38
- }
39
- })
40
- .command({
41
- command: "save <id>",
42
- describe: "save a plan",
43
- builder: (yargs) => yargs.positional("id", {
44
- type: "string",
45
- describe: "plan identifier"
46
- }),
47
- handler: async (argv) => {
48
- const { stdout: root } = await execa("git", ["rev-parse", "--show-toplevel"]);
49
- const planDir = `${root}/.plan/`;
50
- if (!fs.existsSync(planDir))
51
- await mkdirp(planDir);
52
- const planFile = path.join(planDir, `${argv.id}.md`);
53
- const text = fs.readFileSync(0, "utf8");
54
- fs.writeFileSync(planFile, text);
55
- }
56
- })
57
- .command({
58
- command: "edit <id>",
59
- describe: "edit a plan interactively with $EDITOR",
60
- builder: (yargs) => yargs.positional("id", {
61
- type: "string",
62
- describe: "plan identifier"
63
- }),
64
- handler: async (argv) => {
65
- const { stdout: root } = await execa("git", ["rev-parse", "--show-toplevel"]);
66
- const planDir = `${root}/.plan/`;
67
- const planFile = path.join(planDir, `${argv.id}.md`);
68
- if (!fs.existsSync(planDir))
69
- await mkdirp(planDir);
70
- const editor = process.env.EDITOR ?? "vi";
71
- await execa(editor, [planFile], { stdio: "inherit" });
72
- }
73
- })
74
- .demandCommand(1, "You need to specify a sub-command");
75
- },
76
- handler: () => { }
77
- };
78
- export default configCommand;
package/dst/ase-plan.js DELETED
@@ -1,82 +0,0 @@
1
- /*
2
- ** Agentic Software Engineering (ASE)
3
- ** Copyright (c) 2025-2026 Dr. Ralf S. Engelschall <rse@engelschall.com>
4
- ** Licensed under GPL 3.0 <https://spdx.org/licenses/GPL-3.0-only>
5
- */
6
- import path from "node:path";
7
- import fs from "node:fs";
8
- import { execa } from "execa";
9
- import { mkdirp } from "mkdirp";
10
- const planCommand = {
11
- command: "plan <subcommand>",
12
- describe: "Manage plans",
13
- builder: (yargs) => {
14
- return yargs
15
- .command({
16
- command: "ensure",
17
- describe: "ensure plan directory exists",
18
- handler: async () => {
19
- const { stdout: root } = await execa("git", ["rev-parse", "--show-toplevel"]);
20
- const planDir = `${root}/.ase/plan/`;
21
- if (!fs.existsSync(planDir))
22
- await mkdirp(planDir);
23
- process.stdout.write(planDir);
24
- }
25
- })
26
- .command({
27
- command: "load <id>",
28
- describe: "load a plan",
29
- builder: (yargs) => yargs.positional("id", {
30
- type: "string",
31
- describe: "plan identifier"
32
- }),
33
- handler: async (argv) => {
34
- const { stdout: root } = await execa("git", ["rev-parse", "--show-toplevel"]);
35
- const planDir = `${root}/.ase/plan/`;
36
- const planFile = path.join(planDir, `${argv.id}.md`);
37
- const text = fs.existsSync(planFile) ? fs.readFileSync(planFile, "utf8") : "";
38
- process.stdout.write(text);
39
- }
40
- })
41
- .command({
42
- command: "save <id>",
43
- describe: "save a plan",
44
- builder: (yargs) => yargs.positional("id", {
45
- type: "string",
46
- describe: "plan identifier"
47
- }),
48
- handler: async (argv) => {
49
- const { stdout: root } = await execa("git", ["rev-parse", "--show-toplevel"]);
50
- const planDir = `${root}/.ase/plan/`;
51
- if (!fs.existsSync(planDir))
52
- await mkdirp(planDir);
53
- const planFile = path.join(planDir, `${argv.id}.md`);
54
- const chunks = [];
55
- for await (const chunk of process.stdin)
56
- chunks.push(chunk);
57
- const text = Buffer.concat(chunks).toString("utf8");
58
- fs.writeFileSync(planFile, text);
59
- }
60
- })
61
- .command({
62
- command: "edit <id>",
63
- describe: "edit a plan interactively with $EDITOR",
64
- builder: (yargs) => yargs.positional("id", {
65
- type: "string",
66
- describe: "plan identifier"
67
- }),
68
- handler: async (argv) => {
69
- const { stdout: root } = await execa("git", ["rev-parse", "--show-toplevel"]);
70
- const planDir = `${root}/.ase/plan/`;
71
- const planFile = path.join(planDir, `${argv.id}.md`);
72
- if (!fs.existsSync(planDir))
73
- await mkdirp(planDir);
74
- const editor = process.env.EDITOR ?? "vi";
75
- await execa(editor, [planFile], { stdio: "inherit" });
76
- }
77
- })
78
- .demandCommand(1, "You need to specify a sub-command");
79
- },
80
- handler: () => { }
81
- };
82
- export default planCommand;
package/dst/ase.1 DELETED
@@ -1,91 +0,0 @@
1
- .TH "ASE" "1" "April 2026" "" ""
2
- .SH "NAME"
3
- \fBase\fR - Agentic Software Engineering (ASE)
4
- .SH "SYNOPSIS"
5
- .P
6
- \fBase\fR \[lB]\fB-h\fR|\fB--help\fR\[rB] \[lB]\fB-V\fR|\fB--version\fR\[rB] \[lB]\fB-l\fR|\fB--log-level\fR \fIlevel\fR\[rB] \[lB]\fB-L\fR|\fB--log-file\fR \fIfile\fR\[rB] \[lB]\fIcommand\fR \[lB]\fIoptions\fR \[lB]...\[rB]\[rB] \[lB]\fIargs\fR \[lB]...\[rB]\[rB]\[rB]
7
- .SH "DESCRIPTION"
8
- .P
9
- \fBase\fR, \fIAgentic Software Engineering (ASE)\fR, is the command-line companion tool to the \fIASE\fR Claude Code plugin. It provides project-level configuration management and a small per-project background HTTP service for dispatching commands.
10
- .SH "OPTIONS"
11
- .P
12
- The following top-level command-line options exist:
13
- .RS 0
14
- .IP \(bu 4
15
- \[lB]\fB-h\fR|\fB--help\fR\[rB]: Show program usage information only.
16
- .IP \(bu 4
17
- \[lB]\fB-V\fR|\fB--version\fR\[rB]: Show program version information only.
18
- .IP \(bu 4
19
- \[lB]\fB-l\fR|\fB--log-level\fR \fIlevel\fR\[rB]: Set the logging verbosity. Supported \fIlevel\fR values are \fBerror\fR, \fBwarning\fR (default), \fBinfo\fR, and \fBdebug\fR.
20
- .IP \(bu 4
21
- \[lB]\fB-L\fR|\fB--log-file\fR \fIfile\fR\[rB]: Redirect log output to \fIfile\fR (appended). Use \fB-\fR (default) to write log messages to standard output. If \fIfile\fR is connected to a TTY, colors are used in the output.
22
- .RE 0
23
-
24
- .SH "COMMANDS"
25
- .P
26
- The following top-level commands exist for configuration handling:
27
- .RS 0
28
- .IP \(bu 4
29
- \fBase config\fR: Manage \fIASE\fR configuration stored in \fB.ase/config.yaml\fR. Without a subcommand, prints usage information. The file is validated against a schema: on read, unknown or invalid entries are warned about and silently dropped from the in-memory view; on set/write, they cause a fatal error. Recognized keys are grouped under three top-level sections: \fBproject.*\fR (project identity, classification, and artifact globs), \fBagent.*\fR (agent persona and process), and \fBtask.*\fR (currently \fBtask.id\fR, the active task identifier). All \fBase config\fR subcommands accept a \fB--scope\fR \fIscope\fR option that selects the scope chain. The \fIscope\fR value is a comma-separated list of scope terms, in any order; each term is one of \fBuser\fR, \fBproject\fR, \fBtask:\fR\fIid\fR, or \fBsession:\fR\fIid\fR (where \fIid\fR matches \fB\[lB]A-Za-z0-9._-\[rB]+\fR). At most one term per kind is allowed. The chain is canonicalized into the fixed inheritance order \fBuser\fR < \fBproject\fR < \fBtask\fR < \fBsession\fR. \fBuser\fR is always implicitly added at the bottom of the chain. \fBproject\fR is implicitly added only when a \fIproject context\fR exists -- i.e. when the current working directory is inside a Git repository, or a \fB.ase\fR directory is found at or above it. Specifying \fBproject\fR explicitly without a project context is an error. Without an explicit \fB--scope\fR, the target defaults to \fBproject\fR when a project context exists, otherwise to \fBuser\fR. Reads cascade from the strongest (rightmost) scope down to the weakest and return the first value that is defined. Writes (\fBset\fR, \fBdelete\fR, \fBedit\fR, \fBinit\fR) are always confined to the strongest (target) scope's own file -- intermediate and weaker scopes are never modified. See \fIFILES\fR below for the resulting paths. Example: \fB--scope task:T1,session:S1\fR yields the chain \fBuser\fR -> \fBproject\fR -> \fBtask:T1\fR -> \fBsession:S1\fR, with \fBsession:S1\fR as the write target.
30
- .IP \(bu 4
31
- \fBase config init\fR \fItype\fR: Initialize \fB.ase/config.yaml\fR with preset values for all recognized keys. The \fItype\fR argument selects the preset: \fBvibe\fR (solo rookie: small black-box prototype, bare code, fully agent-driven, spec-driven, engineer ambition), \fBpro\fR (solo expert: medium white-box product, framework-based, human-controlled, code-driven, artist ambition), or \fBindustry\fR (team crew: large grey-box MVP, framework-based, human-in-the-loop, code-driven, craftsman ambition).
32
- .IP \(bu 4
33
- \fBase config edit\fR: Open \fB.ase/config.yaml\fR in the editor defined by the \fB$EDITOR\fR or \fB$VISUAL\fR environment variable (falling back to \fBvi\fR). The file and its parent directory are created if missing. After the editor exits, the file is re-read and schema warnings are reported.
34
- .IP \(bu 4
35
- \fBase config list\fR: List all effective configured values across the scope inheritance chain, rendered as a three-column table of \fBkey\fR, \fBvalue\fR, and \fBorigin\fR. The \fBorigin\fR column identifies the scope (\fBuser\fR, \fBproject\fR, \fBtask:\fR\fIid\fR, or \fBsession:\fR\fIid\fR) that supplied each value. For overlapping keys only the value from the strongest scope is shown.
36
- .IP \(bu 4
37
- \fBase config get\fR \fIkey\fR: Print the value at the given dotted \fIkey\fR. Fails with an error if \fIkey\fR does not resolve to a leaf value.
38
- .IP \(bu 4
39
- \fBase config set\fR \fIkey\fR \fIvalue\fR: Set the value at the given dotted \fIkey\fR (creating intermediate maps as needed) and persist the file.
40
- .RE 0
41
-
42
- .P
43
- The following top-level commands exist for service management:
44
- .RS 0
45
- .IP \(bu 4
46
- \fBase service\fR: Manage the per-project background HTTP service. The service is bound to \fB127.0.0.1\fR on a port persisted in \fB.ase/service.yaml\fR and stops itself after 30 minutes of idle time. Without a subcommand, the help text is shown.
47
- .IP \(bu 4
48
- \fBase service start\fR: Start the background service (detached). Allocates a random port in the range \fB42000\fR..\fB44000\fR if none is persisted yet, writes it to \fB.ase/service.yaml\fR, and probes readiness. Exits silently with status 0 if the service is already running; prints \fBase: service: started on port <port>\fR on a fresh start.
49
- .IP \(bu 4
50
- \fBase service status\fR: Report whether the background service is running. Probes the persisted port via HTTP \fBGET /ping\fR and verifies that the responding service belongs to the current project. Prints \fBase: service: running on port <port>\fR and exits with status 0 if a matching service is reachable; otherwise prints a diagnostic message (no port configured, port not responding, or port in use by a foreign service) and exits with status 1.
51
- .IP \(bu 4
52
- \fBase service send\fR \fIcmd\fR: Dispatch the \fIcmd\fR token as a passthrough command to the running service via HTTP \fBPOST /command\fR; if the service is not running, it is auto-started first.
53
- .IP \(bu 4
54
- \fBase service stop\fR: Stop the background service via HTTP \fBGET /stop\fR. Exits silently with status 0 on successful stop. If no port is configured or the port is not responding, prints an informational message and exits with status 0.
55
- .RE 0
56
-
57
- .P
58
- The following top-level commands exist for \fIClaude Code\fR hook integration:
59
- .RS 0
60
- .IP \(bu 4
61
- \fBase hook\fR: Entry point group for \fIClaude Code\fR hook events. Without a subcommand, the help text is shown and the command exits with status 1.
62
- .IP \(bu 4
63
- \fBase hook session-start\fR: Handle the \fIClaude Code\fR \fBSessionStart\fR hook event. This subcommand is intended to be invoked by \fIClaude Code\fR internally as a configured hook handler only, not directly by end users.
64
- .RE 0
65
-
66
- .SH "CONFIGURATION FILES"
67
- .RS 0
68
- .IP \(bu 4
69
- \fBuser\fR: \fIper-user configuration directory\fR\fB/config.yaml\fR: Per-user \fIASE\fR configuration (scope \fBuser\fR). The per-user configuration directory is \fB~/Library/Application Support/ase\fR on macOS, \fB%APPDATA%\[rs]ase\fR on Windows, and \fB$XDG_CONFIG_HOME/ase\fR (falling back to \fB~/.config/ase\fR) on Linux and other Unix systems.
70
- .IP \(bu 4
71
- \fBproject\fR: \fB.ase/config.yaml\fR: Per-project \fIASE\fR configuration (scope \fBproject\fR). Read upward from the current working directory.
72
- .IP \(bu 4
73
- \fBtask\fR: \fB.ase/task/\fR\fIid\fR\fB/config.yaml\fR: Per-task \fIASE\fR configuration (scope \fBtask:\fR\fIid\fR), located relative to the Git top-level directory. Outside a Git repository, the file is placed relative to the current working directory.
74
- .IP \(bu 4
75
- \fBsession\fR: \fB~/.ase/session/\fR\fIid\fR\fB/config.yaml\fR: Per-session \fIASE\fR configuration (scope \fBsession:\fR\fIid\fR), located under the user's home directory (independent of any project context).
76
- .RE 0
77
-
78
- .SH "STATE FILES"
79
- .RS 0
80
- .IP \(bu 4
81
- \fB.ase/service.yaml\fR: Per-project service state.
82
- .IP \(bu 4
83
- \fB.ase/service.log\fR: Stdout/stderr log of the detached background service.
84
- .RE 0
85
-
86
- .SH "HISTORY"
87
- .P
88
- \fBase\fR was started to be developed in October 2025.
89
- .SH "AUTHOR"
90
- .P
91
- Dr. Ralf S. Engelschall \fI\(larse@engelschall.com\(ra\fR