@beastmode-develeap/beastmode 0.1.37 → 0.1.38
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/dist/index.js +260 -16
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -7399,7 +7399,25 @@ function step(n, total, text) {
|
|
|
7399
7399
|
}
|
|
7400
7400
|
|
|
7401
7401
|
// src/cli/commands/init.ts
|
|
7402
|
-
var initCommand = new Command("init").description("Create a new BeastMode factory").argument("[name]", "Factory name (default: current directory name)").option("--project <path>", "Path to target project").option("--preset <preset>", "Pipeline preset (full, lean, prototype, infra, docs)").option("--backend <backend>", "Task backend (beastmode-board, github-issues)").option("--deploy <target>", "Deploy target (pr-only, vercel, aws-ecs, ...)").option("--methodology <name>", "Development methodology plugin").option("--plugin <name>", "Install plugin (repeatable)", collect, []).option("--from <template>", "Import config from template file").option("--ui", "Open web wizard instead of CLI").option("--yes", "Accept all defaults (non-interactive)").option(
|
|
7402
|
+
var initCommand = new Command("init").description("Create a new BeastMode factory").argument("[name]", "Factory name (default: current directory name)").option("--project <path>", "Path to target project").option("--preset <preset>", "Pipeline preset (full, lean, prototype, infra, docs)").option("--backend <backend>", "Task backend (beastmode-board, github-issues)").option("--deploy <target>", "Deploy target (pr-only, vercel, aws-ecs, ...)").option("--methodology <name>", "Development methodology plugin").option("--plugin <name>", "Install plugin (repeatable)", collect, []).option("--from <template>", "Import config from template file").option("--ui", "Open web wizard instead of CLI").option("--yes", "Accept all defaults (non-interactive)").option(
|
|
7403
|
+
"--project-github-token <token>",
|
|
7404
|
+
"GitHub PAT for the daemon's project operations (commit/push/PR/merge against PROJECT_DIR's git remote \u2014 needs `repo` scope). Alias for the legacy --github-token flag."
|
|
7405
|
+
).option(
|
|
7406
|
+
"--project-github-token-file <path>",
|
|
7407
|
+
"Read project GitHub PAT from file (safer than --project-github-token)"
|
|
7408
|
+
).option(
|
|
7409
|
+
"--github-token <token>",
|
|
7410
|
+
"Deprecated alias for --project-github-token. Kept for backward compat."
|
|
7411
|
+
).option(
|
|
7412
|
+
"--github-token-file <path>",
|
|
7413
|
+
"Deprecated alias for --project-github-token-file. Kept for backward compat."
|
|
7414
|
+
).option(
|
|
7415
|
+
"--ghcr-pull-token <token>",
|
|
7416
|
+
"GitHub PAT for pulling private beastmode images from ghcr.io/develeap/beastmode/* \u2014 needs `read:packages` scope. May be the same as --project-github-token but should normally be a separate dedicated token (Gap 16)."
|
|
7417
|
+
).option(
|
|
7418
|
+
"--ghcr-pull-token-file <path>",
|
|
7419
|
+
"Read GHCR pull token from file (safer than --ghcr-pull-token)"
|
|
7420
|
+
).option("--board-password <password>", "Board UI password (avoids interactive prompt)").option("--board-password-file <path>", "Read board password from file").action(async (name, opts) => {
|
|
7403
7421
|
try {
|
|
7404
7422
|
await runInit(name, opts);
|
|
7405
7423
|
} catch (err) {
|
|
@@ -7714,23 +7732,44 @@ async function runImageModeInit(name, opts) {
|
|
|
7714
7732
|
const factoryName = name || ".";
|
|
7715
7733
|
const targetDir = resolve5(factoryName === "." ? "." : factoryName);
|
|
7716
7734
|
step(1, totalSteps, "Credentials");
|
|
7717
|
-
let
|
|
7718
|
-
if (!
|
|
7735
|
+
let projectGithubToken = opts.projectGithubToken || (opts.projectGithubTokenFile ? readSecretFile(opts.projectGithubTokenFile) : "") || opts.githubToken || (opts.githubTokenFile ? readSecretFile(opts.githubTokenFile) : "") || process.env.PROJECT_GITHUB_TOKEN || process.env.GITHUB_TOKEN || "";
|
|
7736
|
+
if (!projectGithubToken && !opts.yes) {
|
|
7719
7737
|
const answer = await inquirer.prompt([
|
|
7720
7738
|
{
|
|
7721
7739
|
type: "password",
|
|
7722
7740
|
name: "token",
|
|
7723
|
-
message: "
|
|
7741
|
+
message: "PROJECT_GITHUB_TOKEN (PAT for project commits/pushes/PRs \u2014 `repo` scope, or `public_repo` for public-only):",
|
|
7724
7742
|
mask: "*"
|
|
7725
7743
|
}
|
|
7726
7744
|
]);
|
|
7727
|
-
|
|
7745
|
+
projectGithubToken = answer.token || "";
|
|
7728
7746
|
}
|
|
7729
|
-
if (
|
|
7730
|
-
success("
|
|
7747
|
+
if (projectGithubToken) {
|
|
7748
|
+
success("PROJECT_GITHUB_TOKEN set");
|
|
7731
7749
|
} else {
|
|
7732
|
-
warn("
|
|
7750
|
+
warn("PROJECT_GITHUB_TOKEN not set \u2014 daemon's git operations will fail until added to .env");
|
|
7733
7751
|
}
|
|
7752
|
+
let ghcrPullToken = opts.ghcrPullToken || (opts.ghcrPullTokenFile ? readSecretFile(opts.ghcrPullTokenFile) : "") || process.env.GHCR_PULL_TOKEN || "";
|
|
7753
|
+
if (!ghcrPullToken && !opts.yes) {
|
|
7754
|
+
const answer = await inquirer.prompt([
|
|
7755
|
+
{
|
|
7756
|
+
type: "password",
|
|
7757
|
+
name: "token",
|
|
7758
|
+
message: "GHCR_PULL_TOKEN (PAT for pulling private beastmode images from ghcr.io/develeap/beastmode/* \u2014 `read:packages` scope. Leave empty to fall back to the project token):",
|
|
7759
|
+
mask: "*"
|
|
7760
|
+
}
|
|
7761
|
+
]);
|
|
7762
|
+
ghcrPullToken = answer.token || "";
|
|
7763
|
+
}
|
|
7764
|
+
if (!ghcrPullToken && projectGithubToken) {
|
|
7765
|
+
ghcrPullToken = projectGithubToken;
|
|
7766
|
+
info("GHCR_PULL_TOKEN: falling back to PROJECT_GITHUB_TOKEN (you can split them later in .env)");
|
|
7767
|
+
} else if (ghcrPullToken) {
|
|
7768
|
+
success("GHCR_PULL_TOKEN set");
|
|
7769
|
+
} else {
|
|
7770
|
+
warn("GHCR_PULL_TOKEN not set \u2014 `docker compose pull` will fail for private images. Add to .env later.");
|
|
7771
|
+
}
|
|
7772
|
+
const githubToken = projectGithubToken;
|
|
7734
7773
|
let uiPassword = opts.boardPassword || (opts.boardPasswordFile ? readSecretFile(opts.boardPasswordFile) : "") || "";
|
|
7735
7774
|
if (!uiPassword && !opts.yes) {
|
|
7736
7775
|
const { password } = await inquirer.prompt([
|
|
@@ -7787,12 +7826,15 @@ async function runImageModeInit(name, opts) {
|
|
|
7787
7826
|
}
|
|
7788
7827
|
step(2, totalSteps, "Docker Registry");
|
|
7789
7828
|
if (!isGhcrAuthenticated()) {
|
|
7790
|
-
|
|
7791
|
-
|
|
7829
|
+
const tokenForLogin = ghcrPullToken || projectGithubToken;
|
|
7830
|
+
if (tokenForLogin && loginToGhcr(tokenForLogin)) {
|
|
7831
|
+
success(
|
|
7832
|
+
`Authenticated to ghcr.io (via ${ghcrPullToken ? "GHCR_PULL_TOKEN" : "PROJECT_GITHUB_TOKEN fallback"})`
|
|
7833
|
+
);
|
|
7792
7834
|
} else {
|
|
7793
7835
|
info("Not logged in to ghcr.io \u2014 images may still pull if public");
|
|
7794
7836
|
info(" To log in manually: docker login ghcr.io -u <your-github-username>");
|
|
7795
|
-
if (!opts.yes && !opts.githubToken) {
|
|
7837
|
+
if (!opts.yes && !opts.githubToken && !opts.projectGithubToken && !opts.ghcrPullToken) {
|
|
7796
7838
|
const { retry } = await inquirer.prompt([
|
|
7797
7839
|
{
|
|
7798
7840
|
type: "confirm",
|
|
@@ -7817,23 +7859,44 @@ async function runImageModeInit(name, opts) {
|
|
|
7817
7859
|
success("docker-compose.yml");
|
|
7818
7860
|
const envLines = [
|
|
7819
7861
|
"# BeastMode environment \u2014 DO NOT COMMIT",
|
|
7820
|
-
|
|
7862
|
+
"",
|
|
7863
|
+
"# \u2500\u2500 Project credentials (Gap 16 \u2014 two-PAT model) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500",
|
|
7864
|
+
"# PROJECT_GITHUB_TOKEN: used by the daemon and Claude to commit /",
|
|
7865
|
+
"# push / open PRs / merge / review against the target project repo.",
|
|
7866
|
+
"# Needs `repo` scope for private repos, `public_repo` for public.",
|
|
7867
|
+
"# Aliased to GITHUB_TOKEN for backward compat with the gh CLI and",
|
|
7868
|
+
"# any code that still reads GITHUB_TOKEN.",
|
|
7869
|
+
`PROJECT_GITHUB_TOKEN=${projectGithubToken}`,
|
|
7870
|
+
`GITHUB_TOKEN=${projectGithubToken}`,
|
|
7871
|
+
"",
|
|
7872
|
+
"# GHCR_PULL_TOKEN: used by `docker compose pull` to fetch the",
|
|
7873
|
+
"# beastmode factory images from ghcr.io/develeap/beastmode/*.",
|
|
7874
|
+
"# Maintainer-provided (shared across a team) or your own PAT with",
|
|
7875
|
+
"# `read:packages` scope added. Rotates rarely. May be the same as",
|
|
7876
|
+
"# PROJECT_GITHUB_TOKEN but is normally a separate dedicated token.",
|
|
7877
|
+
`GHCR_PULL_TOKEN=${ghcrPullToken}`,
|
|
7878
|
+
"",
|
|
7821
7879
|
`BEASTMODE_UI_PASSWORD=${uiPassword}`,
|
|
7822
7880
|
"",
|
|
7823
|
-
"# Project
|
|
7881
|
+
"# \u2500\u2500 Project location \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500",
|
|
7882
|
+
"# Required. The daemon's git operations target the git remote of",
|
|
7883
|
+
"# this path. The daemon auto-resolves the github repo from",
|
|
7884
|
+
"# `git -C $PROJECT_DIR remote get-url origin` at startup.",
|
|
7824
7885
|
`PROJECT_DIR=${projectPath}`,
|
|
7825
7886
|
"",
|
|
7826
|
-
"# Optional
|
|
7887
|
+
"# \u2500\u2500 Optional \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500",
|
|
7888
|
+
"# Uncomment for faster direct Anthropic API calls (bypasses the",
|
|
7889
|
+
"# Claude Code subscription auth via ~/.claude.json).",
|
|
7827
7890
|
"# ANTHROPIC_API_KEY=sk-ant-...",
|
|
7828
7891
|
"",
|
|
7829
|
-
"#
|
|
7892
|
+
"# Last-resort override if the daemon's project_repo auto-resolution",
|
|
7830
7893
|
"# (git remote get-url origin) doesn't work for your setup.",
|
|
7831
7894
|
"# The daemon handles this automatically in >99% of cases.",
|
|
7832
7895
|
"# PROJECT_REPO=owner/repo",
|
|
7833
7896
|
""
|
|
7834
7897
|
];
|
|
7835
7898
|
writeFileSync13(join15(targetDir, ".env"), envLines.join("\n"), "utf-8");
|
|
7836
|
-
success(`.env (PROJECT_DIR=${projectPath})`);
|
|
7899
|
+
success(`.env (PROJECT_DIR=${projectPath}, two-PAT model)`);
|
|
7837
7900
|
for (const dir of ["data", "runs", "daemon/logs", ".beastmode", "config"]) {
|
|
7838
7901
|
mkdirSync12(join15(targetDir, dir), { recursive: true });
|
|
7839
7902
|
}
|
|
@@ -8740,6 +8803,185 @@ function checkGithubToken(env) {
|
|
|
8740
8803
|
}
|
|
8741
8804
|
return { label: "GITHUB_TOKEN / GH_TOKEN", status: "pass", detail: "set" };
|
|
8742
8805
|
}
|
|
8806
|
+
async function checkProjectGithubToken(env, factoryDir) {
|
|
8807
|
+
const token = env.PROJECT_GITHUB_TOKEN || env.GITHUB_TOKEN;
|
|
8808
|
+
if (!token) {
|
|
8809
|
+
return {
|
|
8810
|
+
label: "PROJECT_GITHUB_TOKEN",
|
|
8811
|
+
status: "fail",
|
|
8812
|
+
detail: "not set in env (or factory .env)",
|
|
8813
|
+
fix: "Add PROJECT_GITHUB_TOKEN=ghp_... to .env (needs `repo` scope for private, `public_repo` for public)"
|
|
8814
|
+
};
|
|
8815
|
+
}
|
|
8816
|
+
let ownerRepo = null;
|
|
8817
|
+
if (factoryDir) {
|
|
8818
|
+
const envPath = join22(factoryDir, ".env");
|
|
8819
|
+
if (existsSync24(envPath)) {
|
|
8820
|
+
try {
|
|
8821
|
+
const content = readFileSync21(envPath, "utf-8");
|
|
8822
|
+
const dirLine = content.split("\n").find(
|
|
8823
|
+
(l) => l.trim().startsWith("PROJECT_DIR=") && !l.trim().startsWith("#")
|
|
8824
|
+
);
|
|
8825
|
+
if (dirLine) {
|
|
8826
|
+
const projectDir = dirLine.split("=").slice(1).join("=").trim();
|
|
8827
|
+
if (projectDir && existsSync24(join22(projectDir, ".git"))) {
|
|
8828
|
+
const remote = tryExec(
|
|
8829
|
+
`git -C "${projectDir}" remote get-url origin 2>/dev/null`
|
|
8830
|
+
);
|
|
8831
|
+
if (remote) {
|
|
8832
|
+
const m = remote.match(
|
|
8833
|
+
/(?:https?:\/\/[^/]+\/|git@[^:]+:)([^/\s]+)\/([^/\s]+?)(?:\.git)?\/?$/
|
|
8834
|
+
);
|
|
8835
|
+
if (m) ownerRepo = `${m[1]}/${m[2]}`;
|
|
8836
|
+
}
|
|
8837
|
+
}
|
|
8838
|
+
}
|
|
8839
|
+
} catch {
|
|
8840
|
+
}
|
|
8841
|
+
}
|
|
8842
|
+
}
|
|
8843
|
+
const apiPath = ownerRepo ? `/repos/${ownerRepo}` : "/user";
|
|
8844
|
+
const result = await new Promise((resolveProm) => {
|
|
8845
|
+
const req = https.request(
|
|
8846
|
+
{
|
|
8847
|
+
hostname: "api.github.com",
|
|
8848
|
+
path: apiPath,
|
|
8849
|
+
method: "GET",
|
|
8850
|
+
headers: {
|
|
8851
|
+
"User-Agent": "beastmode-doctor",
|
|
8852
|
+
Authorization: `Bearer ${token}`,
|
|
8853
|
+
Accept: "application/vnd.github+json"
|
|
8854
|
+
},
|
|
8855
|
+
timeout: 8e3
|
|
8856
|
+
},
|
|
8857
|
+
(res) => {
|
|
8858
|
+
let data = "";
|
|
8859
|
+
res.on("data", (chunk) => {
|
|
8860
|
+
data += chunk;
|
|
8861
|
+
});
|
|
8862
|
+
res.on("end", () => {
|
|
8863
|
+
let canPush = null;
|
|
8864
|
+
try {
|
|
8865
|
+
const parsed = JSON.parse(data);
|
|
8866
|
+
if (parsed.permissions && typeof parsed.permissions.push === "boolean") {
|
|
8867
|
+
canPush = parsed.permissions.push;
|
|
8868
|
+
}
|
|
8869
|
+
} catch {
|
|
8870
|
+
}
|
|
8871
|
+
resolveProm({ status: res.statusCode ?? 0, canPush });
|
|
8872
|
+
});
|
|
8873
|
+
}
|
|
8874
|
+
);
|
|
8875
|
+
req.on("error", () => resolveProm({ status: 0, canPush: null }));
|
|
8876
|
+
req.on("timeout", () => {
|
|
8877
|
+
req.destroy();
|
|
8878
|
+
resolveProm({ status: 0, canPush: null });
|
|
8879
|
+
});
|
|
8880
|
+
req.end();
|
|
8881
|
+
});
|
|
8882
|
+
if (result.status === 0) {
|
|
8883
|
+
return {
|
|
8884
|
+
label: "PROJECT_GITHUB_TOKEN",
|
|
8885
|
+
status: "warn",
|
|
8886
|
+
detail: "set but api.github.com unreachable (network issue?)"
|
|
8887
|
+
};
|
|
8888
|
+
}
|
|
8889
|
+
if (result.status === 401 || result.status === 403) {
|
|
8890
|
+
return {
|
|
8891
|
+
label: "PROJECT_GITHUB_TOKEN",
|
|
8892
|
+
status: "fail",
|
|
8893
|
+
detail: `invalid (HTTP ${result.status}${ownerRepo ? ` for ${ownerRepo}` : ""})`,
|
|
8894
|
+
fix: "Check the token at https://github.com/settings/tokens \u2014 needs `repo` scope (or `public_repo` for public repos only)"
|
|
8895
|
+
};
|
|
8896
|
+
}
|
|
8897
|
+
if (result.status === 404 && ownerRepo) {
|
|
8898
|
+
return {
|
|
8899
|
+
label: "PROJECT_GITHUB_TOKEN",
|
|
8900
|
+
status: "fail",
|
|
8901
|
+
detail: `cannot access ${ownerRepo} (HTTP 404 \u2014 repo missing or token has no read permission)`,
|
|
8902
|
+
fix: "Verify the token has access to the target repo + the repo URL is correct in PROJECT_DIR"
|
|
8903
|
+
};
|
|
8904
|
+
}
|
|
8905
|
+
if (result.status >= 200 && result.status < 300) {
|
|
8906
|
+
if (ownerRepo && result.canPush === true) {
|
|
8907
|
+
return {
|
|
8908
|
+
label: "PROJECT_GITHUB_TOKEN",
|
|
8909
|
+
status: "pass",
|
|
8910
|
+
detail: `valid + write access to ${ownerRepo}`
|
|
8911
|
+
};
|
|
8912
|
+
}
|
|
8913
|
+
if (ownerRepo && result.canPush === false) {
|
|
8914
|
+
return {
|
|
8915
|
+
label: "PROJECT_GITHUB_TOKEN",
|
|
8916
|
+
status: "fail",
|
|
8917
|
+
detail: `valid but NO write access to ${ownerRepo}`,
|
|
8918
|
+
fix: "The token's user is not a collaborator on the target repo OR the token lacks `repo` scope"
|
|
8919
|
+
};
|
|
8920
|
+
}
|
|
8921
|
+
return {
|
|
8922
|
+
label: "PROJECT_GITHUB_TOKEN",
|
|
8923
|
+
status: "pass",
|
|
8924
|
+
detail: ownerRepo ? `valid (couldn't determine permissions \u2014 repo response had no permissions field)` : `valid (skipped per-repo check \u2014 no PROJECT_DIR resolvable)`
|
|
8925
|
+
};
|
|
8926
|
+
}
|
|
8927
|
+
return {
|
|
8928
|
+
label: "PROJECT_GITHUB_TOKEN",
|
|
8929
|
+
status: "warn",
|
|
8930
|
+
detail: `HTTP ${result.status}`
|
|
8931
|
+
};
|
|
8932
|
+
}
|
|
8933
|
+
function checkGhcrPullToken(env) {
|
|
8934
|
+
const token = env.GHCR_PULL_TOKEN;
|
|
8935
|
+
if (!token) {
|
|
8936
|
+
if (env.GITHUB_TOKEN || env.PROJECT_GITHUB_TOKEN) {
|
|
8937
|
+
return {
|
|
8938
|
+
label: "GHCR_PULL_TOKEN",
|
|
8939
|
+
status: "warn",
|
|
8940
|
+
detail: "not set; falling back to PROJECT_GITHUB_TOKEN (works if it has read:packages scope)",
|
|
8941
|
+
fix: "Set GHCR_PULL_TOKEN=ghp_... in .env for a dedicated read-only token (read:packages scope)"
|
|
8942
|
+
};
|
|
8943
|
+
}
|
|
8944
|
+
return {
|
|
8945
|
+
label: "GHCR_PULL_TOKEN",
|
|
8946
|
+
status: "fail",
|
|
8947
|
+
detail: "not set \u2014 `docker compose pull` cannot fetch private beastmode images",
|
|
8948
|
+
fix: "Set GHCR_PULL_TOKEN=ghp_... in .env (read:packages scope)"
|
|
8949
|
+
};
|
|
8950
|
+
}
|
|
8951
|
+
const loggedIn = tryExec("docker login ghcr.io --get-login 2>/dev/null");
|
|
8952
|
+
if (!loggedIn) {
|
|
8953
|
+
return {
|
|
8954
|
+
label: "GHCR_PULL_TOKEN",
|
|
8955
|
+
status: "warn",
|
|
8956
|
+
detail: "set in env but docker is not logged in to ghcr.io",
|
|
8957
|
+
fix: "Run `docker login ghcr.io -u <github-username> --password-stdin <<< $GHCR_PULL_TOKEN`"
|
|
8958
|
+
};
|
|
8959
|
+
}
|
|
8960
|
+
const inspect = tryExec(
|
|
8961
|
+
"docker manifest inspect ghcr.io/develeap/beastmode/board:latest 2>&1",
|
|
8962
|
+
15e3
|
|
8963
|
+
);
|
|
8964
|
+
if (inspect && (inspect.includes("schemaVersion") || inspect.includes("mediaType"))) {
|
|
8965
|
+
return {
|
|
8966
|
+
label: "GHCR_PULL_TOKEN",
|
|
8967
|
+
status: "pass",
|
|
8968
|
+
detail: `valid (logged in as ${loggedIn}, can pull beastmode images)`
|
|
8969
|
+
};
|
|
8970
|
+
}
|
|
8971
|
+
if (inspect && inspect.includes("denied")) {
|
|
8972
|
+
return {
|
|
8973
|
+
label: "GHCR_PULL_TOKEN",
|
|
8974
|
+
status: "fail",
|
|
8975
|
+
detail: "logged in but lacks read:packages scope (denied)",
|
|
8976
|
+
fix: "Generate a new PAT at https://github.com/settings/tokens with `read:packages` scope"
|
|
8977
|
+
};
|
|
8978
|
+
}
|
|
8979
|
+
return {
|
|
8980
|
+
label: "GHCR_PULL_TOKEN",
|
|
8981
|
+
status: "warn",
|
|
8982
|
+
detail: `logged in as ${loggedIn} but image inspect didn't return a manifest`
|
|
8983
|
+
};
|
|
8984
|
+
}
|
|
8743
8985
|
function checkDocker() {
|
|
8744
8986
|
const out = tryExec("docker info --format '{{.ServerVersion}}' 2>/dev/null");
|
|
8745
8987
|
if (out) {
|
|
@@ -9374,6 +9616,8 @@ var doctorCommand = new Command11("doctor").description("Health check \u2014 val
|
|
|
9374
9616
|
const checks = [];
|
|
9375
9617
|
checks.push(...await checkClaudeAuth(env.ANTHROPIC_API_KEY));
|
|
9376
9618
|
checks.push(checkGithubToken(env));
|
|
9619
|
+
checks.push(await checkProjectGithubToken(env, hasFactory ? factoryDir : null));
|
|
9620
|
+
checks.push(checkGhcrPullToken(env));
|
|
9377
9621
|
checks.push(checkDocker());
|
|
9378
9622
|
checks.push(checkDockerComposeVersion());
|
|
9379
9623
|
checks.push(checkGhcrAuth());
|