@pushpalsdev/cli 1.0.6 → 1.0.7
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/pushpals-cli.js +483 -37
- package/package.json +3 -2
- package/runtime/.env.example +73 -0
- package/runtime/configs/backend.toml +79 -0
- package/runtime/configs/default.toml +259 -0
- package/runtime/configs/dev.toml +2 -0
- package/runtime/configs/local.example.toml +124 -0
- package/runtime/prompts/localbuddy/local_quick_reply_json_system_suffix.md +2 -0
- package/runtime/prompts/localbuddy/local_quick_reply_system_prompt.md +10 -0
- package/runtime/prompts/localbuddy/local_quick_reply_user_prompt.md +2 -0
- package/runtime/prompts/localbuddy/localbuddy_planner_git_diff_section.md +3 -0
- package/runtime/prompts/localbuddy/localbuddy_planner_git_status_section.md +3 -0
- package/runtime/prompts/localbuddy/localbuddy_planner_output_contract.md +5 -0
- package/runtime/prompts/localbuddy/localbuddy_planner_user_prompt.md +2 -0
- package/runtime/prompts/localbuddy/localbuddy_system_prompt.md +110 -0
- package/runtime/prompts/remotebuddy/autonomy_ideation_system_prompt.md +60 -0
- package/runtime/prompts/remotebuddy/autonomy_planning_system_prompt.md +5 -0
- package/runtime/prompts/remotebuddy/autonomy_scoring_system_prompt.md +6 -0
- package/runtime/prompts/remotebuddy/codex_adapter_json_requirements.md +1 -0
- package/runtime/prompts/remotebuddy/codex_adapter_json_schema_intro.md +1 -0
- package/runtime/prompts/remotebuddy/codex_adapter_max_tokens_line.md +1 -0
- package/runtime/prompts/remotebuddy/codex_adapter_prompt_template.md +14 -0
- package/runtime/prompts/remotebuddy/context_packer_condensed_history_system_prompt.md +1 -0
- package/runtime/prompts/remotebuddy/context_packer_system_prompt.md +1 -0
- package/runtime/prompts/remotebuddy/context_packer_user_prompt.md +11 -0
- package/runtime/prompts/remotebuddy/fallback_file_system_prompt.md +1 -0
- package/runtime/prompts/remotebuddy/fallback_file_user_prompt.md +4 -0
- package/runtime/prompts/remotebuddy/planner_post_system_prompt.md +2 -0
- package/runtime/prompts/remotebuddy/planner_repair_suffix_prompt.md +1 -0
- package/runtime/prompts/remotebuddy/planner_repair_user_prompt.md +7 -0
- package/runtime/prompts/remotebuddy/remotebuddy_system_prompt.md +109 -0
- package/runtime/prompts/review_agent/fix_job_intro_line.md +1 -0
- package/runtime/prompts/review_agent/merge_conflict_context_intro_line.md +1 -0
- package/runtime/prompts/review_agent/merge_conflict_instruction.md +4 -0
- package/runtime/prompts/review_agent/review_prompt_template.md +18 -0
- package/runtime/prompts/review_agent/reviewer.md +39 -0
- package/runtime/prompts/shared/post_system_prompt.md +62 -0
- package/runtime/prompts/workerpals/codex_quality_critic_instruction_prompt.md +14 -0
- package/runtime/prompts/workerpals/commit_message_prompt.md +36 -0
- package/runtime/prompts/workerpals/commit_message_user_prompt.md +7 -0
- package/runtime/prompts/workerpals/miniswe_broker_system_prompt.md +33 -0
- package/runtime/prompts/workerpals/miniswe_broker_task_prompt.md +5 -0
- package/runtime/prompts/workerpals/miniswe_completion_requirement.md +1 -0
- package/runtime/prompts/workerpals/miniswe_context_compaction_retry_prompt.md +1 -0
- package/runtime/prompts/workerpals/miniswe_explicit_targets_block.md +2 -0
- package/runtime/prompts/workerpals/miniswe_recovery_guidance_base.md +4 -0
- package/runtime/prompts/workerpals/miniswe_recovery_guidance_blocker_line.md +1 -0
- package/runtime/prompts/workerpals/miniswe_strict_tool_use_guidance.md +6 -0
- package/runtime/prompts/workerpals/miniswe_supplemental_guidance_section.md +2 -0
- package/runtime/prompts/workerpals/miniswe_timeout_note.md +1 -0
- package/runtime/prompts/workerpals/miniswe_toolcall_retry_guidance.md +1 -0
- package/runtime/prompts/workerpals/openai_codex_default_system_prompt.md +4 -0
- package/runtime/prompts/workerpals/openai_codex_instruction_wrapper.md +5 -0
- package/runtime/prompts/workerpals/openai_codex_runtime_policy_appendix.md +5 -0
- package/runtime/prompts/workerpals/openai_codex_supplemental_guidance_section.md +2 -0
- package/runtime/prompts/workerpals/openai_codex_task_execute_system_prompt.md +12 -0
- package/runtime/prompts/workerpals/openhands_minimal_security_policy.j2 +8 -0
- package/runtime/prompts/workerpals/openhands_minimal_system_prompt.j2 +20 -0
- package/runtime/prompts/workerpals/openhands_strict_tool_use_message.md +1 -0
- package/runtime/prompts/workerpals/openhands_supplemental_guidance_message.md +2 -0
- package/runtime/prompts/workerpals/openhands_task_execute_fallback_system_prompt.md +1 -0
- package/runtime/prompts/workerpals/openhands_task_execute_system_prompt.md +21 -0
- package/runtime/prompts/workerpals/openhands_task_user_prompt.md +6 -0
- package/runtime/prompts/workerpals/openhands_timeout_note.md +1 -0
- package/runtime/prompts/workerpals/pr_description.md +42 -0
- package/runtime/prompts/workerpals/task_quality_critic_system_prompt.md +9 -0
- package/runtime/prompts/workerpals/task_quality_critic_user_prompt.md +17 -0
- package/runtime/prompts/workerpals/workerpals_system_prompt.md +115 -0
- package/runtime/protocol/schemas/approvals.schema.json +6 -0
- package/runtime/protocol/schemas/envelope.schema.json +96 -0
- package/runtime/protocol/schemas/events.schema.json +679 -0
- package/runtime/protocol/schemas/http.schema.json +50 -0
- package/runtime/vision.example.md +191 -0
package/dist/pushpals-cli.js
CHANGED
|
@@ -2,10 +2,14 @@
|
|
|
2
2
|
// @bun
|
|
3
3
|
|
|
4
4
|
// ../../scripts/pushpals-cli.ts
|
|
5
|
-
import { appendFileSync, chmodSync, cpSync, existsSync as
|
|
6
|
-
import { dirname, join as join2, resolve as
|
|
5
|
+
import { appendFileSync, chmodSync, cpSync, existsSync as existsSync3, mkdirSync, readFileSync as readFileSync3, writeFileSync } from "fs";
|
|
6
|
+
import { dirname, join as join2, resolve as resolve3 } from "path";
|
|
7
7
|
import { createInterface } from "readline";
|
|
8
8
|
|
|
9
|
+
// ../shared/src/client_preflight.ts
|
|
10
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
11
|
+
import { relative, resolve as resolve2 } from "path";
|
|
12
|
+
|
|
9
13
|
// ../shared/src/config.ts
|
|
10
14
|
import { existsSync, readFileSync } from "fs";
|
|
11
15
|
import { join, resolve, isAbsolute } from "path";
|
|
@@ -739,6 +743,316 @@ function loadPushPalsConfig(options = {}) {
|
|
|
739
743
|
return config;
|
|
740
744
|
}
|
|
741
745
|
|
|
746
|
+
// ../shared/src/vision.ts
|
|
747
|
+
var SECTION_HEADING_RE = /^##\s+(\d+)\)\s+(.+?)\s*$/;
|
|
748
|
+
var ONE_SENTENCE_PROMPT_RE = /^\>\s*\*\*One sentence:\*\*\s*(.+)\s*$/i;
|
|
749
|
+
var BLOCKQUOTE_RE = /^\>\s*(.+?)\s*$/;
|
|
750
|
+
function toLines(markdown) {
|
|
751
|
+
return String(markdown ?? "").replace(/\r\n/g, `
|
|
752
|
+
`).split(`
|
|
753
|
+
`);
|
|
754
|
+
}
|
|
755
|
+
function extractOneSentence(lines) {
|
|
756
|
+
let expectNextBlockquoteSentence = false;
|
|
757
|
+
for (const line of lines) {
|
|
758
|
+
const marker = line.match(ONE_SENTENCE_PROMPT_RE);
|
|
759
|
+
if (marker) {
|
|
760
|
+
const inline = marker[1].trim();
|
|
761
|
+
if (inline)
|
|
762
|
+
return inline;
|
|
763
|
+
expectNextBlockquoteSentence = true;
|
|
764
|
+
continue;
|
|
765
|
+
}
|
|
766
|
+
const block = line.match(BLOCKQUOTE_RE);
|
|
767
|
+
if (expectNextBlockquoteSentence) {
|
|
768
|
+
if (!block)
|
|
769
|
+
continue;
|
|
770
|
+
const text = block[1].trim();
|
|
771
|
+
if (!text)
|
|
772
|
+
continue;
|
|
773
|
+
if (/^Example:/i.test(text))
|
|
774
|
+
continue;
|
|
775
|
+
return text;
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
for (const line of lines) {
|
|
779
|
+
const block = line.match(BLOCKQUOTE_RE);
|
|
780
|
+
if (!block)
|
|
781
|
+
continue;
|
|
782
|
+
const text = block[1].trim();
|
|
783
|
+
if (!text)
|
|
784
|
+
continue;
|
|
785
|
+
if (/^\*\*One sentence:\*\*/i.test(text))
|
|
786
|
+
continue;
|
|
787
|
+
if (/^Example:/i.test(text))
|
|
788
|
+
continue;
|
|
789
|
+
return text;
|
|
790
|
+
}
|
|
791
|
+
return "";
|
|
792
|
+
}
|
|
793
|
+
function parseVisionDoc(markdown) {
|
|
794
|
+
const lines = toLines(markdown);
|
|
795
|
+
const sections = [];
|
|
796
|
+
let currentNumber = "";
|
|
797
|
+
let currentTitle = "";
|
|
798
|
+
let currentBody = [];
|
|
799
|
+
const flushCurrent = () => {
|
|
800
|
+
if (!currentNumber)
|
|
801
|
+
return;
|
|
802
|
+
sections.push({
|
|
803
|
+
number: currentNumber,
|
|
804
|
+
title: currentTitle,
|
|
805
|
+
markdown: currentBody.join(`
|
|
806
|
+
`).trim()
|
|
807
|
+
});
|
|
808
|
+
currentNumber = "";
|
|
809
|
+
currentTitle = "";
|
|
810
|
+
currentBody = [];
|
|
811
|
+
};
|
|
812
|
+
for (const line of lines) {
|
|
813
|
+
const heading = line.match(SECTION_HEADING_RE);
|
|
814
|
+
if (heading) {
|
|
815
|
+
flushCurrent();
|
|
816
|
+
currentNumber = heading[1];
|
|
817
|
+
currentTitle = heading[2].trim();
|
|
818
|
+
continue;
|
|
819
|
+
}
|
|
820
|
+
if (currentNumber) {
|
|
821
|
+
currentBody.push(line);
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
flushCurrent();
|
|
825
|
+
const sectionByNumber = {};
|
|
826
|
+
for (const section of sections) {
|
|
827
|
+
if (!sectionByNumber[section.number]) {
|
|
828
|
+
sectionByNumber[section.number] = section;
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
return {
|
|
832
|
+
oneSentence: extractOneSentence(lines),
|
|
833
|
+
sections,
|
|
834
|
+
sectionByNumber
|
|
835
|
+
};
|
|
836
|
+
}
|
|
837
|
+
function validateVisionDocStructure(markdown) {
|
|
838
|
+
const parsed = parseVisionDoc(markdown);
|
|
839
|
+
const missingSectionNumbers = [];
|
|
840
|
+
const errors = [];
|
|
841
|
+
if (!parsed.oneSentence) {
|
|
842
|
+
errors.push('Missing one-sentence vision line (expected near the top as a blockquote after "**One sentence:**").');
|
|
843
|
+
}
|
|
844
|
+
return {
|
|
845
|
+
ok: errors.length === 0,
|
|
846
|
+
sectionCount: parsed.sections.length,
|
|
847
|
+
hasOneSentence: Boolean(parsed.oneSentence),
|
|
848
|
+
missingSectionNumbers,
|
|
849
|
+
errors
|
|
850
|
+
};
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
// ../shared/src/client_preflight.ts
|
|
854
|
+
function runtimeHasConfigDir(runtimeRoot, dirName) {
|
|
855
|
+
const dirPath = resolve2(runtimeRoot, dirName);
|
|
856
|
+
return existsSync2(resolve2(dirPath, "default.toml")) || existsSync2(resolve2(dirPath, "local.example.toml")) || existsSync2(resolve2(dirPath, "local.toml"));
|
|
857
|
+
}
|
|
858
|
+
function resolveClientConfigDir(projectRoot, runtimeRoot, explicitConfigDir) {
|
|
859
|
+
if (explicitConfigDir && explicitConfigDir.trim()) {
|
|
860
|
+
return resolve2(explicitConfigDir);
|
|
861
|
+
}
|
|
862
|
+
const runtimeCanonical = resolve2(runtimeRoot, "configs");
|
|
863
|
+
if (runtimeHasConfigDir(runtimeRoot, "configs")) {
|
|
864
|
+
return runtimeCanonical;
|
|
865
|
+
}
|
|
866
|
+
const runtimeLegacy = resolve2(runtimeRoot, "config");
|
|
867
|
+
if (runtimeHasConfigDir(runtimeRoot, "config")) {
|
|
868
|
+
return runtimeLegacy;
|
|
869
|
+
}
|
|
870
|
+
const projectCanonical = resolve2(projectRoot, "configs");
|
|
871
|
+
if (runtimeHasConfigDir(projectRoot, "configs")) {
|
|
872
|
+
return projectCanonical;
|
|
873
|
+
}
|
|
874
|
+
const projectLegacy = resolve2(projectRoot, "config");
|
|
875
|
+
if (runtimeHasConfigDir(projectRoot, "config")) {
|
|
876
|
+
return projectLegacy;
|
|
877
|
+
}
|
|
878
|
+
return runtimeCanonical;
|
|
879
|
+
}
|
|
880
|
+
function toDisplayPath(currentRoot, pathValue) {
|
|
881
|
+
const rel = relative(currentRoot, pathValue);
|
|
882
|
+
if (!rel || rel === "")
|
|
883
|
+
return ".";
|
|
884
|
+
if (rel.startsWith(".."))
|
|
885
|
+
return pathValue;
|
|
886
|
+
return rel.replace(/\\/g, "/");
|
|
887
|
+
}
|
|
888
|
+
function quotePowerShell(pathValue) {
|
|
889
|
+
if (/^[A-Za-z0-9_./\\:-]+$/.test(pathValue))
|
|
890
|
+
return pathValue;
|
|
891
|
+
return `'${pathValue.replace(/'/g, "''")}'`;
|
|
892
|
+
}
|
|
893
|
+
function quoteBash(pathValue) {
|
|
894
|
+
if (/^[A-Za-z0-9_./\\:-]+$/.test(pathValue))
|
|
895
|
+
return pathValue;
|
|
896
|
+
return "'" + pathValue.replace(/'/g, `'"'"'`) + "'";
|
|
897
|
+
}
|
|
898
|
+
function buildCopyCommands(workspaceRoot, sourcePath, destPath) {
|
|
899
|
+
const displaySource = toDisplayPath(workspaceRoot, sourcePath);
|
|
900
|
+
const displayDest = toDisplayPath(workspaceRoot, destPath);
|
|
901
|
+
return {
|
|
902
|
+
windowsPowerShell: `Copy-Item ${quotePowerShell(displaySource)} ${quotePowerShell(displayDest)}`,
|
|
903
|
+
bash: `cp ${quoteBash(displaySource)} ${quoteBash(displayDest)}`
|
|
904
|
+
};
|
|
905
|
+
}
|
|
906
|
+
function evaluateClientRuntimePreflight(options) {
|
|
907
|
+
const projectRoot = resolve2(options.projectRoot);
|
|
908
|
+
const runtimeRoot = resolve2(options.runtimeRoot ?? projectRoot);
|
|
909
|
+
const configDir = resolveClientConfigDir(projectRoot, runtimeRoot, options.configDir);
|
|
910
|
+
const visionTemplateRoot = resolve2(options.visionTemplateRoot ?? runtimeRoot);
|
|
911
|
+
const config = options.config ?? loadPushPalsConfig({
|
|
912
|
+
projectRoot,
|
|
913
|
+
configDir,
|
|
914
|
+
reload: true
|
|
915
|
+
});
|
|
916
|
+
const issues = [];
|
|
917
|
+
const envPath = resolve2(runtimeRoot, ".env");
|
|
918
|
+
if (!existsSync2(envPath)) {
|
|
919
|
+
const envExamplePath = resolve2(runtimeRoot, ".env.example");
|
|
920
|
+
issues.push({
|
|
921
|
+
code: "missing_env_file",
|
|
922
|
+
message: `Missing required local env file: ${toDisplayPath(projectRoot, envPath)}.`,
|
|
923
|
+
copyCommands: existsSync2(envExamplePath) ? buildCopyCommands(projectRoot, envExamplePath, envPath) : undefined
|
|
924
|
+
});
|
|
925
|
+
}
|
|
926
|
+
const localTomlPath = resolve2(runtimeRoot, "configs", "local.toml");
|
|
927
|
+
const legacyLocalTomlPath = resolve2(runtimeRoot, "config", "local.toml");
|
|
928
|
+
if (!existsSync2(localTomlPath) && !existsSync2(legacyLocalTomlPath)) {
|
|
929
|
+
const localExamplePath = resolve2(runtimeRoot, "configs", "local.example.toml");
|
|
930
|
+
issues.push({
|
|
931
|
+
code: "missing_local_toml",
|
|
932
|
+
message: `Missing required local config file: ${toDisplayPath(projectRoot, localTomlPath)}.`,
|
|
933
|
+
copyCommands: existsSync2(localExamplePath) ? buildCopyCommands(projectRoot, localExamplePath, localTomlPath) : undefined
|
|
934
|
+
});
|
|
935
|
+
}
|
|
936
|
+
const autonomyEnabled = Boolean(config.remotebuddy.autonomy.enabled);
|
|
937
|
+
if (!autonomyEnabled) {
|
|
938
|
+
return {
|
|
939
|
+
ok: issues.length === 0,
|
|
940
|
+
projectRoot,
|
|
941
|
+
runtimeRoot,
|
|
942
|
+
config,
|
|
943
|
+
issues,
|
|
944
|
+
autonomyEnabled,
|
|
945
|
+
visionSummary: null
|
|
946
|
+
};
|
|
947
|
+
}
|
|
948
|
+
const visionPath = resolve2(projectRoot, "vision.md");
|
|
949
|
+
const visionTemplatePath = resolve2(visionTemplateRoot, "vision.example.md");
|
|
950
|
+
if (!existsSync2(visionPath)) {
|
|
951
|
+
issues.push({
|
|
952
|
+
code: "missing_vision_doc",
|
|
953
|
+
message: "Missing required autonomy vision file: vision.md " + "(required when remotebuddy.autonomy.enabled=true).",
|
|
954
|
+
copyCommands: existsSync2(visionTemplatePath) ? buildCopyCommands(projectRoot, visionTemplatePath, visionPath) : undefined
|
|
955
|
+
});
|
|
956
|
+
return {
|
|
957
|
+
ok: false,
|
|
958
|
+
projectRoot,
|
|
959
|
+
runtimeRoot,
|
|
960
|
+
config,
|
|
961
|
+
issues,
|
|
962
|
+
autonomyEnabled,
|
|
963
|
+
visionSummary: null
|
|
964
|
+
};
|
|
965
|
+
}
|
|
966
|
+
let rawVision = "";
|
|
967
|
+
try {
|
|
968
|
+
rawVision = readFileSync2(visionPath, "utf8");
|
|
969
|
+
} catch (err) {
|
|
970
|
+
issues.push({
|
|
971
|
+
code: "unreadable_vision_doc",
|
|
972
|
+
message: `Autonomy vision preflight failed: could not read vision.md.`,
|
|
973
|
+
detail: String(err)
|
|
974
|
+
});
|
|
975
|
+
return {
|
|
976
|
+
ok: false,
|
|
977
|
+
projectRoot,
|
|
978
|
+
runtimeRoot,
|
|
979
|
+
config,
|
|
980
|
+
issues,
|
|
981
|
+
autonomyEnabled,
|
|
982
|
+
visionSummary: null
|
|
983
|
+
};
|
|
984
|
+
}
|
|
985
|
+
const visionText = rawVision.trim();
|
|
986
|
+
if (!visionText) {
|
|
987
|
+
issues.push({
|
|
988
|
+
code: "empty_vision_doc",
|
|
989
|
+
message: "Autonomy vision preflight failed: vision.md is empty.",
|
|
990
|
+
detail: "Add repository vision/goals before startup."
|
|
991
|
+
});
|
|
992
|
+
return {
|
|
993
|
+
ok: false,
|
|
994
|
+
projectRoot,
|
|
995
|
+
runtimeRoot,
|
|
996
|
+
config,
|
|
997
|
+
issues,
|
|
998
|
+
autonomyEnabled,
|
|
999
|
+
visionSummary: null
|
|
1000
|
+
};
|
|
1001
|
+
}
|
|
1002
|
+
const validation = validateVisionDocStructure(visionText);
|
|
1003
|
+
if (!validation.ok) {
|
|
1004
|
+
issues.push({
|
|
1005
|
+
code: "invalid_vision_doc",
|
|
1006
|
+
message: "Autonomy vision preflight failed: vision.md is invalid.",
|
|
1007
|
+
detail: validation.errors.join(" ")
|
|
1008
|
+
});
|
|
1009
|
+
return {
|
|
1010
|
+
ok: false,
|
|
1011
|
+
projectRoot,
|
|
1012
|
+
runtimeRoot,
|
|
1013
|
+
config,
|
|
1014
|
+
issues,
|
|
1015
|
+
autonomyEnabled,
|
|
1016
|
+
visionSummary: null
|
|
1017
|
+
};
|
|
1018
|
+
}
|
|
1019
|
+
return {
|
|
1020
|
+
ok: issues.length === 0,
|
|
1021
|
+
projectRoot,
|
|
1022
|
+
runtimeRoot,
|
|
1023
|
+
config,
|
|
1024
|
+
issues,
|
|
1025
|
+
autonomyEnabled,
|
|
1026
|
+
visionSummary: {
|
|
1027
|
+
path: toDisplayPath(projectRoot, visionPath),
|
|
1028
|
+
chars: visionText.length,
|
|
1029
|
+
sectionCount: validation.sectionCount,
|
|
1030
|
+
validation
|
|
1031
|
+
}
|
|
1032
|
+
};
|
|
1033
|
+
}
|
|
1034
|
+
function formatClientRuntimePreflightLines(result, prefix) {
|
|
1035
|
+
const normalizedPrefix = prefix.trim();
|
|
1036
|
+
const lines = [];
|
|
1037
|
+
if (result.ok) {
|
|
1038
|
+
if (result.visionSummary) {
|
|
1039
|
+
lines.push(`${normalizedPrefix} Autonomy preflight: loaded ${result.visionSummary.path} ` + `(${result.visionSummary.chars} chars, ${result.visionSummary.sectionCount} section(s)).`);
|
|
1040
|
+
}
|
|
1041
|
+
return lines;
|
|
1042
|
+
}
|
|
1043
|
+
for (const issue of result.issues) {
|
|
1044
|
+
lines.push(`${normalizedPrefix} ${issue.message}`);
|
|
1045
|
+
if (issue.detail) {
|
|
1046
|
+
lines.push(`${normalizedPrefix} ${issue.detail}`);
|
|
1047
|
+
}
|
|
1048
|
+
if (issue.copyCommands) {
|
|
1049
|
+
lines.push(`${normalizedPrefix} Windows (PowerShell): ${issue.copyCommands.windowsPowerShell}`);
|
|
1050
|
+
lines.push(`${normalizedPrefix} Linux/macOS (bash): ${issue.copyCommands.bash}`);
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
return lines;
|
|
1054
|
+
}
|
|
1055
|
+
|
|
742
1056
|
// ../../scripts/pushpals-cli.ts
|
|
743
1057
|
var DEFAULT_MONITOR_PORT = 8081;
|
|
744
1058
|
var MONITOR_SCAN_PORTS = 32;
|
|
@@ -855,7 +1169,7 @@ function parsePositiveInt(value, fallback) {
|
|
|
855
1169
|
return parsed;
|
|
856
1170
|
}
|
|
857
1171
|
function normalizePath(value) {
|
|
858
|
-
const normalized =
|
|
1172
|
+
const normalized = resolve3(value).replace(/\\/g, "/").replace(/\/+$/, "");
|
|
859
1173
|
if (process.platform === "win32")
|
|
860
1174
|
return normalized.toLowerCase();
|
|
861
1175
|
return normalized;
|
|
@@ -883,11 +1197,39 @@ async function resolveCurrentGitRepoRoot(cwd) {
|
|
|
883
1197
|
const root = await runGit(["rev-parse", "--show-toplevel"], cwd);
|
|
884
1198
|
if (!root.ok || !root.stdout)
|
|
885
1199
|
return null;
|
|
886
|
-
return
|
|
1200
|
+
return resolve3(root.stdout);
|
|
887
1201
|
}
|
|
888
1202
|
function resolveDefaultRuntimeRoot() {
|
|
889
1203
|
const home = process.env.USERPROFILE || process.env.HOME || process.cwd();
|
|
890
|
-
return
|
|
1204
|
+
return resolve3(home, ".pushpals", "runtime");
|
|
1205
|
+
}
|
|
1206
|
+
function buildRuntimeAssetSource(root, protocolSchemasDir) {
|
|
1207
|
+
return {
|
|
1208
|
+
root,
|
|
1209
|
+
envExamplePath: join2(root, ".env.example"),
|
|
1210
|
+
visionExamplePath: join2(root, "vision.example.md"),
|
|
1211
|
+
configsDir: join2(root, "configs"),
|
|
1212
|
+
promptsDir: join2(root, "prompts"),
|
|
1213
|
+
protocolSchemasDir
|
|
1214
|
+
};
|
|
1215
|
+
}
|
|
1216
|
+
function isCompleteRuntimeAssetSource(source) {
|
|
1217
|
+
return existsSync3(source.envExamplePath) && existsSync3(source.visionExamplePath) && existsSync3(join2(source.configsDir, "default.toml")) && existsSync3(source.promptsDir) && existsSync3(join2(source.protocolSchemasDir, "envelope.schema.json")) && existsSync3(join2(source.protocolSchemasDir, "events.schema.json"));
|
|
1218
|
+
}
|
|
1219
|
+
function resolveBundledRuntimeAssetSource() {
|
|
1220
|
+
const candidates = [
|
|
1221
|
+
buildRuntimeAssetSource(resolve3(import.meta.dir, "..", "runtime"), resolve3(import.meta.dir, "..", "runtime", "protocol", "schemas")),
|
|
1222
|
+
buildRuntimeAssetSource(resolve3(import.meta.dir, ".."), resolve3(import.meta.dir, "..", "packages", "protocol", "src", "schemas")),
|
|
1223
|
+
buildRuntimeAssetSource(resolve3(import.meta.dir, "..", "packages", "cli", "runtime"), resolve3(import.meta.dir, "..", "packages", "cli", "runtime", "protocol", "schemas"))
|
|
1224
|
+
];
|
|
1225
|
+
for (const candidate of candidates) {
|
|
1226
|
+
if (isCompleteRuntimeAssetSource(candidate))
|
|
1227
|
+
return candidate;
|
|
1228
|
+
}
|
|
1229
|
+
return null;
|
|
1230
|
+
}
|
|
1231
|
+
function repoLooksLikePushPalsSourceCheckout(repoRoot) {
|
|
1232
|
+
return existsSync3(join2(repoRoot, "configs", "default.toml")) || existsSync3(join2(repoRoot, "config", "default.toml"));
|
|
891
1233
|
}
|
|
892
1234
|
function parseSemverFromPackageVersion(value) {
|
|
893
1235
|
const raw = String(value ?? "").trim();
|
|
@@ -937,18 +1279,56 @@ async function resolveRuntimeReleaseTag(explicitTag) {
|
|
|
937
1279
|
}
|
|
938
1280
|
}
|
|
939
1281
|
function writeTextFileIfMissing(pathValue, text) {
|
|
940
|
-
if (
|
|
1282
|
+
if (existsSync3(pathValue))
|
|
941
1283
|
return;
|
|
942
1284
|
mkdirSync(dirname(pathValue), { recursive: true });
|
|
943
1285
|
writeFileSync(pathValue, text, "utf8");
|
|
944
1286
|
}
|
|
945
|
-
function
|
|
946
|
-
|
|
947
|
-
|
|
1287
|
+
function copyRuntimeAssetBundle(source, runtimeRoot, force) {
|
|
1288
|
+
mkdirSync(runtimeRoot, { recursive: true });
|
|
1289
|
+
cpSync(source.envExamplePath, join2(runtimeRoot, ".env.example"), {
|
|
1290
|
+
force,
|
|
1291
|
+
errorOnExist: false
|
|
1292
|
+
});
|
|
1293
|
+
cpSync(source.visionExamplePath, join2(runtimeRoot, "vision.example.md"), {
|
|
1294
|
+
force,
|
|
1295
|
+
errorOnExist: false
|
|
1296
|
+
});
|
|
1297
|
+
cpSync(source.configsDir, join2(runtimeRoot, "configs"), {
|
|
1298
|
+
recursive: true,
|
|
1299
|
+
force,
|
|
1300
|
+
errorOnExist: false
|
|
1301
|
+
});
|
|
1302
|
+
cpSync(source.promptsDir, join2(runtimeRoot, "prompts"), {
|
|
1303
|
+
recursive: true,
|
|
1304
|
+
force,
|
|
1305
|
+
errorOnExist: false
|
|
1306
|
+
});
|
|
1307
|
+
cpSync(source.protocolSchemasDir, join2(runtimeRoot, "protocol", "schemas"), {
|
|
1308
|
+
recursive: true,
|
|
1309
|
+
force,
|
|
1310
|
+
errorOnExist: false
|
|
1311
|
+
});
|
|
1312
|
+
}
|
|
1313
|
+
function copyBundledRuntimeAssets(runtimeRoot, force = true) {
|
|
1314
|
+
const bundledSource = resolveBundledRuntimeAssetSource();
|
|
1315
|
+
if (!bundledSource)
|
|
948
1316
|
return false;
|
|
949
|
-
|
|
1317
|
+
copyRuntimeAssetBundle(bundledSource, runtimeRoot, force);
|
|
950
1318
|
return true;
|
|
951
1319
|
}
|
|
1320
|
+
function seedRuntimePreflightAssets(runtimeRoot) {
|
|
1321
|
+
copyBundledRuntimeAssets(runtimeRoot, false);
|
|
1322
|
+
writeTextFileIfMissing(join2(runtimeRoot, ".env"), `# Local PushPals runtime environment
|
|
1323
|
+
`);
|
|
1324
|
+
const localExamplePath = join2(runtimeRoot, "configs", "local.example.toml");
|
|
1325
|
+
if (existsSync3(localExamplePath)) {
|
|
1326
|
+
writeTextFileIfMissing(join2(runtimeRoot, "configs", "local.toml"), readFileSync3(localExamplePath, "utf8"));
|
|
1327
|
+
} else {
|
|
1328
|
+
writeTextFileIfMissing(join2(runtimeRoot, "configs", "local.toml"), `# Local PushPals runtime overrides
|
|
1329
|
+
`);
|
|
1330
|
+
}
|
|
1331
|
+
}
|
|
952
1332
|
async function fetchTextFromUrl(url, timeoutMs = 20000) {
|
|
953
1333
|
const response = await fetchWithTimeout(url, { headers: GITHUB_HEADERS }, timeoutMs);
|
|
954
1334
|
if (!response.ok) {
|
|
@@ -963,7 +1343,7 @@ async function downloadRuntimeAssetsFromSourceTag(runtimeRoot, tag) {
|
|
|
963
1343
|
throw new Error(`Failed to fetch runtime source tree for ${tag} (HTTP ${treeResponse.status})`);
|
|
964
1344
|
}
|
|
965
1345
|
const treePayload = await treeResponse.json();
|
|
966
|
-
const paths = (treePayload.tree ?? []).filter((entry) => entry.type === "blob" && typeof entry.path === "string").map((entry) => String(entry.path)).filter((pathValue) => pathValue === ".env.example" || pathValue.startsWith("configs/") || pathValue.startsWith("prompts/") || pathValue.startsWith("packages/protocol/src/schemas/"));
|
|
1346
|
+
const paths = (treePayload.tree ?? []).filter((entry) => entry.type === "blob" && typeof entry.path === "string").map((entry) => String(entry.path)).filter((pathValue) => pathValue === ".env.example" || pathValue === "vision.example.md" || pathValue.startsWith("configs/") || pathValue.startsWith("prompts/") || pathValue.startsWith("packages/protocol/src/schemas/"));
|
|
967
1347
|
if (paths.length === 0) {
|
|
968
1348
|
throw new Error(`Runtime source tree for ${tag} did not include prompts/config assets`);
|
|
969
1349
|
}
|
|
@@ -978,14 +1358,14 @@ async function downloadRuntimeAssetsFromSourceTag(runtimeRoot, tag) {
|
|
|
978
1358
|
}
|
|
979
1359
|
async function ensureRuntimeAssets(runtimeRoot, runtimeTag) {
|
|
980
1360
|
const markerPath = join2(runtimeRoot, ".runtime-assets-tag");
|
|
981
|
-
const currentTag =
|
|
1361
|
+
const currentTag = existsSync3(markerPath) ? readFileSync3(markerPath, "utf8").trim() : "";
|
|
982
1362
|
const protocolSchemasDir = join2(runtimeRoot, "protocol", "schemas");
|
|
983
|
-
const hasProtocolSchemas =
|
|
984
|
-
const hasAssets =
|
|
1363
|
+
const hasProtocolSchemas = existsSync3(join2(protocolSchemasDir, "envelope.schema.json")) && existsSync3(join2(protocolSchemasDir, "events.schema.json"));
|
|
1364
|
+
const hasAssets = existsSync3(join2(runtimeRoot, ".env.example")) && existsSync3(join2(runtimeRoot, "vision.example.md")) && existsSync3(join2(runtimeRoot, "configs", "default.toml")) && existsSync3(join2(runtimeRoot, "prompts")) && hasProtocolSchemas;
|
|
985
1365
|
if (!hasAssets || currentTag !== runtimeTag) {
|
|
986
1366
|
copyBundledRuntimeAssets(runtimeRoot);
|
|
987
|
-
const hasProtocolSchemasAfterCopy =
|
|
988
|
-
const hasAssetsAfterCopy =
|
|
1367
|
+
const hasProtocolSchemasAfterCopy = existsSync3(join2(protocolSchemasDir, "envelope.schema.json")) && existsSync3(join2(protocolSchemasDir, "events.schema.json"));
|
|
1368
|
+
const hasAssetsAfterCopy = existsSync3(join2(runtimeRoot, ".env.example")) && existsSync3(join2(runtimeRoot, "vision.example.md")) && existsSync3(join2(runtimeRoot, "configs", "default.toml")) && existsSync3(join2(runtimeRoot, "prompts")) && hasProtocolSchemasAfterCopy;
|
|
989
1369
|
if (!hasAssetsAfterCopy) {
|
|
990
1370
|
await downloadRuntimeAssetsFromSourceTag(runtimeRoot, runtimeTag);
|
|
991
1371
|
}
|
|
@@ -995,36 +1375,77 @@ async function ensureRuntimeAssets(runtimeRoot, runtimeTag) {
|
|
|
995
1375
|
writeTextFileIfMissing(join2(runtimeRoot, ".env"), `# Local PushPals runtime environment
|
|
996
1376
|
`);
|
|
997
1377
|
const localExamplePath = join2(runtimeRoot, "configs", "local.example.toml");
|
|
998
|
-
if (
|
|
999
|
-
writeTextFileIfMissing(join2(runtimeRoot, "configs", "local.toml"),
|
|
1378
|
+
if (existsSync3(localExamplePath)) {
|
|
1379
|
+
writeTextFileIfMissing(join2(runtimeRoot, "configs", "local.toml"), readFileSync3(localExamplePath, "utf8"));
|
|
1000
1380
|
} else {
|
|
1001
1381
|
writeTextFileIfMissing(join2(runtimeRoot, "configs", "local.toml"), `# Local PushPals runtime overrides
|
|
1002
1382
|
`);
|
|
1003
1383
|
}
|
|
1004
1384
|
}
|
|
1385
|
+
function resolveDeferredRuntimeTagHint(explicitTag) {
|
|
1386
|
+
return String(explicitTag || process.env.PUSHPALS_RUNTIME_TAG || "").trim();
|
|
1387
|
+
}
|
|
1388
|
+
async function prepareCliRuntime(opts) {
|
|
1389
|
+
const runtimeRoot = resolve3(opts.runtimeRoot || process.env.PUSHPALS_RUNTIME_ROOT || resolveDefaultRuntimeRoot());
|
|
1390
|
+
if (repoLooksLikePushPalsSourceCheckout(opts.repoRoot)) {
|
|
1391
|
+
return {
|
|
1392
|
+
runtimeRoot,
|
|
1393
|
+
runtimeTag: "",
|
|
1394
|
+
runtimePreflight: evaluateClientRuntimePreflight({
|
|
1395
|
+
projectRoot: opts.repoRoot
|
|
1396
|
+
}),
|
|
1397
|
+
preflightUsesEmbeddedRuntime: false
|
|
1398
|
+
};
|
|
1399
|
+
}
|
|
1400
|
+
seedRuntimePreflightAssets(runtimeRoot);
|
|
1401
|
+
return {
|
|
1402
|
+
runtimeRoot,
|
|
1403
|
+
runtimeTag: resolveDeferredRuntimeTagHint(opts.runtimeTag),
|
|
1404
|
+
runtimePreflight: evaluateClientRuntimePreflight({
|
|
1405
|
+
projectRoot: opts.repoRoot,
|
|
1406
|
+
runtimeRoot,
|
|
1407
|
+
visionTemplateRoot: runtimeRoot
|
|
1408
|
+
}),
|
|
1409
|
+
preflightUsesEmbeddedRuntime: true
|
|
1410
|
+
};
|
|
1411
|
+
}
|
|
1412
|
+
function emitCliRuntimePreflight(result) {
|
|
1413
|
+
const lines = formatClientRuntimePreflightLines(result, "[pushpals]");
|
|
1414
|
+
if (result.ok) {
|
|
1415
|
+
for (const line of lines)
|
|
1416
|
+
console.log(line);
|
|
1417
|
+
return;
|
|
1418
|
+
}
|
|
1419
|
+
for (const line of lines)
|
|
1420
|
+
console.error(line);
|
|
1421
|
+
}
|
|
1005
1422
|
function runtimeBinaryFilename(serviceName, platformKey) {
|
|
1006
1423
|
const serviceToken = serviceName === "source_control_manager" ? "source-control-manager" : serviceName;
|
|
1007
1424
|
const extension = platformKey.startsWith("windows-") ? ".exe" : "";
|
|
1008
1425
|
return `pushpals-runtime-${serviceToken}-${platformKey}${extension}`;
|
|
1009
1426
|
}
|
|
1010
1427
|
function buildEmbeddedRuntimeEnv(baseEnv, opts) {
|
|
1428
|
+
const useRuntimeConfig = opts.useRuntimeConfig !== false;
|
|
1011
1429
|
return {
|
|
1012
1430
|
...baseEnv,
|
|
1013
1431
|
PUSHPALS_REPO_ROOT_OVERRIDE: opts.repoRoot,
|
|
1014
1432
|
PUSHPALS_PROJECT_ROOT_OVERRIDE: opts.repoRoot,
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1433
|
+
...useRuntimeConfig ? {
|
|
1434
|
+
PUSHPALS_CONFIG_DIR_OVERRIDE: join2(opts.runtimeRoot, "configs"),
|
|
1435
|
+
PUSHPALS_PROMPTS_ROOT_OVERRIDE: opts.runtimeRoot
|
|
1436
|
+
} : {
|
|
1437
|
+
PUSHPALS_PROMPTS_ROOT_OVERRIDE: opts.repoRoot
|
|
1438
|
+
},
|
|
1439
|
+
PUSHPALS_PROTOCOL_SCHEMAS_DIR: join2(opts.runtimeRoot, "protocol", "schemas")
|
|
1019
1440
|
};
|
|
1020
1441
|
}
|
|
1021
1442
|
function timestampFileToken() {
|
|
1022
1443
|
return new Date().toISOString().replace(/[:.]/g, "-");
|
|
1023
1444
|
}
|
|
1024
1445
|
function readLogTail(logPath, maxLines = 40) {
|
|
1025
|
-
if (!
|
|
1446
|
+
if (!existsSync3(logPath))
|
|
1026
1447
|
return "";
|
|
1027
|
-
const raw =
|
|
1448
|
+
const raw = readFileSync3(logPath, "utf8");
|
|
1028
1449
|
const lines = raw.split(/\r?\n/).map((line) => line.trimEnd()).filter((line) => line.length > 0);
|
|
1029
1450
|
if (lines.length === 0)
|
|
1030
1451
|
return "";
|
|
@@ -1058,7 +1479,7 @@ async function ensureRuntimeBinaries(runtimeRoot, runtimeTag) {
|
|
|
1058
1479
|
runtimeBinaries.sourceControlManager
|
|
1059
1480
|
];
|
|
1060
1481
|
for (const binaryPath of requiredAssets) {
|
|
1061
|
-
if (
|
|
1482
|
+
if (existsSync3(binaryPath))
|
|
1062
1483
|
continue;
|
|
1063
1484
|
const assetName = binaryPath.split(/[\\/]/).pop() || "";
|
|
1064
1485
|
await downloadBinaryAsset(runtimeTag, assetName, binaryPath);
|
|
@@ -1193,16 +1614,21 @@ async function probeLocalBuddy(localAgentUrl, authToken) {
|
|
|
1193
1614
|
return await fetchJsonWithTimeout(`${localAgentUrl}/healthz`, { headers: authHeaders(authToken) }, LOCALBUDDY_TIMEOUT_MS);
|
|
1194
1615
|
}
|
|
1195
1616
|
async function autoStartRuntimeServices(opts) {
|
|
1196
|
-
const
|
|
1197
|
-
const
|
|
1198
|
-
const
|
|
1199
|
-
await ensureRuntimeAssets(runtimeRoot, runtimeTag);
|
|
1617
|
+
const { runtimePreflight } = opts.preparedRuntime;
|
|
1618
|
+
const runtimeRoot = opts.preparedRuntime.runtimeRoot;
|
|
1619
|
+
const runtimeTag = opts.preparedRuntime.runtimeTag || await resolveRuntimeReleaseTag(opts.requestedRuntimeTag);
|
|
1200
1620
|
console.log(`[pushpals] LocalBuddy unavailable. Auto-starting runtime for repo: ${opts.repoRoot}`);
|
|
1201
1621
|
console.log(`[pushpals] runtimeRoot=${runtimeRoot}`);
|
|
1202
1622
|
console.log(`[pushpals] runtimeTag=${runtimeTag}`);
|
|
1623
|
+
if (!runtimePreflight.ok) {
|
|
1624
|
+
throw new Error("Embedded runtime preflight failed.");
|
|
1625
|
+
}
|
|
1626
|
+
await ensureRuntimeAssets(runtimeRoot, runtimeTag);
|
|
1627
|
+
const runtimeBinaries = await ensureRuntimeBinaries(runtimeRoot, runtimeTag);
|
|
1203
1628
|
const runtimeEnv = buildEmbeddedRuntimeEnv(process.env, {
|
|
1204
1629
|
repoRoot: opts.repoRoot,
|
|
1205
|
-
runtimeRoot
|
|
1630
|
+
runtimeRoot,
|
|
1631
|
+
useRuntimeConfig: opts.preparedRuntime.preflightUsesEmbeddedRuntime
|
|
1206
1632
|
});
|
|
1207
1633
|
const services = [];
|
|
1208
1634
|
const runToken = timestampFileToken();
|
|
@@ -1308,10 +1734,10 @@ ${tail}` : ""}`);
|
|
|
1308
1734
|
throw new Error(`Timed out waiting for LocalBuddy at ${opts.localAgentUrl} after ${DEFAULT_RUNTIME_BOOT_TIMEOUT_MS}ms`);
|
|
1309
1735
|
}
|
|
1310
1736
|
function readCliState(pathValue) {
|
|
1311
|
-
if (!
|
|
1737
|
+
if (!existsSync3(pathValue))
|
|
1312
1738
|
return {};
|
|
1313
1739
|
try {
|
|
1314
|
-
const raw =
|
|
1740
|
+
const raw = readFileSync3(pathValue, "utf8");
|
|
1315
1741
|
const parsed = JSON.parse(raw);
|
|
1316
1742
|
if (!parsed || typeof parsed !== "object")
|
|
1317
1743
|
return {};
|
|
@@ -1760,7 +2186,6 @@ async function main() {
|
|
|
1760
2186
|
const parsed = parseArgs(argv);
|
|
1761
2187
|
if (!parsed)
|
|
1762
2188
|
return;
|
|
1763
|
-
const config = loadPushPalsConfig();
|
|
1764
2189
|
const cwd = process.cwd();
|
|
1765
2190
|
const repoRoot = await resolveCurrentGitRepoRoot(cwd);
|
|
1766
2191
|
if (!repoRoot) {
|
|
@@ -1769,6 +2194,25 @@ async function main() {
|
|
|
1769
2194
|
console.error("[pushpals] Run from a repo directory, or initialize one with `git init`.");
|
|
1770
2195
|
process.exit(1);
|
|
1771
2196
|
}
|
|
2197
|
+
const preparedRuntime = await prepareCliRuntime({
|
|
2198
|
+
repoRoot,
|
|
2199
|
+
runtimeRoot: parsed.runtimeRoot,
|
|
2200
|
+
runtimeTag: parsed.runtimeTag
|
|
2201
|
+
});
|
|
2202
|
+
console.log("[pushpals] Running runtime preflight...");
|
|
2203
|
+
console.log(`[pushpals] runtimeRoot=${preparedRuntime.runtimeRoot}`);
|
|
2204
|
+
if (preparedRuntime.runtimeTag) {
|
|
2205
|
+
console.log(`[pushpals] runtimeTag=${preparedRuntime.runtimeTag}`);
|
|
2206
|
+
} else if (!preparedRuntime.preflightUsesEmbeddedRuntime) {
|
|
2207
|
+
console.log("[pushpals] runtimeTag=(deferred; using repo config for preflight)");
|
|
2208
|
+
} else {
|
|
2209
|
+
console.log("[pushpals] runtimeTag=(deferred until embedded auto-start is needed)");
|
|
2210
|
+
}
|
|
2211
|
+
emitCliRuntimePreflight(preparedRuntime.runtimePreflight);
|
|
2212
|
+
if (!preparedRuntime.runtimePreflight.ok) {
|
|
2213
|
+
process.exit(1);
|
|
2214
|
+
}
|
|
2215
|
+
const config = preparedRuntime.runtimePreflight.config;
|
|
1772
2216
|
const serverUrl = normalizeUrl(parsed.serverUrl ?? process.env.PUSHPALS_SERVER_URL, config.server.url);
|
|
1773
2217
|
const localAgentUrl = normalizeUrl(parsed.localAgentUrl ?? process.env.EXPO_PUBLIC_LOCAL_AGENT_URL, config.client.localAgentUrl);
|
|
1774
2218
|
const sessionId = String(parsed.sessionId ?? process.env.PUSHPALS_SESSION_ID ?? config.sessionId).trim();
|
|
@@ -1790,8 +2234,8 @@ async function main() {
|
|
|
1790
2234
|
sourceControlManagerPort: config.sourceControlManager.port,
|
|
1791
2235
|
sourceControlManagerRemote: config.sourceControlManager.remote,
|
|
1792
2236
|
authToken,
|
|
1793
|
-
|
|
1794
|
-
|
|
2237
|
+
preparedRuntime,
|
|
2238
|
+
requestedRuntimeTag: parsed.runtimeTag
|
|
1795
2239
|
});
|
|
1796
2240
|
health = await probeLocalBuddy(localAgentUrl, authToken);
|
|
1797
2241
|
} catch (err) {
|
|
@@ -1808,7 +2252,7 @@ async function main() {
|
|
|
1808
2252
|
}
|
|
1809
2253
|
process.exit(1);
|
|
1810
2254
|
}
|
|
1811
|
-
const localBuddyRepo = health.repo ?
|
|
2255
|
+
const localBuddyRepo = health.repo ? resolve3(health.repo) : "";
|
|
1812
2256
|
if (!localBuddyRepo) {
|
|
1813
2257
|
stopAutoStartedServices();
|
|
1814
2258
|
console.error("[pushpals] LocalBuddy health response did not include repo path.");
|
|
@@ -1826,7 +2270,7 @@ async function main() {
|
|
|
1826
2270
|
if (sessionId && sessionId !== localBuddySessionId) {
|
|
1827
2271
|
console.warn(`[pushpals] Requested sessionId=${sessionId}, but LocalBuddy is currently attached to sessionId=${localBuddySessionId}.`);
|
|
1828
2272
|
}
|
|
1829
|
-
const statePath =
|
|
2273
|
+
const statePath = resolve3(repoRoot, ".git", "pushpals-cli-state.json");
|
|
1830
2274
|
const saved = readCliState(statePath);
|
|
1831
2275
|
const preferredHubUrl = normalizeUrl(parsed.monitoringHubUrl ?? process.env.PUSHPALS_MONITOR_URL ?? saved.monitoringHubUrl ?? "");
|
|
1832
2276
|
const monitorPort = parsePositiveInt(process.env.PUSHPALS_CLIENT_PORT, DEFAULT_MONITOR_PORT);
|
|
@@ -1951,6 +2395,8 @@ if (import.meta.main) {
|
|
|
1951
2395
|
}
|
|
1952
2396
|
export {
|
|
1953
2397
|
startEmbeddedMonitoringHub,
|
|
2398
|
+
resolveBundledRuntimeAssetSource,
|
|
2399
|
+
prepareCliRuntime,
|
|
1954
2400
|
buildEmbeddedRuntimeEnv,
|
|
1955
2401
|
buildEmbeddedMonitoringHubHtml
|
|
1956
2402
|
};
|