@bvdm/delano 0.1.0 → 0.1.2

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/README.md CHANGED
@@ -1,122 +1,125 @@
1
1
  # Delano
2
2
 
3
- Delano is an agent-agnostic, runtime-guided, skill-driven delivery system.
3
+ Delano is an agent-agnostic delivery runtime. It keeps planning, execution, and evidence on disk so teams can work with different coding agents without changing the operating model every time.
4
4
 
5
- ## WHY
5
+ ## What Delano is
6
6
 
7
- AI-assisted delivery is fast, but it easily becomes inconsistent.
7
+ - `HANDBOOK.md` is the canonical operating model.
8
+ - `.project/` is the delivery source of truth.
9
+ - `.agents/` is the shared runtime: scripts, rules, hooks, skills, and adapters.
10
+ - `.claude/` is a compatibility mirror of `.agents/`, not a second runtime.
11
+ - `.delano/` is an optional UI layer.
8
12
 
9
- Delano exists to keep teams fast **and** reliable by giving one shared way to move from business outcomes to specs, tasks, code, and evidence.
13
+ The npm package is intentionally thin. It distributes the approved runtime payload and wraps the existing shell-based PM scripts. It does not replace the handbook, the file contracts, or the underlying bash/Python execution layer.
10
14
 
11
- It is designed to reduce:
12
- - execution drift between planning and implementation
13
- - tool-specific lock-in
14
- - undocumented decisions and low-trust delivery flow
15
+ ## Delano CLI
15
16
 
16
- ## WHAT
17
+ - Package: `@bvdm/delano`
18
+ - Binary: `delano`
19
+ - Commands: `install`, `init`, `validate`, `status`, `next`
20
+ - Primary v1.1 goal: bootstrap a repo safely, then stay out of the way
17
21
 
18
- Delano is a spec-first runtime for software delivery, backed by explicit file contracts and deterministic scripts.
22
+ ## One-command bootstrap
19
23
 
20
- Core pieces:
21
- - `HANDBOOK.md` — canonical operating model and governance
22
- - `.project/` — delivery truth (projects, tasks, context, updates, decisions)
23
- - `.agents/` — shared runtime (scripts, rules, hooks, skills, adapters)
24
- - `.claude/` — compatibility mirror for Claude-style paths (symlink where supported, directory mirror otherwise)
25
- - `.delano/` — optional UI layer
24
+ To install the approved Delano runtime into the current repository:
26
25
 
27
- Probe-aware delivery is part of the operating model: draft the spec, make the probe decision explicit, and only approve once uncertainty is retired or consciously accepted.
26
+ ```bash
27
+ npx -y @bvdm/delano@latest --yes
28
+ ```
28
29
 
29
- Supported adapters:
30
- - Claude Code
31
- - Codex CLI
32
- - OpenCode
33
- - Pi coding agent
30
+ That shorthand is equivalent to:
34
31
 
35
- ## HOW
32
+ ```bash
33
+ npx -y @bvdm/delano@latest install --yes
34
+ ```
36
35
 
37
- ### Quick start (inside a Delano repo)
36
+ To install into a different directory:
38
37
 
39
38
  ```bash
40
- # 1) Validate the runtime and required assets
41
- bash .agents/scripts/pm/validate.sh
42
-
43
- # 2) Create a new delivery project scaffold
44
- bash .agents/scripts/pm/init.sh <slug> "<Project Name>" <owner> <lead>
39
+ npx -y @bvdm/delano@latest --target /path/to/repo --yes
40
+ ```
45
41
 
46
- # 3) See portfolio/project status
47
- bash .agents/scripts/pm/status.sh
42
+ If you already have the package installed locally, the same flow is:
48
43
 
49
- # 4) Get next executable tasks
50
- bash .agents/scripts/pm/next.sh
44
+ ```bash
45
+ delano --yes
46
+ delano --target /path/to/repo --yes
51
47
  ```
52
48
 
53
- ### CLI v1 (current package work)
49
+ ## How to use Delano after install
54
50
 
55
- Delano now has a thin npm CLI layer with:
56
- - package name `@bvdm/delano`
57
- - binary name `delano`
58
- - embedded install assets instead of a GitHub-fetch wrapper
59
- - wrapper commands for `install`, `init`, `validate`, `status`, and `next`
51
+ If you bootstrap with one-shot `npx`, keep using `npx` for wrapper commands:
60
52
 
61
- Local development examples from this repository:
53
+ ```bash
54
+ npx -y @bvdm/delano@latest validate
55
+ npx -y @bvdm/delano@latest status
56
+ npx -y @bvdm/delano@latest next -- --all
57
+ ```
58
+
59
+ If the package is installed locally or globally, run these inside the target repository:
62
60
 
