@kal-elsam/kairo-runtime 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.
package/README.md CHANGED
@@ -51,14 +51,14 @@ curl -fsSL https://raw.githubusercontent.com/Kal-elSam/harness/main/scripts/inst
51
51
  The bootstrap installer:
52
52
 
53
53
  - requires Node.js 20.12+ and npm
54
- - runs `@kal-elsam/kairo-runtime` via `npx` (or `npm exec`)
55
- - ends with `kairo setup --dry-run` by default (no agent configs, no `~/.harness` writes)
54
+ - installs `@kal-elsam/kairo-runtime` globally (`kairo` CLI)
55
+ - runs `kairo setup --dry-run` by default (no agent configs, no `~/.harness` writes)
56
56
  - never uses `sudo`, never modifies shell profiles, and never installs AI apps
57
57
 
58
58
  Apply the plan when you are ready:
59
59
 
60
60
  ```bash
61
- npx @kal-elsam/kairo-runtime --yes
61
+ kairo setup --yes
62
62
  # or
63
63
  curl -fsSL https://raw.githubusercontent.com/Kal-elSam/harness/main/scripts/install.sh | sh -s -- --yes
64
64
  ```
@@ -66,8 +66,8 @@ curl -fsSL https://raw.githubusercontent.com/Kal-elSam/harness/main/scripts/inst
66
66
  CI, scripts, and advanced non-interactive configure:
67
67
 
68
68
  ```bash
69
- npx @kal-elsam/kairo-runtime install --agents cursor,codex --yes
70
- npx @kal-elsam/kairo-runtime setup --yes --agents all
69
+ kairo install --agents cursor,codex --yes
70
+ kairo setup --yes --agents all
71
71
  ```
72
72
 
73
73
  Passthrough examples:
@@ -83,11 +83,11 @@ Control plane:
83
83
  kairo status
84
84
  kairo sync
85
85
  kairo upgrade --dry-run
86
- npx @kal-elsam/kairo-runtime@latest setup --yes
86
+ kairo setup --yes
87
87
  ```
88
88
 
89
89
  After `install.sh --yes`, verify health with `kairo status`, repair drift with `kairo sync`,
90
- and move to the latest package with `npx @kal-elsam/kairo-runtime@latest setup --yes`.
90
+ and preview upgrades with `kairo upgrade --dry-run`.
91
91
 
92
92
  ### Version and updates
93
93
 
@@ -737,7 +737,7 @@ git fetch --tags origin
737
737
  git fetch origin main
738
738
  npm run release:published -- --version 0.1.1 --tag kairo-runtime-v0.1.1
739
739
  npm run smoke:registry -- --version 0.1.1
740
- npm run smoke:installer -- --version 0.1.1
740
+ npm run smoke:installer -- --version 0.1.1 --tag kairo-runtime-v0.1.1
741
741
  npm run smoke:bridge
742
742
  ```
743
743
 
@@ -760,7 +760,13 @@ Without `--tag`, provenance checks fall back to `v${version}` (legacy tags).
760
760
 
761
761
  `smoke:registry` installs `@kal-elsam/kairo-runtime` from the npm registry (not the local tarball) into a throwaway workspace with a fake `HARNESS_HOME` and npm cache, then runs the recommended flow via `kairo`: `setup --dry-run`, `setup --yes`, `status`, drift simulation, `sync`, `status --json` (expects `overall=ok`), and `uninstall`. Use `latest` by default, pin with `--version x.y.z`, or override with `--package`.
762
762
 
763
- `smoke:installer` validates the public one-liner path: `curl .../install.sh | sh` against GitHub `raw` and the npm registry with isolated `HARNESS_HOME`. Preview must not write `~/.harness`; `--yes --agents all` must reach `kairo status --json` with `overall=ok`, then `kairo uninstall` must remove managed sections. Pin with `--version x.y.z` after publish.
763
+ `smoke:installer` validates the public one-liner path: `curl .../install.sh | sh` against GitHub `raw` and the npm registry with isolated `HARNESS_HOME`. Preview must not write `~/.harness`; `--yes --agents all` must reach `kairo status --json` with `overall=ok`, then `kairo uninstall` must remove managed sections. Pin with `--version x.y.z` after publish. For package-aware Kairo Runtime tags, pass the git tag explicitly:
764
+
765
+ ```bash
766
+ npm run smoke:installer -- --version 0.1.1 --tag kairo-runtime-v0.1.1
767
+ ```
768
+
769
+ Without `--tag`, the install script resolves from legacy `v${version}` tags.
764
770
 
