agent-control-plane 0.3.0 → 0.4.9
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 +69 -19
- package/assets/workflow-catalog.json +1 -1
- package/bin/pr-risk.sh +22 -7
- package/bin/sync-pr-labels.sh +1 -1
- package/hooks/heartbeat-hooks.sh +125 -12
- package/hooks/issue-reconcile-hooks.sh +1 -1
- package/hooks/pr-reconcile-hooks.sh +1 -1
- package/npm/bin/agent-control-plane.js +256 -58
- package/package.json +7 -6
- package/tools/bin/agent-github-update-labels +36 -2
- package/tools/bin/agent-project-catch-up-merged-prs +3 -2
- package/tools/bin/agent-project-publish-issue-pr +6 -3
- package/tools/bin/agent-project-reconcile-issue-session +12 -1
- package/tools/bin/agent-project-reconcile-pr-session +90 -32
- package/tools/bin/agent-project-retry-state +18 -7
- package/tools/bin/agent-project-run-codex-resilient +13 -5
- package/tools/bin/agent-project-sync-source-repo-main +163 -0
- package/tools/bin/flow-config-lib.sh +1203 -60
- package/tools/bin/flow-shell-lib.sh +32 -0
- package/tools/bin/github-core-rate-limit-state.sh +77 -0
- package/tools/bin/github-write-outbox.sh +470 -0
- package/tools/bin/heartbeat-loop-scheduling-lib.sh +7 -7
- package/tools/bin/heartbeat-safe-auto.sh +42 -0
- package/tools/bin/install-project-launchd.sh +17 -2
- package/tools/bin/project-init.sh +21 -1
- package/tools/bin/project-launchd-bootstrap.sh +5 -1
- package/tools/bin/project-runtimectl.sh +46 -2
- package/tools/bin/resident-issue-controller-lib.sh +2 -2
- package/tools/bin/scaffold-profile.sh +61 -3
- package/tools/bin/start-pr-fix-worker.sh +47 -10
- package/tools/bin/start-resident-issue-loop.sh +2 -2
- package/tools/dashboard/app.js +30 -1
- package/tools/dashboard/dashboard_snapshot.py +55 -0
- package/tools/templates/pr-fix-template.md +3 -1
- package/tools/templates/pr-merge-repair-template.md +2 -1
- package/references/architecture.md +0 -217
- package/references/commands.md +0 -128
- package/references/control-plane-map.md +0 -124
- package/references/docs-map.md +0 -73
- package/references/release-checklist.md +0 -65
- package/references/repo-map.md +0 -36
- package/tools/bin/resident-issue-queue-status.py +0 -35
- package/tools/bin/split-retained-slice.sh +0 -124
|
@@ -45,11 +45,17 @@ Usage:
|
|
|
45
45
|
|
|
46
46
|
Guided install/bootstrap flow for one repo profile. It can detect the current
|
|
47
47
|
repo, suggest sane runtime paths, sync ACP into ~/.agent-runtime, scaffold one
|
|
48
|
-
profile, run doctor checks, and optionally start the runtime.
|
|
48
|
+
profile, run doctor checks, and optionally start the runtime. ACP can run
|
|
49
|
+
GitHub-first or local-first with Gitea as the working forge.
|
|
49
50
|
|
|
50
51
|
Options:
|
|
51
52
|
--profile-id <id> Profile id to create or refresh
|
|
52
|
-
--repo-slug <owner/repo>
|
|
53
|
+
--repo-slug <owner/repo> Forge repo slug
|
|
54
|
+
--forge-provider <provider> One of: github, gitea
|
|
55
|
+
--gitea-base-url <url> Base URL for a local/self-hosted Gitea instance
|
|
56
|
+
--gitea-token <token> Gitea API token written to profile runtime.env
|
|
57
|
+
--gitea-username <user> Gitea username written to profile runtime.env
|
|
58
|
+
--gitea-password <pass> Gitea password written to profile runtime.env
|
|
53
59
|
--repo-root <path> Local checkout to manage (defaults to current git root)
|
|
54
60
|
--agent-root <path> ACP-managed runtime root for this profile
|
|
55
61
|
--agent-repo-root <path> Clean ACP-managed anchor repo root
|
|
@@ -380,6 +386,11 @@ function parseSetupArgs(args) {
|
|
|
380
386
|
const options = {
|
|
381
387
|
profileId: "",
|
|
382
388
|
repoSlug: "",
|
|
389
|
+
forgeProvider: "",
|
|
390
|
+
giteaBaseUrl: "",
|
|
391
|
+
giteaToken: "",
|
|
392
|
+
giteaUsername: "",
|
|
393
|
+
giteaPassword: "",
|
|
383
394
|
repoRoot: "",
|
|
384
395
|
agentRoot: "",
|
|
385
396
|
agentRepoRoot: "",
|
|
@@ -415,6 +426,21 @@ function parseSetupArgs(args) {
|
|
|
415
426
|
case "--repo-slug":
|
|
416
427
|
options.repoSlug = args[++index] || "";
|
|
417
428
|
break;
|
|
429
|
+
case "--forge-provider":
|
|
430
|
+
options.forgeProvider = args[++index] || "";
|
|
431
|
+
break;
|
|
432
|
+
case "--gitea-base-url":
|
|
433
|
+
options.giteaBaseUrl = args[++index] || "";
|
|
434
|
+
break;
|
|
435
|
+
case "--gitea-token":
|
|
436
|
+
options.giteaToken = args[++index] || "";
|
|
437
|
+
break;
|
|
438
|
+
case "--gitea-username":
|
|
439
|
+
options.giteaUsername = args[++index] || "";
|
|
440
|
+
break;
|
|
441
|
+
case "--gitea-password":
|
|
442
|
+
options.giteaPassword = args[++index] || "";
|
|
443
|
+
break;
|
|
418
444
|
case "--repo-root":
|
|
419
445
|
options.repoRoot = args[++index] || "";
|
|
420
446
|
break;
|
|
@@ -581,7 +607,7 @@ Agent schedule: every 4h
|
|
|
581
607
|
|
|
582
608
|
- Run \`pnpm typecheck\` (or the repo-equivalent lint/typecheck) after code changes and record verification.
|
|
583
609
|
`,
|
|
584
|
-
labels: ["agent-
|
|
610
|
+
labels: ["agent-keep-open"]
|
|
585
611
|
},
|
|
586
612
|
{
|
|
587
613
|
key: "test-coverage",
|
|
@@ -597,7 +623,7 @@ Agent schedule: every 6h
|
|
|
597
623
|
|
|
598
624
|
- Run the narrowest relevant test command after code changes and record verification.
|
|
599
625
|
`,
|
|
600
|
-
labels: ["agent-
|
|
626
|
+
labels: ["agent-keep-open"]
|
|
601
627
|
},
|
|
602
628
|
{
|
|
603
629
|
key: "documentation",
|
|
@@ -613,7 +639,7 @@ Agent schedule: every 8h
|
|
|
613
639
|
|
|
614
640
|
- Run any doc-build or link-check command after changes and record verification.
|
|
615
641
|
`,
|
|
616
|
-
labels: ["agent-
|
|
642
|
+
labels: ["agent-keep-open"]
|
|
617
643
|
},
|
|
618
644
|
{
|
|
619
645
|
key: "dependency-audit",
|
|
@@ -629,7 +655,7 @@ Agent schedule: every 12h
|
|
|
629
655
|
|
|
630
656
|
- Run \`pnpm audit\` and \`pnpm install --frozen-lockfile\` after changes and record verification.
|
|
631
657
|
`,
|
|
632
|
-
labels: ["agent-
|
|
658
|
+
labels: ["agent-keep-open"]
|
|
633
659
|
},
|
|
634
660
|
{
|
|
635
661
|
key: "refactor",
|
|
@@ -645,7 +671,7 @@ Agent schedule: every 8h
|
|
|
645
671
|
|
|
646
672
|
- Run the narrowest relevant test command after refactoring and record verification.
|
|
647
673
|
`,
|
|
648
|
-
labels: ["agent-
|
|
674
|
+
labels: ["agent-keep-open"]
|
|
649
675
|
}
|
|
650
676
|
];
|
|
651
677
|
|
|
@@ -656,8 +682,8 @@ async function maybeCreateStarterIssues(options, config, prereq) {
|
|
|
656
682
|
return result;
|
|
657
683
|
}
|
|
658
684
|
|
|
659
|
-
if (!prereq.
|
|
660
|
-
result.reason =
|
|
685
|
+
if (!prereq.forgeAuthOk) {
|
|
686
|
+
result.reason = `${config.forge.provider}-auth-not-ready`;
|
|
661
687
|
return result;
|
|
662
688
|
}
|
|
663
689
|
|
|
@@ -701,24 +727,28 @@ async function maybeCreateStarterIssues(options, config, prereq) {
|
|
|
701
727
|
// Ensure labels exist
|
|
702
728
|
console.log("\nCreating labels and issues...");
|
|
703
729
|
const requiredLabels = [
|
|
704
|
-
{ name: "agent-ready", color: "0E8A16", description: "Ready for agent automation" },
|
|
705
730
|
{ name: "agent-keep-open", color: "D4C5F9", description: "Recurring issue — agent works on this continuously" }
|
|
706
731
|
];
|
|
707
|
-
|
|
708
|
-
|
|
732
|
+
if (config.forge.provider === "gitea") {
|
|
733
|
+
for (const label of requiredLabels) {
|
|
734
|
+
runForgeFlowConfigCommand(config, [
|
|
735
|
+
"flow_github_label_create",
|
|
736
|
+
shellQuote(config.repoSlug),
|
|
737
|
+
shellQuote(label.name),
|
|
738
|
+
shellQuote(label.description),
|
|
739
|
+
shellQuote(label.color)
|
|
740
|
+
]);
|
|
741
|
+
}
|
|
742
|
+
} else {
|
|
743
|
+
for (const label of requiredLabels) {
|
|
744
|
+
spawnSync("gh", ["label", "create", label.name, "--repo", config.repoSlug, "--description", label.description, "--color", label.color, "--force"], { stdio: "pipe", timeout: 15000 });
|
|
745
|
+
}
|
|
709
746
|
}
|
|
710
747
|
|
|
711
748
|
for (const { issue } of toCreate) {
|
|
712
|
-
const
|
|
713
|
-
|
|
714
|
-
"
|
|
715
|
-
"--title", issue.title,
|
|
716
|
-
"--body", issue.body,
|
|
717
|
-
"--label", issue.labels.join(",")
|
|
718
|
-
];
|
|
719
|
-
const ghResult = spawnSync("gh", ghArgs, { encoding: "utf8", stdio: "pipe", timeout: 30000 });
|
|
720
|
-
if (ghResult.status === 0) {
|
|
721
|
-
const url = (ghResult.stdout || "").trim();
|
|
749
|
+
const createResult = createStarterIssueOnForge(config, issue);
|
|
750
|
+
if (createResult.status === 0) {
|
|
751
|
+
const url = (createResult.stdout || "").trim();
|
|
722
752
|
result.created.push({ key: issue.key, title: issue.title, url });
|
|
723
753
|
console.log(` Created: ${issue.title}`);
|
|
724
754
|
if (url) {
|
|
@@ -726,7 +756,7 @@ async function maybeCreateStarterIssues(options, config, prereq) {
|
|
|
726
756
|
}
|
|
727
757
|
} else {
|
|
728
758
|
console.log(` Failed to create: ${issue.title}`);
|
|
729
|
-
const stderr = (
|
|
759
|
+
const stderr = (createResult.stderr || "").trim();
|
|
730
760
|
if (stderr) {
|
|
731
761
|
console.log(` ${stderr.split("\n")[0]}`);
|
|
732
762
|
}
|
|
@@ -739,6 +769,87 @@ async function maybeCreateStarterIssues(options, config, prereq) {
|
|
|
739
769
|
return result;
|
|
740
770
|
}
|
|
741
771
|
|
|
772
|
+
function buildForgeCommandEnv(config) {
|
|
773
|
+
const env = { ...process.env };
|
|
774
|
+
env.ACP_FORGE_PROVIDER = config.forge.provider;
|
|
775
|
+
env.F_LOSNING_FORGE_PROVIDER = config.forge.provider;
|
|
776
|
+
if (config.forge.provider === "gitea") {
|
|
777
|
+
if (config.forge.giteaBaseUrl) {
|
|
778
|
+
env.ACP_GITEA_BASE_URL = config.forge.giteaBaseUrl;
|
|
779
|
+
env.GITEA_BASE_URL = config.forge.giteaBaseUrl;
|
|
780
|
+
}
|
|
781
|
+
if (config.forge.giteaToken) {
|
|
782
|
+
env.ACP_GITEA_TOKEN = config.forge.giteaToken;
|
|
783
|
+
env.GITEA_TOKEN = config.forge.giteaToken;
|
|
784
|
+
}
|
|
785
|
+
if (config.forge.giteaUsername) {
|
|
786
|
+
env.ACP_GITEA_USERNAME = config.forge.giteaUsername;
|
|
787
|
+
env.GITEA_USERNAME = config.forge.giteaUsername;
|
|
788
|
+
}
|
|
789
|
+
if (config.forge.giteaPassword) {
|
|
790
|
+
env.ACP_GITEA_PASSWORD = config.forge.giteaPassword;
|
|
791
|
+
env.GITEA_PASSWORD = config.forge.giteaPassword;
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
return env;
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
function runForgeFlowConfigCommand(config, commandParts, extraEnv = {}) {
|
|
798
|
+
const flowConfigLib = path.join(packageRoot, "tools", "bin", "flow-config-lib.sh");
|
|
799
|
+
const script = `set -euo pipefail\nsource ${shellQuote(flowConfigLib)}\n${commandParts.join(" ")}\n`;
|
|
800
|
+
return spawnSync("bash", ["-lc", script], {
|
|
801
|
+
encoding: "utf8",
|
|
802
|
+
stdio: "pipe",
|
|
803
|
+
timeout: 30000,
|
|
804
|
+
env: {
|
|
805
|
+
...buildForgeCommandEnv(config),
|
|
806
|
+
...extraEnv
|
|
807
|
+
}
|
|
808
|
+
});
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
function createStarterIssueOnForge(config, issue) {
|
|
812
|
+
if (config.forge.provider !== "gitea") {
|
|
813
|
+
const ghArgs = [
|
|
814
|
+
"issue", "create",
|
|
815
|
+
"--repo", config.repoSlug,
|
|
816
|
+
"--title", issue.title,
|
|
817
|
+
"--body", issue.body,
|
|
818
|
+
"--label", issue.labels.join(",")
|
|
819
|
+
];
|
|
820
|
+
return spawnSync("gh", ghArgs, { encoding: "utf8", stdio: "pipe", timeout: 30000 });
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
const bodyFile = fs.mkdtempSync(path.join(os.tmpdir(), "acp-starter-issue-"));
|
|
824
|
+
const bodyPath = path.join(bodyFile, "body.md");
|
|
825
|
+
fs.writeFileSync(bodyPath, issue.body);
|
|
826
|
+
try {
|
|
827
|
+
const createResult = runForgeFlowConfigCommand(
|
|
828
|
+
config,
|
|
829
|
+
["flow_github_issue_create", shellQuote(config.repoSlug), "$ACP_ISSUE_TITLE", "$ACP_ISSUE_BODY_FILE"],
|
|
830
|
+
{
|
|
831
|
+
ACP_ISSUE_TITLE: issue.title,
|
|
832
|
+
ACP_ISSUE_BODY_FILE: bodyPath
|
|
833
|
+
}
|
|
834
|
+
);
|
|
835
|
+
const issueUrl = (createResult.stdout || "").trim();
|
|
836
|
+
if (createResult.status === 0 && issueUrl && issue.labels.length > 0) {
|
|
837
|
+
const issueNumber = issueUrl.split("/").pop();
|
|
838
|
+
for (const labelName of issue.labels) {
|
|
839
|
+
spawnSync("bash", [path.join(packageRoot, "tools", "bin", "agent-github-update-labels"), "--repo-slug", config.repoSlug, "--number", issueNumber, "--add", labelName], {
|
|
840
|
+
encoding: "utf8",
|
|
841
|
+
stdio: "pipe",
|
|
842
|
+
timeout: 30000,
|
|
843
|
+
env: buildForgeCommandEnv(config)
|
|
844
|
+
});
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
return createResult;
|
|
848
|
+
} finally {
|
|
849
|
+
fs.rmSync(bodyFile, { recursive: true, force: true });
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
|
|
742
853
|
function buildSetupPaths(platformHome, repoRoot, profileId, overrides) {
|
|
743
854
|
const agentRoot = path.resolve(overrides.agentRoot || path.join(platformHome, "projects", profileId));
|
|
744
855
|
const repoRootResolved = path.resolve(repoRoot);
|
|
@@ -753,12 +864,27 @@ function buildSetupPaths(platformHome, repoRoot, profileId, overrides) {
|
|
|
753
864
|
};
|
|
754
865
|
}
|
|
755
866
|
|
|
756
|
-
function collectPrereqStatus(codingWorker) {
|
|
757
|
-
const
|
|
867
|
+
function collectPrereqStatus(codingWorker, forge) {
|
|
868
|
+
const forgeProvider = (forge && forge.provider) || "github";
|
|
869
|
+
const requiredTools = ["bash", "git", "jq", "python3", "tmux"];
|
|
870
|
+
if (forgeProvider !== "gitea") {
|
|
871
|
+
requiredTools.push("gh");
|
|
872
|
+
}
|
|
758
873
|
const missingRequired = requiredTools.filter((tool) => !commandExists(tool));
|
|
759
874
|
const workerCommand = codingWorker;
|
|
760
875
|
const workerAvailable = commandExists(workerCommand);
|
|
761
876
|
const ghAuthResult = commandExists("gh") ? runCapture("gh", ["auth", "status"]) : { status: 1, stdout: "", stderr: "" };
|
|
877
|
+
const giteaAuthOk = forgeProvider !== "gitea"
|
|
878
|
+
? false
|
|
879
|
+
: Boolean(
|
|
880
|
+
forge &&
|
|
881
|
+
forge.giteaBaseUrl &&
|
|
882
|
+
(
|
|
883
|
+
forge.giteaToken ||
|
|
884
|
+
(forge.giteaUsername && forge.giteaPassword)
|
|
885
|
+
)
|
|
886
|
+
);
|
|
887
|
+
const forgeAuthOk = forgeProvider === "gitea" ? giteaAuthOk : ghAuthResult.status === 0;
|
|
762
888
|
|
|
763
889
|
return {
|
|
764
890
|
missingRequired,
|
|
@@ -766,6 +892,8 @@ function collectPrereqStatus(codingWorker) {
|
|
|
766
892
|
workerCommand,
|
|
767
893
|
workerAvailable,
|
|
768
894
|
ghAuthOk: ghAuthResult.status === 0,
|
|
895
|
+
forgeProvider,
|
|
896
|
+
forgeAuthOk,
|
|
769
897
|
ghAuthOutput: `${ghAuthResult.stdout}${ghAuthResult.stderr}`.trim()
|
|
770
898
|
};
|
|
771
899
|
}
|
|
@@ -1021,6 +1149,9 @@ async function maybeInstallMissingDependencies(options, prereq) {
|
|
|
1021
1149
|
}
|
|
1022
1150
|
|
|
1023
1151
|
async function maybeRunGithubAuthLogin(options, prereq) {
|
|
1152
|
+
if (prereq.forgeProvider === "gitea") {
|
|
1153
|
+
return { status: prereq.forgeAuthOk ? "not-needed" : "skipped", reason: prereq.forgeAuthOk ? "" : "gitea-auth-not-ready" };
|
|
1154
|
+
}
|
|
1024
1155
|
if (prereq.ghAuthOk) {
|
|
1025
1156
|
return { status: "not-needed", reason: "" };
|
|
1026
1157
|
}
|
|
@@ -1357,7 +1488,7 @@ function printPrereqSummary(prereq) {
|
|
|
1357
1488
|
console.log("\nPrerequisite check");
|
|
1358
1489
|
console.log(`- core tools: ${prereq.coreToolsOk ? "ok" : `missing ${prereq.missingRequired.join(", ")}`}`);
|
|
1359
1490
|
console.log(`- worker backend (${prereq.workerCommand}): ${prereq.workerAvailable ? "found" : "missing on PATH"}`);
|
|
1360
|
-
console.log(`- GitHub auth: ${prereq.
|
|
1491
|
+
console.log(`- ${prereq.forgeProvider === "gitea" ? "Gitea auth" : "GitHub auth"}: ${prereq.forgeAuthOk ? "ok" : "not ready"}`);
|
|
1361
1492
|
console.log(`- backend note: ${backendReadinessHint(prereq.workerCommand)}`);
|
|
1362
1493
|
}
|
|
1363
1494
|
|
|
@@ -1465,7 +1596,11 @@ function buildScopedContext(context, profileId) {
|
|
|
1465
1596
|
function renderSetupSummary(config) {
|
|
1466
1597
|
console.log("\nSetup plan");
|
|
1467
1598
|
console.log(`- profile id: ${config.profileId}`);
|
|
1599
|
+
console.log(`- forge provider: ${config.forge.provider}`);
|
|
1468
1600
|
console.log(`- repo slug: ${config.repoSlug}`);
|
|
1601
|
+
if (config.forge.provider === "gitea") {
|
|
1602
|
+
console.log(`- gitea base url: ${config.forge.giteaBaseUrl || "(not set)"}`);
|
|
1603
|
+
}
|
|
1469
1604
|
console.log(`- repo root: ${config.paths.repoRoot}`);
|
|
1470
1605
|
console.log(`- agent root: ${config.paths.agentRoot}`);
|
|
1471
1606
|
console.log(`- agent repo root: ${config.paths.agentRepoRoot}`);
|
|
@@ -1473,6 +1608,10 @@ function renderSetupSummary(config) {
|
|
|
1473
1608
|
console.log(`- coding worker: ${config.codingWorker}`);
|
|
1474
1609
|
}
|
|
1475
1610
|
|
|
1611
|
+
function forgeAuthLabel(config) {
|
|
1612
|
+
return config.forge.provider === "gitea" ? "Gitea auth" : "GitHub auth";
|
|
1613
|
+
}
|
|
1614
|
+
|
|
1476
1615
|
function planStatusWithReason(status, reason = "") {
|
|
1477
1616
|
return {
|
|
1478
1617
|
status,
|
|
@@ -1514,8 +1653,10 @@ function buildSetupDryRunPlan(options, context, config) {
|
|
|
1514
1653
|
}
|
|
1515
1654
|
|
|
1516
1655
|
let githubAuthAction = planStatusWithReason("not-needed");
|
|
1517
|
-
if (!prereq.
|
|
1518
|
-
if (
|
|
1656
|
+
if (!prereq.forgeAuthOk) {
|
|
1657
|
+
if (config.forge.provider === "gitea") {
|
|
1658
|
+
githubAuthAction = planStatusWithReason("blocked", "gitea-auth-not-ready");
|
|
1659
|
+
} else if (!commandExists("gh")) {
|
|
1519
1660
|
githubAuthAction = planStatusWithReason("blocked", "gh-missing");
|
|
1520
1661
|
} else if (options.ghAuthLogin === false) {
|
|
1521
1662
|
githubAuthAction = planStatusWithReason("skipped", "disabled");
|
|
@@ -1534,8 +1675,8 @@ function buildSetupDryRunPlan(options, context, config) {
|
|
|
1534
1675
|
runtimeStartAction = planStatusWithReason("blocked", `missing-worker:${prereq.workerCommand}`);
|
|
1535
1676
|
} else if (anchorSync.status !== "ok") {
|
|
1536
1677
|
runtimeStartAction = planStatusWithReason("blocked", `anchor-sync-${anchorSync.reason}`);
|
|
1537
|
-
} else if (!prereq.
|
|
1538
|
-
runtimeStartAction = planStatusWithReason("blocked",
|
|
1678
|
+
} else if (!prereq.forgeAuthOk) {
|
|
1679
|
+
runtimeStartAction = planStatusWithReason("blocked", `${config.forge.provider}-auth-not-ready`);
|
|
1539
1680
|
} else {
|
|
1540
1681
|
runtimeStartAction = planStatusWithReason("would-run");
|
|
1541
1682
|
}
|
|
@@ -1587,9 +1728,13 @@ function printSetupDryRunPlan(context, config, plan) {
|
|
|
1587
1728
|
if (plan.workerAction.status !== "not-needed" && plan.workerInstallPlan && plan.workerInstallPlan.commands.length > 0) {
|
|
1588
1729
|
console.log(` command preview: ${plan.workerInstallPlan.commands.map(formatCommand).join(" && ")}`);
|
|
1589
1730
|
}
|
|
1590
|
-
console.log(`-
|
|
1731
|
+
console.log(`- ${forgeAuthLabel(config)} step: ${plan.githubAuthAction.status}${plan.githubAuthAction.reason ? ` (${plan.githubAuthAction.reason})` : ""}`);
|
|
1591
1732
|
if (plan.githubAuthAction.status !== "not-needed") {
|
|
1592
|
-
|
|
1733
|
+
if (config.forge.provider === "github") {
|
|
1734
|
+
console.log(` command preview: gh auth login`);
|
|
1735
|
+
} else {
|
|
1736
|
+
console.log(` next step: pass --gitea-base-url plus --gitea-token or --gitea-username/--gitea-password`);
|
|
1737
|
+
}
|
|
1593
1738
|
}
|
|
1594
1739
|
console.log(`- runtime start: ${plan.runtimeStartAction.status}${plan.runtimeStartAction.reason ? ` (${plan.runtimeStartAction.reason})` : ""}`);
|
|
1595
1740
|
if (process.platform === "darwin") {
|
|
@@ -1603,6 +1748,7 @@ function buildSetupResultPayload(params) {
|
|
|
1603
1748
|
setupMode: params.setupMode,
|
|
1604
1749
|
profileId: params.profileId,
|
|
1605
1750
|
repoSlug: params.repoSlug,
|
|
1751
|
+
forge: params.forge,
|
|
1606
1752
|
codingWorker: params.codingWorker,
|
|
1607
1753
|
profileExists: params.profileExists,
|
|
1608
1754
|
paths: {
|
|
@@ -1679,8 +1825,8 @@ function collectFinalSetupIssues(config, prereq, doctorKv, runtimeStartStatus) {
|
|
|
1679
1825
|
if (!prereq.workerAvailable) {
|
|
1680
1826
|
issues.push(`missing worker backend on PATH: ${prereq.workerCommand}`);
|
|
1681
1827
|
}
|
|
1682
|
-
if (!prereq.
|
|
1683
|
-
issues.push("GitHub CLI is not authenticated");
|
|
1828
|
+
if (!prereq.forgeAuthOk) {
|
|
1829
|
+
issues.push(config.forge.provider === "gitea" ? "Gitea auth is not configured" : "GitHub CLI is not authenticated");
|
|
1684
1830
|
}
|
|
1685
1831
|
if ((doctorKv.DOCTOR_STATUS || "") !== "ok") {
|
|
1686
1832
|
issues.push(`doctor status is ${doctorKv.DOCTOR_STATUS || "unknown"}`);
|
|
@@ -1723,8 +1869,12 @@ async function maybeRunFinalSetupFixups(options, scopedContext, config, currentS
|
|
|
1723
1869
|
else if (worker === "claude") console.log(" Fix: npm install -g @anthropic-ai/claude-code && claude auth login");
|
|
1724
1870
|
else console.log(` Fix: install ${worker} and add it to PATH`);
|
|
1725
1871
|
}
|
|
1726
|
-
if (!currentState.prereq.
|
|
1727
|
-
|
|
1872
|
+
if (!currentState.prereq.forgeAuthOk) {
|
|
1873
|
+
if (config.forge.provider === "gitea") {
|
|
1874
|
+
console.log(" Fix: pass --gitea-base-url plus --gitea-token or --gitea-username/--gitea-password");
|
|
1875
|
+
} else {
|
|
1876
|
+
console.log(" Fix: run gh auth login");
|
|
1877
|
+
}
|
|
1728
1878
|
}
|
|
1729
1879
|
|
|
1730
1880
|
if (!options.interactive) {
|
|
@@ -1767,19 +1917,19 @@ async function maybeRunFinalSetupFixups(options, scopedContext, config, currentS
|
|
|
1767
1917
|
if (!prereq.coreToolsOk) {
|
|
1768
1918
|
actions.push("install-core-tools");
|
|
1769
1919
|
dependencyInstall = await maybeInstallMissingDependencies({ ...options, installMissingDeps: true, interactive: false }, prereq);
|
|
1770
|
-
prereq = collectPrereqStatus(config.codingWorker);
|
|
1920
|
+
prereq = collectPrereqStatus(config.codingWorker, config.forge);
|
|
1771
1921
|
}
|
|
1772
1922
|
|
|
1773
1923
|
if (!prereq.workerAvailable) {
|
|
1774
1924
|
actions.push("install-worker-backend");
|
|
1775
1925
|
workerSetupStep = await maybeShowWorkerSetupGuide({ ...options, installMissingBackend: true, interactive: options.interactive }, prereq);
|
|
1776
|
-
prereq = collectPrereqStatus(config.codingWorker);
|
|
1926
|
+
prereq = collectPrereqStatus(config.codingWorker, config.forge);
|
|
1777
1927
|
}
|
|
1778
1928
|
|
|
1779
|
-
if (!prereq.
|
|
1929
|
+
if (!prereq.forgeAuthOk) {
|
|
1780
1930
|
actions.push("github-auth-login");
|
|
1781
1931
|
githubAuthStep = await maybeRunGithubAuthLogin({ ...options, ghAuthLogin: true, interactive: false }, prereq);
|
|
1782
|
-
prereq = collectPrereqStatus(config.codingWorker);
|
|
1932
|
+
prereq = collectPrereqStatus(config.codingWorker, config.forge);
|
|
1783
1933
|
}
|
|
1784
1934
|
|
|
1785
1935
|
if ((doctorKv.DOCTOR_STATUS || "") !== "ok") {
|
|
@@ -1799,9 +1949,9 @@ async function maybeRunFinalSetupFixups(options, scopedContext, config, currentS
|
|
|
1799
1949
|
} else if (anchorSync && anchorSync.status !== "ok") {
|
|
1800
1950
|
runtimeStartStatus = "skipped";
|
|
1801
1951
|
runtimeStartReason = `anchor-sync-${anchorSync.reason}`;
|
|
1802
|
-
} else if (!prereq.
|
|
1952
|
+
} else if (!prereq.forgeAuthOk) {
|
|
1803
1953
|
runtimeStartStatus = "skipped";
|
|
1804
|
-
runtimeStartReason =
|
|
1954
|
+
runtimeStartReason = `${config.forge.provider}-auth-not-ready`;
|
|
1805
1955
|
} else if ((doctorKv.DOCTOR_STATUS || "") !== "ok") {
|
|
1806
1956
|
runtimeStartStatus = "skipped";
|
|
1807
1957
|
runtimeStartReason = `doctor-${doctorKv.DOCTOR_STATUS || "not-ok"}`;
|
|
@@ -1852,11 +2002,18 @@ async function collectSetupConfig(options, context) {
|
|
|
1852
2002
|
const detectedRepoSlug = options.repoSlug || detectRepoSlug(detectedRepoRoot);
|
|
1853
2003
|
const suggestedProfileId = options.profileId || sanitizeProfileId((detectedRepoSlug.split("/").pop() || path.basename(detectedRepoRoot)));
|
|
1854
2004
|
const suggestedWorker = options.codingWorker || detectPreferredWorker();
|
|
2005
|
+
const detectedForgeProvider = options.forgeProvider || process.env.ACP_FORGE_PROVIDER || "github";
|
|
2006
|
+
const defaultGiteaBaseUrl = options.giteaBaseUrl || process.env.ACP_GITEA_BASE_URL || process.env.GITEA_BASE_URL || "http://127.0.0.1:3000";
|
|
1855
2007
|
|
|
1856
2008
|
let repoRoot = detectedRepoRoot;
|
|
1857
2009
|
let repoSlug = detectedRepoSlug;
|
|
1858
2010
|
let profileId = suggestedProfileId;
|
|
1859
2011
|
let codingWorker = suggestedWorker;
|
|
2012
|
+
let forgeProvider = detectedForgeProvider;
|
|
2013
|
+
let giteaBaseUrl = defaultGiteaBaseUrl;
|
|
2014
|
+
let giteaToken = options.giteaToken || process.env.ACP_GITEA_TOKEN || process.env.GITEA_TOKEN || "";
|
|
2015
|
+
let giteaUsername = options.giteaUsername || process.env.ACP_GITEA_USERNAME || process.env.GITEA_USERNAME || "";
|
|
2016
|
+
let giteaPassword = options.giteaPassword || process.env.ACP_GITEA_PASSWORD || process.env.GITEA_PASSWORD || "";
|
|
1860
2017
|
|
|
1861
2018
|
const detectedRepoRootExists = fs.existsSync(detectedRepoRoot);
|
|
1862
2019
|
if (!detectedRepoRootExists && !options.allowMissingRepo) {
|
|
@@ -1879,7 +2036,22 @@ async function collectSetupConfig(options, context) {
|
|
|
1879
2036
|
printWizardStep(1, 4, "Project details");
|
|
1880
2037
|
|
|
1881
2038
|
repoRoot = path.resolve(await promptText(rl, "Local repo root", detectedRepoRoot));
|
|
1882
|
-
|
|
2039
|
+
let forgeInput = forgeProvider;
|
|
2040
|
+
while (!["github", "gitea"].includes(forgeInput)) {
|
|
2041
|
+
forgeInput = await promptText(rl, "Forge provider (github / gitea)", forgeProvider || "github");
|
|
2042
|
+
}
|
|
2043
|
+
forgeProvider = forgeInput;
|
|
2044
|
+
repoSlug = await promptText(rl, "Forge repo slug", repoSlug || "");
|
|
2045
|
+
if (forgeProvider === "gitea") {
|
|
2046
|
+
giteaBaseUrl = await promptText(rl, "Gitea base URL", giteaBaseUrl);
|
|
2047
|
+
giteaToken = await promptText(rl, "Gitea token (Enter to skip)", giteaToken);
|
|
2048
|
+
if (!giteaToken) {
|
|
2049
|
+
giteaUsername = await promptText(rl, "Gitea username (Enter to skip)", giteaUsername);
|
|
2050
|
+
if (giteaUsername) {
|
|
2051
|
+
giteaPassword = await promptText(rl, "Gitea password (Enter to skip)", giteaPassword);
|
|
2052
|
+
}
|
|
2053
|
+
}
|
|
2054
|
+
}
|
|
1883
2055
|
profileId = sanitizeProfileId(await promptText(rl, "Profile id", profileId));
|
|
1884
2056
|
|
|
1885
2057
|
let workerInput = codingWorker;
|
|
@@ -1897,13 +2069,21 @@ async function collectSetupConfig(options, context) {
|
|
|
1897
2069
|
}
|
|
1898
2070
|
|
|
1899
2071
|
const paths = buildSetupPaths(context.platformHome, repoRoot, profileId, options);
|
|
1900
|
-
const
|
|
2072
|
+
const forge = {
|
|
2073
|
+
provider: forgeProvider,
|
|
2074
|
+
giteaBaseUrl,
|
|
2075
|
+
giteaToken,
|
|
2076
|
+
giteaUsername,
|
|
2077
|
+
giteaPassword
|
|
2078
|
+
};
|
|
2079
|
+
const prereq = collectPrereqStatus(codingWorker, forge);
|
|
1901
2080
|
const config = {
|
|
1902
2081
|
profileId,
|
|
1903
2082
|
repoSlug,
|
|
1904
2083
|
repoRoot,
|
|
1905
2084
|
codingWorker,
|
|
1906
2085
|
paths,
|
|
2086
|
+
forge,
|
|
1907
2087
|
prereq
|
|
1908
2088
|
};
|
|
1909
2089
|
|
|
@@ -1916,7 +2096,7 @@ async function collectSetupConfig(options, context) {
|
|
|
1916
2096
|
printPrereqSummary(prereq);
|
|
1917
2097
|
const rl = createPromptInterface();
|
|
1918
2098
|
try {
|
|
1919
|
-
if (!prereq.coreToolsOk || !prereq.workerAvailable || !prereq.
|
|
2099
|
+
if (!prereq.coreToolsOk || !prereq.workerAvailable || !prereq.forgeAuthOk) {
|
|
1920
2100
|
console.log("\nACP can still scaffold the profile now, but runtime start may be skipped until these checks are green.");
|
|
1921
2101
|
}
|
|
1922
2102
|
const shouldContinue = await promptYesNo(rl, "Continue with these values", true);
|
|
@@ -2063,7 +2243,7 @@ async function runSetupFlow(forwardedArgs) {
|
|
|
2063
2243
|
workerBackendInstallExample: plan.workerGuide.installExamples[0] || "",
|
|
2064
2244
|
workerBackendAuthExample: plan.workerGuide.authExamples[0] || "",
|
|
2065
2245
|
workerBackendVerifyExample: plan.workerGuide.verifyExamples[0] || "",
|
|
2066
|
-
githubAuthStatus: plan.prereq.
|
|
2246
|
+
githubAuthStatus: plan.prereq.forgeAuthOk ? "ok" : "not-ready",
|
|
2067
2247
|
githubAuthStepStatus: plan.githubAuthAction.status,
|
|
2068
2248
|
githubAuthStepReason: plan.githubAuthAction.reason || "",
|
|
2069
2249
|
dependencyInstallStatus: plan.dependencyAction.status,
|
|
@@ -2087,6 +2267,7 @@ async function runSetupFlow(forwardedArgs) {
|
|
|
2087
2267
|
console.log(`SETUP_STATUS=dry-run`);
|
|
2088
2268
|
console.log(`SETUP_MODE=dry-run`);
|
|
2089
2269
|
console.log(`PROFILE_ID=${config.profileId}`);
|
|
2270
|
+
console.log(`FORGE_PROVIDER=${config.forge.provider}`);
|
|
2090
2271
|
console.log(`REPO_SLUG=${config.repoSlug}`);
|
|
2091
2272
|
console.log(`REPO_ROOT=${config.paths.repoRoot}`);
|
|
2092
2273
|
console.log(`AGENT_ROOT=${config.paths.agentRoot}`);
|
|
@@ -2105,7 +2286,7 @@ async function runSetupFlow(forwardedArgs) {
|
|
|
2105
2286
|
}
|
|
2106
2287
|
console.log(`WORKER_BACKEND_COMMAND=${plan.prereq.workerCommand}`);
|
|
2107
2288
|
console.log(`WORKER_BACKEND_STATUS=${plan.prereq.workerAvailable ? "ok" : "missing"}`);
|
|
2108
|
-
console.log(`GITHUB_AUTH_STATUS=${plan.prereq.
|
|
2289
|
+
console.log(`GITHUB_AUTH_STATUS=${plan.prereq.forgeAuthOk ? "ok" : "not-ready"}`);
|
|
2109
2290
|
console.log(`DEPENDENCY_INSTALL_STATUS=${plan.dependencyAction.status}`);
|
|
2110
2291
|
if (plan.dependencyAction.reason) {
|
|
2111
2292
|
console.log(`DEPENDENCY_INSTALL_REASON=${plan.dependencyAction.reason}`);
|
|
@@ -2171,16 +2352,16 @@ async function runSetupFlow(forwardedArgs) {
|
|
|
2171
2352
|
console.error("dependency installation failed");
|
|
2172
2353
|
return 1;
|
|
2173
2354
|
}
|
|
2174
|
-
prereq = collectPrereqStatus(config.codingWorker);
|
|
2355
|
+
prereq = collectPrereqStatus(config.codingWorker, config.forge);
|
|
2175
2356
|
|
|
2176
2357
|
let githubAuthStep = await maybeRunGithubAuthLogin(options, prereq);
|
|
2177
2358
|
if (githubAuthStep.status === "failed") {
|
|
2178
|
-
console.error("GitHub authentication failed");
|
|
2359
|
+
console.error(config.forge.provider === "gitea" ? "Gitea authentication failed" : "GitHub authentication failed");
|
|
2179
2360
|
return 1;
|
|
2180
2361
|
}
|
|
2181
|
-
prereq = collectPrereqStatus(config.codingWorker);
|
|
2362
|
+
prereq = collectPrereqStatus(config.codingWorker, config.forge);
|
|
2182
2363
|
let workerSetupStep = await maybeShowWorkerSetupGuide(options, prereq);
|
|
2183
|
-
prereq = collectPrereqStatus(config.codingWorker);
|
|
2364
|
+
prereq = collectPrereqStatus(config.codingWorker, config.forge);
|
|
2184
2365
|
|
|
2185
2366
|
// Check OpenRouter API key when openclaw or pi is selected
|
|
2186
2367
|
if ((config.codingWorker === "openclaw" || config.codingWorker === "pi") && !process.env.OPENROUTER_API_KEY) {
|
|
@@ -2252,6 +2433,7 @@ async function runSetupFlow(forwardedArgs) {
|
|
|
2252
2433
|
const initArgs = [
|
|
2253
2434
|
"--profile-id", config.profileId,
|
|
2254
2435
|
"--repo-slug", config.repoSlug,
|
|
2436
|
+
"--forge-provider", config.forge.provider,
|
|
2255
2437
|
"--repo-root", config.paths.repoRoot,
|
|
2256
2438
|
"--agent-root", config.paths.agentRoot,
|
|
2257
2439
|
"--agent-repo-root", config.paths.agentRepoRoot,
|
|
@@ -2261,6 +2443,12 @@ async function runSetupFlow(forwardedArgs) {
|
|
|
2261
2443
|
"--source-repo-root", config.paths.sourceRepoRoot,
|
|
2262
2444
|
"--coding-worker", config.codingWorker
|
|
2263
2445
|
];
|
|
2446
|
+
if (config.forge.provider === "gitea") {
|
|
2447
|
+
if (config.forge.giteaBaseUrl) initArgs.push("--gitea-base-url", config.forge.giteaBaseUrl);
|
|
2448
|
+
if (config.forge.giteaToken) initArgs.push("--gitea-token", config.forge.giteaToken);
|
|
2449
|
+
if (config.forge.giteaUsername) initArgs.push("--gitea-username", config.forge.giteaUsername);
|
|
2450
|
+
if (config.forge.giteaPassword) initArgs.push("--gitea-password", config.forge.giteaPassword);
|
|
2451
|
+
}
|
|
2264
2452
|
if (options.force) {
|
|
2265
2453
|
initArgs.push("--force");
|
|
2266
2454
|
}
|
|
@@ -2294,9 +2482,13 @@ async function runSetupFlow(forwardedArgs) {
|
|
|
2294
2482
|
} else if (anchorSync.status !== "ok") {
|
|
2295
2483
|
runtimeStartReason = `anchor-sync-${anchorSync.reason}`;
|
|
2296
2484
|
console.log("runtime start skipped: ACP deferred anchor repo sync for this setup run.");
|
|
2297
|
-
} else if (!prereq.
|
|
2298
|
-
runtimeStartReason =
|
|
2299
|
-
|
|
2485
|
+
} else if (!prereq.forgeAuthOk) {
|
|
2486
|
+
runtimeStartReason = `${config.forge.provider}-auth-not-ready`;
|
|
2487
|
+
if (config.forge.provider === "gitea") {
|
|
2488
|
+
console.log("runtime start skipped: Gitea auth is not configured yet. Pass --gitea-base-url and --gitea-token (or username/password), then re-run setup or start the runtime afterwards.");
|
|
2489
|
+
} else {
|
|
2490
|
+
console.log("runtime start skipped: GitHub CLI is not authenticated yet. Run `gh auth login` and start the runtime afterwards.");
|
|
2491
|
+
}
|
|
2300
2492
|
} else {
|
|
2301
2493
|
runSetupStep(scopedContext, "Start the runtime", "tools/bin/project-runtimectl.sh", ["start", "--profile-id", config.profileId], { useRuntimeCopy: true });
|
|
2302
2494
|
const runtimeStatusOutput = runSetupStep(scopedContext, "Read back runtime status", "tools/bin/project-runtimectl.sh", ["status", "--profile-id", config.profileId], { useRuntimeCopy: true });
|
|
@@ -2402,6 +2594,7 @@ async function runSetupFlow(forwardedArgs) {
|
|
|
2402
2594
|
setupMode: "run",
|
|
2403
2595
|
profileId: config.profileId,
|
|
2404
2596
|
repoSlug: config.repoSlug,
|
|
2597
|
+
forge: config.forge,
|
|
2405
2598
|
codingWorker: config.codingWorker,
|
|
2406
2599
|
profileExists: true,
|
|
2407
2600
|
repoRoot: config.paths.repoRoot,
|
|
@@ -2426,7 +2619,7 @@ async function runSetupFlow(forwardedArgs) {
|
|
|
2426
2619
|
workerBackendInstallExample: workerSetupStep.guide.installExamples[0] || "",
|
|
2427
2620
|
workerBackendAuthExample: workerSetupStep.guide.authExamples[0] || "",
|
|
2428
2621
|
workerBackendVerifyExample: workerSetupStep.guide.verifyExamples[0] || "",
|
|
2429
|
-
githubAuthStatus: prereq.
|
|
2622
|
+
githubAuthStatus: prereq.forgeAuthOk ? "ok" : "not-ready",
|
|
2430
2623
|
githubAuthStepStatus: githubAuthStep.status,
|
|
2431
2624
|
githubAuthStepReason: githubAuthStep.reason || "",
|
|
2432
2625
|
dependencyInstallStatus: dependencyInstall.status,
|
|
@@ -2457,7 +2650,10 @@ async function runSetupFlow(forwardedArgs) {
|
|
|
2457
2650
|
console.log(` Runtime : ${context.runtimeHome}`);
|
|
2458
2651
|
|
|
2459
2652
|
const pendingItems = [];
|
|
2460
|
-
if (!prereq.
|
|
2653
|
+
if (!prereq.forgeAuthOk) {
|
|
2654
|
+
if (config.forge.provider === "gitea") pendingItems.push("Gitea auth not configured — rerun setup with --gitea-base-url and --gitea-token");
|
|
2655
|
+
else pendingItems.push("GitHub CLI not authenticated — run: gh auth login");
|
|
2656
|
+
}
|
|
2461
2657
|
if (!prereq.workerAvailable) pendingItems.push(`${config.codingWorker} not found on PATH — install it before starting`);
|
|
2462
2658
|
if (config.codingWorker === "openclaw" && !process.env.OPENROUTER_API_KEY) {
|
|
2463
2659
|
pendingItems.push("OPENROUTER_API_KEY not set — required for openclaw workers");
|
|
@@ -2496,7 +2692,7 @@ async function runSetupFlow(forwardedArgs) {
|
|
|
2496
2692
|
}
|
|
2497
2693
|
} else {
|
|
2498
2694
|
console.log("\n Getting started:");
|
|
2499
|
-
console.log(` 1.
|
|
2695
|
+
console.log(` 1. Leave a normal issue open in ${config.repoSlug}, or add 'agent-keep-open' for a recurring issue`);
|
|
2500
2696
|
console.log(" 2. ACP picks it up automatically, assigns a worker, and opens a PR");
|
|
2501
2697
|
console.log(" 3. Watch progress in the dashboard or with 'runtime status'");
|
|
2502
2698
|
}
|
|
@@ -2509,11 +2705,13 @@ async function runSetupFlow(forwardedArgs) {
|
|
|
2509
2705
|
// Machine-readable KV output for non-interactive / scripted runs
|
|
2510
2706
|
console.log("\nSetup complete.");
|
|
2511
2707
|
console.log(`- profile: ${config.profileId}`);
|
|
2708
|
+
console.log(`- forge provider: ${config.forge.provider}`);
|
|
2512
2709
|
console.log(`- repo: ${config.repoSlug}`);
|
|
2513
2710
|
console.log(`- runtime home: ${context.runtimeHome}`);
|
|
2514
2711
|
|
|
2515
2712
|
console.log(`SETUP_STATUS=ok`);
|
|
2516
2713
|
console.log(`PROFILE_ID=${config.profileId}`);
|
|
2714
|
+
console.log(`FORGE_PROVIDER=${config.forge.provider}`);
|
|
2517
2715
|
console.log(`REPO_SLUG=${config.repoSlug}`);
|
|
2518
2716
|
console.log(`REPO_ROOT=${config.paths.repoRoot}`);
|
|
2519
2717
|
console.log(`AGENT_ROOT=${config.paths.agentRoot}`);
|
|
@@ -2558,7 +2756,7 @@ async function runSetupFlow(forwardedArgs) {
|
|
|
2558
2756
|
if (workerSetupStep.guide.verifyExamples[0]) {
|
|
2559
2757
|
console.log(`WORKER_BACKEND_VERIFY_EXAMPLE=${workerSetupStep.guide.verifyExamples[0]}`);
|
|
2560
2758
|
}
|
|
2561
|
-
console.log(`GITHUB_AUTH_STATUS=${prereq.
|
|
2759
|
+
console.log(`GITHUB_AUTH_STATUS=${prereq.forgeAuthOk ? "ok" : "not-ready"}`);
|
|
2562
2760
|
console.log(`FINAL_FIXUP_STATUS=${finalFixup.status}`);
|
|
2563
2761
|
console.log(`FINAL_FIXUP_ACTIONS=${finalFixup.actions.join(",")}`);
|
|
2564
2762
|
console.log(`DEPENDENCY_INSTALL_STATUS=${dependencyInstall.status}`);
|