63
61
  ```bash
64
- # Build the packaged asset payload
65
- npm run build:assets
62
+ delano validate
63
+ delano status
64
+ delano next -- --all
65
+ delano init <slug> "<Project Name>" <owner> <lead>
66
+ ```
66
67
 
67
- # Inspect the CLI surface
68
- node bin/delano.js --help
68
+ The wrapper commands call the existing PM scripts under `.agents/scripts/pm/`. You can also run those scripts directly:
69
69
 
70
- # Install the approved base payload into another repo or scratch target
71
- node bin/delano.js install --target /path/to/repo --yes
70
+ ```bash
71
+ bash .agents/scripts/pm/validate.sh
72
+ bash .agents/scripts/pm/status.sh
73
+ bash .agents/scripts/pm/next.sh --all
72
74
  ```
73
75
 
74
- ### Daily operating loop
76
+ ## Required dependencies
75
77
 
76
- 1. Keep project intent and execution synced in `.project/projects/<slug>/`.
77
- 2. Execute work through workstreams and atomic tasks (`tasks/T-xxx.md`).
78
- 3. Record progress/blockers in `updates/*.md`.
79
- 4. Re-run validation before merge/handoff:
80
- ```bash
81
- bash .agents/scripts/pm/validate.sh
82
- ```
78
+ Delano v1.1 assumes these tools are available:
83
79
 
84
- ### Install Delano into another repository
80
+ - `node` 18 or newer
81
+ - `bash`
82
+ - `git`
83
+ - `python3` or compatible `python` / `py`
85
84
 
86
- Preferred v1 path:
85
+ The CLI does not bundle its own shell or Python runtime.
87
86
 
88
- ```bash
89
- delano install --target /path/to/repo --yes
90
- ```
87
+ ## Install behavior
91
88
 
92
- Current source-repo development path:
89
+ `delano install` is conflict-first by default:
93
90
 
94
- ```bash
95
- node bin/delano.js install --target /path/to/repo --yes
96
- ```
91
+ - it computes the full install plan before writing files
92
+ - it aborts if an approved target path already exists
93
+ - it reports each conflict as file, directory, or symlink
94
+ - it only overwrites approved allowlist paths when `--force` is used
95
+ - it does not touch unrelated files outside the allowlist
96
+ - it does not install or overwrite a repo-root `.gitignore`
97
97
 
98
- Base install behavior:
99
- - installs only the approved allowlist payload
100
- - aborts on existing-path conflicts unless `--force` is used
101
- - does not install `AGENTS.md`, `CLAUDE.md`, `CODEX.md`, `OPENCODE.md`, or `PI.md` by default
98
+ The base install payload intentionally excludes top-level adapter entry docs such as `AGENTS.md`, `CLAUDE.md`, `CODEX.md`, `OPENCODE.md`, and `PI.md`. Those remain opt-in only.
102
99
 
103
- Legacy bridge path:
100
+ ## v1.1 boundaries
104
101
 
105
- ```bash
106
- ./install-delano.sh
107
- ```
102
+ This package is deliberately narrow:
108
103
 
109
- The shell installer remains available for migration, but it is broader than the npm base install path and should be treated as the compatibility bridge rather than the preferred v1 behavior.
104
+ - npm is the distribution surface
105
+ - `.project` remains repo-owned after install
106
+ - `.agents` remains the runtime surface
107
+ - wrapper commands stay thin in v1.1
108
+ - `install-delano.sh` remains available as the legacy bridge installer
110
109
 
111
- Legacy non-interactive example:
110
+ ## Local development
111
+
112
+ From this repository:
112
113
 
113
114
  ```bash
114
- ./install-delano.sh --target /path/to/repo --agents claude,codex --yes
115
+ npm run build:assets
116
+ node bin/delano.js --help
117
+ node bin/delano.js --yes --target ./tmp/cli-install-smoke
115
118
  ```
116
119
 
117
- ### Read next
120
+ ## Read next
118
121
 
119
- - `docs/user-guide.md` for the user-facing overview
120
- - `HANDBOOK.md` for full operating semantics
121
- - `.agents/scripts/README.md` for runtime script inventory
122
- - `AGENTS.md` and adapter entrypoints (`CLAUDE.md`, `CODEX.md`, etc.) for agent-specific bootstraps
122
+ - `docs/user-guide.md` for the practical user flow
123
+ - `HANDBOOK.md` for the full operating model
124
+ - `.agents/scripts/README.md` for the runtime script inventory
125
+ - `AGENTS.md` for adapter-neutral instructions
@@ -76,7 +76,6 @@
76
76
  ".agents/skills/sync-skill/templates/drift-report.md",
