@aiviatic/kindling 0.1.1 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bootstrap/setup.ps1 +64 -8
- package/bootstrap/setup.sh +1 -1
- package/dist/{chunk-6VTQGOJR.js → chunk-G2SKKJWZ.js} +121 -51
- package/dist/chunk-G2SKKJWZ.js.map +1 -0
- package/dist/cli/main.js +3 -3
- package/dist/cli/main.js.map +1 -1
- package/dist/engine/index.d.ts +21 -15
- package/dist/engine/index.js +6 -17
- package/dist/engine/index.js.map +1 -1
- package/dist/ui/assets/{index-Bw_xLj6a.css → index-B1p-7hfY.css} +1 -1
- package/dist/ui/assets/index-DBBYdu67.js +40 -0
- package/dist/ui/index.html +2 -2
- package/package.json +1 -1
- package/dist/chunk-6VTQGOJR.js.map +0 -1
- package/dist/ui/assets/index-BF3LDvt7.js +0 -40
package/bootstrap/setup.ps1
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
$ErrorActionPreference = 'Stop'
|
|
11
11
|
|
|
12
12
|
$KindlingNodeVersion = '24.16.0' # == pins.node
|
|
13
|
-
$KindlingVersion = '0.1.
|
|
13
|
+
$KindlingVersion = '0.1.3' # == 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,13 +78,61 @@ 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
|
-
#
|
|
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."
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
# --- Persist the portable runtime on the USER PATH ---------------------------
|
|
121
|
+
# So the tools actually WORK in a normal terminal afterward (not just during this run): node/npm/npx
|
|
122
|
+
# live in the Node dir, git in MinGit's cmd\, and any globally-installed agent CLI (claude/codex)
|
|
123
|
+
# gets its shim written INTO the Node dir (npm's global prefix) - so putting the Node dir on PATH
|
|
124
|
+
# covers those too. Only the PORTABLE paths need this; a reused system Node/Git is already on PATH.
|
|
125
|
+
# User-scope (no admin), idempotent, prepended so the pinned runtime wins. Future terminals pick it up.
|
|
126
|
+
function Add-UserPath([string]$dir) {
|
|
127
|
+
if (-not $dir -or -not (Test-Path $dir)) { return }
|
|
128
|
+
$cur = [Environment]::GetEnvironmentVariable('Path', 'User')
|
|
129
|
+
$parts = @(($cur -split ';') | Where-Object { $_ -ne '' })
|
|
130
|
+
if ($parts -notcontains $dir) {
|
|
131
|
+
[Environment]::SetEnvironmentVariable('Path', ((@($dir) + $parts) -join ';'), 'User')
|
|
132
|
+
}
|
|
82
133
|
}
|
|
134
|
+
if ($NodeExe) { Add-UserPath (Split-Path $NodeExe) }
|
|
135
|
+
if ($GitCmdDir) { Add-UserPath $GitCmdDir }
|
|
83
136
|
|
|
84
137
|
# --- Launch Kindling (clean-runtime: absolute node when portable, else npx on PATH) -----------
|
|
85
138
|
Say "Starting Kindling..."
|
|
@@ -91,6 +144,9 @@ Say "Starting Kindling..."
|
|
|
91
144
|
$launchDir = Join-Path $env:LOCALAPPDATA 'kindling'
|
|
92
145
|
New-Item -ItemType Directory -Force -Path $launchDir | Out-Null
|
|
93
146
|
Set-Location -LiteralPath $launchDir
|
|
147
|
+
# Portable Git on PATH (the engine spawns `git` by name to scaffold the project's history). Applies
|
|
148
|
+
# to both launch branches; the provisioned Node dir is added inside the portable-Node branch below.
|
|
149
|
+
if ($GitCmdDir) { $env:Path = "$GitCmdDir;$env:Path" }
|
|
94
150
|
if ($null -eq $NodeExe) {
|
|
95
151
|
& npx -y "@aiviatic/kindling@$KindlingVersion"
|
|
96
152
|
} else {
|
package/bootstrap/setup.sh
CHANGED
|
@@ -40,75 +40,75 @@ var pins = Object.freeze({
|
|
|
40
40
|
node: "24.16.0",
|
|
41
41
|
bmad: "6.9.0",
|
|
42
42
|
// 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.
|
|
43
|
+
kindling: "0.1.3"
|
|
44
44
|
});
|
|
45
45
|
|
|
46
46
|
// engine/messages.ts
|
|
47
47
|
var stepMessages = {
|
|
48
|
-
[StepId.ProvisionNode]: "Setting up Node
|
|
49
|
-
[StepId.ProvisionGit]: "Setting up Git
|
|
50
|
-
[StepId.ProvisionXcodeClt]: "macOS is installing some developer tools. A system dialog popped up
|
|
48
|
+
[StepId.ProvisionNode]: "Setting up Node - the engine your project runs on.",
|
|
49
|
+
[StepId.ProvisionGit]: "Setting up Git - it keeps the history of your project safe.",
|
|
50
|
+
[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
51
|
[StepId.ScaffoldGitInit]: "Creating your project folder and starting its history.",
|
|
52
|
-
[StepId.InstallBmad]: "Installing BMad
|
|
52
|
+
[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
53
|
[StepId.InstallAgentCli]: "Installing your AI coding assistant so it\u2019s ready to run right after setup.",
|
|
54
54
|
[StepId.FinalizeSelfCheck]: "Double-checking everything is in place."
|
|
55
55
|
};
|
|
56
56
|
var agentCliMessages = {
|
|
57
57
|
working: (name) => `Installing ${name} so you can start right away.`,
|
|
58
58
|
done: (name) => `${name} is installed and ready to run.`,
|
|
59
|
-
skipped: (name) => `${name} is already installed
|
|
60
|
-
failed: (name) => `${name} didn\u2019t finish installing
|
|
59
|
+
skipped: (name) => `${name} is already installed, reusing it.`,
|
|
60
|
+
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
61
|
manualInstall: (pkg) => `To install it yourself later, run: npm install -g ${pkg}`
|
|
62
62
|
};
|
|
63
63
|
var scaffoldMessages = {
|
|
64
64
|
done: "Your project folder is ready.",
|
|
65
|
-
skipped: "Project already set up
|
|
66
|
-
blocked: "This folder already has files in it. Kindling won\u2019t change anything without your OK
|
|
65
|
+
skipped: "Project already set up, nothing to do.",
|
|
66
|
+
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
67
|
failed: "Setting up your project folder ran into a problem. Check the details, then press Retry."
|
|
68
68
|
};
|
|
69
69
|
var provisionMessages = {
|
|
70
|
-
nodePresent: "Node is already installed
|
|
71
|
-
nodeQueued: "Node needs setting up
|
|
72
|
-
gitPresent: "Git is already installed
|
|
73
|
-
gitQueued: "Git needs setting up
|
|
70
|
+
nodePresent: "Node is already installed, reusing it.",
|
|
71
|
+
nodeQueued: "Node needs setting up - the engine your project runs on.",
|
|
72
|
+
gitPresent: "Git is already installed, reusing it.",
|
|
73
|
+
gitQueued: "Git needs setting up - it keeps the history of your project.",
|
|
74
74
|
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
|
|
76
|
-
xcodeDone: "Developer tools are ready
|
|
75
|
+
xcodeWaiting: "Still installing developer tools\u2026 the macOS dialog is doing its thing. This can take a few minutes, hang tight, nothing is stuck.",
|
|
76
|
+
xcodeDone: "Developer tools are ready - Git is set up.",
|
|
77
77
|
xcodeTimeout: "The developer-tools install is taking longer than expected. If the macOS dialog is still open, let it finish, then press Retry.",
|
|
78
78
|
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
|
|
79
|
+
gitInstallFailed: "Setting up Git ran into a problem, it may need permission to install. Check the details, then press Retry."
|
|
80
80
|
};
|
|
81
81
|
var selfCheckMessages = {
|
|
82
|
-
done: "Everything checks out
|
|
83
|
-
failed: "Some checks didn\u2019t pass
|
|
82
|
+
done: "Everything checks out, you\u2019re ready.",
|
|
83
|
+
failed: "Some checks didn\u2019t pass, see the readiness details."
|
|
84
84
|
};
|
|
85
85
|
var installMessages = {
|
|
86
|
-
notPinned: "BMad isn\u2019t pinned to a version yet
|
|
86
|
+
notPinned: "BMad isn\u2019t pinned to a version yet, set the cohort version before installing.",
|
|
87
87
|
done: (version) => `BMad ${version} installed.`
|
|
88
88
|
};
|
|
89
89
|
var errorMessages = {
|
|
90
|
-
[ErrorCode.ExecFailed]: "Something needs a quick fix
|
|
90
|
+
[ErrorCode.ExecFailed]: "Something needs a quick fix: a step did not finish. Check the next step below, then press Retry.",
|
|
91
91
|
[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
|
|
93
|
-
[ErrorCode.AgentCliInstallFailed]: "Your AI coding assistant didn\u2019t finish installing
|
|
94
|
-
[ErrorCode.ExecPolicyBlocked]: "Windows blocked the script because it\u2019s unsigned
|
|
95
|
-
[ErrorCode.SmartScreenBlocked]: "Windows SmartScreen (or your antivirus) paused the script
|
|
92
|
+
[ErrorCode.BmadInstallFailed]: "BMad didn\u2019t finish installing. The details are below, press Retry.",
|
|
93
|
+
[ErrorCode.AgentCliInstallFailed]: "Your AI coding assistant didn\u2019t finish installing - your project is still ready. Press Retry, or install it yourself later.",
|
|
94
|
+
[ErrorCode.ExecPolicyBlocked]: "Windows blocked the script because it\u2019s unsigned, that\u2019s expected, safe, and reversible.",
|
|
95
|
+
[ErrorCode.SmartScreenBlocked]: "Windows SmartScreen (or your antivirus) paused the script, that\u2019s expected, safe, and reversible.",
|
|
96
96
|
[ErrorCode.ProjectConflict]: "That folder already has files in it that Kindling didn\u2019t create."
|
|
97
97
|
};
|
|
98
98
|
var recoveryGuidance = {
|
|
99
99
|
[ErrorCode.ExecFailed]: {
|
|
100
100
|
title: "Something needs a quick fix.",
|
|
101
|
-
detail: "A step didn\u2019t finish. This usually clears up on a second try
|
|
101
|
+
detail: "A step didn\u2019t finish. This usually clears up on a second try, press Retry.",
|
|
102
102
|
recovery: "retry"
|
|
103
103
|
},
|
|
104
104
|
[ErrorCode.NetworkLost]: {
|
|
105
105
|
title: "We lost the connection.",
|
|
106
|
-
detail: "A download was interrupted. Reconnect to the internet, then press Retry
|
|
106
|
+
detail: "A download was interrupted. Reconnect to the internet, then press Retry, Kindling resumes where it left off.",
|
|
107
107
|
recovery: "retry"
|
|
108
108
|
},
|
|
109
109
|
[ErrorCode.BmadInstallFailed]: {
|
|
110
110
|
title: "BMad didn\u2019t install.",
|
|
111
|
-
detail: "The install step didn\u2019t finish. This is usually temporary
|
|
111
|
+
detail: "The install step didn\u2019t finish. This is usually temporary, press Retry. The step details below show what happened.",
|
|
112
112
|
recovery: "retry"
|
|
113
113
|
},
|
|
114
114
|
[ErrorCode.AgentCliInstallFailed]: {
|
|
@@ -116,18 +116,18 @@ var recoveryGuidance = {
|
|
|
116
116
|
// concrete, copy-pasteable `npm install -g <package>` line ships in the failed step's own
|
|
117
117
|
// message (agentCliMessages.manualInstall) rather than in this static, error-code-keyed entry.
|
|
118
118
|
title: "Your AI assistant didn\u2019t install.",
|
|
119
|
-
detail: "Your project is set up and ready either way
|
|
119
|
+
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
120
|
recovery: "retry"
|
|
121
121
|
},
|
|
122
122
|
[ErrorCode.ExecPolicyBlocked]: {
|
|
123
123
|
title: "Something needs a quick fix.",
|
|
124
|
-
detail: "Windows blocked the script because it\u2019s unsigned
|
|
124
|
+
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
125
|
fixCommand: "Set-ExecutionPolicy -Scope Process Bypass",
|
|
126
126
|
recovery: "retry"
|
|
127
127
|
},
|
|
128
128
|
[ErrorCode.SmartScreenBlocked]: {
|
|
129
129
|
title: "Windows asked you to confirm.",
|
|
130
|
-
detail: "SmartScreen or your antivirus paused the script
|
|
130
|
+
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
131
|
recovery: "retry"
|
|
132
132
|
},
|
|
133
133
|
[ErrorCode.ProjectConflict]: {
|
|
@@ -304,14 +304,30 @@ async function runBmadInstall(opts) {
|
|
|
304
304
|
const alreadyInstalled = opts.bmadAlreadyInstalled ?? defaultBmadInstalled;
|
|
305
305
|
action = await alreadyInstalled(opts.config.projectDir) ? "update" : "install";
|
|
306
306
|
}
|
|
307
|
-
const args = [
|
|
307
|
+
const args = [
|
|
308
|
+
...opts.npxPrefixArgs ?? [],
|
|
309
|
+
`bmad-method@${versionTag}`,
|
|
310
|
+
...composeInstallArgs(opts.config, action)
|
|
311
|
+
];
|
|
308
312
|
result = await exec2(npx, args);
|
|
309
313
|
} catch (err) {
|
|
310
|
-
|
|
314
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
315
|
+
emit(
|
|
316
|
+
Status.Failed,
|
|
317
|
+
`${errorMessages[ErrorCode.BmadInstallFailed]} (${detail})`,
|
|
318
|
+
"error",
|
|
319
|
+
ErrorCode.BmadInstallFailed
|
|
320
|
+
);
|
|
311
321
|
throw err;
|
|
312
322
|
}
|
|
313
323
|
if (result.code !== 0) {
|
|
314
|
-
|
|
324
|
+
const raw = (result.stderr.trim() ? result.stderr : result.stdout).trim();
|
|
325
|
+
const detail = raw.slice(-600).trim();
|
|
326
|
+
const humanMessage = detail ? `${errorMessages[ErrorCode.BmadInstallFailed]}
|
|
327
|
+
|
|
328
|
+
Details:
|
|
329
|
+
${detail}` : errorMessages[ErrorCode.BmadInstallFailed];
|
|
330
|
+
emit(Status.Failed, humanMessage, "error", ErrorCode.BmadInstallFailed);
|
|
315
331
|
return { ok: false, bmadVersion: versionTag };
|
|
316
332
|
}
|
|
317
333
|
emit(Status.Done, installMessages.done(versionTag));
|
|
@@ -331,6 +347,15 @@ async function probeVersion(exec2, cmd) {
|
|
|
331
347
|
return null;
|
|
332
348
|
}
|
|
333
349
|
}
|
|
350
|
+
async function probeCliVersion(exec2, bin, isWindows) {
|
|
351
|
+
try {
|
|
352
|
+
const r = isWindows ? await exec2("cmd", ["/c", bin, "--version"]) : await exec2(bin, ["--version"]);
|
|
353
|
+
const out = r.stdout.trim() || r.stderr.trim();
|
|
354
|
+
return r.code === 0 && out ? out : null;
|
|
355
|
+
} catch {
|
|
356
|
+
return null;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
334
359
|
|
|
335
360
|
// engine/orchestrate/agent-cli.ts
|
|
336
361
|
var AGENT_CLI_TABLE = {
|
|
@@ -346,7 +371,7 @@ function eligibleAgentClis(installCli) {
|
|
|
346
371
|
async function installAgentCli(opts) {
|
|
347
372
|
const exec2 = opts.exec ?? exec;
|
|
348
373
|
const npm = opts.npmCommand ?? "npm";
|
|
349
|
-
const
|
|
374
|
+
const isWindows = opts.isWindows ?? false;
|
|
350
375
|
const now = opts.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
|
|
351
376
|
const emit = (status, humanMessage, level = "info", errorCode) => {
|
|
352
377
|
opts.emitter.emit({
|
|
@@ -365,7 +390,7 @@ async function installAgentCli(opts) {
|
|
|
365
390
|
const failed = [];
|
|
366
391
|
const eligible = eligibleAgentClis(opts.config.installCli);
|
|
367
392
|
for (const { id, pkg, bin, name } of eligible) {
|
|
368
|
-
if (await
|
|
393
|
+
if (await probeCliVersion(exec2, bin, isWindows) !== null) {
|
|
369
394
|
emit(Status.Skipped, agentCliMessages.skipped(name));
|
|
370
395
|
skipped.push(id);
|
|
371
396
|
continue;
|
|
@@ -373,29 +398,61 @@ async function installAgentCli(opts) {
|
|
|
373
398
|
emit(Status.Working, agentCliMessages.working(name));
|
|
374
399
|
const failMessage = `${agentCliMessages.failed(name)} ${agentCliMessages.manualInstall(pkg)}`;
|
|
375
400
|
try {
|
|
376
|
-
const result = await exec2(npm, ["install", "-g", pkg]);
|
|
401
|
+
const result = await exec2(npm, [...opts.npmPrefixArgs ?? [], "install", "-g", pkg]);
|
|
377
402
|
if (result.code === 0) {
|
|
378
403
|
emit(Status.Done, agentCliMessages.done(name));
|
|
379
404
|
installed.push(id);
|
|
380
405
|
} else {
|
|
381
|
-
|
|
406
|
+
const raw = (result.stderr.trim() ? result.stderr : result.stdout).trim();
|
|
407
|
+
const detail = raw.slice(-600).trim();
|
|
408
|
+
emit(
|
|
409
|
+
Status.Failed,
|
|
410
|
+
detail ? `${failMessage}
|
|
411
|
+
|
|
412
|
+
Details:
|
|
413
|
+
${detail}` : failMessage,
|
|
414
|
+
"error",
|
|
415
|
+
ErrorCode.AgentCliInstallFailed
|
|
416
|
+
);
|
|
382
417
|
failed.push(id);
|
|
383
418
|
}
|
|
384
|
-
} catch {
|
|
385
|
-
|
|
419
|
+
} catch (err) {
|
|
420
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
421
|
+
emit(
|
|
422
|
+
Status.Failed,
|
|
423
|
+
`${failMessage} (${detail})`,
|
|
424
|
+
"error",
|
|
425
|
+
ErrorCode.AgentCliInstallFailed
|
|
426
|
+
);
|
|
386
427
|
failed.push(id);
|
|
387
428
|
}
|
|
388
429
|
}
|
|
389
430
|
return { ok: true, installed, skipped, failed };
|
|
390
431
|
}
|
|
391
432
|
|
|
433
|
+
// engine/orchestrate/launch.ts
|
|
434
|
+
import { dirname, join as join3 } from "path";
|
|
435
|
+
function npxCliPath(nodeExe) {
|
|
436
|
+
return join3(dirname(nodeExe), "node_modules", "npm", "bin", "npx-cli.js");
|
|
437
|
+
}
|
|
438
|
+
function npmCliPath(nodeExe) {
|
|
439
|
+
return join3(dirname(nodeExe), "node_modules", "npm", "bin", "npm-cli.js");
|
|
440
|
+
}
|
|
441
|
+
function composeLaunchCommand({ nodeExe, kindlingVersion }) {
|
|
442
|
+
const spec = `@aiviatic/kindling@${kindlingVersion}`;
|
|
443
|
+
if (nodeExe === null) {
|
|
444
|
+
return { cmd: "npx", args: ["-y", spec] };
|
|
445
|
+
}
|
|
446
|
+
return { cmd: nodeExe, args: [npxCliPath(nodeExe), "-y", spec] };
|
|
447
|
+
}
|
|
448
|
+
|
|
392
449
|
// engine/bmad-manifest.ts
|
|
393
450
|
import { readFile } from "fs/promises";
|
|
394
|
-
import { join as
|
|
451
|
+
import { join as join4 } from "path";
|
|
395
452
|
import { load } from "js-yaml";
|
|
396
453
|
async function readInstalledBmadVersion(projectDir) {
|
|
397
454
|
try {
|
|
398
|
-
const raw = await readFile(
|
|
455
|
+
const raw = await readFile(join4(projectDir, "_bmad", "_config", "manifest.yaml"), "utf8");
|
|
399
456
|
const doc = load(raw);
|
|
400
457
|
if (typeof doc !== "object" || doc === null) return null;
|
|
401
458
|
const installation = doc.installation;
|
|
@@ -455,7 +512,6 @@ import { randomUUID as randomUUID4 } from "crypto";
|
|
|
455
512
|
async function runSelfCheck(opts) {
|
|
456
513
|
const exec2 = opts.exec ?? exec;
|
|
457
514
|
const now = opts.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
|
|
458
|
-
const resolveBin = opts.resolveBin ?? ((bin) => bin);
|
|
459
515
|
const readInstalledBmadVersion2 = opts.readInstalledBmadVersion ?? readInstalledBmadVersion;
|
|
460
516
|
const platform = opts.platform ?? {
|
|
461
517
|
os: process.platform,
|
|
@@ -480,9 +536,10 @@ async function runSelfCheck(opts) {
|
|
|
480
536
|
const nodeVersion = await probeVersion(exec2, opts.node ?? "node");
|
|
481
537
|
const gitVersion = await probeVersion(exec2, opts.git ?? "git");
|
|
482
538
|
const nodeMajor = parseMajor(nodeVersion);
|
|
539
|
+
const isWindows = platform.os === "win32";
|
|
483
540
|
const cli = [];
|
|
484
541
|
for (const c of opts.agentClis ?? []) {
|
|
485
|
-
const present = await
|
|
542
|
+
const present = await probeCliVersion(exec2, c.bin, isWindows) !== null;
|
|
486
543
|
cli.push({ id: c.id, name: c.name, bin: c.bin, pkg: c.pkg, present });
|
|
487
544
|
}
|
|
488
545
|
const installedVersion = await readInstalledBmadVersion2(opts.projectDir);
|
|
@@ -625,14 +682,14 @@ async function provisionGitUnix(opts) {
|
|
|
625
682
|
|
|
626
683
|
// engine/log.ts
|
|
627
684
|
import { mkdir as mkdir2, writeFile as writeFile2 } from "fs/promises";
|
|
628
|
-
import { join as
|
|
685
|
+
import { join as join5 } from "path";
|
|
629
686
|
import { homedir } from "os";
|
|
630
687
|
import { randomUUID as randomUUID7 } from "crypto";
|
|
631
688
|
function defaultLogDir() {
|
|
632
689
|
if (process.platform === "win32" && process.env.LOCALAPPDATA) {
|
|
633
|
-
return
|
|
690
|
+
return join5(process.env.LOCALAPPDATA, "kindling", "logs");
|
|
634
691
|
}
|
|
635
|
-
return
|
|
692
|
+
return join5(homedir(), ".kindling", "logs");
|
|
636
693
|
}
|
|
637
694
|
function render(entry, timestamp) {
|
|
638
695
|
const lines = [
|
|
@@ -644,7 +701,7 @@ function render(entry, timestamp) {
|
|
|
644
701
|
entry.error,
|
|
645
702
|
``,
|
|
646
703
|
`Event log:`,
|
|
647
|
-
...entry.events.map((e) => ` [${e.status}] ${e.step}
|
|
704
|
+
...entry.events.map((e) => ` [${e.status}] ${e.step} - ${e.humanMessage}`),
|
|
648
705
|
``
|
|
649
706
|
];
|
|
650
707
|
return lines.join("\n");
|
|
@@ -655,7 +712,7 @@ async function writeFailureLog(entry, opts = {}) {
|
|
|
655
712
|
const safeStamp = timestamp.replace(/[:.]/g, "-");
|
|
656
713
|
const suffix = randomUUID7().slice(0, 8);
|
|
657
714
|
await mkdir2(dir, { recursive: true });
|
|
658
|
-
const path =
|
|
715
|
+
const path = join5(dir, `kindling-report-${safeStamp}-${suffix}.log`);
|
|
659
716
|
await writeFile2(path, render(entry, timestamp));
|
|
660
717
|
return path;
|
|
661
718
|
}
|
|
@@ -733,7 +790,11 @@ var Engine = class {
|
|
|
733
790
|
{
|
|
734
791
|
id: StepId.InstallBmad,
|
|
735
792
|
run: async () => {
|
|
736
|
-
const result = await this.deps.runBmadInstall({
|
|
793
|
+
const result = await this.deps.runBmadInstall({
|
|
794
|
+
config: this.config,
|
|
795
|
+
emitter: this.emitter,
|
|
796
|
+
...this.deps.platform === "win32" ? { npxCommand: process.execPath, npxPrefixArgs: [npxCliPath(process.execPath)] } : {}
|
|
797
|
+
});
|
|
737
798
|
this.bmadInstalled = result.ok;
|
|
738
799
|
return result.ok;
|
|
739
800
|
}
|
|
@@ -748,7 +809,14 @@ var Engine = class {
|
|
|
748
809
|
// CLI-presence guidance (retry() skips the already-completed self-check). See deferred-work.md.
|
|
749
810
|
id: StepId.InstallAgentCli,
|
|
750
811
|
run: async () => {
|
|
751
|
-
await this.deps.installAgentCli({
|
|
812
|
+
await this.deps.installAgentCli({
|
|
813
|
+
config: this.config,
|
|
814
|
+
emitter: this.emitter,
|
|
815
|
+
// Windows: the idempotent-skip probe must go through `cmd /c <bin> --version` so the
|
|
816
|
+
// installed `claude.cmd` shim is detected (Node won't spawn `.cmd` with shell:false).
|
|
817
|
+
isWindows: this.deps.platform === "win32",
|
|
818
|
+
...this.deps.platform === "win32" ? { npmCommand: process.execPath, npmPrefixArgs: [npmCliPath(process.execPath)] } : {}
|
|
819
|
+
});
|
|
752
820
|
return true;
|
|
753
821
|
}
|
|
754
822
|
},
|
|
@@ -872,6 +940,8 @@ export {
|
|
|
872
940
|
AGENT_CLI_TABLE,
|
|
873
941
|
eligibleAgentClis,
|
|
874
942
|
installAgentCli,
|
|
943
|
+
npxCliPath,
|
|
944
|
+
composeLaunchCommand,
|
|
875
945
|
readInstalledBmadVersion,
|
|
876
946
|
SCHEMA_VERSION,
|
|
877
947
|
NODE_FLOOR_MAJOR,
|
|
@@ -887,4 +957,4 @@ export {
|
|
|
887
957
|
writeFailureLog,
|
|
888
958
|
Engine
|
|
889
959
|
};
|
|
890
|
-
//# sourceMappingURL=chunk-
|
|
960
|
+
//# sourceMappingURL=chunk-G2SKKJWZ.js.map
|