@schilderlabs/pitown 0.1.2 → 0.2.6
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 +25 -0
- package/dist/{config-Bw-mNdF5.mjs → config-BG1v4iIi.mjs} +29 -50
- package/dist/config-BG1v4iIi.mjs.map +1 -0
- package/dist/doctor.d.mts +8 -0
- package/dist/doctor.mjs +42 -0
- package/dist/doctor.mjs.map +1 -0
- package/dist/entrypoint-WBAQmFbT.mjs +61 -0
- package/dist/entrypoint-WBAQmFbT.mjs.map +1 -0
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +1265 -8
- package/dist/index.mjs.map +1 -1
- package/dist/loop-CocC9qO1.mjs +678 -0
- package/dist/loop-CocC9qO1.mjs.map +1 -0
- package/dist/pi-C7HRNjBG.mjs +12 -0
- package/dist/pi-C7HRNjBG.mjs.map +1 -0
- package/dist/repo-context-BuA2JqPm.mjs +45 -0
- package/dist/repo-context-BuA2JqPm.mjs.map +1 -0
- package/dist/run.d.mts +3 -69
- package/dist/run.mjs +39 -19
- package/dist/run.mjs.map +1 -1
- package/dist/status.mjs +2 -1
- package/dist/status.mjs.map +1 -1
- package/dist/tasks-De4IAy3x.mjs +195 -0
- package/dist/tasks-De4IAy3x.mjs.map +1 -0
- package/dist/types-COGNGvsY.d.mts +142 -0
- package/dist/watch.d.mts +35 -1
- package/dist/watch.mjs +129 -16
- package/dist/watch.mjs.map +1 -1
- package/package.json +21 -23
- package/dist/config-Bw-mNdF5.mjs.map +0 -1
- package/dist/controller-D7lezZjg.mjs +0 -342
- package/dist/controller-D7lezZjg.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -4,6 +4,12 @@ The installable Pi Town CLI.
|
|
|
4
4
|
|
|
5
5
|
Pi Town is an experimental orchestration tool for Pi.
|
|
6
6
|
|
|
7
|
+
## Credits
|
|
8
|
+
|
|
9
|
+
Pi Town is built on top of Pi. Credit to [Mario Zechner](https://github.com/badlogic) and the Pi project for the underlying coding agent runtime Pi Town orchestrates.
|
|
10
|
+
|
|
11
|
+
Pi Town was also inspired by [Gastown](https://github.com/steveyegge/gastown). Credit to [Steve Yegge](https://github.com/steveyegge) for pushing on multi-agent orchestration ideas that made this project worth exploring.
|
|
12
|
+
|
|
7
13
|
For the full project overview, roadmap, and architecture context, see the main repo:
|
|
8
14
|
|
|
9
15
|
- https://github.com/schilderlabs/pitown
|
|
@@ -19,6 +25,7 @@ npm install -g @mariozechner/pi-coding-agent
|
|
|
19
25
|
Verify Pi first:
|
|
20
26
|
|
|
21
27
|
```bash
|
|
28
|
+
pitown doctor
|
|
22
29
|
pi -p "hello"
|
|
23
30
|
```
|
|
24
31
|
|
|
@@ -26,10 +33,28 @@ pi -p "hello"
|
|
|
26
33
|
|
|
27
34
|
```bash
|
|
28
35
|
pitown --help
|
|
36
|
+
pitown
|
|
37
|
+
pitown mayor
|
|
38
|
+
pitown mayor "plan the next milestones"
|
|
29
39
|
pitown run --repo /path/to/repo --plan /path/to/private/plans --goal "continue from current scaffold state"
|
|
30
40
|
pitown status
|
|
31
41
|
```
|
|
32
42
|
|
|
43
|
+
If you are already inside a repo, `pitown` and `pitown mayor` use the current working repo by default.
|
|
44
|
+
|
|
45
|
+
The main workflow is:
|
|
46
|
+
|
|
47
|
+
1. `cd` into a repo
|
|
48
|
+
2. run `pitown` or `pitown mayor`
|
|
49
|
+
3. use `/plan` inside the mayor session when you want a read-only plan first
|
|
50
|
+
4. use `pitown board`, `pitown peek mayor`, or `pitown msg mayor "..."` as needed
|
|
51
|
+
|
|
52
|
+
Inside the mayor session:
|
|
53
|
+
|
|
54
|
+
- `/plan` toggles read-only planning mode
|
|
55
|
+
- `/todos` shows the captured numbered plan
|
|
56
|
+
- leaving `/plan` returns the mayor to normal execution and delegation mode
|
|
57
|
+
|
|
33
58
|
## Runtime storage
|
|
34
59
|
|
|
35
60
|
By default, Pi Town stores local runtime state under `~/.pi-town` and keeps private plans outside the target repo.
|
|
@@ -1,55 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { a as runCommandSync, r as assertSuccess } from "./entrypoint-WBAQmFbT.mjs";
|
|
2
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
3
|
import { basename, dirname, isAbsolute, join, resolve } from "node:path";
|
|
3
|
-
import { fileURLToPath } from "node:url";
|
|
4
4
|
import { homedir } from "node:os";
|
|
5
5
|
import { createHash } from "node:crypto";
|
|
6
|
-
import { spawnSync } from "node:child_process";
|
|
7
6
|
|
|
8
|
-
//#region src/entrypoint.ts
|
|
9
|
-
function normalizePath(path) {
|
|
10
|
-
if (!path) return null;
|
|
11
|
-
try {
|
|
12
|
-
return realpathSync(path);
|
|
13
|
-
} catch {
|
|
14
|
-
return resolve(path);
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
function isDirectExecution(fileUrl, argv1 = process.argv[1]) {
|
|
18
|
-
const modulePath = normalizePath(fileURLToPath(fileUrl));
|
|
19
|
-
const invokedPath = normalizePath(argv1);
|
|
20
|
-
return modulePath !== null && invokedPath !== null && modulePath === invokedPath;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
//#endregion
|
|
24
|
-
//#region ../core/src/shell.ts
|
|
25
|
-
function runCommandSync(command, args, options) {
|
|
26
|
-
const result = spawnSync(command, args, {
|
|
27
|
-
cwd: options?.cwd,
|
|
28
|
-
env: options?.env,
|
|
29
|
-
encoding: "utf-8"
|
|
30
|
-
});
|
|
31
|
-
const errorText = result.error instanceof Error ? `${result.error.message}
|
|
32
|
-
` : "";
|
|
33
|
-
return {
|
|
34
|
-
stdout: result.stdout ?? "",
|
|
35
|
-
stderr: `${errorText}${result.stderr ?? ""}`,
|
|
36
|
-
exitCode: result.status ?? 1
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
function assertCommandAvailable(command) {
|
|
40
|
-
const result = spawnSync(command, ["--help"], {
|
|
41
|
-
encoding: "utf-8",
|
|
42
|
-
stdio: "ignore"
|
|
43
|
-
});
|
|
44
|
-
if (result.error instanceof Error) throw new Error(result.error.message);
|
|
45
|
-
}
|
|
46
|
-
function assertSuccess(result, context) {
|
|
47
|
-
if (result.exitCode === 0) return;
|
|
48
|
-
const details = [result.stdout.trim(), result.stderr.trim()].filter(Boolean).join("\n");
|
|
49
|
-
throw new Error(`${context} failed${details ? `\n${details}` : ""}`);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
//#endregion
|
|
53
7
|
//#region ../core/src/repo.ts
|
|
54
8
|
function gitResult(cwd, args) {
|
|
55
9
|
return runCommandSync("git", args, { cwd });
|
|
@@ -142,6 +96,7 @@ function parseCliFlags(argv) {
|
|
|
142
96
|
const flags = { help: false };
|
|
143
97
|
for (let index = 0; index < argv.length; index += 1) {
|
|
144
98
|
const arg = argv[index];
|
|
99
|
+
if (arg === void 0) continue;
|
|
145
100
|
if (arg === "--help" || arg === "-h") {
|
|
146
101
|
flags.help = true;
|
|
147
102
|
continue;
|
|
@@ -183,6 +138,30 @@ function parseCliFlags(argv) {
|
|
|
183
138
|
}
|
|
184
139
|
return flags;
|
|
185
140
|
}
|
|
141
|
+
function parseOptionalRepoFlag(argv) {
|
|
142
|
+
const rest = [];
|
|
143
|
+
let repo;
|
|
144
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
145
|
+
const arg = argv[index];
|
|
146
|
+
if (arg === void 0) continue;
|
|
147
|
+
if (arg.startsWith("--repo=")) {
|
|
148
|
+
repo = arg.slice(7);
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
if (arg === "--repo") {
|
|
152
|
+
const value = argv[index + 1];
|
|
153
|
+
if (!value) throw new Error("Missing value for --repo");
|
|
154
|
+
repo = value;
|
|
155
|
+
index += 1;
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
rest.push(arg);
|
|
159
|
+
}
|
|
160
|
+
return repo === void 0 ? { rest } : {
|
|
161
|
+
repo,
|
|
162
|
+
rest
|
|
163
|
+
};
|
|
164
|
+
}
|
|
186
165
|
function loadUserConfig() {
|
|
187
166
|
const configPath = getUserConfigPath();
|
|
188
167
|
if (!existsSync(configPath)) return {};
|
|
@@ -202,5 +181,5 @@ function resolveRunConfig(argv) {
|
|
|
202
181
|
}
|
|
203
182
|
|
|
204
183
|
//#endregion
|
|
205
|
-
export {
|
|
206
|
-
//# sourceMappingURL=config-
|
|
184
|
+
export { getRecommendedPlanDir as a, getReposRootDir as c, createRepoSlug as d, getCurrentBranch as f, isGitRepo as h, getLatestRunPointerPath as i, getTownHomeDir as l, getRepoRoot as m, parseOptionalRepoFlag as n, getRepoArtifactsDir as o, getRepoIdentity as p, resolveRunConfig as r, getRepoLatestRunPointerPath as s, parseCliFlags as t, getUserConfigPath as u };
|
|
185
|
+
//# sourceMappingURL=config-BG1v4iIi.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-BG1v4iIi.mjs","names":[],"sources":["../../core/src/repo.ts","../src/paths.ts","../src/config.ts"],"sourcesContent":["import { createHash } from \"node:crypto\"\nimport { existsSync } from \"node:fs\"\nimport { basename, resolve } from \"node:path\"\nimport { assertSuccess, runCommandSync } from \"./shell.js\"\n\nfunction gitResult(cwd: string, args: string[]) {\n\treturn runCommandSync(\"git\", args, { cwd })\n}\n\nfunction sanitize(value: string): string {\n\treturn value.replace(/[^a-zA-Z0-9._-]+/g, \"-\").replace(/^-+|-+$/g, \"\") || \"repo\"\n}\n\nexport function isGitRepo(cwd: string): boolean {\n\tconst result = gitResult(cwd, [\"rev-parse\", \"--is-inside-work-tree\"])\n\treturn result.exitCode === 0 && result.stdout.trim() === \"true\"\n}\n\nexport function getRepoRoot(cwd: string): string {\n\tif (!isGitRepo(cwd)) return resolve(cwd)\n\tconst result = gitResult(cwd, [\"rev-parse\", \"--show-toplevel\"])\n\tassertSuccess(result, \"git rev-parse --show-toplevel\")\n\treturn resolve(result.stdout.trim())\n}\n\nexport function getCurrentBranch(cwd: string): string | null {\n\tif (!isGitRepo(cwd)) return null\n\tconst result = gitResult(cwd, [\"rev-parse\", \"--abbrev-ref\", \"HEAD\"])\n\tif (result.exitCode !== 0) return null\n\tconst branch = result.stdout.trim()\n\treturn branch || null\n}\n\nexport function getRepoIdentity(cwd: string): string {\n\tif (!isGitRepo(cwd)) return resolve(cwd)\n\n\tconst remote = gitResult(cwd, [\"config\", \"--get\", \"remote.origin.url\"])\n\tconst remoteValue = remote.stdout.trim()\n\tif (remote.exitCode === 0 && remoteValue) return remoteValue\n\n\tconst root = gitResult(cwd, [\"rev-parse\", \"--show-toplevel\"])\n\tassertSuccess(root, \"git rev-parse --show-toplevel\")\n\tconst commonDir = gitResult(cwd, [\"rev-parse\", \"--git-common-dir\"])\n\tassertSuccess(commonDir, \"git rev-parse --git-common-dir\")\n\n\tconst rootPath = resolve(root.stdout.trim())\n\tconst commonDirPath = commonDir.stdout.trim()\n\treturn `${basename(rootPath)}:${rootPath}:${existsSync(commonDirPath) ? resolve(commonDirPath) : commonDirPath}`\n}\n\nexport function createRepoSlug(repoId: string, repoRoot: string): string {\n\tconst name = sanitize(basename(repoRoot))\n\tconst digest = createHash(\"sha1\").update(repoId).digest(\"hex\").slice(0, 8)\n\treturn `${name}-${digest}`\n}\n","import { homedir } from \"node:os\"\nimport { join } from \"node:path\"\n\nexport function getTownHomeDir(): string {\n\treturn join(homedir(), \".pi-town\")\n}\n\nexport function getUserConfigPath(): string {\n\treturn join(getTownHomeDir(), \"config.json\")\n}\n\nexport function getPlansRootDir(): string {\n\treturn join(getTownHomeDir(), \"plans\")\n}\n\nexport function getReposRootDir(): string {\n\treturn join(getTownHomeDir(), \"repos\")\n}\n\nexport function getRepoArtifactsDir(repoSlug: string): string {\n\treturn join(getReposRootDir(), repoSlug)\n}\n\nexport function getRepoAgentsDir(repoSlug: string): string {\n\treturn join(getRepoArtifactsDir(repoSlug), \"agents\")\n}\n\nexport function getLatestRunPointerPath(): string {\n\treturn join(getTownHomeDir(), \"latest-run.json\")\n}\n\nexport function getRepoLatestRunPointerPath(repoSlug: string): string {\n\treturn join(getRepoArtifactsDir(repoSlug), \"latest-run.json\")\n}\n\nexport function getRecommendedPlanDir(repoSlug: string): string {\n\treturn join(getPlansRootDir(), repoSlug)\n}\n","import { existsSync, readFileSync } from \"node:fs\"\nimport { dirname, isAbsolute, resolve } from \"node:path\"\nimport { homedir } from \"node:os\"\nimport { getUserConfigPath } from \"./paths.js\"\n\nconst DEFAULT_GOAL = \"continue from current scaffold state\"\n\nexport interface CliFlags {\n\trepo?: string\n\tplan?: string\n\tgoal?: string\n\thelp: boolean\n}\n\nexport interface OptionalRepoFlagResult {\n\trepo?: string\n\trest: string[]\n}\n\ninterface UserConfig {\n\trepo?: string\n\tplan?: string\n\tgoal?: string\n}\n\nexport interface ResolvedRunConfig {\n\trepo: string\n\tplan: string | null\n\tgoal: string\n\tconfigPath: string\n}\n\nfunction expandHome(value: string): string {\n\tif (value === \"~\") return homedir()\n\tif (value.startsWith(\"~/\")) return resolve(homedir(), value.slice(2))\n\treturn value\n}\n\nfunction resolvePathValue(value: string | undefined, baseDir: string): string | undefined {\n\tif (!value) return undefined\n\tconst expanded = expandHome(value)\n\treturn isAbsolute(expanded) ? resolve(expanded) : resolve(baseDir, expanded)\n}\n\nexport function parseCliFlags(argv: string[]): CliFlags {\n\tconst flags: CliFlags = { help: false }\n\n\tfor (let index = 0; index < argv.length; index += 1) {\n\t\tconst arg = argv[index]\n\t\tif (arg === undefined) continue\n\n\t\tif (arg === \"--help\" || arg === \"-h\") {\n\t\t\tflags.help = true\n\t\t\tcontinue\n\t\t}\n\n\t\tif (arg.startsWith(\"--repo=\")) {\n\t\t\tflags.repo = arg.slice(\"--repo=\".length)\n\t\t\tcontinue\n\t\t}\n\n\t\tif (arg === \"--repo\") {\n\t\t\tconst value = argv[index + 1]\n\t\t\tif (!value) throw new Error(\"Missing value for --repo\")\n\t\t\tflags.repo = value\n\t\t\tindex += 1\n\t\t\tcontinue\n\t\t}\n\n\t\tif (arg.startsWith(\"--plan=\")) {\n\t\t\tflags.plan = arg.slice(\"--plan=\".length)\n\t\t\tcontinue\n\t\t}\n\n\t\tif (arg === \"--plan\") {\n\t\t\tconst value = argv[index + 1]\n\t\t\tif (!value) throw new Error(\"Missing value for --plan\")\n\t\t\tflags.plan = value\n\t\t\tindex += 1\n\t\t\tcontinue\n\t\t}\n\n\t\tif (arg.startsWith(\"--goal=\")) {\n\t\t\tflags.goal = arg.slice(\"--goal=\".length)\n\t\t\tcontinue\n\t\t}\n\n\t\tif (arg === \"--goal\") {\n\t\t\tconst value = argv[index + 1]\n\t\t\tif (!value) throw new Error(\"Missing value for --goal\")\n\t\t\tflags.goal = value\n\t\t\tindex += 1\n\t\t\tcontinue\n\t\t}\n\n\t\tthrow new Error(`Unknown argument: ${arg}`)\n\t}\n\n\treturn flags\n}\n\nexport function parseOptionalRepoFlag(argv: string[]): OptionalRepoFlagResult {\n\tconst rest: string[] = []\n\tlet repo: string | undefined\n\n\tfor (let index = 0; index < argv.length; index += 1) {\n\t\tconst arg = argv[index]\n\t\tif (arg === undefined) continue\n\n\t\tif (arg.startsWith(\"--repo=\")) {\n\t\t\trepo = arg.slice(\"--repo=\".length)\n\t\t\tcontinue\n\t\t}\n\n\t\tif (arg === \"--repo\") {\n\t\t\tconst value = argv[index + 1]\n\t\t\tif (!value) throw new Error(\"Missing value for --repo\")\n\t\t\trepo = value\n\t\t\tindex += 1\n\t\t\tcontinue\n\t\t}\n\n\t\trest.push(arg)\n\t}\n\n\treturn repo === undefined ? { rest } : { repo, rest }\n}\n\nexport function loadUserConfig(): UserConfig {\n\tconst configPath = getUserConfigPath()\n\tif (!existsSync(configPath)) return {}\n\treturn JSON.parse(readFileSync(configPath, \"utf-8\")) as UserConfig\n}\n\nexport function resolveRunConfig(argv: string[]): ResolvedRunConfig {\n\tconst flags = parseCliFlags(argv)\n\tconst configPath = getUserConfigPath()\n\tconst userConfig = loadUserConfig()\n\tconst configDir = dirname(configPath)\n\n\tconst repo =\n\t\tresolvePathValue(flags.repo, process.cwd()) ??\n\t\tresolvePathValue(userConfig.repo, configDir) ??\n\t\tresolve(process.cwd())\n\tconst plan = resolvePathValue(flags.plan, process.cwd()) ?? resolvePathValue(userConfig.plan, configDir) ?? null\n\tconst goal = flags.goal ?? userConfig.goal ?? DEFAULT_GOAL\n\n\treturn {\n\t\trepo,\n\t\tplan,\n\t\tgoal,\n\t\tconfigPath,\n\t}\n}\n"],"mappings":"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"}
|
package/dist/doctor.mjs
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { n as detectPiAuthFailure, t as createPiAuthHelpMessage } from "./pi-C7HRNjBG.mjs";
|
|
2
|
+
import { a as runCommandSync, t as isDirectExecution } from "./entrypoint-WBAQmFbT.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/doctor.ts
|
|
5
|
+
function runDoctor() {
|
|
6
|
+
console.log("[pitown] doctor");
|
|
7
|
+
if (runCommandSync("pi", ["--help"]).exitCode !== 0) {
|
|
8
|
+
console.log("- pi cli: missing");
|
|
9
|
+
console.log("- install: npm install -g @mariozechner/pi-coding-agent");
|
|
10
|
+
console.log("- verify: pi -p \"hello\"");
|
|
11
|
+
return { ok: false };
|
|
12
|
+
}
|
|
13
|
+
const check = runCommandSync("pi", [
|
|
14
|
+
"--no-session",
|
|
15
|
+
"-p",
|
|
16
|
+
"hello"
|
|
17
|
+
]);
|
|
18
|
+
if (check.exitCode === 0) {
|
|
19
|
+
console.log("- pi cli: installed");
|
|
20
|
+
console.log("- pi auth: ready");
|
|
21
|
+
console.log("- status: ok");
|
|
22
|
+
return { ok: true };
|
|
23
|
+
}
|
|
24
|
+
if (detectPiAuthFailure(check.stderr, check.stdout)) {
|
|
25
|
+
console.log("- pi cli: installed");
|
|
26
|
+
console.log("- pi auth: not ready");
|
|
27
|
+
console.log(`- note: ${createPiAuthHelpMessage()}`);
|
|
28
|
+
return { ok: false };
|
|
29
|
+
}
|
|
30
|
+
console.log("- pi cli: installed");
|
|
31
|
+
console.log("- pi check: failed");
|
|
32
|
+
if (check.stderr.trim()) console.log(`- stderr: ${check.stderr.trim()}`);
|
|
33
|
+
else if (check.stdout.trim()) console.log(`- stdout: ${check.stdout.trim()}`);
|
|
34
|
+
return { ok: false };
|
|
35
|
+
}
|
|
36
|
+
if (isDirectExecution(import.meta.url)) {
|
|
37
|
+
if (!runDoctor().ok) process.exitCode = 1;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
//#endregion
|
|
41
|
+
export { runDoctor };
|
|
42
|
+
//# sourceMappingURL=doctor.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.mjs","names":[],"sources":["../src/doctor.ts"],"sourcesContent":["import { createPiAuthHelpMessage, detectPiAuthFailure, runCommandSync } from \"../../core/src/index.js\"\nimport { isDirectExecution } from \"./entrypoint.js\"\n\nexport interface DoctorResult {\n\tok: boolean\n}\n\nexport function runDoctor(): DoctorResult {\n\tconsole.log(\"[pitown] doctor\")\n\n\tconst availability = runCommandSync(\"pi\", [\"--help\"])\n\tif (availability.exitCode !== 0) {\n\t\tconsole.log(\"- pi cli: missing\")\n\t\tconsole.log(\"- install: npm install -g @mariozechner/pi-coding-agent\")\n\t\tconsole.log('- verify: pi -p \"hello\"')\n\t\treturn { ok: false }\n\t}\n\n\tconst check = runCommandSync(\"pi\", [\"--no-session\", \"-p\", \"hello\"])\n\tif (check.exitCode === 0) {\n\t\tconsole.log(\"- pi cli: installed\")\n\t\tconsole.log(\"- pi auth: ready\")\n\t\tconsole.log(\"- status: ok\")\n\t\treturn { ok: true }\n\t}\n\n\tif (detectPiAuthFailure(check.stderr, check.stdout)) {\n\t\tconsole.log(\"- pi cli: installed\")\n\t\tconsole.log(\"- pi auth: not ready\")\n\t\tconsole.log(`- note: ${createPiAuthHelpMessage()}`)\n\t\treturn { ok: false }\n\t}\n\n\tconsole.log(\"- pi cli: installed\")\n\tconsole.log(\"- pi check: failed\")\n\tif (check.stderr.trim()) console.log(`- stderr: ${check.stderr.trim()}`)\n\telse if (check.stdout.trim()) console.log(`- stdout: ${check.stdout.trim()}`)\n\treturn { ok: false }\n}\n\nif (isDirectExecution(import.meta.url)) {\n\tconst result = runDoctor()\n\tif (!result.ok) process.exitCode = 1\n}\n"],"mappings":";;;;AAOA,SAAgB,YAA0B;AACzC,SAAQ,IAAI,kBAAkB;AAG9B,KADqB,eAAe,MAAM,CAAC,SAAS,CAAC,CACpC,aAAa,GAAG;AAChC,UAAQ,IAAI,oBAAoB;AAChC,UAAQ,IAAI,0DAA0D;AACtE,UAAQ,IAAI,4BAA0B;AACtC,SAAO,EAAE,IAAI,OAAO;;CAGrB,MAAM,QAAQ,eAAe,MAAM;EAAC;EAAgB;EAAM;EAAQ,CAAC;AACnE,KAAI,MAAM,aAAa,GAAG;AACzB,UAAQ,IAAI,sBAAsB;AAClC,UAAQ,IAAI,mBAAmB;AAC/B,UAAQ,IAAI,eAAe;AAC3B,SAAO,EAAE,IAAI,MAAM;;AAGpB,KAAI,oBAAoB,MAAM,QAAQ,MAAM,OAAO,EAAE;AACpD,UAAQ,IAAI,sBAAsB;AAClC,UAAQ,IAAI,uBAAuB;AACnC,UAAQ,IAAI,WAAW,yBAAyB,GAAG;AACnD,SAAO,EAAE,IAAI,OAAO;;AAGrB,SAAQ,IAAI,sBAAsB;AAClC,SAAQ,IAAI,qBAAqB;AACjC,KAAI,MAAM,OAAO,MAAM,CAAE,SAAQ,IAAI,aAAa,MAAM,OAAO,MAAM,GAAG;UAC/D,MAAM,OAAO,MAAM,CAAE,SAAQ,IAAI,aAAa,MAAM,OAAO,MAAM,GAAG;AAC7E,QAAO,EAAE,IAAI,OAAO;;AAGrB,IAAI,kBAAkB,OAAO,KAAK,IAAI,EAErC;KAAI,CADW,WAAW,CACd,GAAI,SAAQ,WAAW"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { realpathSync } from "node:fs";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { spawnSync } from "node:child_process";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
|
|
6
|
+
//#region ../core/src/shell.ts
|
|
7
|
+
function runCommandSync(command, args, options) {
|
|
8
|
+
const result = spawnSync(command, args, {
|
|
9
|
+
cwd: options?.cwd,
|
|
10
|
+
env: options?.env,
|
|
11
|
+
encoding: "utf-8"
|
|
12
|
+
});
|
|
13
|
+
const errorText = result.error instanceof Error ? `${result.error.message}
|
|
14
|
+
` : "";
|
|
15
|
+
return {
|
|
16
|
+
stdout: result.stdout ?? "",
|
|
17
|
+
stderr: `${errorText}${result.stderr ?? ""}`,
|
|
18
|
+
exitCode: result.status ?? 1
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function assertCommandAvailable(command) {
|
|
22
|
+
const result = spawnSync(command, ["--help"], {
|
|
23
|
+
encoding: "utf-8",
|
|
24
|
+
stdio: "ignore"
|
|
25
|
+
});
|
|
26
|
+
if (result.error instanceof Error) throw new Error(result.error.message);
|
|
27
|
+
}
|
|
28
|
+
function runCommandInteractive(command, args, options) {
|
|
29
|
+
const result = spawnSync(command, args, {
|
|
30
|
+
cwd: options?.cwd,
|
|
31
|
+
env: options?.env,
|
|
32
|
+
stdio: "inherit"
|
|
33
|
+
});
|
|
34
|
+
if (result.error instanceof Error) throw new Error(result.error.message);
|
|
35
|
+
return result.status ?? 1;
|
|
36
|
+
}
|
|
37
|
+
function assertSuccess(result, context) {
|
|
38
|
+
if (result.exitCode === 0) return;
|
|
39
|
+
const details = [result.stdout.trim(), result.stderr.trim()].filter(Boolean).join("\n");
|
|
40
|
+
throw new Error(`${context} failed${details ? `\n${details}` : ""}`);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
//#endregion
|
|
44
|
+
//#region src/entrypoint.ts
|
|
45
|
+
function normalizePath(path) {
|
|
46
|
+
if (!path) return null;
|
|
47
|
+
try {
|
|
48
|
+
return realpathSync(path);
|
|
49
|
+
} catch {
|
|
50
|
+
return resolve(path);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function isDirectExecution(fileUrl, argv1 = process.argv[1]) {
|
|
54
|
+
const modulePath = normalizePath(fileURLToPath(fileUrl));
|
|
55
|
+
const invokedPath = normalizePath(argv1);
|
|
56
|
+
return modulePath !== null && invokedPath !== null && modulePath === invokedPath;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
//#endregion
|
|
60
|
+
export { runCommandSync as a, runCommandInteractive as i, assertCommandAvailable as n, assertSuccess as r, isDirectExecution as t };
|
|
61
|
+
//# sourceMappingURL=entrypoint-WBAQmFbT.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entrypoint-WBAQmFbT.mjs","names":[],"sources":["../../core/src/shell.ts","../src/entrypoint.ts"],"sourcesContent":["import { spawnSync } from \"node:child_process\"\n\nexport interface CommandResult {\n\tstdout: string\n\tstderr: string\n\texitCode: number\n}\n\nexport function runCommandSync(\n\tcommand: string,\n\targs: string[],\n\toptions?: { cwd?: string; env?: NodeJS.ProcessEnv },\n): CommandResult {\n\tconst result = spawnSync(command, args, {\n\t\tcwd: options?.cwd,\n\t\tenv: options?.env,\n\t\tencoding: \"utf-8\",\n\t})\n\tconst errorText = result.error instanceof Error ? `${result.error.message}\n` : \"\"\n\n\treturn {\n\t\tstdout: result.stdout ?? \"\",\n\t\tstderr: `${errorText}${result.stderr ?? \"\"}`,\n\t\texitCode: result.status ?? 1,\n\t}\n}\n\nexport function assertCommandAvailable(command: string) {\n\tconst result = spawnSync(command, [\"--help\"], {\n\t\tencoding: \"utf-8\",\n\t\tstdio: \"ignore\",\n\t})\n\n\tif (result.error instanceof Error) {\n\t\tthrow new Error(result.error.message)\n\t}\n}\n\nexport function runCommandInteractive(\n\tcommand: string,\n\targs: string[],\n\toptions?: { cwd?: string; env?: NodeJS.ProcessEnv },\n): number {\n\tconst result = spawnSync(command, args, {\n\t\tcwd: options?.cwd,\n\t\tenv: options?.env,\n\t\tstdio: \"inherit\",\n\t})\n\n\tif (result.error instanceof Error) {\n\t\tthrow new Error(result.error.message)\n\t}\n\n\treturn result.status ?? 1\n}\n\nexport function assertSuccess(result: CommandResult, context: string) {\n\tif (result.exitCode === 0) return\n\tconst details = [result.stdout.trim(), result.stderr.trim()].filter(Boolean).join(\"\\n\")\n\tthrow new Error(`${context} failed${details ? `\\n${details}` : \"\"}`)\n}\n","import { realpathSync } from \"node:fs\"\nimport { resolve } from \"node:path\"\nimport { fileURLToPath } from \"node:url\"\n\nfunction normalizePath(path: string | undefined): string | null {\n\tif (!path) return null\n\ttry {\n\t\treturn realpathSync(path)\n\t} catch {\n\t\treturn resolve(path)\n\t}\n}\n\nexport function isDirectExecution(fileUrl: string, argv1 = process.argv[1]): boolean {\n\tconst modulePath = normalizePath(fileURLToPath(fileUrl))\n\tconst invokedPath = normalizePath(argv1)\n\treturn modulePath !== null && invokedPath !== null && modulePath === invokedPath\n}\n"],"mappings":";;;;;;AAQA,SAAgB,eACf,SACA,MACA,SACgB;CAChB,MAAM,SAAS,UAAU,SAAS,MAAM;EACvC,KAAK,SAAS;EACd,KAAK,SAAS;EACd,UAAU;EACV,CAAC;CACF,MAAM,YAAY,OAAO,iBAAiB,QAAQ,GAAG,OAAO,MAAM,QAAQ;IACvE;AAEH,QAAO;EACN,QAAQ,OAAO,UAAU;EACzB,QAAQ,GAAG,YAAY,OAAO,UAAU;EACxC,UAAU,OAAO,UAAU;EAC3B;;AAGF,SAAgB,uBAAuB,SAAiB;CACvD,MAAM,SAAS,UAAU,SAAS,CAAC,SAAS,EAAE;EAC7C,UAAU;EACV,OAAO;EACP,CAAC;AAEF,KAAI,OAAO,iBAAiB,MAC3B,OAAM,IAAI,MAAM,OAAO,MAAM,QAAQ;;AAIvC,SAAgB,sBACf,SACA,MACA,SACS;CACT,MAAM,SAAS,UAAU,SAAS,MAAM;EACvC,KAAK,SAAS;EACd,KAAK,SAAS;EACd,OAAO;EACP,CAAC;AAEF,KAAI,OAAO,iBAAiB,MAC3B,OAAM,IAAI,MAAM,OAAO,MAAM,QAAQ;AAGtC,QAAO,OAAO,UAAU;;AAGzB,SAAgB,cAAc,QAAuB,SAAiB;AACrE,KAAI,OAAO,aAAa,EAAG;CAC3B,MAAM,UAAU,CAAC,OAAO,OAAO,MAAM,EAAE,OAAO,OAAO,MAAM,CAAC,CAAC,OAAO,QAAQ,CAAC,KAAK,KAAK;AACvF,OAAM,IAAI,MAAM,GAAG,QAAQ,SAAS,UAAU,KAAK,YAAY,KAAK;;;;;ACxDrE,SAAS,cAAc,MAAyC;AAC/D,KAAI,CAAC,KAAM,QAAO;AAClB,KAAI;AACH,SAAO,aAAa,KAAK;SAClB;AACP,SAAO,QAAQ,KAAK;;;AAItB,SAAgB,kBAAkB,SAAiB,QAAQ,QAAQ,KAAK,IAAa;CACpF,MAAM,aAAa,cAAc,cAAc,QAAQ,CAAC;CACxD,MAAM,cAAc,cAAc,MAAM;AACxC,QAAO,eAAe,QAAQ,gBAAgB,QAAQ,eAAe"}
|
package/dist/index.d.mts
CHANGED