promptkit-os 1.9.0
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 +50 -0
- package/bin/promptkit-os.js +159 -0
- package/package.json +40 -0
package/README.md
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# `promptkit-os` (npm)
|
|
2
|
+
|
|
3
|
+
The **courier**, not the product. PromptKit OS itself is pure markdown with no runtime, no daemon, and no model lock-in — it lives at [lowqualityloey/promptkit-os](https://github.com/lowqualityloey/promptkit-os).
|
|
4
|
+
|
|
5
|
+
This package does one thing: fetch the GitHub release tarball that matches its own version, extract it into `./.promptkit/`, and run the canonical `init.sh` (POSIX) or `init.ps1` (Windows). All installation logic stays in the fetched repository; nothing is reimplemented here.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npx promptkit-os@latest # interactive picker when in a TTY
|
|
11
|
+
npx promptkit-os@latest --balanced # explicit profile
|
|
12
|
+
npx promptkit-os@latest --lite
|
|
13
|
+
npx promptkit-os@latest --turbo --experimental
|
|
14
|
+
npx promptkit-os@latest /path/to/project
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Pass-through flags: `--lite`, `--balanced`, `--turbo`, `--experimental`, `--host=`, `--target=`, `--tracking=`, `--reconfigure`.
|
|
18
|
+
|
|
19
|
+
Requires Node 18+ (the courier runs on Node; the installed product does not). On Windows it also requires **PowerShell 7 (`pwsh`)**, which is what `init.ps1` targets — stock Windows PowerShell 5.1 is not supported.
|
|
20
|
+
|
|
21
|
+
## Updating an existing install
|
|
22
|
+
|
|
23
|
+
If `.promptkit/` already exists and is not empty, the courier **refuses to overlay it** — a tarball merge can leave stale files behind and mix delivery doors. The right update path depends on how it was installed:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
# git-submodule install
|
|
27
|
+
git submodule update --remote --merge .promptkit && bash .promptkit/init.sh
|
|
28
|
+
|
|
29
|
+
# courier install (tarball is pinned per version — replace it)
|
|
30
|
+
rm -rf .promptkit
|
|
31
|
+
npx promptkit-os@latest --balanced
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
The courier detects which case applies (a submodule install has `.promptkit/.git`) and prints the matching command. `--force` overlays anyway, but it is not recommended.
|
|
35
|
+
|
|
36
|
+
## Version pinning
|
|
37
|
+
|
|
38
|
+
`npx promptkit-os@X.Y.Z` fetches release tag `vX.Y.Z` and never a moving ref, so a given install is reproducible forever.
|
|
39
|
+
|
|
40
|
+
## Removal
|
|
41
|
+
|
|
42
|
+
Delete `.promptkit/` — plus the generated `PROMPTKIT.md` and `docs/STATE.md` if you don't want them. No daemon, no cache, no registration, nothing left behind.
|
|
43
|
+
|
|
44
|
+
## Which path should I use?
|
|
45
|
+
|
|
46
|
+
The git submodule flow remains canonical and is documented first in the [README](https://github.com/lowqualityloey/promptkit-os#readme) and [QUICKSTART](https://github.com/lowqualityloey/promptkit-os/blob/main/QUICKSTART.md). Use npm when you want a one-command install without submodule ceremony; the resulting `.promptkit/` tree is identical either way.
|
|
47
|
+
|
|
48
|
+
## License
|
|
49
|
+
|
|
50
|
+
MIT. Not affiliated with `microsoft/PromptKit` or `erikgeiser/promptkit`.
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// PromptKit OS installer courier.
|
|
3
|
+
//
|
|
4
|
+
// This package is a delivery vehicle, not a second implementation. It fetches the
|
|
5
|
+
// GitHub release tarball that matches its own package version, extracts it into
|
|
6
|
+
// ./.promptkit/, and executes the canonical init.sh (POSIX) or init.ps1 (Windows).
|
|
7
|
+
// All installation logic lives in the fetched repository; nothing is reimplemented here.
|
|
8
|
+
|
|
9
|
+
"use strict";
|
|
10
|
+
|
|
11
|
+
const { spawnSync } = require("node:child_process");
|
|
12
|
+
const fs = require("node:fs");
|
|
13
|
+
const path = require("node:path");
|
|
14
|
+
const os = require("node:os");
|
|
15
|
+
|
|
16
|
+
const PKG = require("../package.json");
|
|
17
|
+
const REPO = "lowqualityloey/promptkit-os";
|
|
18
|
+
const KIT_DIR = ".promptkit";
|
|
19
|
+
|
|
20
|
+
function die(msg) {
|
|
21
|
+
process.stderr.write(`[promptkit-os] ${msg}\n`);
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function passthroughFlags(argv) {
|
|
26
|
+
const known = new Set([
|
|
27
|
+
"--lite",
|
|
28
|
+
"--balanced",
|
|
29
|
+
"--turbo",
|
|
30
|
+
"--experimental",
|
|
31
|
+
"--reconfigure",
|
|
32
|
+
"-h",
|
|
33
|
+
"--help",
|
|
34
|
+
]);
|
|
35
|
+
const out = [];
|
|
36
|
+
for (const arg of argv) {
|
|
37
|
+
if (arg === "--force") continue; // courier-only flag, never forwarded to the installer
|
|
38
|
+
if (known.has(arg) || arg.startsWith("--host=") || arg.startsWith("--target=") || arg.startsWith("--tracking=")) {
|
|
39
|
+
out.push(arg);
|
|
40
|
+
} else if (!arg.startsWith("-")) {
|
|
41
|
+
out.push(arg); // positional project root
|
|
42
|
+
} else {
|
|
43
|
+
die(`unknown flag '${arg}' — pass it through after the install target, or see init --help`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return out;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Extracting a tarball over an existing tree is not idempotent the way the canonical
|
|
50
|
+
// git-submodule path is: it merges, leaving stale files behind and producing a franken
|
|
51
|
+
// state that mixes delivery doors. Refuse instead, and say exactly how to proceed —
|
|
52
|
+
// the correct update command depends on which door produced the existing install.
|
|
53
|
+
function assertInstallTargetIsClean(kitDir, force) {
|
|
54
|
+
if (!fs.existsSync(kitDir)) return;
|
|
55
|
+
const entries = fs.readdirSync(kitDir);
|
|
56
|
+
if (entries.length === 0 || force) return;
|
|
57
|
+
|
|
58
|
+
const isSubmoduleInstall = fs.existsSync(path.join(kitDir, ".git"));
|
|
59
|
+
const update = isSubmoduleInstall
|
|
60
|
+
? " git submodule update --remote --merge .promptkit && bash .promptkit/init.sh"
|
|
61
|
+
: ` rm -rf ${KIT_DIR}\n` +
|
|
62
|
+
` npx promptkit-os@latest --balanced # or: npx promptkit-os@latest --lite`;
|
|
63
|
+
const updateIntro = isSubmoduleInstall
|
|
64
|
+
? "To update this git-submodule install:"
|
|
65
|
+
: "To update this courier install, replace it (the tarball is pinned per version):";
|
|
66
|
+
|
|
67
|
+
die(
|
|
68
|
+
`${KIT_DIR}/ already exists and is not empty.\n` +
|
|
69
|
+
" Refusing to overlay it — a tarball merge can leave stale files behind.\n" +
|
|
70
|
+
` ${updateIntro}\n` +
|
|
71
|
+
update +
|
|
72
|
+
"\n To force an overlay anyway (not recommended), re-run with --force."
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function projectRootFrom(args) {
|
|
77
|
+
const positional = args.filter((a) => !a.startsWith("-"));
|
|
78
|
+
return path.resolve(positional[0] || process.cwd());
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async function download(url) {
|
|
82
|
+
process.stderr.write(`[promptkit-os] fetching ${url}\n`);
|
|
83
|
+
const res = await fetch(url, { redirect: "follow" });
|
|
84
|
+
if (!res.ok) die(`download failed (HTTP ${res.status}) for ${url}`);
|
|
85
|
+
return Buffer.from(await res.arrayBuffer());
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async function extract(tarball, dest) {
|
|
89
|
+
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "promptkit-os-"));
|
|
90
|
+
const tarPath = path.join(tmp, "release.tar.gz");
|
|
91
|
+
fs.writeFileSync(tarPath, tarball);
|
|
92
|
+
|
|
93
|
+
const res = spawnSync("tar", ["-xzf", tarPath, "-C", dest, "--strip-components=1"], { stdio: "inherit" });
|
|
94
|
+
if (res.status !== 0) die("failed to extract release tarball (is `tar` available?)");
|
|
95
|
+
fs.rmSync(tmp, { recursive: true, force: true });
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function runInstaller(kitDir, args) {
|
|
99
|
+
const isWindows = process.platform === "win32";
|
|
100
|
+
if (isWindows) {
|
|
101
|
+
const ps = path.join(kitDir, "init.ps1");
|
|
102
|
+
if (!fs.existsSync(ps)) die("init.ps1 missing from release tarball");
|
|
103
|
+
const res = spawnSync("pwsh", ["-NoProfile", "-File", ps, ...args], { stdio: "inherit" });
|
|
104
|
+
if (res.status !== 0) die("init.ps1 failed");
|
|
105
|
+
} else {
|
|
106
|
+
const sh = path.join(kitDir, "init.sh");
|
|
107
|
+
if (!fs.existsSync(sh)) die("init.sh missing from release tarball");
|
|
108
|
+
fs.chmodSync(sh, 0o755);
|
|
109
|
+
const res = spawnSync("bash", [sh, ...args], { stdio: "inherit" });
|
|
110
|
+
if (res.status !== 0) die("init.sh failed");
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
async function main() {
|
|
115
|
+
const version = PKG.version;
|
|
116
|
+
if (version === "0.0.0") {
|
|
117
|
+
die(
|
|
118
|
+
"this build is unreleased (version 0.0.0) — install a published version instead:\n" +
|
|
119
|
+
" npx promptkit-os@latest --balanced"
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const args = passthroughFlags(process.argv.slice(2));
|
|
124
|
+
const force = process.argv.slice(2).includes("--force");
|
|
125
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
126
|
+
process.stdout.write(
|
|
127
|
+
"promptkit-os <version> — installs PromptKit OS into ./.promptkit and runs the canonical installer\n\n" +
|
|
128
|
+
"Usage:\n" +
|
|
129
|
+
" npx promptkit-os@latest # install (interactive picker if TTY)\n" +
|
|
130
|
+
" npx promptkit-os@latest --balanced # explicit profile\n" +
|
|
131
|
+
" npx promptkit-os@latest --lite\n" +
|
|
132
|
+
" npx promptkit-os@latest --turbo --experimental\n" +
|
|
133
|
+
" npx promptkit-os@latest /path/to/project\n\n" +
|
|
134
|
+
"Pass-through flags: --lite --balanced --turbo --experimental --host= --target= --tracking= --reconfigure\n" +
|
|
135
|
+
"Courier flags: --force (overlay a non-empty .promptkit/; not recommended)\n\n" +
|
|
136
|
+
"Updating an existing install? Use the canonical path instead:\n" +
|
|
137
|
+
" git submodule update --remote --merge .promptkit && bash .promptkit/init.sh\n\n" +
|
|
138
|
+
"The npm package is a courier, not a dependency. Removal: delete .promptkit/ (and generated\n" +
|
|
139
|
+
"PROMPTKIT.md / docs/STATE.md if unwanted). No daemon, nothing left behind.\n"
|
|
140
|
+
);
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const root = projectRootFrom(args);
|
|
145
|
+
if (!fs.existsSync(root)) die(`project root not found: ${root}`);
|
|
146
|
+
|
|
147
|
+
const url = `https://github.com/${REPO}/archive/refs/tags/v${version}.tar.gz`;
|
|
148
|
+
const kitDir = path.join(root, KIT_DIR);
|
|
149
|
+
assertInstallTargetIsClean(kitDir, force);
|
|
150
|
+
fs.mkdirSync(kitDir, { recursive: true });
|
|
151
|
+
|
|
152
|
+
const tarball = await download(url);
|
|
153
|
+
await extract(tarball, kitDir);
|
|
154
|
+
process.stderr.write(`[promptkit-os] extracted release v${version} into ${KIT_DIR}/\n`);
|
|
155
|
+
|
|
156
|
+
runInstaller(kitDir, args);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
main().catch((err) => die(err && err.message ? err.message : String(err)));
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "promptkit-os",
|
|
3
|
+
"version": "1.9.0",
|
|
4
|
+
"description": "Courier for PromptKit OS: fetches a pinned release tarball and runs the canonical installer. Not a runtime dependency.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"promptkit",
|
|
7
|
+
"ai",
|
|
8
|
+
"agent",
|
|
9
|
+
"workflow",
|
|
10
|
+
"markdown",
|
|
11
|
+
"governance",
|
|
12
|
+
"cli"
|
|
13
|
+
],
|
|
14
|
+
"homepage": "https://github.com/lowqualityloey/promptkit-os#readme",
|
|
15
|
+
"bugs": {
|
|
16
|
+
"url": "https://github.com/lowqualityloey/promptkit-os/issues"
|
|
17
|
+
},
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+https://github.com/lowqualityloey/promptkit-os.git"
|
|
21
|
+
},
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"bin": {
|
|
24
|
+
"promptkit-os": "bin/promptkit-os.js"
|
|
25
|
+
},
|
|
26
|
+
"files": [
|
|
27
|
+
"bin/promptkit-os.js",
|
|
28
|
+
"README.md"
|
|
29
|
+
],
|
|
30
|
+
"engines": {
|
|
31
|
+
"node": ">=18"
|
|
32
|
+
},
|
|
33
|
+
"scripts": {
|
|
34
|
+
"test": "bash test/smoke.sh"
|
|
35
|
+
},
|
|
36
|
+
"publishConfig": {
|
|
37
|
+
"access": "public",
|
|
38
|
+
"provenance": true
|
|
39
|
+
}
|
|
40
|
+
}
|