765
771
  Suggested first Kairo Runtime tag after bootstrap: `kairo-runtime-v0.1.1`.
766
772
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kal-elsam/kairo-runtime",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Kairo Runtime — local agent operating system for Codex, Cursor, Claude, Gemini, Copilot, Engram, and Graphify.",
5
5
  "type": "module",
6
6
  "homepage": "https://github.com/Kal-elSam/harness#readme",
@@ -43,8 +43,9 @@ usage() {
43
43
  "" \
44
44
  "What it does:" \
45
45
  " 1. Checks for Node.js and npm." \
46
- " 2. Runs the package via npx (or npm exec) with setup --dry-run (default) or setup --yes (--yes)." \
47
- " 3. Prints next steps." \
46
+ " 2. Installs ${PACKAGE} globally (adds kairo to npm global bin)." \
47
+ " 3. Runs kairo setup --dry-run (default) or kairo setup --yes (--yes)." \
48
+ " 4. Prints next steps." \
48
49
  "" \
49
50
  "Security:" \
50
51
  " - Never uses sudo." \
@@ -62,6 +63,51 @@ append_setup_arg() {
62
63
  SETUP_EXTRA="${SETUP_EXTRA}${SETUP_EXTRA:+ }$1"
63
64
  }
64
65
 
66
+ resolve_global_spec() {
67
+ if [ "$VERSION" = "latest" ]; then
68
+ printf '%s@latest' "$PACKAGE"
69
+ else
70
+ printf '%s@%s' "$PACKAGE" "$VERSION"
71
+ fi
72
+ }
73
+
74
+ resolve_npm_global_bin() {
75
+ npm_prefix="$(npm prefix -g 2>/dev/null || true)"
76
+ [ -n "$npm_prefix" ] || return 1
77
+ printf '%s/bin' "$(printf '%s' "$npm_prefix" | sed 's#/*$##')"
78
+ }
79
+
80
+ resolve_kairo_bin() {
81
+ if command -v "$PREFERRED_CLI" >/dev/null 2>&1; then
82
+ command -v "$PREFERRED_CLI"
83
+ return 0
84
+ fi
85
+
86
+ global_bin="$(resolve_npm_global_bin || true)"
87
+ if [ -n "$global_bin" ] && [ -x "${global_bin}/${PREFERRED_CLI}" ]; then
88
+ printf '%s\n' "${global_bin}/${PREFERRED_CLI}"
89
+ return 0
90
+ fi
91
+
92
+ return 1
93
+ }
94
+
95
+ print_path_hint_if_needed() {
96
+ if command -v "$PREFERRED_CLI" >/dev/null 2>&1; then
97
+ return 0
98
+ fi
99
+
100
+ global_bin="$(resolve_npm_global_bin || true)"
101
+ if [ -n "$global_bin" ]; then
102
+ printf '%s\n' \
103
+ "" \
104
+ "PATH note:" \
105
+ " ${PREFERRED_CLI} was installed to ${global_bin}." \
106
+ " Add it to PATH if the command is not found:" \
107
+ " export PATH=\"${global_bin}:\$PATH\""
108
+ fi
109
+ }
110
+
65
111
  while [ "$#" -gt 0 ]; do
66
112
  case "$1" in
67
113
  --dry-run)
@@ -137,14 +183,9 @@ require_cmd npm
137
183
 
138
184
  NODE_VERSION="$(node --version 2>/dev/null || true)"
139
185
  NPM_VERSION="$(npm --version 2>/dev/null || true)"
140
-
141
- if command -v npx >/dev/null 2>&1; then
142
- RUNNER="npx"
143
- RUN_CMD="npx --yes ${PACKAGE}@${VERSION} setup ${SETUP_MODE}${SETUP_EXTRA:+ ${SETUP_EXTRA}}"
144
- else
145
- RUNNER="npm-exec"
146
- RUN_CMD="npm exec --yes --package=${PACKAGE}@${VERSION} -- ${PREFERRED_CLI} setup ${SETUP_MODE}${SETUP_EXTRA:+ ${SETUP_EXTRA}}"
147
- fi
186
+ GLOBAL_SPEC="$(resolve_global_spec)"
187
+ GLOBAL_INSTALL_CMD="npm install -g ${GLOBAL_SPEC}"
188
+ SETUP_CMD="${PREFERRED_CLI} setup ${SETUP_MODE}${SETUP_EXTRA:+ ${SETUP_EXTRA}}"
148
189
 