77
77
  ".delano/README.md",
78
78
  ".gitattributes",
79
- ".gitignore",
80
79
  ".project/context/gui-testing.md",
81
80
  ".project/context/product-context.md",
82
81
  ".project/context/progress.md",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bvdm/delano",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Thin npm CLI for the Delano delivery runtime.",
5
5
  "license": "UNLICENSED",
6
6
  "bin": {
@@ -12,6 +12,7 @@ function getInstallHelp() {
12
12
  return [
13
13
  "Usage:",
14
14
  " delano install [options]",
15
+ " delano [options]",
15
16
  "",
16
17
  "Options:",
17
18
  " --target <dir> Install into the given directory. Defaults to the current working directory.",
@@ -23,7 +24,12 @@ function getInstallHelp() {
23
24
  "Behavior:",
24
25
  " - Computes the full install plan before writing files.",
25
26
  " - Aborts on conflicts by default.",
26
- " - Only installs the approved base payload; top-level adapter entry docs remain opt-in and are not installed in v1."
27
+ " - Only installs the approved base payload; top-level adapter entry docs remain opt-in and are not installed in v1.",
28
+ "",
29
+ "Examples:",
30
+ " delano install --target ../repo --yes",
31
+ " delano --yes",
32
+ " npx -y @bvdm/delano@latest --yes"
27
33
  ].join("\n");
28
34
  }
29
35
 
package/src/cli/index.js CHANGED
@@ -25,6 +25,51 @@ const commands = {
25
25
  next: wrapperCommands.next
26
26
  };
27
27
 
28
+ function isInstallShorthand(argv) {
29
+ if (argv.length === 0) {
30
+ return false;
31
+ }
32
+
33
+ return argv[0].startsWith("-");
34
+ }
35
+
36
+ function resolveInvocation(argv) {
37
+ if (argv.length === 0) {
38
+ return { kind: "help" };
39
+ }
40
+
41
+ const [commandName, ...commandArgs] = argv;
42
+
43
+ if (commandName === "-h" || commandName === "--help" || commandName === "help") {
44
+ return { kind: "help" };
45
+ }
46
+
47
+ if (commandName === "-v" || commandName === "--version" || commandName === "version") {
48
+ return { kind: "version" };
49
+ }
50
+
51
+ if (isInstallShorthand(argv)) {
52
+ return {
53
+ kind: "command",
54
+ commandName: "install",
55
+ commandArgs: argv,
56
+ command: commands.install
57
+ };
58
+ }
59
+
60
+ const command = commands[commandName];
61
+ if (!command) {
62
+ throw new CliError(`Unknown command: ${commandName}\n\n${getGeneralHelp()}`, 1);
63
+ }
64
+
65
+ return {
66
+ kind: "command",
67
+ commandName,
68
+ commandArgs,
69
+ command
70
+ };
71
+ }
72
+
28
73
  function getPackageVersion() {
29
74
  const packageJsonPath = path.join(getPackageRoot(), "package.json");
30
75
  const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf8"));
@@ -50,36 +95,33 @@ function getGeneralHelp() {
50
95
  " -v, --version Show version",
51
96
  "",
52
97
  "Examples:",
53
- " delano install --target ../my-repo --yes",
98
+ " delano --yes",
99
+ " delano --target ../my-repo --yes",
100
+ " npx -y @bvdm/delano@latest --yes",
54
101
  " delano validate",
55
102
  " delano next -- --all",
56
103
  "",
104
+ "Shorthand:",
105
+ " delano [install-options] is equivalent to delano install [install-options].",
106
+ "",
57
107
  "Use 'delano <command> --help' for command-specific help."
58
108
  ].join("\n");
59
109
  }
60
110
 
61
111
  async function run(argv) {
62
- if (argv.length === 0) {
63
- console.log(getGeneralHelp());
64
- return 0;
65
- }
66
-
67
- const [commandName, ...commandArgs] = argv;
112
+ const invocation = resolveInvocation(argv);
68
113
 
69
- if (commandName === "-h" || commandName === "--help" || commandName === "help") {
114
+ if (invocation.kind === "help") {
70
115
  console.log(getGeneralHelp());
71
116
  return 0;
72
117
  }
73
118
 
74
- if (commandName === "-v" || commandName === "--version" || commandName === "version") {
119
+ if (invocation.kind === "version") {
75
120
  console.log(getPackageVersion());
76
121
  return 0;
77
122
  }
78
123
 
79
- const command = commands[commandName];
80
- if (!command) {
81
- throw new CliError(`Unknown command: ${commandName}\n\n${getGeneralHelp()}`, 1);
82
- }
124
+ const { command, commandArgs } = invocation;
83
125
 
84
126
  if (commandArgs.includes("--help") || commandArgs.includes("-h")) {
85
127
  const helpText = typeof command.help === "function" ? command.help() : getGeneralHelp();
@@ -93,5 +135,6 @@ async function run(argv) {
93
135
  module.exports = {
94
136
  commands,
95
137
  getGeneralHelp,
138
+ resolveInvocation,
96
139
  run
97
140
  };
@@ -16,6 +16,14 @@ const { getPackageRoot, getPathType } = require("./runtime");
16
16
 
17
17
  const SUPPORTED_AGENTS = ["claude", "codex", "opencode", "pi"];
18
18
 
19
+ function getMissingPackagedAssetMessage(relativePath) {
20
+ return [
21
+ `Packaged asset missing for '${relativePath}'.`,
22
+ "If you are running from a source checkout, run 'npm run build:assets' first.",
23
+ "If you installed the published npm package, the package is incomplete and needs to be rebuilt and republished."
24
+ ].join(" ");
25
+ }
26
+
19
27
  function readInstallManifest() {
20
28
  const manifestPath = path.join(getPackageRoot(), "assets", "install-manifest.json");
21
29
  const manifest = JSON.parse(readFileSync(manifestPath, "utf8"));
@@ -116,10 +124,7 @@ function buildInstallPlan(options) {
116
124
  const items = manifest.paths.map((relativePath) => {
117
125
  const sourcePath = path.join(payloadRoot, relativePath);
118
126
  if (!existsSync(sourcePath)) {
119
- throw new CliError(
120
- `Packaged asset missing for '${relativePath}'. Run 'npm run build:assets' before using 'delano install' from a source checkout.`,
121
- 1
122
- );
127
+ throw new CliError(getMissingPackagedAssetMessage(relativePath), 1);
123
128
  }
124
129
 
125
130
  return {
@@ -257,5 +262,6 @@ module.exports = {
257
262
  parseInstallArgs,
258
263
  printConflicts,
259
264
  printPlanSummary,
260
- readInstallManifest
265
+ readInstallManifest,
266
+ getMissingPackagedAssetMessage
261
267
  };
@@ -50,6 +50,11 @@ function resolveBash() {
50
50
  }
51
51
 
52
52
  if (process.platform === "win32") {
53
+ candidates.push(
54
+ "C:\\Program Files\\Git\\bin\\bash.exe",
55
+ "C:\\Program Files\\Git\\usr\\bin\\bash.exe"
56
+ );
57
+
53
58
  const whereResult = spawnSync("where.exe", ["bash"], {
54
59
  encoding: "utf8",
55
60
  stdio: ["ignore", "pipe", "ignore"]
@@ -62,11 +67,6 @@ function resolveBash() {
62
67
  }
63
68
  }
64
69
  }
65
-
66
- candidates.push(
67
- "C:\\Program Files\\Git\\usr\\bin\\bash.exe",
68
- "C:\\Program Files\\Git\\bin\\bash.exe"
69
- );
70
70
  } else {
71
71
  const whichResult = spawnSync("which", ["bash"], {
72
72
  encoding: "utf8",
@@ -90,9 +90,18 @@ function resolveBash() {
90
90
  );
91
91
  }
92
92
 
93
+ function normalizeBashScriptPath(scriptPath) {
94
+ if (process.platform !== "win32") {
95
+ return scriptPath;
96
+ }
97
+
98
+ return scriptPath.replace(/\\/g, "/");
99
+ }
100
+
93
101
  function runBashScript(scriptPath, args, options = {}) {
94
102
  const bashPath = resolveBash();
95
- const result = spawnSync(bashPath, [scriptPath, ...args], {
103
+ const normalizedScriptPath = normalizeBashScriptPath(scriptPath);
104
+ const result = spawnSync(bashPath, [normalizedScriptPath, ...args], {
96
105
  cwd: options.cwd || process.cwd(),
97
106
  stdio: "inherit",
98
107
  env: options.env || process.env
@@ -117,6 +126,7 @@ module.exports = {
117
126
  findDelanoRoot,
118
127
  getPackageRoot,
119
128
  getPathType,
129
+ normalizeBashScriptPath,
120
130
  resolveBash,
121
131
  runBashScript
122
132
  };