@aiviatic/kindling 0.1.1 → 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.
@@ -10,7 +10,7 @@
10
10
  $ErrorActionPreference = 'Stop'
11
11
 
12
12
  $KindlingNodeVersion = '24.16.0' # == pins.node
13
- $KindlingVersion = '0.1.1' # == pins.kindling
13
+ $KindlingVersion = '0.1.2' # == pins.kindling
14
14
  $NodeFloorMajor = 20
15
15
 
16
16
  # --- Inline helpers (were bootstrap/lib/common.ps1; inlined for the file-less delivery) ----------
@@ -39,19 +39,24 @@ Say " - This window already runs with -ExecutionPolicy Bypass for THIS process o
39
39
  # $NodeExe stays $null when a system Node is reused (launch via PATH); the portable-install path
40
40
  # sets it to the absolute node.exe so the launch never depends on PATH (clean-runtime rule, AR6).
41
41
  $NodeExe = $null
42
+ $arch = if ($env:PROCESSOR_ARCHITECTURE -eq 'ARM64') { 'arm64' } else { 'x64' }
43
+ $distName = "node-v$KindlingNodeVersion-win-$arch"
44
+ $nodeRoot = Join-Path $env:LOCALAPPDATA 'kindling\node'
45
+ $portableNode = Join-Path $nodeRoot "$distName\node.exe"
42
46
  if (Test-NodeOk $NodeFloorMajor) {
43
47
  Say "Node is already installed - reusing it."
48
+ } elseif (Test-Path $portableNode) {
49
+ # Portable Node from a previous run is already extracted here - reuse it, don't re-download the
50
+ # 30 MB. (The portable dir is never persisted to PATH, so Test-NodeOk alone can't see it.)
51
+ Say "Node is already installed - reusing it."
52
+ $NodeExe = $portableNode
44
53
  } else {
45
54
  Say "Setting up Node - the engine your project runs on. This downloads about 30 MB, one time."
46
55
  # Portable Node: download the pinned Windows zip from nodejs.org, VERIFY its SHA-256 against Node's
47
56
  # published SHASUMS256.txt before touching it, extract, and point the launch at the absolute
48
57
  # node.exe (clean-runtime rule AR6 — never rely on a mutated PATH). Mirrors node-windows.ts.
49
- # NOTE: newly implemented; validate on real Windows (proxy/TLS-interception, extract, non-admin exec).
50
58
  $ProgressPreference = 'SilentlyContinue' # a visible progress bar makes Invoke-WebRequest ~10x slower
51
59
  [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
52
- $arch = if ($env:PROCESSOR_ARCHITECTURE -eq 'ARM64') { 'arm64' } else { 'x64' }
53
- $distName = "node-v$KindlingNodeVersion-win-$arch"
54
- $nodeRoot = Join-Path $env:LOCALAPPDATA 'kindling\node'
55
60
  $zipPath = Join-Path $nodeRoot "$distName.zip"
56
61
  $baseUrl = "https://nodejs.org/dist/v$KindlingNodeVersion"
57
62
  New-Item -ItemType Directory -Force -Path $nodeRoot | Out-Null
@@ -73,12 +78,43 @@ if (Test-NodeOk $NodeFloorMajor) {
73
78
  Say "Node is ready."
74
79
  }
75
80
 
76
- # --- Git (portable) -----------------------------------------------------------
81
+ # --- Git (pinned, portable MinGit) -------------------------------------------
82
+ # $GitCmdDir stays $null when a system Git is reused (already on PATH); the portable path sets it to
83
+ # MinGit's cmd\ dir, prepended to PATH at launch so the engine can `git init` the new project.
84
+ $GitCmdDir = $null
85
+ $gitRoot = Join-Path $env:LOCALAPPDATA 'kindling\git'
86
+ $portableGitCmd = Join-Path $gitRoot 'cmd'
77
87
  if (Test-Cmd 'git') {
78
88
  Say "Git is already installed - reusing it."
89
+ } elseif (Test-Path (Join-Path $portableGitCmd 'git.exe')) {
90
+ # Portable MinGit from a previous run is already extracted here - reuse it, don't re-download.
91
+ Say "Git is already installed - reusing it."
92
+ $GitCmdDir = $portableGitCmd
79
93
  } else {
80
- Say "Setting up Git - it keeps the history of your project."
81
- # PortableGit download/extract deferred (needs pinned version + release URL); resolved at rehearsal.
94
+ Say "Setting up Git - it keeps the history of your project. This downloads about 35 MB, one time."
95
+ # Portable MinGit (the ZIP build made for bundling): download the pinned release, VERIFY its SHA-256
96
+ # before touching it, extract, and expose cmd\ on PATH. Mirrors the Node block. Pinned version +
97
+ # hash below MUST be bumped together (git-for-windows publishes the digest on each release asset).
98
+ $ProgressPreference = 'SilentlyContinue'
99
+ [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
100
+ $gitVersion = '2.55.0.2'
101
+ $gitZip = Join-Path $env:LOCALAPPDATA 'kindling\mingit.zip'
102
+ $gitUrl = "https://github.com/git-for-windows/git/releases/download/v2.55.0.windows.2/MinGit-$gitVersion-64-bit.zip"
103
+ $gitSha = 'e3ea2944cea4b3fabcd69c7c1669ef69b1b66c05ac7806d81224d0abad2dec31'
104
+ New-Item -ItemType Directory -Force -Path $gitRoot | Out-Null
105
+ try {
106
+ Invoke-WebRequest -Uri $gitUrl -OutFile $gitZip -UseBasicParsing
107
+ $actual = (Get-FileHash -Path $gitZip -Algorithm SHA256).Hash.ToLower()
108
+ if ($actual -ne $gitSha) {
109
+ throw "downloaded Git failed its integrity check (expected '$gitSha', got '$actual')"
110
+ }
111
+ Expand-Archive -Path $gitZip -DestinationPath $gitRoot -Force
112
+ } catch {
113
+ throw "Couldn't set up Git ($($_.Exception.Message)). Check your internet connection, then run this again - it's safe to re-run."
114
+ }
115
+ $GitCmdDir = $portableGitCmd
116
+ if (-not (Test-Path (Join-Path $GitCmdDir 'git.exe'))) { throw "Git was downloaded but git.exe wasn't found at $GitCmdDir." }
117
+ Say "Git is ready."
82
118
  }
83
119
 
84
120
  # --- Launch Kindling (clean-runtime: absolute node when portable, else npx on PATH) -----------
@@ -91,6 +127,9 @@ Say "Starting Kindling..."
91
127
  $launchDir = Join-Path $env:LOCALAPPDATA 'kindling'
92
128
  New-Item -ItemType Directory -Force -Path $launchDir | Out-Null
93
129
  Set-Location -LiteralPath $launchDir
130
+ # Portable Git on PATH (the engine spawns `git` by name to scaffold the project's history). Applies
131
+ # to both launch branches; the provisioned Node dir is added inside the portable-Node branch below.
132
+ if ($GitCmdDir) { $env:Path = "$GitCmdDir;$env:Path" }
94
133
  if ($null -eq $NodeExe) {
95
134
  & npx -y "@aiviatic/kindling@$KindlingVersion"
96
135
  } else {
@@ -7,7 +7,7 @@
7
7
  set -euo pipefail
8
8
 
9
9
  KINDLING_NODE_VERSION="24.16.0" # == pins.node
10
- KINDLING_VERSION="0.1.1" # == pins.kindling
10
+ KINDLING_VERSION="0.1.2" # == pins.kindling
11
11
  NVM_VERSION="v0.40.3" # == NVM_VERSION (engine/provision/node-unix.ts)
12
12
  NODE_FLOOR_MAJOR=20
13
13
 
@@ -7,108 +7,80 @@ import {
7
7
  expandTilde
8
8
  } from "./chunk-OU3WSB6B.js";
9
9
 
10
- // engine/emitter.ts
11
- var EngineEmitter = class {
12
- log = [];
13
- listeners = /* @__PURE__ */ new Set();
14
- /** Subscribe to events. Returns an unsubscribe function. */
15
- on(listener) {
16
- this.listeners.add(listener);
17
- return () => {
18
- this.listeners.delete(listener);
19
- };
20
- }
21
- /** Emit an event: freeze it, append to the log, then notify listeners in subscription order. */
22
- emit(event) {
23
- const frozen = Object.freeze({ ...event });
24
- this.log.push(frozen);
25
- for (const listener of [...this.listeners]) {
26
- try {
27
- listener(frozen);
28
- } catch {
29
- }
30
- }
31
- }
32
- /** A snapshot of the append-only event log, in emission order. */
33
- events() {
34
- return [...this.log];
35
- }
36
- };
37
-
38
10
  // engine/pins.ts
39
11
  var pins = Object.freeze({
40
12
  node: "24.16.0",
41
13
  bmad: "6.9.0",
42
14
  // frozen for the Cohort #1 cycle (matches this repo's BMad install; tools + install flags verified vs the real 6.9.0 CLI 2026-07-02); bump between cohorts
43
- kindling: "0.1.1"
15
+ kindling: "0.1.2"
44
16
  });
45
17
 
46
18
  // engine/messages.ts
47
19
  var stepMessages = {
48
- [StepId.ProvisionNode]: "Setting up Node \u2014 the engine your project runs on.",
49
- [StepId.ProvisionGit]: "Setting up Git \u2014 it keeps the history of your project safe.",
50
- [StepId.ProvisionXcodeClt]: "macOS is installing some developer tools. A system dialog popped up \u2014 click Install. This is completely normal and usually takes about 5 minutes. You can grab a coffee.",
20
+ [StepId.ProvisionNode]: "Setting up Node - the engine your project runs on.",
21
+ [StepId.ProvisionGit]: "Setting up Git - it keeps the history of your project safe.",
22
+ [StepId.ProvisionXcodeClt]: "macOS is installing some developer tools. A system dialog popped up: click Install. This is completely normal and usually takes about 5 minutes. You can grab a coffee.",
51
23
  [StepId.ScaffoldGitInit]: "Creating your project folder and starting its history.",
52
- [StepId.InstallBmad]: "Installing BMad \u2014 the toolkit that powers your project. This is a sizeable download, so it can take a couple of minutes. Nothing is stuck; hang tight.",
24
+ [StepId.InstallBmad]: "Installing BMad - the toolkit that powers your project. This is a sizeable download, so it can take a couple of minutes. Nothing is stuck; hang tight.",
53
25
  [StepId.InstallAgentCli]: "Installing your AI coding assistant so it\u2019s ready to run right after setup.",
54
26
  [StepId.FinalizeSelfCheck]: "Double-checking everything is in place."
55
27
  };
56
28
  var agentCliMessages = {
57
29
  working: (name) => `Installing ${name} so you can start right away.`,
58
30
  done: (name) => `${name} is installed and ready to run.`,
59
- skipped: (name) => `${name} is already installed \u2014 reusing it.`,
60
- failed: (name) => `${name} didn\u2019t finish installing \u2014 your project is still set up and ready. You can press Retry, or install it yourself later.`,
31
+ skipped: (name) => `${name} is already installed, reusing it.`,
32
+ failed: (name) => `${name} didn\u2019t finish installing - your project is still set up and ready. You can press Retry, or install it yourself later.`,
61
33
  manualInstall: (pkg) => `To install it yourself later, run: npm install -g ${pkg}`
62
34
  };
63
35
  var scaffoldMessages = {
64
36
  done: "Your project folder is ready.",
65
- skipped: "Project already set up \u2014 nothing to do.",
66
- blocked: "This folder already has files in it. Kindling won\u2019t change anything without your OK \u2014 pick an empty folder, or confirm before continuing.",
37
+ skipped: "Project already set up, nothing to do.",
38
+ blocked: "This folder already has files in it. Kindling won\u2019t change anything without your OK, pick an empty folder, or confirm before continuing.",
67
39
  failed: "Setting up your project folder ran into a problem. Check the details, then press Retry."
68
40
  };
69
41
  var provisionMessages = {
70
- nodePresent: "Node is already installed \u2014 reusing it.",
71
- nodeQueued: "Node needs setting up \u2014 the engine your project runs on.",
72
- gitPresent: "Git is already installed \u2014 reusing it.",
73
- gitQueued: "Git needs setting up \u2014 it keeps the history of your project.",
42
+ nodePresent: "Node is already installed, reusing it.",
43
+ nodeQueued: "Node needs setting up - the engine your project runs on.",
44
+ gitPresent: "Git is already installed, reusing it.",
45
+ gitQueued: "Git needs setting up - it keeps the history of your project.",
74
46
  gitInstalled: "Git is set up.",
75
- xcodeWaiting: "Still installing developer tools\u2026 the macOS dialog is doing its thing. This can take a few minutes \u2014 hang tight, nothing is stuck.",
76
- xcodeDone: "Developer tools are ready \u2014 Git is set up.",
47
+ xcodeWaiting: "Still installing developer tools\u2026 the macOS dialog is doing its thing. This can take a few minutes, hang tight, nothing is stuck.",
48
+ xcodeDone: "Developer tools are ready - Git is set up.",
77
49
  xcodeTimeout: "The developer-tools install is taking longer than expected. If the macOS dialog is still open, let it finish, then press Retry.",
78
50
  xcodeInstallFailed: "We couldn\u2019t start the developer-tools install. Make sure you\u2019re connected, then press Retry.",
79
- gitInstallFailed: "Setting up Git ran into a problem \u2014 it may need permission to install. Check the details, then press Retry."
51
+ gitInstallFailed: "Setting up Git ran into a problem, it may need permission to install. Check the details, then press Retry."
80
52
  };
81
53
  var selfCheckMessages = {
82
- done: "Everything checks out \u2014 you\u2019re ready.",
83
- failed: "Some checks didn\u2019t pass \u2014 see the readiness details."
54
+ done: "Everything checks out, you\u2019re ready.",
55
+ failed: "Some checks didn\u2019t pass, see the readiness details."
84
56
  };
85
57
  var installMessages = {
86
- notPinned: "BMad isn\u2019t pinned to a version yet \u2014 set the cohort version before installing.",
58
+ notPinned: "BMad isn\u2019t pinned to a version yet, set the cohort version before installing.",
87
59
  done: (version) => `BMad ${version} installed.`
88
60
  };
89
61
  var errorMessages = {
90
- [ErrorCode.ExecFailed]: "Something needs a quick fix \u2014 a step did not finish. Check the next step below, then press Retry.",
62
+ [ErrorCode.ExecFailed]: "Something needs a quick fix: a step did not finish. Check the next step below, then press Retry.",
91
63
  [ErrorCode.NetworkLost]: "We lost the connection. Reconnect to the internet, then press Retry.",
92
- [ErrorCode.BmadInstallFailed]: "BMad didn\u2019t finish installing. The details are below \u2014 press Retry.",
93
- [ErrorCode.AgentCliInstallFailed]: "Your AI coding assistant didn\u2019t finish installing \u2014 your project is still ready. Press Retry, or install it yourself later.",
94
- [ErrorCode.ExecPolicyBlocked]: "Windows blocked the script because it\u2019s unsigned \u2014 that\u2019s expected, safe, and reversible.",
95
- [ErrorCode.SmartScreenBlocked]: "Windows SmartScreen (or your antivirus) paused the script \u2014 that\u2019s expected, safe, and reversible.",
64
+ [ErrorCode.BmadInstallFailed]: "BMad didn\u2019t finish installing. The details are below, press Retry.",
65
+ [ErrorCode.AgentCliInstallFailed]: "Your AI coding assistant didn\u2019t finish installing - your project is still ready. Press Retry, or install it yourself later.",
66
+ [ErrorCode.ExecPolicyBlocked]: "Windows blocked the script because it\u2019s unsigned, that\u2019s expected, safe, and reversible.",
67
+ [ErrorCode.SmartScreenBlocked]: "Windows SmartScreen (or your antivirus) paused the script, that\u2019s expected, safe, and reversible.",
96
68
  [ErrorCode.ProjectConflict]: "That folder already has files in it that Kindling didn\u2019t create."
97
69
  };
98
70
  var recoveryGuidance = {
99
71
  [ErrorCode.ExecFailed]: {
100
72
  title: "Something needs a quick fix.",
101
- detail: "A step didn\u2019t finish. This usually clears up on a second try \u2014 press Retry.",
73
+ detail: "A step didn\u2019t finish. This usually clears up on a second try, press Retry.",
102
74
  recovery: "retry"
103
75
  },
104
76
  [ErrorCode.NetworkLost]: {
105
77
  title: "We lost the connection.",
106
- detail: "A download was interrupted. Reconnect to the internet, then press Retry \u2014 Kindling resumes where it left off.",
78
+ detail: "A download was interrupted. Reconnect to the internet, then press Retry, Kindling resumes where it left off.",
107
79
  recovery: "retry"
108
80
  },
109
81
  [ErrorCode.BmadInstallFailed]: {
110
82
  title: "BMad didn\u2019t install.",
111
- detail: "The install step didn\u2019t finish. This is usually temporary \u2014 press Retry. The step details below show what happened.",
83
+ detail: "The install step didn\u2019t finish. This is usually temporary, press Retry. The step details below show what happened.",
112
84
  recovery: "retry"
113
85
  },
114
86
  [ErrorCode.AgentCliInstallFailed]: {
@@ -116,18 +88,18 @@ var recoveryGuidance = {
116
88
  // concrete, copy-pasteable `npm install -g <package>` line ships in the failed step's own
117
89
  // message (agentCliMessages.manualInstall) rather than in this static, error-code-keyed entry.
118
90
  title: "Your AI assistant didn\u2019t install.",
119
- detail: "Your project is set up and ready either way \u2014 this step is optional. Press Retry to try again, or install it yourself later using the command shown in the step details below.",
91
+ detail: "Your project is set up and ready either way, this step is optional. Press Retry to try again, or install it yourself later using the command shown in the step details below.",
120
92
  recovery: "retry"
121
93
  },
122
94
  [ErrorCode.ExecPolicyBlocked]: {
123
95
  title: "Something needs a quick fix.",
124
- detail: "Windows blocked the script because it\u2019s unsigned \u2014 that\u2019s expected, and it\u2019s safe and reversible. Run this one line in PowerShell, then come back and press Retry:",
96
+ detail: "Windows blocked the script because it\u2019s unsigned, that\u2019s expected, and it\u2019s safe and reversible. Run this one line in PowerShell, then come back and press Retry:",
125
97
  fixCommand: "Set-ExecutionPolicy -Scope Process Bypass",
126
98
  recovery: "retry"
127
99
  },
128
100
  [ErrorCode.SmartScreenBlocked]: {
129
101
  title: "Windows asked you to confirm.",
130
- detail: "SmartScreen or your antivirus paused the script \u2014 this is expected and safe. Choose \u201CMore info\u201D, then \u201CRun anyway\u201D, and press Retry. Nothing was changed on your computer.",
102
+ detail: "SmartScreen or your antivirus paused the script, this is expected and safe. Choose \u201CMore info\u201D, then \u201CRun anyway\u201D, and press Retry. Nothing was changed on your computer.",
131
103
  recovery: "retry"
132
104
  },
133
105
  [ErrorCode.ProjectConflict]: {
@@ -137,6 +109,34 @@ var recoveryGuidance = {
137
109
  }
138
110
  };
139
111
 
112
+ // engine/emitter.ts
113
+ var EngineEmitter = class {
114
+ log = [];
115
+ listeners = /* @__PURE__ */ new Set();
116
+ /** Subscribe to events. Returns an unsubscribe function. */
117
+ on(listener) {
118
+ this.listeners.add(listener);
119
+ return () => {
120
+ this.listeners.delete(listener);
121
+ };
122
+ }
123
+ /** Emit an event: freeze it, append to the log, then notify listeners in subscription order. */
124
+ emit(event) {
125
+ const frozen = Object.freeze({ ...event });
126
+ this.log.push(frozen);
127
+ for (const listener of [...this.listeners]) {
128
+ try {
129
+ listener(frozen);
130
+ } catch {
131
+ }
132
+ }
133
+ }
134
+ /** A snapshot of the append-only event log, in emission order. */
135
+ events() {
136
+ return [...this.log];
137
+ }
138
+ };
139
+
140
140
  // engine/orchestrate/scaffold.ts
141
141
  import { mkdir, readdir, writeFile } from "fs/promises";
142
142
  import { join } from "path";
@@ -261,13 +261,29 @@ function composeInstallArgs(config, action = "install") {
261
261
  return args;
262
262
  }
263
263
 
264
+ // engine/orchestrate/launch.ts
265
+ import { dirname, join as join2 } from "path";
266
+ function npxCliPath(nodeExe) {
267
+ return join2(dirname(nodeExe), "node_modules", "npm", "bin", "npx-cli.js");
268
+ }
269
+ function npmCliPath(nodeExe) {
270
+ return join2(dirname(nodeExe), "node_modules", "npm", "bin", "npm-cli.js");
271
+ }
272
+ function composeLaunchCommand({ nodeExe, kindlingVersion }) {
273
+ const spec = `@aiviatic/kindling@${kindlingVersion}`;
274
+ if (nodeExe === null) {
275
+ return { cmd: "npx", args: ["-y", spec] };
276
+ }
277
+ return { cmd: nodeExe, args: [npxCliPath(nodeExe), "-y", spec] };
278
+ }
279
+
264
280
  // engine/orchestrate/bmad-install.ts
265
281
  import { randomUUID as randomUUID2 } from "crypto";
266
282
  import { stat } from "fs/promises";
267
- import { join as join2 } from "path";
283
+ import { join as join3 } from "path";
268
284
  async function defaultBmadInstalled(projectDir) {
269
285
  try {
270
- return (await stat(join2(projectDir, "_bmad"))).isDirectory();
286
+ return (await stat(join3(projectDir, "_bmad"))).isDirectory();
271
287
  } catch {
272
288
  return false;
273
289
  }
@@ -304,14 +320,30 @@ async function runBmadInstall(opts) {
304
320
  const alreadyInstalled = opts.bmadAlreadyInstalled ?? defaultBmadInstalled;
305
321
  action = await alreadyInstalled(opts.config.projectDir) ? "update" : "install";
306
322
  }
307
- const args = [`bmad-method@${versionTag}`, ...composeInstallArgs(opts.config, action)];
323
+ const args = [
324
+ ...opts.npxPrefixArgs ?? [],
325
+ `bmad-method@${versionTag}`,
326
+ ...composeInstallArgs(opts.config, action)
327
+ ];
308
328
  result = await exec2(npx, args);
309
329
  } catch (err) {
310
- emit(Status.Failed, errorMessages[ErrorCode.BmadInstallFailed], "error", ErrorCode.BmadInstallFailed);
330
+ const detail = err instanceof Error ? err.message : String(err);
331
+ emit(
332
+ Status.Failed,
333
+ `${errorMessages[ErrorCode.BmadInstallFailed]} (${detail})`,
334
+ "error",
335
+ ErrorCode.BmadInstallFailed
336
+ );
311
337
  throw err;
312
338
  }
313
339
  if (result.code !== 0) {
314
- emit(Status.Failed, errorMessages[ErrorCode.BmadInstallFailed], "error", ErrorCode.BmadInstallFailed);
340
+ const raw = (result.stderr.trim() ? result.stderr : result.stdout).trim();
341
+ const detail = raw.slice(-600).trim();
342
+ const humanMessage = detail ? `${errorMessages[ErrorCode.BmadInstallFailed]}
343
+
344
+ Details:
345
+ ${detail}` : errorMessages[ErrorCode.BmadInstallFailed];
346
+ emit(Status.Failed, humanMessage, "error", ErrorCode.BmadInstallFailed);
315
347
  return { ok: false, bmadVersion: versionTag };
316
348
  }
317
349
  emit(Status.Done, installMessages.done(versionTag));
@@ -373,16 +405,32 @@ async function installAgentCli(opts) {
373
405
  emit(Status.Working, agentCliMessages.working(name));
374
406
  const failMessage = `${agentCliMessages.failed(name)} ${agentCliMessages.manualInstall(pkg)}`;
375
407
  try {
376
- const result = await exec2(npm, ["install", "-g", pkg]);
408
+ const result = await exec2(npm, [...opts.npmPrefixArgs ?? [], "install", "-g", pkg]);
377
409
  if (result.code === 0) {
378
410
  emit(Status.Done, agentCliMessages.done(name));
379
411
  installed.push(id);
380
412
  } else {
381
- emit(Status.Failed, failMessage, "error", ErrorCode.AgentCliInstallFailed);
413
+ const raw = (result.stderr.trim() ? result.stderr : result.stdout).trim();
414
+ const detail = raw.slice(-600).trim();
415
+ emit(
416
+ Status.Failed,
417
+ detail ? `${failMessage}
418
+
419
+ Details:
420
+ ${detail}` : failMessage,
421
+ "error",
422
+ ErrorCode.AgentCliInstallFailed
423
+ );
382
424
  failed.push(id);
383
425
  }
384
- } catch {
385
- emit(Status.Failed, failMessage, "error", ErrorCode.AgentCliInstallFailed);
426
+ } catch (err) {
427
+ const detail = err instanceof Error ? err.message : String(err);
428
+ emit(
429
+ Status.Failed,
430
+ `${failMessage} (${detail})`,
431
+ "error",
432
+ ErrorCode.AgentCliInstallFailed
433
+ );
386
434
  failed.push(id);
387
435
  }
388
436
  }
@@ -391,11 +439,11 @@ async function installAgentCli(opts) {
391
439
 
392
440
  // engine/bmad-manifest.ts
393
441
  import { readFile } from "fs/promises";
394
- import { join as join3 } from "path";
442
+ import { join as join4 } from "path";
395
443
  import { load } from "js-yaml";
396
444
  async function readInstalledBmadVersion(projectDir) {
397
445
  try {
398
- const raw = await readFile(join3(projectDir, "_bmad", "_config", "manifest.yaml"), "utf8");
446
+ const raw = await readFile(join4(projectDir, "_bmad", "_config", "manifest.yaml"), "utf8");
399
447
  const doc = load(raw);
400
448
  if (typeof doc !== "object" || doc === null) return null;
401
449
  const installation = doc.installation;
@@ -625,14 +673,14 @@ async function provisionGitUnix(opts) {
625
673
 
626
674
  // engine/log.ts
627
675
  import { mkdir as mkdir2, writeFile as writeFile2 } from "fs/promises";
628
- import { join as join4 } from "path";
676
+ import { join as join5 } from "path";
629
677
  import { homedir } from "os";
630
678
  import { randomUUID as randomUUID7 } from "crypto";
631
679
  function defaultLogDir() {
632
680
  if (process.platform === "win32" && process.env.LOCALAPPDATA) {
633
- return join4(process.env.LOCALAPPDATA, "kindling", "logs");
681
+ return join5(process.env.LOCALAPPDATA, "kindling", "logs");
634
682
  }
635
- return join4(homedir(), ".kindling", "logs");
683
+ return join5(homedir(), ".kindling", "logs");
636
684
  }
637
685
  function render(entry, timestamp) {
638
686
  const lines = [
@@ -644,7 +692,7 @@ function render(entry, timestamp) {
644
692
  entry.error,
645
693
  ``,
646
694
  `Event log:`,
647
- ...entry.events.map((e) => ` [${e.status}] ${e.step} \u2014 ${e.humanMessage}`),
695
+ ...entry.events.map((e) => ` [${e.status}] ${e.step} - ${e.humanMessage}`),
648
696
  ``
649
697
  ];
650
698
  return lines.join("\n");
@@ -655,7 +703,7 @@ async function writeFailureLog(entry, opts = {}) {
655
703
  const safeStamp = timestamp.replace(/[:.]/g, "-");
656
704
  const suffix = randomUUID7().slice(0, 8);
657
705
  await mkdir2(dir, { recursive: true });
658
- const path = join4(dir, `kindling-report-${safeStamp}-${suffix}.log`);
706
+ const path = join5(dir, `kindling-report-${safeStamp}-${suffix}.log`);
659
707
  await writeFile2(path, render(entry, timestamp));
660
708
  return path;
661
709
  }
@@ -733,7 +781,11 @@ var Engine = class {
733
781
  {
734
782
  id: StepId.InstallBmad,
735
783
  run: async () => {
736
- const result = await this.deps.runBmadInstall({ config: this.config, emitter: this.emitter });
784
+ const result = await this.deps.runBmadInstall({
785
+ config: this.config,
786
+ emitter: this.emitter,
787
+ ...this.deps.platform === "win32" ? { npxCommand: process.execPath, npxPrefixArgs: [npxCliPath(process.execPath)] } : {}
788
+ });
737
789
  this.bmadInstalled = result.ok;
738
790
  return result.ok;
739
791
  }
@@ -748,7 +800,11 @@ var Engine = class {
748
800
  // CLI-presence guidance (retry() skips the already-completed self-check). See deferred-work.md.
749
801
  id: StepId.InstallAgentCli,
750
802
  run: async () => {
751
- await this.deps.installAgentCli({ config: this.config, emitter: this.emitter });
803
+ await this.deps.installAgentCli({
804
+ config: this.config,
805
+ emitter: this.emitter,
806
+ ...this.deps.platform === "win32" ? { npmCommand: process.execPath, npmPrefixArgs: [npmCliPath(process.execPath)] } : {}
807
+ });
752
808
  return true;
753
809
  }
754
810
  },
@@ -859,14 +915,16 @@ var Engine = class {
859
915
  };
860
916
 
861
917
  export {
862
- EngineEmitter,
863
918
  pins,
864
919
  stepMessages,
865
920
  provisionMessages,
866
921
  errorMessages,
867
922
  recoveryGuidance,
923
+ EngineEmitter,
868
924
  scaffold,
869
925
  composeInstallArgs,
926
+ npxCliPath,
927
+ composeLaunchCommand,
870
928
  defaultBmadInstalled,
871
929
  runBmadInstall,
872
930
  AGENT_CLI_TABLE,
@@ -887,4 +945,4 @@ export {
887
945
  writeFailureLog,
888
946
  Engine
889
947
  };
890
- //# sourceMappingURL=chunk-6VTQGOJR.js.map
948
+ //# sourceMappingURL=chunk-DZ2RR3SP.js.map