149
190
  printf '%s\n' \
150
191
  "Kairo Runtime bootstrap installer" \
@@ -153,13 +194,13 @@ printf '%s\n' \
153
194
  "Prerequisites:" \
154
195
  " node ${NODE_VERSION:-unknown}" \
155
196
  " npm ${NPM_VERSION:-unknown}" \
156
- " runner ${RUNNER}" \
157
197
  "" \
158
198
  "Will run:" \
159
- " ${RUN_CMD}" \
199
+ " ${GLOBAL_INSTALL_CMD}" \
200
+ " ${SETUP_CMD}" \
160
201
  "" \
161
202
  "Effects:" \
162
- " - Downloads/runs ${PACKAGE}@${VERSION} via npm (no global install required)." \
203
+ " - Installs ${GLOBAL_SPEC} globally (kairo CLI in npm global bin)." \
163
204
  " - Configures managed sections only (never installs AI apps)." \
164
205
  " - Never uses sudo or modifies shell profiles." \
165
206
  ""
@@ -181,19 +222,25 @@ if [ "$INSTALLER_DRY_RUN" -eq 1 ]; then
181
222
  exit 0
182
223
  fi
183
224
 
225
+ printf '%s\n' "Installing global CLI..." ""
226
+ # shellcheck disable=SC2086
227
+ npm install -g ${GLOBAL_SPEC}
228
+
229
+ KAIRO_BIN="$(resolve_kairo_bin || true)"
230
+ if [ -z "$KAIRO_BIN" ]; then
231
+ die "Installed ${GLOBAL_SPEC}, but ${PREFERRED_CLI} is not available.
232
+ Check npm global bin: $(resolve_npm_global_bin || echo unknown)
233
+ Add it to PATH, then re-run: ${SETUP_CMD}"
234
+ fi
235
+
184
236
  if [ "$APPLY" -eq 1 ]; then
185
237
  printf '%s\n' "Applying setup..." ""
186
238
  else
187
239
  printf '%s\n' "Running preview..." ""
188
240
  fi
189
241
 
190
- if [ "$RUNNER" = "npx" ]; then
191
- # shellcheck disable=SC2086
192
- npx --yes "${PACKAGE}@${VERSION}" setup ${SETUP_MODE} ${SETUP_EXTRA}
193
- else
194
- # shellcheck disable=SC2086
195
- npm exec --yes --package="${PACKAGE}@${VERSION}" -- ${PREFERRED_CLI} setup ${SETUP_MODE} ${SETUP_EXTRA}
196
- fi
242
+ # shellcheck disable=SC2086
243
+ "$KAIRO_BIN" setup ${SETUP_MODE} ${SETUP_EXTRA}
197
244
 
198
245
  if [ "$APPLY" -eq 1 ]; then
199
246
  printf '%s\n' \
@@ -202,24 +249,25 @@ if [ "$APPLY" -eq 1 ]; then
202
249
  "Next steps:" \
203
250
  " 1. Check health: ${PREFERRED_CLI} status" \
204
251
  " 2. Repair drift: ${PREFERRED_CLI} sync" \
205
- " 3. Upgrade latest: npx ${PACKAGE}@latest setup --yes" \
252
+ " 3. Upgrade latest: ${PREFERRED_CLI} upgrade --dry-run" \
206
253
  "" \
207
254
  "Version:" \
208
- " Installed CLI: npx ${PACKAGE} --version" \
209
- " Published package: npm view ${PACKAGE} version" \
210
- " Preview upgrade: ${PREFERRED_CLI} upgrade --dry-run"
255
+ " Installed CLI: ${PREFERRED_CLI} --version" \
256
+ " Published package: npm view ${PACKAGE} version"
257
+ print_path_hint_if_needed
211
258
  else
212
259
  printf '%s\n' \
213
260
  "" \
214
261
  "Bootstrap complete." \
215
262
  "Next steps:" \
216
- " 1. Apply the plan: npx ${PACKAGE}@${VERSION} setup --yes" \
263
+ " 1. Apply the plan: ${PREFERRED_CLI} setup --yes" \
217
264
  " (or re-run installer: curl ... | sh -s -- --yes)" \
