@kal-elsam/kairo-runtime 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 +76 -19
- package/package.json +2 -1
- package/scripts/bridge-smoke-test.sh +91 -0
- package/scripts/check-published-release.mjs +33 -9
- package/scripts/install.sh +77 -29
- package/scripts/installer-smoke-test.sh +41 -6
- package/scripts/lib/install-script-url.mjs +85 -0
- package/src/cli.js +4 -34
- package/src/global/brand/cli.js +41 -0
- package/src/global/brand/index.js +7 -1
- package/src/global/ink/setup-state.js +1 -1
package/README.md
CHANGED
|
@@ -12,6 +12,10 @@ The npm package (`@kal-elsam/kairo-runtime`) is how Kairo Runtime is distributed
|
|
|
12
12
|
product identity is the local control plane: setup, status, sync, doctor (with `update`
|
|
13
13
|
as a technical alias).
|
|
14
14
|
|
|
15
|
+
`@kal-elsam/harness` remains available as a **compatibility bridge** that delegates to
|
|
16
|
+
Kairo Runtime and prints a migration warning. Prefer `@kal-elsam/kairo-runtime` and the
|
|
17
|
+
`kairo` CLI for new installs. See [`packages/harness-bridge/README.md`](packages/harness-bridge/README.md).
|
|
18
|
+
|
|
15
19
|
Terminal UX aims for Pi-like clarity (clear modes, non-interactive flags, extensible
|
|
16
20
|
commands) without depending on Pi as a runtime or adding a Pi adapter.
|
|
17
21
|
|
|
@@ -47,14 +51,14 @@ curl -fsSL https://raw.githubusercontent.com/Kal-elSam/harness/main/scripts/inst
|
|
|
47
51
|
The bootstrap installer:
|
|
48
52
|
|
|
49
53
|
- requires Node.js 20.12+ and npm
|
|
50
|
-
-
|
|
51
|
-
-
|
|
54
|
+
- installs `@kal-elsam/kairo-runtime` globally (`kairo` CLI)
|
|
55
|
+
- runs `kairo setup --dry-run` by default (no agent configs, no `~/.harness` writes)
|
|
52
56
|
- never uses `sudo`, never modifies shell profiles, and never installs AI apps
|
|
53
57
|
|
|
54
58
|
Apply the plan when you are ready:
|
|
55
59
|
|
|
56
60
|
```bash
|
|
57
|
-
|
|
61
|
+
kairo setup --yes
|
|
58
62
|
# or
|
|
59
63
|
curl -fsSL https://raw.githubusercontent.com/Kal-elSam/harness/main/scripts/install.sh | sh -s -- --yes
|
|
60
64
|
```
|
|
@@ -62,8 +66,8 @@ curl -fsSL https://raw.githubusercontent.com/Kal-elSam/harness/main/scripts/inst
|
|
|
62
66
|
CI, scripts, and advanced non-interactive configure:
|
|
63
67
|
|
|
64
68
|
```bash
|
|
65
|
-
|
|
66
|
-
|
|
69
|
+
kairo install --agents cursor,codex --yes
|
|
70
|
+
kairo setup --yes --agents all
|
|
67
71
|
```
|
|
68
72
|
|
|
69
73
|
Passthrough examples:
|
|
@@ -79,11 +83,11 @@ Control plane:
|
|
|
79
83
|
kairo status
|
|
80
84
|
kairo sync
|
|
81
85
|
kairo upgrade --dry-run
|
|
82
|
-
|
|
86
|
+
kairo setup --yes
|
|
83
87
|
```
|
|
84
88
|
|
|
85
89
|
After `install.sh --yes`, verify health with `kairo status`, repair drift with `kairo sync`,
|
|
86
|
-
and
|
|
90
|
+
and preview upgrades with `kairo upgrade --dry-run`.
|
|
87
91
|
|
|
88
92
|
### Version and updates
|
|
89
93
|
|
|
@@ -649,7 +653,23 @@ Install the harness in enterprise mode because this project will have AI, API, D
|
|
|
649
653
|
|
|
650
654
|
## Publishing
|
|
651
655
|
|
|
652
|
-
Published on npm as `@kal-elsam/kairo-runtime`. Releases use **npm Trusted Publishing/OIDC**
|
|
656
|
+
Published on npm as `@kal-elsam/kairo-runtime`. Releases use **npm Trusted Publishing/OIDC**
|
|
657
|
+
from GitHub Actions — no `NPM_TOKEN`.
|
|
658
|
+
|
|
659
|
+
`@kal-elsam/harness` is published separately as a compatibility bridge from
|
|
660
|
+
`packages/harness-bridge/` (see bridge README).
|
|
661
|
+
|
|
662
|
+
### Git tags (package-aware)
|
|
663
|
+
|
|
664
|
+
| Tag pattern | Package | Publish root |
|
|
665
|
+
|---|---|---|
|
|
666
|
+
| `kairo-runtime-v*` | `@kal-elsam/kairo-runtime` | repo root |
|
|
667
|
+
| `harness-bridge-v*` | `@kal-elsam/harness` | `packages/harness-bridge/` |
|
|
668
|
+
| `v*` | legacy / historical root releases | repo root |
|
|
669
|
+
|
|
670
|
+
Kairo Runtime releases should use `kairo-runtime-vX.Y.Z` going forward. The first
|
|
671
|
+
bootstrap used `v0.1.0`; later releases use package-aware tags such as
|
|
672
|
+
`kairo-runtime-v0.1.1`.
|
|
653
673
|
|
|
654
674
|
Before tagging a new version:
|
|
655
675
|
|
|
@@ -684,37 +704,74 @@ to end:
|
|
|
684
704
|
rollback apply (with safety backup), `uninstall`.
|
|
685
705
|
- **workspace:** `install --scope=workspace`, `doctor`, `update --dry-run`.
|
|
686
706
|
|
|
687
|
-
Release flow:
|
|
707
|
+
Release flow (Kairo Runtime):
|
|
688
708
|
|
|
689
709
|
```bash
|
|
690
710
|
# bump version in package.json and package-lock.json
|
|
691
711
|
git add .
|
|
692
|
-
git commit -m "chore: release 0.
|
|
712
|
+
git commit -m "chore: release kairo-runtime 0.1.1"
|
|
693
713
|
npm run release:check
|
|
694
|
-
git tag v0.
|
|
714
|
+
git tag kairo-runtime-v0.1.1
|
|
695
715
|
git push origin main
|
|
696
|
-
git push origin v0.
|
|
716
|
+
git push origin kairo-runtime-v0.1.1
|
|
697
717
|
```
|
|
698
718
|
|
|
719
|
+
Bridge release flow:
|
|
720
|
+
|
|
721
|
+
```bash
|
|
722
|
+
# bump packages/harness-bridge/package.json (+ lockfile)
|
|
723
|
+
git add .
|
|
724
|
+
git commit -m "chore: release harness bridge 0.30.0"
|
|
725
|
+
npm run release:check
|
|
726
|
+
git tag harness-bridge-v0.30.0
|
|
727
|
+
git push origin main
|
|
728
|
+
git push origin harness-bridge-v0.30.0
|
|
729
|
+
```
|
|
730
|
+
|
|
731
|
+
Legacy `v*` tags still publish from the repo root for historical continuity.
|
|
732
|
+
|
|
699
733
|
After npm publishes the tag, verify published provenance against git and the registry:
|
|
700
734
|
|
|
701
735
|
```bash
|
|
702
736
|
git fetch --tags origin
|
|
703
737
|
git fetch origin main
|
|
704
|
-
npm run release:published -- --version 0.1.
|
|
705
|
-
npm run smoke:registry -- --version 0.1.
|
|
706
|
-
npm run smoke:installer -- --version 0.1.
|
|
738
|
+
npm run release:published -- --version 0.1.1 --tag kairo-runtime-v0.1.1
|
|
739
|
+
npm run smoke:registry -- --version 0.1.1
|
|
740
|
+
npm run smoke:installer -- --version 0.1.1 --tag kairo-runtime-v0.1.1
|
|
741
|
+
npm run smoke:bridge
|
|
742
|
+
```
|
|
743
|
+
|
|
744
|
+
`release:published` checks npm `version`, npm `gitHead`, the release git tag on
|
|
745
|
+
`origin`, and `origin/main`. Override the package and tag when needed:
|
|
746
|
+
|
|
747
|
+
```bash
|
|
748
|
+
npm run release:published -- \
|
|
749
|
+
--package @kal-elsam/kairo-runtime \
|
|
750
|
+
--tag kairo-runtime-v0.1.1 \
|
|
751
|
+
--version 0.1.1
|
|
752
|
+
|
|
753
|
+
npm run release:published -- \
|
|
754
|
+
--package @kal-elsam/harness \
|
|
755
|
+
--tag harness-bridge-v0.30.0 \
|
|
756
|
+
--version 0.30.0
|
|
707
757
|
```
|
|
708
758
|
|
|
709
|
-
|
|
759
|
+
Without `--tag`, provenance checks fall back to `v${version}` (legacy tags).
|
|
710
760
|
|
|
711
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`.
|
|
712
762
|
|
|
713
|
-
`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.
|
|
714
770
|
|
|
715
|
-
Suggested first
|
|
771
|
+
Suggested first Kairo Runtime tag after bootstrap: `kairo-runtime-v0.1.1`.
|
|
716
772
|
|
|
717
|
-
The `publish.yml` workflow runs on `v
|
|
773
|
+
The `publish.yml` workflow runs on `v*`, `kairo-runtime-v*`, and `harness-bridge-v*`
|
|
774
|
+
tags and publishes to npm using the `npm-publish` environment.
|
|
718
775
|
It runs `npm run release:check` on `HEAD` immediately before `npm publish`.
|
|
719
776
|
|
|
720
777
|
See the full policy in `SECURITY.md`.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kal-elsam/kairo-runtime",
|
|
3
|
-
"version": "0.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",
|
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
"ux:smoke": "bash scripts/ux-smoke-test.sh",
|
|
36
36
|
"smoke:registry": "bash scripts/registry-smoke-test.sh",
|
|
37
37
|
"smoke:installer": "bash scripts/installer-smoke-test.sh",
|
|
38
|
+
"smoke:bridge": "bash scripts/bridge-smoke-test.sh",
|
|
38
39
|
"release:check": "node scripts/check-release-commit.mjs",
|
|
39
40
|
"release:published": "node scripts/check-published-release.mjs"
|
|
40
41
|
},
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
5
|
+
BRIDGE_DIR="$ROOT/packages/harness-bridge"
|
|
6
|
+
WORKDIR="$(mktemp -d)"
|
|
7
|
+
FAKE_HOME="$(mktemp -d)"
|
|
8
|
+
NPM_CACHE="$(mktemp -d)"
|
|
9
|
+
|
|
10
|
+
cleanup() {
|
|
11
|
+
rm -rf "$WORKDIR" "$FAKE_HOME" "$NPM_CACHE"
|
|
12
|
+
}
|
|
13
|
+
trap cleanup EXIT
|
|
14
|
+
|
|
15
|
+
export HARNESS_HOME="$FAKE_HOME"
|
|
16
|
+
export npm_config_cache="$NPM_CACHE"
|
|
17
|
+
|
|
18
|
+
mkdir -p \
|
|
19
|
+
"$FAKE_HOME/.cursor" \
|
|
20
|
+
"$FAKE_HOME/.codex" \
|
|
21
|
+
"$FAKE_HOME/.config/opencode" \
|
|
22
|
+
"$FAKE_HOME/.claude"
|
|
23
|
+
|
|
24
|
+
echo "Packing @kal-elsam/kairo-runtime from $ROOT"
|
|
25
|
+
RUNTIME_TGZ="$(cd "$ROOT" && npm pack --silent --pack-destination "$WORKDIR")"
|
|
26
|
+
RUNTIME_TGZ_PATH="$WORKDIR/$RUNTIME_TGZ"
|
|
27
|
+
|
|
28
|
+
echo "Packing @kal-elsam/harness bridge"
|
|
29
|
+
BRIDGE_TGZ="$(cd "$BRIDGE_DIR" && npm pack --silent --pack-destination "$WORKDIR")"
|
|
30
|
+
BRIDGE_TGZ_PATH="$WORKDIR/$BRIDGE_TGZ"
|
|
31
|
+
|
|
32
|
+
INSTALL_DIR="$WORKDIR/project"
|
|
33
|
+
mkdir -p "$INSTALL_DIR"
|
|
34
|
+
(
|
|
35
|
+
cd "$INSTALL_DIR"
|
|
36
|
+
npm init -y >/dev/null
|
|
37
|
+
npm install "$RUNTIME_TGZ_PATH" "$BRIDGE_TGZ_PATH" --ignore-scripts
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
HARNESS_BIN="$INSTALL_DIR/node_modules/@kal-elsam/harness/bin/harness.js"
|
|
41
|
+
|
|
42
|
+
echo
|
|
43
|
+
echo "== harness --version (warning on stderr, version on stdout) =="
|
|
44
|
+
VERSION_OUTPUT="$(node "$HARNESS_BIN" --version 2>"$WORKDIR/version.stderr" || true)"
|
|
45
|
+
VERSION_STDERR="$(cat "$WORKDIR/version.stderr")"
|
|
46
|
+
|
|
47
|
+
if ! grep -q "@kal-elsam/harness has moved to @kal-elsam/kairo-runtime" <<<"$VERSION_STDERR"; then
|
|
48
|
+
echo "Expected migration warning on stderr" >&2
|
|
49
|
+
echo "stderr: $VERSION_STDERR" >&2
|
|
50
|
+
exit 1
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
if ! grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+$' <<<"$VERSION_OUTPUT"; then
|
|
54
|
+
echo "Expected semver on stdout, got: $VERSION_OUTPUT" >&2
|
|
55
|
+
exit 1
|
|
56
|
+
fi
|
|
57
|
+
|
|
58
|
+
if grep -q "@kal-elsam/harness has moved" <<<"$VERSION_OUTPUT"; then
|
|
59
|
+
echo "Migration warning must not appear on stdout" >&2
|
|
60
|
+
exit 1
|
|
61
|
+
fi
|
|
62
|
+
|
|
63
|
+
echo "stdout version: $VERSION_OUTPUT"
|
|
64
|
+
|
|
65
|
+
echo
|
|
66
|
+
echo "== harness status --json (JSON on stdout only) =="
|
|
67
|
+
set +e
|
|
68
|
+
STATUS_OUTPUT="$(node "$HARNESS_BIN" status --json 2>"$WORKDIR/status.stderr")"
|
|
69
|
+
STATUS_EXIT=$?
|
|
70
|
+
set -e
|
|
71
|
+
STATUS_STDERR="$(cat "$WORKDIR/status.stderr")"
|
|
72
|
+
|
|
73
|
+
if [ "$STATUS_EXIT" -ne 0 ] && [ "$STATUS_EXIT" -ne 1 ]; then
|
|
74
|
+
echo "Unexpected exit code from harness status --json: $STATUS_EXIT" >&2
|
|
75
|
+
exit 1
|
|
76
|
+
fi
|
|
77
|
+
|
|
78
|
+
if ! grep -q "@kal-elsam/harness has moved to @kal-elsam/kairo-runtime" <<<"$STATUS_STDERR"; then
|
|
79
|
+
echo "Expected migration warning on stderr for status --json" >&2
|
|
80
|
+
exit 1
|
|
81
|
+
fi
|
|
82
|
+
|
|
83
|
+
node -e "JSON.parse(process.argv[1])" "$STATUS_OUTPUT"
|
|
84
|
+
|
|
85
|
+
if grep -q "@kal-elsam/harness has moved" <<<"$STATUS_OUTPUT"; then
|
|
86
|
+
echo "Migration warning must not appear in JSON stdout" >&2
|
|
87
|
+
exit 1
|
|
88
|
+
fi
|
|
89
|
+
|
|
90
|
+
echo
|
|
91
|
+
echo "Bridge smoke test passed."
|
|
@@ -15,10 +15,19 @@ async function defaultFetchJson(url) {
|
|
|
15
15
|
return response.json();
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
export function resolveReleaseTag({ version, tag = null }) {
|
|
19
|
+
if (tag) {
|
|
20
|
+
return tag;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return `v${version}`;
|
|
24
|
+
}
|
|
25
|
+
|
|
18
26
|
export function parsePublishedReleaseArgs(argv) {
|
|
19
27
|
const args = [...argv];
|
|
20
28
|
let version = null;
|
|
21
29
|
let packageName = "@kal-elsam/kairo-runtime";
|
|
30
|
+
let tag = null;
|
|
22
31
|
|
|
23
32
|
for (let index = 2; index < args.length; index += 1) {
|
|
24
33
|
const arg = args[index];
|
|
@@ -43,6 +52,16 @@ export function parsePublishedReleaseArgs(argv) {
|
|
|
43
52
|
continue;
|
|
44
53
|
}
|
|
45
54
|
|
|
55
|
+
if (arg === "--tag") {
|
|
56
|
+
tag = args[++index];
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (arg.startsWith("--tag=")) {
|
|
61
|
+
tag = arg.slice("--tag=".length);
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
|
|
46
65
|
throw new Error(`Unknown option "${arg}".`);
|
|
47
66
|
}
|
|
48
67
|
|
|
@@ -50,16 +69,17 @@ export function parsePublishedReleaseArgs(argv) {
|
|
|
50
69
|
throw new Error("Missing required --version <x.y.z>.");
|
|
51
70
|
}
|
|
52
71
|
|
|
53
|
-
return { version, packageName };
|
|
72
|
+
return { version, packageName, tag };
|
|
54
73
|
}
|
|
55
74
|
|
|
56
75
|
export async function verifyPublishedRelease({
|
|
57
76
|
version,
|
|
58
77
|
packageName = "@kal-elsam/kairo-runtime",
|
|
78
|
+
tag = null,
|
|
59
79
|
runGit = defaultRunGit,
|
|
60
80
|
fetchJson = defaultFetchJson
|
|
61
81
|
}) {
|
|
62
|
-
const
|
|
82
|
+
const releaseTag = resolveReleaseTag({ version, tag });
|
|
63
83
|
const encodedPackage = encodeURIComponent(packageName);
|
|
64
84
|
const meta = await fetchJson(`https://registry.npmjs.org/${encodedPackage}/${version}`);
|
|
65
85
|
|
|
@@ -72,10 +92,12 @@ export async function verifyPublishedRelease({
|
|
|
72
92
|
}
|
|
73
93
|
|
|
74
94
|
const gitHead = meta.gitHead.trim();
|
|
75
|
-
const tagSha = runGit(`git rev-parse ${
|
|
95
|
+
const tagSha = runGit(`git rev-parse ${releaseTag}^{commit}`).trim();
|
|
76
96
|
|
|
77
97
|
if (tagSha !== gitHead) {
|
|
78
|
-
throw new Error(
|
|
98
|
+
throw new Error(
|
|
99
|
+
`Local tag ${releaseTag} (${tagSha}) does not match npm gitHead (${gitHead})`
|
|
100
|
+
);
|
|
79
101
|
}
|
|
80
102
|
|
|
81
103
|
const mainSha = runGit("git rev-parse origin/main").trim();
|
|
@@ -90,17 +112,19 @@ export async function verifyPublishedRelease({
|
|
|
90
112
|
}
|
|
91
113
|
}
|
|
92
114
|
|
|
93
|
-
const remoteTagLine = runGit(`git ls-remote --tags origin refs/tags/${
|
|
115
|
+
const remoteTagLine = runGit(`git ls-remote --tags origin refs/tags/${releaseTag}`).trim();
|
|
94
116
|
|
|
95
117
|
if (!remoteTagLine.startsWith(gitHead)) {
|
|
96
|
-
throw new Error(
|
|
118
|
+
throw new Error(
|
|
119
|
+
`Remote tag ${releaseTag} on origin does not point to npm gitHead (${gitHead})`
|
|
120
|
+
);
|
|
97
121
|
}
|
|
98
122
|
|
|
99
123
|
return {
|
|
100
124
|
version,
|
|
101
125
|
packageName,
|
|
102
126
|
gitHead,
|
|
103
|
-
tag,
|
|
127
|
+
tag: releaseTag,
|
|
104
128
|
mainSha,
|
|
105
129
|
tagSha,
|
|
106
130
|
mainAhead: mainSha !== gitHead
|
|
@@ -114,8 +138,8 @@ function isMainModule() {
|
|
|
114
138
|
}
|
|
115
139
|
|
|
116
140
|
if (isMainModule()) {
|
|
117
|
-
const { version, packageName } = parsePublishedReleaseArgs(process.argv);
|
|
118
|
-
const result = await verifyPublishedRelease({ version, packageName });
|
|
141
|
+
const { version, packageName, tag } = parsePublishedReleaseArgs(process.argv);
|
|
142
|
+
const result = await verifyPublishedRelease({ version, packageName, tag });
|
|
119
143
|
|
|
120
144
|
console.log("Published release provenance OK");
|
|
121
145
|
console.log(`Package: ${result.packageName}@${result.version}`);
|
package/scripts/install.sh
CHANGED
|
@@ -43,8 +43,9 @@ usage() {
|
|
|
43
43
|
"" \
|
|
44
44
|
"What it does:" \
|
|
45
45
|
" 1. Checks for Node.js and npm." \
|
|
46
|
-
" 2.
|
|
47
|
-
" 3.
|
|
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
|
-
|
|
142
|
-
|
|
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
|
-
" ${
|
|
199
|
+
" ${GLOBAL_INSTALL_CMD}" \
|
|
200
|
+
" ${SETUP_CMD}" \
|
|
160
201
|
"" \
|
|
161
202
|
"Effects:" \
|
|
162
|
-
" -
|
|
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
|
-
|
|
191
|
-
|
|
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:
|
|
252
|
+
" 3. Upgrade latest: ${PREFERRED_CLI} upgrade --dry-run" \
|
|
206
253
|
"" \
|
|
207
254
|
"Version:" \
|
|
208
|
-
" Installed CLI:
|
|
209
|
-
" Published package: npm view ${PACKAGE} version"
|
|
210
|
-
|
|
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:
|
|
263
|
+
" 1. Apply the plan: ${PREFERRED_CLI} setup --yes" \
|
|
217
264
|
" (or re-run installer: curl ... | sh -s -- --yes)" \
|
|
218
|
-
" 2. Check health:
|
|
219
|
-
" 3. Repair drift:
|
|
265
|
+
" 2. Check health: ${PREFERRED_CLI} status" \
|
|
266
|
+
" 3. Repair drift: ${PREFERRED_CLI} sync" \
|
|
220
267
|
"" \
|
|
221
268
|
"Version:" \
|
|
222
|
-
" Installed CLI:
|
|
269
|
+
" Installed CLI: ${PREFERRED_CLI} --version" \
|
|
223
270
|
" Published package: npm view ${PACKAGE} version" \
|
|
224
|
-
" Update / converge:
|
|
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
|
-
|
|
57
|
-
|
|
58
|
-
|
|
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
|
-
|
|
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="$(
|
|
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
|
-
|
|
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 });
|
package/src/global/brand/cli.js
CHANGED
|
@@ -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 {
|
|
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,
|
|
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 = {
|