218
- " 2. Check health: npx ${PACKAGE}@${VERSION} status" \
219
- " 3. Repair drift: npx ${PACKAGE}@${VERSION} sync" \
265
+ " 2. Check health: ${PREFERRED_CLI} status" \
266
+ " 3. Repair drift: ${PREFERRED_CLI} sync" \
220
267
  "" \
221
268
  "Version:" \
222
- " Installed CLI: npx ${PACKAGE} --version" \
269
+ " Installed CLI: ${PREFERRED_CLI} --version" \
223
270
  " Published package: npm view ${PACKAGE} version" \
224
- " Update / converge: npx ${PACKAGE}@latest sync"
271
+ " Update / converge: ${PREFERRED_CLI} sync"
272
+ print_path_hint_if_needed
225
273
  fi
@@ -4,7 +4,9 @@ set -euo pipefail
4
4
  PACKAGE="@kal-elsam/kairo-runtime"
5
5
  PREFERRED_CLI="kairo"
6
6
  VERSION="latest"
7
+ GIT_TAG=""
7
8
  REPO="Kal-elSam/harness"
9
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
8
10
 
9
11
  while [ "$#" -gt 0 ]; do
10
12
  case "$1" in
@@ -24,6 +26,14 @@ while [ "$#" -gt 0 ]; do
24
26
  VERSION="${1#*=}"
25
27
  shift
26
28
  ;;
29
+ --tag)
30
+ GIT_TAG="$2"
31
+ shift 2
32
+ ;;
33
+ --tag=*)
34
+ GIT_TAG="${1#*=}"
35
+ shift
36
+ ;;
27
37
  *)
28
38
  echo "Unknown option: $1" >&2
29
39
  exit 1
@@ -53,12 +63,13 @@ assert_harness_home_isolated() {
53
63
  }
54
64
 
55
65
  resolve_install_script_url() {
56
- if [ "$VERSION" = "latest" ]; then
57
- printf '%s\n' "https://raw.githubusercontent.com/${REPO}/main/scripts/install.sh"
58
- return
66
+ local args=(--version "$VERSION" --repo "$REPO")
67
+
68
+ if [ -n "$GIT_TAG" ]; then
69
+ args+=(--tag "$GIT_TAG")
59
70
  fi
60
71
 
61
- printf '%s\n' "https://raw.githubusercontent.com/${REPO}/v${VERSION}/scripts/install.sh"
72
+ node "${SCRIPT_DIR}/lib/install-script-url.mjs" "${args[@]}"
62
73
  }
63
74
 
64
75
  assert_no_harness_state() {
@@ -117,6 +128,9 @@ cd "$WORKDIR"
117
128
 
118
129
  INSTALL_SCRIPT_URL="$(resolve_install_script_url)"
119
130
  echo "Installer smoke for ${PACKAGE}@${VERSION}"
131
+ if [ -n "$GIT_TAG" ]; then
132
+ echo "Git tag: ${GIT_TAG}"
133
+ fi
120
134
  echo "Install script: ${INSTALL_SCRIPT_URL}"
121
135
  echo "Harness home: ${HARNESS_HOME}"
122
136
 
@@ -140,15 +154,36 @@ if [ ! -d "$FAKE_HOME/.harness" ]; then
140
154
  exit 1
141
155
  fi
142
156
 
157
+ NPM_GLOBAL_BIN="$(npm prefix -g 2>/dev/null)/bin"
158
+ export PATH="${NPM_GLOBAL_BIN}:${PATH}"
159
+
160
+ resolve_kairo_bin() {
161
+ if command -v "$PREFERRED_CLI" >/dev/null 2>&1; then
162
+ command -v "$PREFERRED_CLI"
163
+ return 0
164
+ fi
165
+ if [ -x "${NPM_GLOBAL_BIN}/${PREFERRED_CLI}" ]; then
166
+ printf '%s\n' "${NPM_GLOBAL_BIN}/${PREFERRED_CLI}"
167
+ return 0
168
+ fi
169
+ return 1
170
+ }
171
+
172
+ KAIRO_BIN="$(resolve_kairo_bin || true)"
173
+ if [ -z "$KAIRO_BIN" ]; then
174
+ echo "Expected ${PREFERRED_CLI} after install.sh global install" >&2
175
+ exit 1
176
+ fi
177
+
143
178
  echo
144
179
  echo "== ${PREFERRED_CLI} status --json =="
145
- STATUS_JSON="$(npx --yes "${PACKAGE}@${VERSION}" status --json)"
180
+ STATUS_JSON="$("$KAIRO_BIN" status --json)"
146
181
  echo "$STATUS_JSON"
147
182
  assert_status_ok "$STATUS_JSON"
148
183
 
149
184
  echo
150
185
  echo "== ${PREFERRED_CLI} uninstall =="
151
- npx --yes "${PACKAGE}@${VERSION}" uninstall
186
+ "$KAIRO_BIN" uninstall
152
187
  assert_managed_configs_removed
153
188
 
154
189
  echo
@@ -0,0 +1,85 @@
1
+ import { fileURLToPath } from "node:url";
2
+ import path from "node:path";
3
+
4
+ const DEFAULT_REPO = "Kal-elSam/harness";
5
+
6
+ export function resolveInstallScriptRef({ version, tag = null }) {
7
+ if (version === "latest") {
8
+ return "main";
9
+ }
10
+
11
+ if (tag) {
12
+ return tag;
13
+ }
14
+
15
+ return `v${version}`;
16
+ }
17
+
18
+ export function resolveInstallScriptUrl({
19
+ repo = DEFAULT_REPO,
20
+ version,
21
+ tag = null
22
+ }) {
23
+ const ref = resolveInstallScriptRef({ version, tag });
24
+ return `https://raw.githubusercontent.com/${repo}/${ref}/scripts/install.sh`;
25
+ }
26
+
27
+ export function parseInstallScriptUrlArgs(argv) {
28
+ const args = [...argv];
29
+ let version = "latest";
30
+ let tag = null;
31
+ let repo = DEFAULT_REPO;
32
+
33
+ for (let index = 2; index < args.length; index += 1) {
34
+ const arg = args[index];
35
+
36
+ if (arg === "--version") {
37
+ version = args[++index];
38
+ continue;
39
+ }
40
+
41
+ if (arg.startsWith("--version=")) {
42
+ version = arg.slice("--version=".length);
43
+ continue;
44
+ }
45
+
46
+ if (arg === "--tag") {
47
+ tag = args[++index];
48
+ continue;
49
+ }
50
+
51
+ if (arg.startsWith("--tag=")) {
52
+ tag = arg.slice("--tag=".length);
53
+ continue;
54
+ }
55
+
56
+ if (arg === "--repo") {
57
+ repo = args[++index];
58
+ continue;
59
+ }
60
+
61
+ if (arg.startsWith("--repo=")) {
62
+ repo = arg.slice("--repo=".length);
63
+ continue;
64
+ }
65
+
66
+ throw new Error(`Unknown option "${arg}".`);
67
+ }
68
+
69
+ return { version, tag, repo };
70
+ }
71
+
72
+ function isMainModule() {
73
+ const entry = process.argv[1];
74
+
75
+ if (!entry) {
76
+ return false;
77
+ }
78
+
79
+ return path.resolve(fileURLToPath(import.meta.url)) === path.resolve(entry);
80
+ }
81
+
82
+ if (isMainModule()) {
83
+ const { version, tag, repo } = parseInstallScriptUrlArgs(process.argv);
84
+ console.log(resolveInstallScriptUrl({ repo, version, tag }));
85
+ }
package/src/cli.js CHANGED
@@ -31,51 +31,21 @@ import { applyPolicyToOptions, loadPolicyFile } from "./global/policy.js";
31
31
  import { resolveHomeDir } from "./global/paths.js";
32
32
  import { runWorkspaceDetect, runWorkspaceDoctor, runWorkspaceInit, runWorkspaceUpdate } from "./workspace-cli.js";
33
33
  import {
34
- ALL_CLI_NAMES,
35
34
  LEGACY_PACKAGE_NAME,
36
35
  PACKAGE_NAME,
37
36
  PREFERRED_CLI,
38
37
  formatCliCommand,
39
- maybeWarnLegacyCli
38
+ maybeWarnLegacyCli,
39
+ resolveSuggestedInvocation
40
40
  } from "./global/brand/cli.js";
41
41
  import { BRAND } from "./global/brand/index.js";
42
42
 
43
+ export { resolveSuggestedInvocation };
44
+
43
45
  const __dirname = dirname(fileURLToPath(import.meta.url));
44
46
  const packageRoot = resolve(__dirname, "..");
45
47
  const SCOPES = new Set(["agent-global", "workspace"]);
46
48
 
47
- export function resolveSuggestedInvocation(packageName, argv = process.argv) {
48
- const invokedPath = argv[1] ?? PREFERRED_CLI;
49
- const invokedBase = basename(invokedPath);
50
-
51
- if (!invokedBase.endsWith(".js") && ALL_CLI_NAMES.has(invokedBase)) {
52
- return invokedBase;
53
- }
54
-
55
- const packageManager = detectInvocationPackageManager();
56
-
57
- switch (packageManager) {
58
- case "pnpm":
59
- return `pnpm dlx ${packageName}`;
60
- case "yarn":
61
- return `yarn dlx ${packageName}`;
62
- case "bun":
63
- return `bunx ${packageName}`;
64
- default:
65
- return `npx ${packageName}`;
66
- }
67
- }
68
-
69
- function detectInvocationPackageManager() {
70
- const execPath = process.env.npm_execpath ?? "";
71
- const userAgent = process.env.npm_config_user_agent ?? "";
72
-
73
- if (execPath.includes("pnpm") || userAgent.startsWith("pnpm/")) return "pnpm";
74
- if (execPath.includes("yarn") || userAgent.startsWith("yarn/")) return "yarn";
75
- if (execPath.includes("bun") || userAgent.startsWith("bun/")) return "bun";
76
- return "npm";
77
- }
78
-
79
49
  export async function runCli(argv) {
80
50
  const { command, options } = parseArgs(argv);
81
51
  maybeWarnLegacyCli(process.argv, { json: options.json });
@@ -50,3 +50,44 @@ export function formatCliCommand(subcommand, cliName = PREFERRED_CLI) {
50
50
  const trimmed = subcommand.trim();
51
51
  return trimmed ? `${cliName} ${trimmed}` : cliName;
52
52
  }
53
+
54
+ function detectInvocationPackageManager() {
55
+ const execPath = process.env.npm_execpath ?? "";
56
+ const userAgent = process.env.npm_config_user_agent ?? "";
57
+
58
+ if (execPath.includes("pnpm") || userAgent.startsWith("pnpm/")) return "pnpm";
59
+ if (execPath.includes("yarn") || userAgent.startsWith("yarn/")) return "yarn";
60
+ if (execPath.includes("bun") || userAgent.startsWith("bun/")) return "bun";
61
+ return "npm";
62
+ }
63
+
64
+ export function resolveSuggestedInvocation(packageName = PACKAGE_NAME, argv = process.argv) {
65
+ const invokedPath = argv[1] ?? PREFERRED_CLI;
66
+ const invokedBase = basename(invokedPath);
67
+
68
+ if (!invokedBase.endsWith(".js") && ALL_CLI_NAMES.has(invokedBase)) {
69
+ return invokedBase;
70
+ }
71
+
72
+ const packageManager = detectInvocationPackageManager();
73
+
74
+ switch (packageManager) {
75
+ case "pnpm":
76
+ return `pnpm dlx ${packageName}`;
77
+ case "yarn":
78
+ return `yarn dlx ${packageName}`;
79
+ case "bun":
80
+ return `bunx ${packageName}`;
81
+ default:
82
+ return `npx ${packageName}`;
83
+ }
84
+ }
85
+
86
+ export function formatSuggestedCliCommand(
87
+ subcommand,
88
+ { packageName = PACKAGE_NAME, argv = process.argv, suggestedInvocation } = {}
89
+ ) {
90
+ const invoke = suggestedInvocation ?? resolveSuggestedInvocation(packageName, argv);
91
+ const trimmed = subcommand.trim();
92
+ return trimmed ? `${invoke} ${trimmed}` : invoke;
93
+ }
@@ -82,4 +82,10 @@ export function commandHeader(label) {
82
82
  return `${BRAND.displayName} ${label}`;
83
83
  }
84
84
 
85
- export { formatCliCommand, PREFERRED_CLI } from "./cli.js";
85
+ export {
86
+ formatCliCommand,
87
+ formatSuggestedCliCommand,
88
+ PACKAGE_NAME,
89
+ PREFERRED_CLI,
90
+ resolveSuggestedInvocation
91
+ } from "./cli.js";
@@ -1,4 +1,4 @@
1
- import { AGENT_HINTS, BRAND, PREFERRED_CLI, formatCliCommand, getAgentLabel, WIZARD_COPY } from "../brand/index.js";
1
+ import { AGENT_HINTS, BRAND, formatCliCommand, getAgentLabel, PREFERRED_CLI, WIZARD_COPY } from "../brand/index.js";
2
2
  import { formatAgentMultiselectHint } from "../clack/theme.js";
3
3
 
4
4
  export const SETUP_STEPS = {